Skip to content

Commit

Permalink
validation on Select field (#8316)
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
ketanMehtaa and FelixMalfait authored Nov 14, 2024
1 parent 15b8b9b commit 51c54d4
Show file tree
Hide file tree
Showing 22 changed files with 96 additions and 204 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export const variables = {
description: null,
icon: undefined,
label: 'fieldLabel',
name: 'fieldLabel',
name: 'fieldlabel',
options: undefined,
settings: undefined,
objectMetadataId,
Expand Down
Original file line number Diff line number Diff line change
@@ -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<
Expand All @@ -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,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -12,7 +12,7 @@ export const metadataLabelSchema = (existingLabels?: string[]) => {
.refine(
(label) => {
try {
computeMetadataNameFromLabelOrThrow(label);
computeMetadataNameFromLabel(label);
return true;
} catch (error) {
return false;
Expand All @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -15,7 +15,7 @@ const selectOptionSchema = z
.refine(
(option) => {
try {
computeOptionValueFromLabelOrThrow(option.label);
computeOptionValueFromLabel(option.label);
return true;
} catch (error) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ export const SettingsDataModelFieldSelectForm = ({
color={MAIN_COLORS.yellow}
/>
</StyledIconContainer>
<StyledApiKey>API keys</StyledApiKey>
<StyledApiKey>API values</StyledApiKey>
</StyledApiKeyContainer>
</motion.div>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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;
Expand Down Expand Up @@ -124,7 +124,7 @@ export const SettingsDataModelFieldSelectFormOptionRow = ({
onChange={(input) =>
onChange({
...option,
value: getOptionValueFromLabel(input),
value: computeOptionValueFromLabel(input),
})
}
RightIcon={isDefault ? IconCheck : undefined}
Expand Down Expand Up @@ -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}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ({
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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[],
Expand All @@ -15,6 +15,6 @@ export const generateNewSelectOption = (
id: v4(),
label: newOptionLabel,
position: options.length,
value: getOptionValueFromLabel(newOptionLabel),
value: computeOptionValueFromLabel(newOptionLabel),
};
};

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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({})
Expand Down Expand Up @@ -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),
}
: {}),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
});
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
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>(
(values) => ({
...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,
}),
);
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const METADATA_LABEL_VALID_PATTERN = /^[^0-9].*$/;
export const METADATA_LABEL_VALID_PATTERN = /^.*$/;
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const OPTION_VALUE_VALID_PATTERN = /^[a-zA-Z0-9]+$/;
export const OPTION_VALUE_VALID_PATTERN = /^[A-Z_][A-Z0-9_]*$/;
Original file line number Diff line number Diff line change
@@ -1,27 +1,9 @@
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';

describe('computeMetadataNameFromLabel', () => {
it('throws if empty label', () => {
const label = ' ';

expect(() => computeMetadataNameFromLabelOrThrow(label)).toThrow();
});

it('computes name for 1 char long label', () => {
const label = 'a';

expect(computeMetadataNameFromLabelOrThrow(label)).toEqual('a');
});

it('throws if label starts with digits', () => {
const label = '1string';

expect(() => computeMetadataNameFromLabelOrThrow(label)).toThrow();
});

it('computes name for label with non-latin char', () => {
const label = 'λλλ!';

expect(computeMetadataNameFromLabelOrThrow(label)).toEqual('lll');
expect(computeMetadataNameFromLabel(label)).toEqual('lll');
});
});

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
import { METADATA_NAME_VALID_PATTERN } from '~/pages/settings/data-model/constants/MetadataNameValidPattern';
import { transliterateAndFormatOrThrow } from '~/pages/settings/data-model/utils/transliterate-and-format.utils';
import camelCase from 'lodash.camelcase';
import { slugify } from 'transliteration';

export const computeMetadataNameFromLabelOrThrow = (label: string): string => {
if (label === '') {
export const computeMetadataNameFromLabel = (label: string): string => {
const prefixedLabel = /^\d/.test(label) ? `n${label}` : label;

if (prefixedLabel === '') {
return '';
}
return transliterateAndFormatOrThrow(label, METADATA_NAME_VALID_PATTERN);

const formattedString = slugify(prefixedLabel, {
trim: true,
separator: '_',
allowedChars: 'a-zA-Z0-9',
});

if (formattedString === '') {
throw new Error('Invalid label');
}

return camelCase(formattedString);
};
Loading

0 comments on commit 51c54d4

Please sign in to comment.