validation on Select field (#8316)
fix #8204 I changed "API keys" to "API values". Stopped inputting special characters in Select field option keys. @lucasbordeau please check the changes and tell me if I need to do any other changes. :) --------- Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
@ -116,7 +116,7 @@ export const variables = {
|
||||
description: null,
|
||||
icon: undefined,
|
||||
label: 'fieldLabel',
|
||||
name: 'fieldLabel',
|
||||
name: 'fieldlabel',
|
||||
options: undefined,
|
||||
settings: undefined,
|
||||
objectMetadataId,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { computeMetadataNameFromLabelOrThrow } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
|
||||
import { computeMetadataNameFromLabel } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
|
||||
|
||||
export const formatFieldMetadataItemInput = (
|
||||
input: Partial<
|
||||
@ -22,7 +22,7 @@ export const formatFieldMetadataItemInput = (
|
||||
description: input.description?.trim() ?? null,
|
||||
icon: input.icon,
|
||||
label,
|
||||
name: label ? computeMetadataNameFromLabelOrThrow(label) : undefined,
|
||||
name: label ? computeMetadataNameFromLabel(label) : undefined,
|
||||
options: input.options,
|
||||
settings: input.settings,
|
||||
};
|
||||
|
||||
@ -2,7 +2,7 @@ import { errors } from '@/settings/data-model/fields/forms/utils/errorMessages';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { METADATA_LABEL_VALID_PATTERN } from '~/pages/settings/data-model/constants/MetadataLabelValidPattern';
|
||||
import { computeMetadataNameFromLabelOrThrow } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
|
||||
import { computeMetadataNameFromLabel } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
|
||||
export const metadataLabelSchema = (existingLabels?: string[]) => {
|
||||
return z
|
||||
.string()
|
||||
@ -12,7 +12,7 @@ export const metadataLabelSchema = (existingLabels?: string[]) => {
|
||||
.refine(
|
||||
(label) => {
|
||||
try {
|
||||
computeMetadataNameFromLabelOrThrow(label);
|
||||
computeMetadataNameFromLabel(label);
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
@ -28,9 +28,7 @@ export const metadataLabelSchema = (existingLabels?: string[]) => {
|
||||
if (!existingLabels || !label?.length) {
|
||||
return true;
|
||||
}
|
||||
return !existingLabels.includes(
|
||||
computeMetadataNameFromLabelOrThrow(label),
|
||||
);
|
||||
return !existingLabels.includes(computeMetadataNameFromLabel(label));
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ import { themeColorSchema } from 'twenty-ui';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { computeOptionValueFromLabelOrThrow } from '~/pages/settings/data-model/utils/compute-option-value-from-label.utils';
|
||||
import { computeOptionValueFromLabel } from '~/pages/settings/data-model/utils/compute-option-value-from-label.utils';
|
||||
|
||||
const selectOptionSchema = z
|
||||
.object({
|
||||
@ -15,7 +15,7 @@ const selectOptionSchema = z
|
||||
.refine(
|
||||
(option) => {
|
||||
try {
|
||||
computeOptionValueFromLabelOrThrow(option.label);
|
||||
computeOptionValueFromLabel(option.label);
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
|
||||
@ -266,7 +266,7 @@ export const SettingsDataModelFieldSelectForm = ({
|
||||
color={MAIN_COLORS.yellow}
|
||||
/>
|
||||
</StyledIconContainer>
|
||||
<StyledApiKey>API keys</StyledApiKey>
|
||||
<StyledApiKey>API values</StyledApiKey>
|
||||
</StyledApiKeyContainer>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
@ -18,7 +18,6 @@ import { v4 } from 'uuid';
|
||||
import { FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { EXPANDED_WIDTH_ANIMATION_VARIANTS } from '@/settings/constants/ExpandedWidthAnimationVariants';
|
||||
import { OPTION_VALUE_MAXIMUM_LENGTH } from '@/settings/data-model/constants/OptionValueMaximumLength';
|
||||
import { getOptionValueFromLabel } from '@/settings/data-model/fields/forms/select/utils/getOptionValueFromLabel';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||
@ -27,6 +26,7 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { computeOptionValueFromLabel } from '~/pages/settings/data-model/utils/compute-option-value-from-label.utils';
|
||||
|
||||
type SettingsDataModelFieldSelectFormOptionRowProps = {
|
||||
className?: string;
|
||||
@ -124,7 +124,7 @@ export const SettingsDataModelFieldSelectFormOptionRow = ({
|
||||
onChange={(input) =>
|
||||
onChange({
|
||||
...option,
|
||||
value: getOptionValueFromLabel(input),
|
||||
value: computeOptionValueFromLabel(input),
|
||||
})
|
||||
}
|
||||
RightIcon={isDefault ? IconCheck : undefined}
|
||||
@ -162,14 +162,14 @@ export const SettingsDataModelFieldSelectFormOptionRow = ({
|
||||
value={option.label}
|
||||
onChange={(label) => {
|
||||
const optionNameHasBeenEdited = !(
|
||||
option.value === getOptionValueFromLabel(option.label)
|
||||
option.value === computeOptionValueFromLabel(option.label)
|
||||
);
|
||||
onChange({
|
||||
...option,
|
||||
label,
|
||||
value: optionNameHasBeenEdited
|
||||
? option.value
|
||||
: getOptionValueFromLabel(label),
|
||||
: computeOptionValueFromLabel(label),
|
||||
});
|
||||
}}
|
||||
RightIcon={isDefault ? IconCheck : undefined}
|
||||
|
||||
@ -7,14 +7,14 @@ import {
|
||||
FieldMetadataItemOption,
|
||||
} from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { SettingsDataModelFieldSelectFormValues } from '@/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectForm';
|
||||
import { getOptionValueFromLabel } from '@/settings/data-model/fields/forms/select/utils/getOptionValueFromLabel';
|
||||
import { computeOptionValueFromLabel } from '~/pages/settings/data-model/utils/compute-option-value-from-label.utils';
|
||||
|
||||
const DEFAULT_OPTION: FieldMetadataItemOption = {
|
||||
color: 'green',
|
||||
id: v4(),
|
||||
label: 'Option 1',
|
||||
position: 0,
|
||||
value: getOptionValueFromLabel('Option 1'),
|
||||
value: computeOptionValueFromLabel('Option 1'),
|
||||
};
|
||||
|
||||
export const useSelectSettingsFormInitialValues = ({
|
||||
|
||||
@ -1,39 +0,0 @@
|
||||
import { getOptionValueFromLabel } from '../getOptionValueFromLabel';
|
||||
|
||||
describe('getOptionValueFromLabel', () => {
|
||||
it('should return the option value from the label', () => {
|
||||
const label = 'Example Label';
|
||||
const expected = 'EXAMPLE_LABEL';
|
||||
|
||||
const result = getOptionValueFromLabel(label);
|
||||
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should handle labels with accents', () => {
|
||||
const label = 'Éxàmplè Làbèl';
|
||||
const expected = 'EXAMPLE_LABEL';
|
||||
|
||||
const result = getOptionValueFromLabel(label);
|
||||
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should handle labels with special characters', () => {
|
||||
const label = 'Example!@#$%^&*() Label';
|
||||
const expected = 'EXAMPLE_LABEL';
|
||||
|
||||
const result = getOptionValueFromLabel(label);
|
||||
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should handle labels with emojis', () => {
|
||||
const label = '📱 Example Label';
|
||||
const expected = 'EXAMPLE_LABEL';
|
||||
|
||||
const result = getOptionValueFromLabel(label);
|
||||
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
});
|
||||
@ -3,7 +3,7 @@ import { v4 } from 'uuid';
|
||||
|
||||
import { FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { generateNewSelectOptionLabel } from '@/settings/data-model/fields/forms/select/utils/generateNewSelectOptionLabel';
|
||||
import { getOptionValueFromLabel } from '@/settings/data-model/fields/forms/select/utils/getOptionValueFromLabel';
|
||||
import { computeOptionValueFromLabel } from '~/pages/settings/data-model/utils/compute-option-value-from-label.utils';
|
||||
|
||||
export const generateNewSelectOption = (
|
||||
options: FieldMetadataItemOption[],
|
||||
@ -15,6 +15,6 @@ export const generateNewSelectOption = (
|
||||
id: v4(),
|
||||
label: newOptionLabel,
|
||||
position: options.length,
|
||||
value: getOptionValueFromLabel(newOptionLabel),
|
||||
value: computeOptionValueFromLabel(newOptionLabel),
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
import snakeCase from 'lodash.snakecase';
|
||||
|
||||
import { computeOptionValueFromLabelOrThrow } from '~/pages/settings/data-model/utils/compute-option-value-from-label.utils';
|
||||
|
||||
export const getOptionValueFromLabel = (label: string) => {
|
||||
let transliteratedLabel = label;
|
||||
try {
|
||||
transliteratedLabel = computeOptionValueFromLabelOrThrow(label);
|
||||
} catch (error) {
|
||||
return label;
|
||||
}
|
||||
|
||||
return snakeCase(transliteratedLabel).toUpperCase();
|
||||
};
|
||||
@ -29,7 +29,7 @@ import isEmpty from 'lodash.isempty';
|
||||
import pick from 'lodash.pick';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { updatedObjectSlugState } from '~/pages/settings/data-model/states/updatedObjectSlugState';
|
||||
import { computeMetadataNameFromLabelOrThrow } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
|
||||
import { computeMetadataNameFromLabel } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
|
||||
|
||||
const objectEditFormSchema = z
|
||||
.object({})
|
||||
@ -93,16 +93,14 @@ export const ObjectSettings = ({ objectMetadataItem }: ObjectSettingsProps) => {
|
||||
...values,
|
||||
...(values.labelSingular && dirtyFieldKeys.includes('labelSingular')
|
||||
? {
|
||||
nameSingular: computeMetadataNameFromLabelOrThrow(
|
||||
nameSingular: computeMetadataNameFromLabel(
|
||||
formValues.labelSingular,
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
...(values.labelPlural && dirtyFieldKeys.includes('labelPlural')
|
||||
? {
|
||||
namePlural: computeMetadataNameFromLabelOrThrow(
|
||||
formValues.labelPlural,
|
||||
),
|
||||
namePlural: computeMetadataNameFromLabel(formValues.labelPlural),
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
|
||||
@ -21,7 +21,7 @@ import {
|
||||
TooltipDelay,
|
||||
} from 'twenty-ui';
|
||||
import { z } from 'zod';
|
||||
import { computeMetadataNameFromLabelOrThrow } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
|
||||
import { computeMetadataNameFromLabel } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const settingsDataModelObjectAboutFormSchema = objectMetadataItemSchema
|
||||
@ -144,16 +144,14 @@ export const SettingsDataModelObjectAboutForm = ({
|
||||
|
||||
const fillNameSingularFromLabelSingular = (labelSingular: string) => {
|
||||
isDefined(labelSingular) &&
|
||||
setValue(
|
||||
'nameSingular',
|
||||
computeMetadataNameFromLabelOrThrow(labelSingular),
|
||||
{ shouldDirty: true },
|
||||
);
|
||||
setValue('nameSingular', computeMetadataNameFromLabel(labelSingular), {
|
||||
shouldDirty: true,
|
||||
});
|
||||
};
|
||||
|
||||
const fillNamePluralFromLabelPlural = (labelPlural: string) => {
|
||||
isDefined(labelPlural) &&
|
||||
setValue('namePlural', computeMetadataNameFromLabelOrThrow(labelPlural), {
|
||||
setValue('namePlural', computeMetadataNameFromLabel(labelPlural), {
|
||||
shouldDirty: true,
|
||||
});
|
||||
};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { settingsDataModelObjectAboutFormSchema } from '@/settings/data-model/objects/forms/components/SettingsDataModelObjectAboutForm';
|
||||
import { CreateObjectInput } from '~/generated-metadata/graphql';
|
||||
import { computeMetadataNameFromLabelOrThrow } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
|
||||
import { computeMetadataNameFromLabel } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
|
||||
|
||||
export const settingsCreateObjectInputSchema =
|
||||
settingsDataModelObjectAboutFormSchema.transform<CreateObjectInput>(
|
||||
@ -8,10 +8,9 @@ export const settingsCreateObjectInputSchema =
|
||||
...values,
|
||||
nameSingular:
|
||||
values.nameSingular ??
|
||||
computeMetadataNameFromLabelOrThrow(values.labelSingular),
|
||||
computeMetadataNameFromLabel(values.labelSingular),
|
||||
namePlural:
|
||||
values.namePlural ??
|
||||
computeMetadataNameFromLabelOrThrow(values.labelPlural),
|
||||
values.namePlural ?? computeMetadataNameFromLabel(values.labelPlural),
|
||||
isLabelSyncedWithName: values.isLabelSyncedWithName ?? true,
|
||||
}),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user