refactor: 解决前端打包ts报错

This commit is contained in:
RubyLiu 2023-12-29 16:54:52 +08:00 committed by Craftsman
parent 32aca6799b
commit d19c001a8b
22 changed files with 348 additions and 56 deletions

View File

@ -203,9 +203,9 @@
watchEffect(() => {
props.models.forEach((e) => {
//
let value = null;
let value: string | number | boolean | string[] | number[] | undefined;
if (e.type === 'inputNumber') {
value = null;
value = undefined;
} else if (e.type === 'tagInput') {
value = [];
} else {

View File

@ -202,7 +202,7 @@
async function initFileTypes() {
try {
fileTypeLoading.value = true;
let res = null;
let res: string[] = [];
if (fileType.value === 'storage') {
res = await getRepositoryFileTypes(appStore.currentProjectId);
} else {

View File

@ -47,7 +47,9 @@ export interface RadioProps {
export interface MsSearchSelectSlots {
prefix?: string;
// @ts-ignore
header?: (() => JSX.Element) | Slot<any>;
// @ts-ignore
default?: () => JSX.Element[];
footer?: Slot<any>;
empty?: Slot<any>;

View File

@ -29,6 +29,7 @@ export default function ClipboardRuntime(this: any) {
function encode(nodes: Array<INode>): string {
const _nodes = [];
for (let i = 0, l = nodes.length; i < l; i++) {
// @ts-ignore
_nodes.push(minder.exportNode(nodes[i]));
}
return kmencode(Data.getRegisterProtocol('json').encode(_nodes));

View File

@ -21,6 +21,7 @@ if (!('innerText' in document.createElement('a')) && 'getSelection' in window) {
let i;
if (selection) {
for (i = 0; i < selection.rangeCount; i++) {
// @ts-ignore
ranges[i] = selection.getRangeAt(i);
}
@ -52,7 +53,7 @@ function InputRuntime(this: any) {
this.isGecko = window.kity.Browser.gecko;
const updatePosition = (): void => {
let timer = null;
let timer: null | NodeJS.Timeout = null;
const focusNode = this.minder.getSelectedNode();
if (!focusNode) return;

View File

@ -7,8 +7,8 @@
<div class="text-[var(--color-text-2)]">{{ t('advanceFilter.accordBelow') }}</div>
<div class="ml-[16px]">
<a-select v-model:model-value="accordBelow" size="small">
<a-option value="all">{{ t('advanceFilter.all') }}</a-option>
<a-option value="any">{{ t('advanceFilter.any') }}</a-option>
<a-option value="AND">{{ t('advanceFilter.all') }}</a-option>
<a-option value="OR">{{ t('advanceFilter.any') }}</a-option>
</a-select>
</div>
<div class="ml-[8px] text-[var(--color-text-2)]">{{ t('advanceFilter.condition') }}</div>
@ -212,12 +212,13 @@
import { useI18n } from '@/hooks/useI18n';
import { SelectValue } from '@/models/projectManagement/menuManagement';
import { OptionsItem } from '@/models/setting/log';
import { OPERATOR_MAP } from './index';
import { AccordBelowType, BackEndEnum, FilterFormItem, FilterResult, FilterType } from './type';
import { AccordBelowType, BackEndEnum, CombineItem, FilterFormItem, FilterResult, FilterType } from './type';
const { t } = useI18n();
const accordBelow = ref<AccordBelowType>('all');
const accordBelow = ref<AccordBelowType>('AND');
const formRef = ref<FormInstance | null>(null);
const formModel = reactive<{ list: FilterFormItem[] }>({
list: [],
@ -245,7 +246,7 @@
};
const getOperationOption = (type: FilterType, dataIndex: string) => {
let result = [];
let result: { label: string; value: string }[] = [];
switch (type) {
case FilterType.NUMBER:
result = OPERATOR_MAP.number;
@ -322,15 +323,17 @@
const handleFilter = () => {
formRef.value?.validate((errors) => {
if (!errors) {
const tmpObj: FilterResult = {};
const tmpObj: FilterResult = { accordBelow: 'AND', combine: {} };
const combine: CombineItem = {};
formModel.list.forEach((item) => {
tmpObj[item.dataIndex as string] = {
combine[item.dataIndex as string] = {
operator: item.operator,
value: item.value,
backendType: item.backendType,
};
});
tmpObj.accordBelow = accordBelow.value;
tmpObj.combine = combine;
emit('onSearch', tmpObj);
}
});

View File

@ -82,6 +82,7 @@
};
const handleFilter = (filter: FilterResult) => {
console.log('filter', filter);
emit('advSearch', filter);
};

View File

@ -1,9 +1,30 @@
import { MsCascaderProps } from '@/components/business/ms-cascader/index.vue';
import type { MsSearchSelectProps, RadioProps } from '@/components/business/ms-select';
import type { CascaderOption, TreeNodeData } from '@arco-design/web-vue';
import type { VirtualListProps } from '@arco-design/web-vue/es/_components/virtual-list-v2/interface';
import type { TreeSelectProps } from '@arco-design/web-vue/es/tree-select/interface';
export type CascaderModelValue = string | number | Record<string, any> | (string | number | Record<string, any>)[];
export interface MsCascaderProps {
modelValue: CascaderModelValue;
options: CascaderOption[];
mode?: 'MS' | 'native'; // MS的多选、原生;这里的多选指的是出了一级以外的多选,一级是顶级分类选项只能单选。原生模式使用 arco-design 的 cascader 组件只加了getOptionComputedStyle
prefix?: string; // 输入框前缀
levelTop?: string[]; // 顶级选项,多选时则必传
level?: string; // 顶级选项,该级别为单选选项
multiple?: boolean; // 是否多选
strictly?: boolean; // 是否严格模式
virtualListProps?: VirtualListProps; // 传入开启虚拟滚动
panelWidth?: number; // 下拉框宽度,默认为 150px
placeholder?: string;
loading?: boolean;
optionSize?: 'small' | 'default';
pathMode?: boolean; // 是否开启路径模式
valueKey?: string;
labelKey?: string; // 传入自定义的 labelKey
}
/* eslint-disable no-shadow */
export enum BackEndEnum {
STRING = 'string',
@ -41,10 +62,17 @@ export interface FilterFormItem {
checkProps?: Partial<RadioProps>;
}
export type AccordBelowType = 'all' | 'any';
export type AccordBelowType = 'AND' | 'OR';
export interface CombineItem {
[key: string]: Pick<FilterFormItem, 'value' | 'operator' | 'backendType'>;
}
export interface FilterResult {
[key: string]: Pick<FilterFormItem, 'value' | 'operator' | 'backendType'> | AccordBelowType;
// 匹配模式 所有/任一
accordBelow: AccordBelowType;
// 高级搜索
combine: CombineItem;
}
export interface FilterFormProps {

View File

@ -95,8 +95,8 @@
//
function getControlFormItemsMaps() {
const parentControlsItems = [];
formItems.value.forEach((item: FormItem) => {
const parentControlsItems: FormItem[] = [];
formItems.value.forEach((item) => {
if (!item.displayConditions) {
parentControlsItems.push(item);
} else {

View File

@ -1,7 +1,5 @@
import { FieldRule } from '@arco-design/web-vue';
import { FormRule, Rule } from '@form-create/arco-design';
export type FormItemType =
| 'INPUT'
| 'TEXTAREA'

View File

@ -270,6 +270,7 @@ export default defineComponent({
};
const pageList = computed(() => {
// @ts-ignore
const pageListArr: Array<JSX.Element | JSX.Element[]> = [];
if (pages.value < props.baseSize + props.bufferSize * 2) {

View File

@ -140,4 +140,9 @@ export interface BatchActionQueryParams {
selectAll: boolean; // 是否跨页全选
params?: TableQueryParams; // 查询参数
currentSelectCount: number; // 当前选中的数量
condition?: any; // 查询条件
}
export interface CombineParams {
[key: string]: any;
}

View File

@ -9,7 +9,15 @@ import { useAppStore, useTableStore } from '@/store';
import type { CommonList, TableQueryParams } from '@/models/common';
import { SelectAllEnum } from '@/enums/tableEnum';
import type { MsTableColumn, MsTableDataItem, MsTableErrorStatus, MsTableProps, SetPaginationPrams } from './type';
import { FilterResult } from '../ms-advance-filter/type';
import type {
CombineParams,
MsTableColumn,
MsTableDataItem,
MsTableErrorStatus,
MsTableProps,
SetPaginationPrams,
} from './type';
import type { TableData } from '@arco-design/web-vue';
export interface Pagination {
@ -84,6 +92,8 @@ export default function useTableProps<T>(
// keyword
const keyword = ref('');
// 高级筛选
const advanceFilter = reactive<FilterResult>({ accordBelow: 'AND', combine: {} });
// 是否分页
if (propsRes.value.showPagination) {
@ -151,11 +161,16 @@ export default function useTableProps<T>(
const setLoadListParams = (params?: object) => {
loadListParams.value = params || {};
};
// 设置keyword
const setKeyword = (v: string) => {
keyword.value = v;
};
// 设置 advanceFilter
const setAdvanceFilter = (v: CombineParams) => {
advanceFilter.accordBelow = v.accordBelow;
advanceFilter.combine = v.combine;
};
// 给表格设置选中项 - add rowKey to selectedKeys
const setTableSelected = (key: string) => {
const { selectedKeys } = propsRes.value;
@ -184,6 +199,8 @@ export default function useTableProps<T>(
sort: sortItem.value,
filter: filterItem.value,
keyword: keyword.value,
combine: advanceFilter.combine,
searchMode: advanceFilter.accordBelow,
...loadListParams.value,
});
const tmpArr = data.list;
@ -421,6 +438,7 @@ export default function useTableProps<T>(
setPagination,
setLoadListParams,
setKeyword,
setAdvanceFilter,
resetPagination,
getSelectedCount,
resetSelector,

View File

@ -34,6 +34,7 @@ export interface BugEditCustomField {
value: string;
platformOptionJson?: string; // 选项的 Json
required: boolean;
isMutiple?: boolean;
}
export interface BugEditFormObject {
[key: string]: any;
@ -44,4 +45,11 @@ export interface BugEditCustomFieldItem {
type: string;
value: string;
}
export type BugBatchUpdateFiledType = 'single_select' | 'multiple_select' | 'tag' | 'input' | 'user_selector' | 'date';
export interface BugBatchUpdateFiledForm {
attribute: string;
value: string[];
append: boolean;
inputValue: string;
}
export default {};

View File

@ -8,7 +8,7 @@
>
<template #title>
<div class="flex flex-row items-center">
<div class="ml-[8px]">{{ t('bugManagement.batchEdit') }}</div>
<div>{{ t('bugManagement.batchEdit') }}</div>
<div v-if="selectCount" class="ml-[8px] text-[var(--color-text-4)]">
{{ t('bugManagement.selectedCount', { count: selectCount }) }}
</div>
@ -22,25 +22,99 @@
:label="t('bugManagement.batchUpdate.attribute')"
:rules="[{ required: true }]"
>
<a-select v-model:model-value="form.attribute" :options="[]" />
<a-select v-model:model-value="form.attribute" @change="handleArrtibuteChange">
<a-optgroup :label="t('bugManagement.batchUpdate.systemFiled')">
<a-option
v-for="item in systemOptionList"
:key="item.value"
:disabled="form.attribute === 'status'"
:value="item.value"
>{{ item.label }}</a-option
>
</a-optgroup>
<a-optgroup :label="t('bugManagement.batchUpdate.customFiled')">
<a-option v-for="item in customOptionList" :key="item.value" :value="item.value">{{
item.label
}}</a-option>
</a-optgroup>
</a-select>
</a-form-item>
<a-form-item
v-if="['input', 'date', 'single_select'].includes(valueMode)"
field="inputValue"
asterisk-position="end"
:label="t('bugManagement.batchUpdate.update')"
:rules="[{ required: true }]"
>
<template v-if="valueMode === 'input'">
<a-input v-model:model-value="form.inputValue" :disabled="!form.attribute" />
</template>
<template v-else-if="valueMode === 'date'">
<a-date-picker v-model:model-value="form.inputValue" :disabled="!form.attribute" />
</template>
<template v-else-if="valueMode === 'single_select'">
<a-select v-model:model-value="form.inputValue" :disabled="!form.attribute">
<a-option v-for="item in customFiledOption" :key="item.value" :value="item.value">{{
item.text
}}</a-option>
</a-select>
</template>
</a-form-item>
<a-form-item
v-else
field="value"
asterisk-position="end"
:label="t('bugManagement.batchUpdate.update')"
:rules="[{ required: true }]"
>
<a-select v-model:model-value="form.value" :disabled="!form.attribute" :options="[]" />
<template v-if="valueMode === 'tag'">
<a-input-tag v-model:model-value="form.value" :disabled="!form.attribute" />
</template>
<template v-else-if="valueMode === 'user_selector'">
<MsUserSelector
v-model:model-value="form.value"
:type="UserRequestTypeEnum.PROJECT_PERMISSION_MEMBER"
:load-option-params="{ projectId: appStore.currentProjectId }"
:disabled="!form.attribute"
/>
</template>
<template v-else-if="valueMode === 'multiple_select'">
<a-select v-model:model-value="form.value" :disabled="!form.attribute" multiple>
<a-option v-for="item in customFiledOption" :key="item.value" :value="item.value">{{
item.text
}}</a-option>
</a-select>
</template>
</a-form-item>
</a-form>
</div>
<template #footer>
<a-button type="secondary" :loading="loading" @click="handleCancel">
{{ t('common.cancel') }}
</a-button>
<a-button type="primary" :loading="loading" @click="handleConfirm">
{{ t('common.update') }}
</a-button>
<div class="flex flex-row items-center justify-between">
<div>
<div v-if="showAppend" class="flex flex-row items-center gap-[4px]">
<a-switch v-model:model-value="form.append" size="small" />
<span class="text-[var(--color-text-1)]">{{ t('bugManagement.batchUpdate.update') }}</span>
<a-tooltip position="top">
<template #content>
<div>{{ t('bugManagement.batchUpdate.openAppend') }}</div>
<div>{{ t('bugManagement.batchUpdate.closeAppend') }}</div>
</template>
<MsIcon
type="icon-icon-maybe_outlined"
class="text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
/>
</a-tooltip>
</div>
</div>
<div class="flex flex-row gap-[8px]"
><a-button type="secondary" :loading="loading" @click="handleCancel">
{{ t('common.cancel') }}
</a-button>
<a-button type="primary" :loading="loading" @click="handleConfirm">
{{ t('common.update') }}
</a-button></div
>
</div>
</template>
</a-modal>
</template>
@ -50,19 +124,45 @@
import { type FormInstance, Message, type ValidatedError } from '@arco-design/web-vue';
import { BatchActionQueryParams } from '@/components/pure/ms-table/type';
import { MsUserSelector } from '@/components/business/ms-user-selector';
import { UserRequestTypeEnum } from '@/components/business/ms-user-selector/utils';
import { updateBatchBug } from '@/api/modules/bug-management';
import { useI18n } from '@/hooks/useI18n';
import { useAppStore } from '@/store';
import type { BugBatchUpdateFiledType } from '@/models/bug-management';
import { BugBatchUpdateFiledForm, BugEditCustomField } from '@/models/bug-management';
import { SelectValue } from '@/models/projectManagement/menuManagement';
const { t } = useI18n();
const props = defineProps<{
visible: boolean;
selectParam: BatchActionQueryParams;
customFields: BugEditCustomField[];
}>();
const emit = defineEmits<{
(e: 'submit'): void;
(e: 'update:visible', value: boolean): void;
}>();
const appStore = useAppStore();
const selectCount = computed(() => props.selectParam.currentSelectCount);
const systemOptionList = computed(() => [
{
label: t('bugManagement.batchUpdate.handleUser'),
value: 'handleUser',
},
{
label: t('bugManagement.batchUpdate.tag'),
value: 'tag',
},
]);
const customOptionList = computed(() => {
return props.customFields.map((item) => ({
label: item.fieldName,
value: item.fieldId,
}));
});
const currentVisible = computed({
get() {
return props.visible;
@ -73,24 +173,71 @@
});
const loading = ref(false);
const form = reactive({
const form = reactive<BugBatchUpdateFiledForm>({
//
attribute: '',
//
value: [],
append: false,
inputValue: '',
});
const valueMode = ref<BugBatchUpdateFiledType>('single_select');
const showAppend = ref(false);
const formRef = ref<FormInstance>();
const handleCancel = () => {
currentVisible.value = false;
loading.value = false;
};
const customFiledOption = ref<{ text: string; value: string }[]>([]);
const handleArrtibuteChange = (value: SelectValue) => {
form.value = [];
form.inputValue = '';
if (value === 'tag') {
valueMode.value = 'tag';
showAppend.value = true;
} else if (value === 'handleUser') {
valueMode.value = 'user_selector';
showAppend.value = true;
} else {
//
const customField = props.customFields.find((item) => item.fieldId === value);
if (customField) {
if (customField.type?.toLowerCase() === 'input') {
showAppend.value = false;
valueMode.value = 'input';
form.inputValue = '';
} else {
// select
customFiledOption.value = JSON.parse(customField.platformOptionJson as string) || [];
const isMutiple = customField.type?.toLocaleLowerCase() === 'select' && customField.isMutiple;
showAppend.value = isMutiple || false;
valueMode.value = isMutiple ? 'multiple_select' : 'single_select';
}
}
}
};
const handleConfirm = () => {
formRef.value?.validate(async (errors: undefined | Record<string, ValidatedError>) => {
if (!errors) {
try {
loading.value = true;
const params = {
excludeIds: props.selectParam.excludeIds,
selectIds: props.selectParam.selectedIds,
selectAll: props.selectParam.selectAll,
//
condition: props.selectParam.condition,
projectId: appStore.currentProjectId,
[form.attribute]: form.value || form.inputValue,
append: form.append,
};
await updateBatchBug(params);
Message.success(t('common.deleteSuccess'));
handleCancel();
emit('submit');

View File

@ -165,7 +165,6 @@
import { AssociatedList, AttachFileInfo } from '@/models/caseManagement/featureCase';
import { TableQueryParams } from '@/models/common';
import { SelectValue } from '@/models/projectManagement/menuManagement';
import { FormCreateKeyEnum } from '@/enums/formCreateEnum';
import { convertToFile } from '../case-management/caseManagementFeature/components/utils';

View File

@ -1,6 +1,11 @@
<template>
<MsCard simple>
<MsAdvanceFilter :filter-config-list="filterConfigList" :row-count="filterRowCount" @keyword-search="fetchData">
<MsAdvanceFilter
:filter-config-list="filterConfigList"
:row-count="filterRowCount"
@keyword-search="fetchData"
@adv-search="handleAdvSearch"
>
<template #left>
<div class="flex gap-[12px]">
<a-button type="primary" @click="handleCreate">{{ t('bugManagement.createBug') }} </a-button>
@ -118,7 +123,7 @@
import { Message, TableData } from '@arco-design/web-vue';
import { MsAdvanceFilter, timeSelectOptions } from '@/components/pure/ms-advance-filter';
import { FilterFormItem, FilterType } from '@/components/pure/ms-advance-filter/type';
import { FilterFormItem, FilterResult, FilterType } from '@/components/pure/ms-advance-filter/type';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsCard from '@/components/pure/ms-card/index.vue';
import MsExportDrawer from '@/components/pure/ms-export-drawer/index.vue';
@ -148,7 +153,7 @@
import { useAppStore, useTableStore } from '@/store';
import useLicenseStore from '@/store/modules/setting/license';
import { BugListItem } from '@/models/bug-management';
import { BugEditCustomField, BugListItem } from '@/models/bug-management';
import { RouteEnum } from '@/enums/routeEnum';
import { ColumnEditTypeEnum, TableKeyEnum } from '@/enums/tableEnum';
@ -169,13 +174,14 @@
const activeCaseIndex = ref<number>(0);
const currentDeleteObj = reactive<{ id: string; title: string }>({ id: '', title: '' });
const deleteVisible = ref(false);
const batchEditVisible = ref(true);
const batchEditVisible = ref(false);
const keyword = ref('');
const filterResult = ref<FilterResult>({ accordBelow: 'AND', combine: {} });
const licenseStore = useLicenseStore();
const isXpack = computed(() => licenseStore.hasLicense());
const { openDeleteModal } = useModal();
//
const customFields = ref<MsTableColumn[]>([]);
const customFields = ref<BugEditCustomField[]>([]);
//
const currentSelectParams = ref<BatchActionQueryParams>({ selectAll: false, currentSelectCount: 0 });
@ -327,19 +333,20 @@
}
};
const { propsRes, propsEvent, setKeyword, setLoadListParams, setProps, resetSelector, loadList } = useTable(
getBugList,
{
tableKey: TableKeyEnum.BUG_MANAGEMENT,
selectable: true,
noDisable: false,
showJumpMethod: true,
showSetting: true,
scroll: { x: '1800px' },
},
undefined,
(record) => handleNameChange(record)
);
const { propsRes, propsEvent, setKeyword, setAdvanceFilter, setLoadListParams, setProps, resetSelector, loadList } =
useTable(
getBugList,
{
tableKey: TableKeyEnum.BUG_MANAGEMENT,
selectable: true,
noDisable: false,
showJumpMethod: true,
showSetting: true,
scroll: { x: '1800px' },
},
undefined,
(record) => handleNameChange(record)
);
const tableBatchActions = {
baseAction: [
@ -363,6 +370,50 @@
setKeyword(v);
keyword.value = v;
await loadList();
customFields.value = propsRes.value.customFields || [
{
fieldId: 'handleUser',
fieldName: '处理人',
required: true,
apiFieldId: null,
defaultValue: null,
type: 'select',
options: null,
platformOptionJson:
'[{"text":"副驾仙人","value":"728495172886530"},{"text":"社恐的程序员","value":"728495172886645"}]',
supportSearch: null,
optionMethod: null,
isMutiple: true,
},
{
fieldId: 'status',
fieldName: '状态',
required: true,
apiFieldId: null,
defaultValue: null,
type: 'select',
options: null,
platformOptionJson: '[{"text":"新建","value":"100555929702892317"}]',
supportSearch: null,
optionMethod: null,
},
];
};
const handleAdvSearch = (filter: FilterResult) => {
filterResult.value = filter;
const { accordBelow, combine } = filter;
setAdvanceFilter(filter);
currentSelectParams.value = {
...currentSelectParams.value,
condition: {
keyword: keyword.value,
searchMode: accordBelow,
filter: propsRes.value.filter,
combine,
},
};
fetchData();
};
const exportConfirm = async (option: MsExportDrawerOption[]) => {
@ -472,8 +523,16 @@
const handleBatchEdit = (params: BatchActionQueryParams) => {
batchEditVisible.value = true;
// eslint-disable-next-line no-console
console.log('create', params);
const condition = {
keyword: keyword.value,
searchMode: filterResult.value.accordBelow,
filter: propsRes.value.filter,
combine: filterResult.value.combine,
};
currentSelectParams.value = {
...params,
condition,
};
};
const handleExport = () => {

View File

@ -69,6 +69,26 @@ export default {
attribute: '选择属性',
update: '批量更新为',
updatePlaceholder: '请选择更新后的选项',
systemFiled: '系统字段',
customFiled: '自定义字段',
append: '追加',
openAppend: '开启: 追加字段',
closeAppend: '关闭: 覆盖原有字段',
handleUser: '处理人',
tag: '标签',
},
severityO: {
fatal: '致命',
serious: '严重',
general: '一般',
reminder: '提醒',
},
statusO: {
create: '新建',
processing: '处理中',
resolved: '已解决',
closed: '已关闭',
refused: '已拒绝',
},
},
};

View File

@ -394,7 +394,7 @@
async function initFileTypes() {
try {
fileTypeLoading.value = true;
let res = null;
let res: string[] = [];
if (fileType.value === 'storage') {
res = await getRepositoryFileTypes(appStore.currentProjectId);
} else {

View File

@ -245,7 +245,7 @@
},
},
(item) => {
const children = [];
const children: TableMessageChildrenItem[] = [];
for (let i = 0; i < (item as unknown as MessageItem).messageTaskTypeDTOList.length; i++) {
const child = (item as unknown as MessageItem).messageTaskTypeDTOList[i];
for (let j = 0; j < child.messageTaskDetailDTOList.length; j++) {

View File

@ -480,8 +480,8 @@
}
return e;
});
let projectIds = [];
let organizationIds = [];
let projectIds: any[] = [];
let organizationIds: any[] = [];
if (!MENU_LEVEL.includes(level.value) && typeof operateRange.value[0] === 'object') {
if (operateRange.value[0].level === MENU_LEVEL[1]) {

View File

@ -39,6 +39,7 @@
//
"@/*": ["./src/*"],
"#/*": ["types/*"]
}
},
"noImplicitAny": false,
}
}