diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFieldMetadataItem.ts b/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFieldMetadataItem.ts
index b69870f22..0facf2c51 100644
--- a/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFieldMetadataItem.ts
+++ b/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFieldMetadataItem.ts
@@ -116,7 +116,7 @@ export const variables = {
description: null,
icon: undefined,
label: 'fieldLabel',
- name: 'fieldLabel',
+ name: 'fieldlabel',
options: undefined,
settings: undefined,
objectMetadataId,
diff --git a/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemInput.ts b/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemInput.ts
index 5900beed1..bfcca728d 100644
--- a/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemInput.ts
+++ b/packages/twenty-front/src/modules/object-metadata/utils/formatFieldMetadataItemInput.ts
@@ -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,
};
diff --git a/packages/twenty-front/src/modules/object-metadata/validation-schemas/metadataLabelSchema.ts b/packages/twenty-front/src/modules/object-metadata/validation-schemas/metadataLabelSchema.ts
index 4e196f0fa..96a160240 100644
--- a/packages/twenty-front/src/modules/object-metadata/validation-schemas/metadataLabelSchema.ts
+++ b/packages/twenty-front/src/modules/object-metadata/validation-schemas/metadataLabelSchema.ts
@@ -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;
}
diff --git a/packages/twenty-front/src/modules/object-metadata/validation-schemas/selectOptionsSchema.ts b/packages/twenty-front/src/modules/object-metadata/validation-schemas/selectOptionsSchema.ts
index 3893306c8..b91bdfade 100644
--- a/packages/twenty-front/src/modules/object-metadata/validation-schemas/selectOptionsSchema.ts
+++ b/packages/twenty-front/src/modules/object-metadata/validation-schemas/selectOptionsSchema.ts
@@ -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;
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectForm.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectForm.tsx
index 6796f34a2..48af1e38e 100644
--- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectForm.tsx
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectForm.tsx
@@ -266,7 +266,7 @@ export const SettingsDataModelFieldSelectForm = ({
color={MAIN_COLORS.yellow}
/>
- API keys
+ API values
)}
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectFormOptionRow.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectFormOptionRow.tsx
index fd169354b..b92c97e5d 100644
--- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectFormOptionRow.tsx
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/components/SettingsDataModelFieldSelectFormOptionRow.tsx
@@ -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}
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/hooks/useSelectSettingsFormInitialValues.ts b/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/hooks/useSelectSettingsFormInitialValues.ts
index 2d19e0507..dc1f745bd 100644
--- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/hooks/useSelectSettingsFormInitialValues.ts
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/hooks/useSelectSettingsFormInitialValues.ts
@@ -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 = ({
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/utils/__tests__/getOptionValueFromLabel.test.ts b/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/utils/__tests__/getOptionValueFromLabel.test.ts
deleted file mode 100644
index 07b60304e..000000000
--- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/utils/__tests__/getOptionValueFromLabel.test.ts
+++ /dev/null
@@ -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);
- });
-});
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/utils/generateNewSelectOption.ts b/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/utils/generateNewSelectOption.ts
index d8289070e..851dd8892 100644
--- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/utils/generateNewSelectOption.ts
+++ b/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/utils/generateNewSelectOption.ts
@@ -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),
};
};
diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/utils/getOptionValueFromLabel.ts b/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/utils/getOptionValueFromLabel.ts
deleted file mode 100644
index 9a263fa6c..000000000
--- a/packages/twenty-front/src/modules/settings/data-model/fields/forms/select/utils/getOptionValueFromLabel.ts
+++ /dev/null
@@ -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();
-};
diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/components/tabs/ObjectSettings.tsx b/packages/twenty-front/src/modules/settings/data-model/object-details/components/tabs/ObjectSettings.tsx
index 105443082..5cdd83653 100644
--- a/packages/twenty-front/src/modules/settings/data-model/object-details/components/tabs/ObjectSettings.tsx
+++ b/packages/twenty-front/src/modules/settings/data-model/object-details/components/tabs/ObjectSettings.tsx
@@ -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),
}
: {}),
};
diff --git a/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectAboutForm.tsx b/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectAboutForm.tsx
index 1e7752d9a..05056a1e5 100644
--- a/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectAboutForm.tsx
+++ b/packages/twenty-front/src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectAboutForm.tsx
@@ -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,
});
};
diff --git a/packages/twenty-front/src/modules/settings/data-model/validation-schemas/settingsCreateObjectInputSchema.ts b/packages/twenty-front/src/modules/settings/data-model/validation-schemas/settingsCreateObjectInputSchema.ts
index 8fa20cdcf..37cc3c2d3 100644
--- a/packages/twenty-front/src/modules/settings/data-model/validation-schemas/settingsCreateObjectInputSchema.ts
+++ b/packages/twenty-front/src/modules/settings/data-model/validation-schemas/settingsCreateObjectInputSchema.ts
@@ -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(
@@ -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,
}),
);
diff --git a/packages/twenty-front/src/pages/settings/data-model/constants/MetadataLabelValidPattern.ts b/packages/twenty-front/src/pages/settings/data-model/constants/MetadataLabelValidPattern.ts
index 8cc887e6a..379d1c951 100644
--- a/packages/twenty-front/src/pages/settings/data-model/constants/MetadataLabelValidPattern.ts
+++ b/packages/twenty-front/src/pages/settings/data-model/constants/MetadataLabelValidPattern.ts
@@ -1 +1 @@
-export const METADATA_LABEL_VALID_PATTERN = /^[^0-9].*$/;
+export const METADATA_LABEL_VALID_PATTERN = /^.*$/;
diff --git a/packages/twenty-front/src/pages/settings/data-model/constants/OptionValueValidPattern.ts b/packages/twenty-front/src/pages/settings/data-model/constants/OptionValueValidPattern.ts
index 2d8ef0210..3db373acc 100644
--- a/packages/twenty-front/src/pages/settings/data-model/constants/OptionValueValidPattern.ts
+++ b/packages/twenty-front/src/pages/settings/data-model/constants/OptionValueValidPattern.ts
@@ -1 +1 @@
-export const OPTION_VALUE_VALID_PATTERN = /^[a-zA-Z0-9]+$/;
+export const OPTION_VALUE_VALID_PATTERN = /^[A-Z_][A-Z0-9_]*$/;
diff --git a/packages/twenty-front/src/pages/settings/data-model/utils/__tests__/compute-metadata-name-from-label.test.ts b/packages/twenty-front/src/pages/settings/data-model/utils/__tests__/compute-metadata-name-from-label.test.ts
index 972bcaafd..eb9673278 100644
--- a/packages/twenty-front/src/pages/settings/data-model/utils/__tests__/compute-metadata-name-from-label.test.ts
+++ b/packages/twenty-front/src/pages/settings/data-model/utils/__tests__/compute-metadata-name-from-label.test.ts
@@ -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');
});
});
diff --git a/packages/twenty-front/src/pages/settings/data-model/utils/__tests__/compute-option-value-from-label.test.ts b/packages/twenty-front/src/pages/settings/data-model/utils/__tests__/compute-option-value-from-label.test.ts
deleted file mode 100644
index 72b524d8d..000000000
--- a/packages/twenty-front/src/pages/settings/data-model/utils/__tests__/compute-option-value-from-label.test.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { computeOptionValueFromLabelOrThrow } from '~/pages/settings/data-model/utils/compute-option-value-from-label.utils';
-
-describe('computeOptionValueFromLabel', () => {
- it('throws if empty label', () => {
- const label = ' ';
-
- expect(() => computeOptionValueFromLabelOrThrow(label)).toThrow();
- });
-
- it('computes name for 1 char long label', () => {
- const label = 'a';
-
- expect(computeOptionValueFromLabelOrThrow(label)).toEqual('a');
- });
-
- it('compute name if starts with digits', () => {
- const label = '1';
-
- expect(computeOptionValueFromLabelOrThrow(label)).toEqual('1');
- });
-
- it('computes name for label with non-latin char', () => {
- const label = 'λλλ';
-
- expect(computeOptionValueFromLabelOrThrow(label)).toEqual('lll');
- });
-});
diff --git a/packages/twenty-front/src/pages/settings/data-model/utils/compute-metadata-name-from-label.utils.ts b/packages/twenty-front/src/pages/settings/data-model/utils/compute-metadata-name-from-label.utils.ts
index 9a8b46a40..58d727bf9 100644
--- a/packages/twenty-front/src/pages/settings/data-model/utils/compute-metadata-name-from-label.utils.ts
+++ b/packages/twenty-front/src/pages/settings/data-model/utils/compute-metadata-name-from-label.utils.ts
@@ -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);
};
diff --git a/packages/twenty-front/src/pages/settings/data-model/utils/compute-option-value-from-label.utils.ts b/packages/twenty-front/src/pages/settings/data-model/utils/compute-option-value-from-label.utils.ts
index ebf66346a..9298870ad 100644
--- a/packages/twenty-front/src/pages/settings/data-model/utils/compute-option-value-from-label.utils.ts
+++ b/packages/twenty-front/src/pages/settings/data-model/utils/compute-option-value-from-label.utils.ts
@@ -1,6 +1,17 @@
-import { OPTION_VALUE_VALID_PATTERN } from '~/pages/settings/data-model/constants/OptionValueValidPattern';
-import { transliterateAndFormatOrThrow } from '~/pages/settings/data-model/utils/transliterate-and-format.utils';
+import { slugify } from 'transliteration';
-export const computeOptionValueFromLabelOrThrow = (label: string): string => {
- return transliterateAndFormatOrThrow(label, OPTION_VALUE_VALID_PATTERN);
+export const computeOptionValueFromLabel = (label: string): string => {
+ const prefixedLabel = /^\d/.test(label) ? `OPT${label}` : label;
+
+ const formattedString = slugify(prefixedLabel, {
+ trim: true,
+ separator: '_',
+ allowedChars: 'a-zA-Z0-9_',
+ });
+
+ if (formattedString === '') {
+ throw new Error('Invalid label');
+ }
+
+ return formattedString.toUpperCase();
};
diff --git a/packages/twenty-front/src/pages/settings/data-model/utils/transliterate-and-format.utils.ts b/packages/twenty-front/src/pages/settings/data-model/utils/transliterate-and-format.utils.ts
deleted file mode 100644
index b3b441902..000000000
--- a/packages/twenty-front/src/pages/settings/data-model/utils/transliterate-and-format.utils.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import toCamelCase from 'lodash.camelcase';
-import { slugify, transliterate } from 'transliteration';
-
-import { isDefined } from '~/utils/isDefined';
-
-export const transliterateAndFormatOrThrow = (
- string: string,
- validStringPattern: RegExp,
-): string => {
- let formattedString = string;
-
- if (isDefined(formattedString.match(validStringPattern))) {
- return toCamelCase(formattedString);
- }
-
- formattedString = toCamelCase(
- slugify(transliterate(formattedString, { trim: true })),
- );
-
- if (!formattedString.match(validStringPattern)) {
- throw new Error(`"${string}" is not a valid name`);
- }
-
- return formattedString;
-};
diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/validate-object-metadata-input.util.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/validate-object-metadata-input.util.ts
index 8eaa446be..d2333ae1b 100644
--- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/validate-object-metadata-input.util.ts
+++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/validate-object-metadata-input.util.ts
@@ -1,5 +1,4 @@
-import toCamelCase from 'lodash.camelcase';
-import { slugify, transliterate } from 'transliteration';
+import { slugify } from 'transliteration';
import { CreateObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/create-object.input';
import { UpdateObjectPayload } from 'src/engine/metadata-modules/object-metadata/dtos/update-object.input';
@@ -63,30 +62,6 @@ export const validateObjectMetadataInputOrThrow = <
validateNameIsNotTooLongThrow(objectMetadataInput.namePlural);
};
-export const transliterateAndFormatOrThrow = (string?: string): string => {
- if (!string) {
- throw new ObjectMetadataException(
- 'Name is required',
- ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT,
- );
- }
- let formattedString = string;
-
- if (formattedString.match(METADATA_NAME_VALID_PATTERN) !== null) {
- return toCamelCase(formattedString);
- }
-
- formattedString = toCamelCase(
- slugify(transliterate(formattedString, { trim: true })),
- );
-
- if (!formattedString.match(METADATA_NAME_VALID_PATTERN)) {
- throw new Error(`"${string}" is not a valid name`);
- }
-
- return formattedString;
-};
-
const validateNameIsNotReservedKeywordOrThrow = (name?: string) => {
if (name) {
if (reservedKeywords.includes(name)) {
@@ -133,17 +108,41 @@ const validateNameCharactersOrThrow = (name?: string) => {
}
};
-export const computeMetadataNameFromLabelOrThrow = (label: string): string => {
- const formattedString = transliterateAndFormatOrThrow(label);
+export const computeMetadataNameFromLabel = (label: string): string => {
+ if (!label) {
+ throw new ObjectMetadataException(
+ 'Label is required',
+ ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT,
+ );
+ }
- return formattedString;
+ const prefixedLabel = /^\d/.test(label) ? `n${label}` : label;
+
+ if (prefixedLabel === '') {
+ return '';
+ }
+
+ const formattedString = slugify(prefixedLabel, {
+ trim: true,
+ separator: '_',
+ allowedChars: 'a-zA-Z0-9',
+ });
+
+ if (formattedString === '') {
+ throw new ObjectMetadataException(
+ `Invalid label: "${label}"`,
+ ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT,
+ );
+ }
+
+ return camelCase(formattedString);
};
export const validateNameAndLabelAreSyncOrThrow = (
label: string,
name: string,
) => {
- const computedName = computeMetadataNameFromLabelOrThrow(label);
+ const computedName = computeMetadataNameFromLabel(label);
if (name !== computedName) {
throw new ObjectMetadataException(
diff --git a/packages/twenty-ui/src/display/tag/components/Tag.tsx b/packages/twenty-ui/src/display/tag/components/Tag.tsx
index 3b5f84b08..a8ab14dd3 100644
--- a/packages/twenty-ui/src/display/tag/components/Tag.tsx
+++ b/packages/twenty-ui/src/display/tag/components/Tag.tsx
@@ -43,12 +43,11 @@ const StyledTag = styled.h3<{
border: ${({ variant, theme }) =>
variant === 'outline' || variant === 'border'
? `1px ${variant === 'border' ? 'solid' : 'dashed'} ${theme.border.color.strong}`
- : ''};
+ : 'none'};
gap: ${spacing1};
- min-width: ${({ preventShrink }) =>
- preventShrink ? 'fit-content' : 'none;'};
+ min-width: ${({ preventShrink }) => (preventShrink ? 'fit-content' : 'none')};
`;
const StyledContent = styled.span`