Fix display empty value if boolean instead of false on show page (#4468)
* default value boolean fixed * fixed creation, fixed updating a value to false * fixed default value for default value if boolean * fixed tests --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
@ -17,7 +17,7 @@ export const useFieldMetadataItem = () => {
|
|||||||
const { deleteOneFieldMetadataItem } = useDeleteOneFieldMetadataItem();
|
const { deleteOneFieldMetadataItem } = useDeleteOneFieldMetadataItem();
|
||||||
|
|
||||||
const createMetadataField = (
|
const createMetadataField = (
|
||||||
input: Pick<Field, 'label' | 'icon' | 'description'> & {
|
input: Pick<Field, 'label' | 'icon' | 'description' | 'defaultValue'> & {
|
||||||
defaultValue?: unknown;
|
defaultValue?: unknown;
|
||||||
objectMetadataId: string;
|
objectMetadataId: string;
|
||||||
options?: Omit<FieldMetadataOption, 'id'>[];
|
options?: Omit<FieldMetadataOption, 'id'>[];
|
||||||
@ -26,7 +26,9 @@ export const useFieldMetadataItem = () => {
|
|||||||
) => {
|
) => {
|
||||||
const formatedInput = formatFieldMetadataItemInput(input);
|
const formatedInput = formatFieldMetadataItemInput(input);
|
||||||
const defaultValue = input.defaultValue
|
const defaultValue = input.defaultValue
|
||||||
? `'${input.defaultValue}'`
|
? typeof input.defaultValue == 'string'
|
||||||
|
? `'${input.defaultValue}'`
|
||||||
|
: input.defaultValue
|
||||||
: formatedInput.defaultValue ?? undefined;
|
: formatedInput.defaultValue ?? undefined;
|
||||||
|
|
||||||
return createOneFieldMetadataItem({
|
return createOneFieldMetadataItem({
|
||||||
@ -38,14 +40,25 @@ export const useFieldMetadataItem = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const editMetadataField = (
|
const editMetadataField = (
|
||||||
input: Pick<Field, 'id' | 'label' | 'icon' | 'description'> & {
|
input: Pick<
|
||||||
|
Field,
|
||||||
|
'id' | 'label' | 'icon' | 'description' | 'defaultValue'
|
||||||
|
> & {
|
||||||
options?: FieldMetadataOption[];
|
options?: FieldMetadataOption[];
|
||||||
},
|
},
|
||||||
) =>
|
) => {
|
||||||
updateOneFieldMetadataItem({
|
const formatedInput = formatFieldMetadataItemInput(input);
|
||||||
|
const defaultValue = input.defaultValue
|
||||||
|
? typeof input.defaultValue == 'string'
|
||||||
|
? `'${input.defaultValue}'`
|
||||||
|
: input.defaultValue
|
||||||
|
: formatedInput.defaultValue ?? undefined;
|
||||||
|
|
||||||
|
return updateOneFieldMetadataItem({
|
||||||
fieldMetadataIdToUpdate: input.id,
|
fieldMetadataIdToUpdate: input.id,
|
||||||
updatePayload: formatFieldMetadataItemInput({
|
updatePayload: formatFieldMetadataItemInput({
|
||||||
...input,
|
...input,
|
||||||
|
defaultValue,
|
||||||
// In Edit mode, all options need an id,
|
// In Edit mode, all options need an id,
|
||||||
// so we generate an id for newly created options.
|
// so we generate an id for newly created options.
|
||||||
options: input.options?.map((option) =>
|
options: input.options?.map((option) =>
|
||||||
@ -53,6 +66,7 @@ export const useFieldMetadataItem = () => {
|
|||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const activateMetadataField = (metadataField: FieldMetadataItem) =>
|
const activateMetadataField = (metadataField: FieldMetadataItem) =>
|
||||||
updateOneFieldMetadataItem({
|
updateOneFieldMetadataItem({
|
||||||
|
|||||||
@ -45,7 +45,7 @@ export const formatFieldMetadataItemInput = (
|
|||||||
return {
|
return {
|
||||||
defaultValue: defaultOption
|
defaultValue: defaultOption
|
||||||
? `'${getOptionValueFromLabel(defaultOption.label)}'`
|
? `'${getOptionValueFromLabel(defaultOption.label)}'`
|
||||||
: undefined,
|
: input.defaultValue,
|
||||||
description: input.description?.trim() ?? null,
|
description: input.description?.trim() ?? null,
|
||||||
icon: input.icon,
|
icon: input.icon,
|
||||||
label: input.label.trim(),
|
label: input.label.trim(),
|
||||||
|
|||||||
@ -0,0 +1,60 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { IconCheck, IconX } from '@/ui/display/icon';
|
||||||
|
import { Select } from '@/ui/input/components/Select';
|
||||||
|
import { CardContent } from '@/ui/layout/card/components/CardContent';
|
||||||
|
|
||||||
|
type SettingsDataModelDefaultValueFormProps = {
|
||||||
|
className?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
onChange?: (defaultValue: SettingsDataModelDefaultValue) => void;
|
||||||
|
value?: SettingsDataModelDefaultValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SettingsDataModelDefaultValue = any;
|
||||||
|
|
||||||
|
const StyledContainer = styled(CardContent)`
|
||||||
|
padding-bottom: ${({ theme }) => theme.spacing(3.5)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledLabel = styled.span`
|
||||||
|
color: ${({ theme }) => theme.font.color.light};
|
||||||
|
display: block;
|
||||||
|
font-size: ${({ theme }) => theme.font.size.xs};
|
||||||
|
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||||
|
margin-bottom: 6px;
|
||||||
|
margin-top: ${({ theme }) => theme.spacing(1)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const SettingsDataModelDefaultValueForm = ({
|
||||||
|
className,
|
||||||
|
disabled,
|
||||||
|
onChange,
|
||||||
|
value,
|
||||||
|
}: SettingsDataModelDefaultValueFormProps) => {
|
||||||
|
return (
|
||||||
|
<StyledContainer>
|
||||||
|
<StyledLabel>Default Value</StyledLabel>
|
||||||
|
<Select
|
||||||
|
className={className}
|
||||||
|
fullWidth
|
||||||
|
disabled={disabled}
|
||||||
|
dropdownId="object-field-default-value-select"
|
||||||
|
value={value}
|
||||||
|
onChange={(value) => onChange?.(value)}
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
label: 'True',
|
||||||
|
Icon: IconCheck,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: false,
|
||||||
|
label: 'False',
|
||||||
|
Icon: IconX,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</StyledContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -2,6 +2,7 @@ import styled from '@emotion/styled';
|
|||||||
|
|
||||||
import { useObjectMetadataItemForSettings } from '@/object-metadata/hooks/useObjectMetadataItemForSettings';
|
import { useObjectMetadataItemForSettings } from '@/object-metadata/hooks/useObjectMetadataItemForSettings';
|
||||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||||
|
import { SettingsDataModelDefaultValueForm } from '@/settings/data-model/components/SettingsDataModelDefaultValue';
|
||||||
import { SettingsDataModelPreviewFormCard } from '@/settings/data-model/components/SettingsDataModelPreviewFormCard';
|
import { SettingsDataModelPreviewFormCard } from '@/settings/data-model/components/SettingsDataModelPreviewFormCard';
|
||||||
import {
|
import {
|
||||||
SettingsObjectFieldCurrencyForm,
|
SettingsObjectFieldCurrencyForm,
|
||||||
@ -26,6 +27,7 @@ export type SettingsDataModelFieldSettingsFormValues = {
|
|||||||
currency: SettingsObjectFieldCurrencyFormValues;
|
currency: SettingsObjectFieldCurrencyFormValues;
|
||||||
relation: SettingsObjectFieldRelationFormValues;
|
relation: SettingsObjectFieldRelationFormValues;
|
||||||
select: SettingsObjectFieldSelectFormValues;
|
select: SettingsObjectFieldSelectFormValues;
|
||||||
|
defaultValue: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SettingsDataModelFieldSettingsFormCardProps = {
|
type SettingsDataModelFieldSettingsFormCardProps = {
|
||||||
@ -152,6 +154,13 @@ export const SettingsDataModelFieldSettingsFormCard = ({
|
|||||||
onChange({ select: nextSelectValues })
|
onChange({ select: nextSelectValues })
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
) : fieldMetadataItem.type === FieldMetadataType.Boolean ? (
|
||||||
|
<SettingsDataModelDefaultValueForm
|
||||||
|
value={values.defaultValue}
|
||||||
|
onChange={(nextValueDefaultValue) =>
|
||||||
|
onChange({ defaultValue: nextValueDefaultValue })
|
||||||
|
}
|
||||||
|
/>
|
||||||
) : undefined
|
) : undefined
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -6,12 +6,19 @@ import {
|
|||||||
} from '@/settings/data-model/constants/SettingsFieldTypeConfigs';
|
} from '@/settings/data-model/constants/SettingsFieldTypeConfigs';
|
||||||
import { SettingsSupportedFieldType } from '@/settings/data-model/types/SettingsSupportedFieldType';
|
import { SettingsSupportedFieldType } from '@/settings/data-model/types/SettingsSupportedFieldType';
|
||||||
import { Select, SelectOption } from '@/ui/input/components/Select';
|
import { Select, SelectOption } from '@/ui/input/components/Select';
|
||||||
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
type SettingsDataModelFieldTypeSelectProps = {
|
type SettingsDataModelFieldTypeSelectProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
excludedFieldTypes?: SettingsSupportedFieldType[];
|
excludedFieldTypes?: SettingsSupportedFieldType[];
|
||||||
onChange?: ({ type }: { type: SettingsSupportedFieldType }) => void;
|
onChange?: ({
|
||||||
|
type,
|
||||||
|
defaultValue,
|
||||||
|
}: {
|
||||||
|
type: SettingsSupportedFieldType;
|
||||||
|
defaultValue: any;
|
||||||
|
}) => void;
|
||||||
value?: SettingsSupportedFieldType;
|
value?: SettingsSupportedFieldType;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -41,7 +48,12 @@ export const SettingsDataModelFieldTypeSelect = ({
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
dropdownId="object-field-type-select"
|
dropdownId="object-field-type-select"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(value) => onChange?.({ type: value })}
|
onChange={(value) =>
|
||||||
|
onChange?.({
|
||||||
|
type: value,
|
||||||
|
defaultValue: value === FieldMetadataType.Boolean ? false : undefined,
|
||||||
|
})
|
||||||
|
}
|
||||||
options={fieldTypeOptions}
|
options={fieldTypeOptions}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -26,6 +26,7 @@ const defaultValues = {
|
|||||||
currency: fieldMetadataFormDefaultValues.currency,
|
currency: fieldMetadataFormDefaultValues.currency,
|
||||||
relation: fieldMetadataFormDefaultValues.relation,
|
relation: fieldMetadataFormDefaultValues.relation,
|
||||||
select: fieldMetadataFormDefaultValues.select,
|
select: fieldMetadataFormDefaultValues.select,
|
||||||
|
defaultValue: fieldMetadataFormDefaultValues.defaultValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
const meta: Meta<typeof SettingsDataModelFieldSettingsFormCard> = {
|
const meta: Meta<typeof SettingsDataModelFieldSettingsFormCard> = {
|
||||||
@ -110,6 +111,7 @@ export const WithSelectForm: Story = {
|
|||||||
},
|
},
|
||||||
{ color: 'green', label: '🌏 NGO', value: 'NGO' },
|
{ color: 'green', label: '🌏 NGO', value: 'NGO' },
|
||||||
],
|
],
|
||||||
|
defaultValue: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -23,6 +23,7 @@ describe('useFieldMetadataForm', () => {
|
|||||||
objectMetadataId: '',
|
objectMetadataId: '',
|
||||||
field: { label: '' },
|
field: { label: '' },
|
||||||
},
|
},
|
||||||
|
defaultValue: null,
|
||||||
select: [
|
select: [
|
||||||
{ color: 'green', label: 'Option 1', value: expect.any(String) },
|
{ color: 'green', label: 'Option 1', value: expect.any(String) },
|
||||||
],
|
],
|
||||||
|
|||||||
@ -18,6 +18,7 @@ type FormValues = {
|
|||||||
description?: string;
|
description?: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
label: string;
|
label: string;
|
||||||
|
defaultValue: any;
|
||||||
type: SettingsSupportedFieldType;
|
type: SettingsSupportedFieldType;
|
||||||
} & SettingsDataModelFieldSettingsFormValues;
|
} & SettingsDataModelFieldSettingsFormValues;
|
||||||
|
|
||||||
@ -31,6 +32,7 @@ export const fieldMetadataFormDefaultValues: FormValues = {
|
|||||||
objectMetadataId: '',
|
objectMetadataId: '',
|
||||||
field: { label: '' },
|
field: { label: '' },
|
||||||
},
|
},
|
||||||
|
defaultValue: null,
|
||||||
select: [{ color: 'green', label: 'Option 1', value: v4() }],
|
select: [{ color: 'green', label: 'Option 1', value: v4() }],
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -38,6 +40,7 @@ const fieldSchema = z.object({
|
|||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
icon: z.string().startsWith('Icon'),
|
icon: z.string().startsWith('Icon'),
|
||||||
label: z.string().min(1),
|
label: z.string().min(1),
|
||||||
|
defaultValue: z.any(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const currencySchema = fieldSchema.merge(
|
const currencySchema = fieldSchema.merge(
|
||||||
@ -124,6 +127,8 @@ export const useFieldMetadataForm = () => {
|
|||||||
const [hasCurrencyFormChanged, setHasCurrencyFormChanged] = useState(false);
|
const [hasCurrencyFormChanged, setHasCurrencyFormChanged] = useState(false);
|
||||||
const [hasRelationFormChanged, setHasRelationFormChanged] = useState(false);
|
const [hasRelationFormChanged, setHasRelationFormChanged] = useState(false);
|
||||||
const [hasSelectFormChanged, setHasSelectFormChanged] = useState(false);
|
const [hasSelectFormChanged, setHasSelectFormChanged] = useState(false);
|
||||||
|
const [hasDefaultValueChanged, setHasDefaultValueFormChanged] =
|
||||||
|
useState(false);
|
||||||
const [validationResult, setValidationResult] = useState(
|
const [validationResult, setValidationResult] = useState(
|
||||||
schema.safeParse(formValues),
|
schema.safeParse(formValues),
|
||||||
);
|
);
|
||||||
@ -169,12 +174,14 @@ export const useFieldMetadataForm = () => {
|
|||||||
currency: initialCurrencyFormValues,
|
currency: initialCurrencyFormValues,
|
||||||
relation: initialRelationFormValues,
|
relation: initialRelationFormValues,
|
||||||
select: initialSelectFormValues,
|
select: initialSelectFormValues,
|
||||||
|
defaultValue: initalDefaultValue,
|
||||||
...initialFieldFormValues
|
...initialFieldFormValues
|
||||||
} = initialFormValues;
|
} = initialFormValues;
|
||||||
const {
|
const {
|
||||||
currency: nextCurrencyFormValues,
|
currency: nextCurrencyFormValues,
|
||||||
relation: nextRelationFormValues,
|
relation: nextRelationFormValues,
|
||||||
select: nextSelectFormValues,
|
select: nextSelectFormValues,
|
||||||
|
defaultValue: nextDefaultValue,
|
||||||
...nextFieldFormValues
|
...nextFieldFormValues
|
||||||
} = nextFormValues;
|
} = nextFormValues;
|
||||||
|
|
||||||
@ -193,6 +200,10 @@ export const useFieldMetadataForm = () => {
|
|||||||
nextFieldFormValues.type === FieldMetadataType.Select &&
|
nextFieldFormValues.type === FieldMetadataType.Select &&
|
||||||
!isDeeplyEqual(initialSelectFormValues, nextSelectFormValues),
|
!isDeeplyEqual(initialSelectFormValues, nextSelectFormValues),
|
||||||
);
|
);
|
||||||
|
setHasDefaultValueFormChanged(
|
||||||
|
nextFieldFormValues.type === FieldMetadataType.Boolean &&
|
||||||
|
!isDeeplyEqual(initalDefaultValue, nextDefaultValue),
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -203,9 +214,11 @@ export const useFieldMetadataForm = () => {
|
|||||||
hasFieldFormChanged ||
|
hasFieldFormChanged ||
|
||||||
hasCurrencyFormChanged ||
|
hasCurrencyFormChanged ||
|
||||||
hasRelationFormChanged ||
|
hasRelationFormChanged ||
|
||||||
hasSelectFormChanged,
|
hasSelectFormChanged ||
|
||||||
|
hasDefaultValueChanged,
|
||||||
hasRelationFormChanged,
|
hasRelationFormChanged,
|
||||||
hasSelectFormChanged,
|
hasSelectFormChanged,
|
||||||
|
hasDefaultValueChanged,
|
||||||
initForm,
|
initForm,
|
||||||
isInitialized,
|
isInitialized,
|
||||||
isValid: validationResult.success,
|
isValid: validationResult.success,
|
||||||
|
|||||||
@ -83,6 +83,7 @@ export const SettingsObjectFieldEdit = () => {
|
|||||||
formValues,
|
formValues,
|
||||||
handleFormChange,
|
handleFormChange,
|
||||||
hasFieldFormChanged,
|
hasFieldFormChanged,
|
||||||
|
hasDefaultValueChanged,
|
||||||
hasFormChanged,
|
hasFormChanged,
|
||||||
hasRelationFormChanged,
|
hasRelationFormChanged,
|
||||||
hasSelectFormChanged,
|
hasSelectFormChanged,
|
||||||
@ -132,6 +133,7 @@ export const SettingsObjectFieldEdit = () => {
|
|||||||
objectMetadataId: relationObjectMetadataItem?.id || '',
|
objectMetadataId: relationObjectMetadataItem?.id || '',
|
||||||
type: relationType || RelationMetadataType.OneToMany,
|
type: relationType || RelationMetadataType.OneToMany,
|
||||||
},
|
},
|
||||||
|
defaultValue: activeMetadataField.defaultValue,
|
||||||
...(selectOptions?.length ? { select: selectOptions } : {}),
|
...(selectOptions?.length ? { select: selectOptions } : {}),
|
||||||
});
|
});
|
||||||
}, [
|
}, [
|
||||||
@ -170,13 +172,17 @@ export const SettingsObjectFieldEdit = () => {
|
|||||||
label: validatedFormValues.relation.field.label,
|
label: validatedFormValues.relation.field.label,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
if (hasFieldFormChanged || hasSelectFormChanged) {
|
hasFieldFormChanged ||
|
||||||
|
hasSelectFormChanged ||
|
||||||
|
hasDefaultValueChanged
|
||||||
|
) {
|
||||||
await editMetadataField({
|
await editMetadataField({
|
||||||
description: validatedFormValues.description,
|
description: validatedFormValues.description,
|
||||||
icon: validatedFormValues.icon,
|
icon: validatedFormValues.icon,
|
||||||
id: activeMetadataField.id,
|
id: activeMetadataField.id,
|
||||||
label: validatedFormValues.label,
|
label: validatedFormValues.label,
|
||||||
|
defaultValue: validatedFormValues.defaultValue,
|
||||||
options:
|
options:
|
||||||
validatedFormValues.type === FieldMetadataType.Select
|
validatedFormValues.type === FieldMetadataType.Select
|
||||||
? validatedFormValues.select
|
? validatedFormValues.select
|
||||||
@ -255,6 +261,7 @@ export const SettingsObjectFieldEdit = () => {
|
|||||||
currency: formValues.currency,
|
currency: formValues.currency,
|
||||||
relation: formValues.relation,
|
relation: formValues.relation,
|
||||||
select: formValues.select,
|
select: formValues.select,
|
||||||
|
defaultValue: formValues.defaultValue,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Section>
|
</Section>
|
||||||
|
|||||||
@ -213,7 +213,7 @@ export const SettingsObjectNewFieldStep2 = () => {
|
|||||||
amountMicros: null,
|
amountMicros: null,
|
||||||
currencyCode: validatedFormValues.currency.currencyCode,
|
currencyCode: validatedFormValues.currency.currencyCode,
|
||||||
}
|
}
|
||||||
: undefined,
|
: validatedFormValues.defaultValue,
|
||||||
description: validatedFormValues.description,
|
description: validatedFormValues.description,
|
||||||
icon: validatedFormValues.icon,
|
icon: validatedFormValues.icon,
|
||||||
label: validatedFormValues.label ?? '',
|
label: validatedFormValues.label ?? '',
|
||||||
@ -320,6 +320,7 @@ export const SettingsObjectNewFieldStep2 = () => {
|
|||||||
currency: formValues.currency,
|
currency: formValues.currency,
|
||||||
relation: formValues.relation,
|
relation: formValues.relation,
|
||||||
select: formValues.select,
|
select: formValues.select,
|
||||||
|
defaultValue: formValues.defaultValue,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Section>
|
</Section>
|
||||||
|
|||||||
@ -300,10 +300,12 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
|
|||||||
await fieldMetadataRepository.update(id, {
|
await fieldMetadataRepository.update(id, {
|
||||||
...updatableFieldInput,
|
...updatableFieldInput,
|
||||||
defaultValue:
|
defaultValue:
|
||||||
// Todo: we need to handle default value for all field types. Right now we are only allowing update for SELECt
|
// Todo: we handle default value for all field types.
|
||||||
existingFieldMetadata.type !== FieldMetadataType.SELECT
|
![FieldMetadataType.SELECT, FieldMetadataType.BOOLEAN].includes(
|
||||||
|
existingFieldMetadata.type,
|
||||||
|
)
|
||||||
? existingFieldMetadata.defaultValue
|
? existingFieldMetadata.defaultValue
|
||||||
: updatableFieldInput.defaultValue
|
: updatableFieldInput.defaultValue !== null
|
||||||
? updatableFieldInput.defaultValue
|
? updatableFieldInput.defaultValue
|
||||||
: null,
|
: null,
|
||||||
// If the name is updated, the targetColumnMap should be updated as well
|
// If the name is updated, the targetColumnMap should be updated as well
|
||||||
|
|||||||
Reference in New Issue
Block a user