Fixes #6094 Description: Added logic inside SettingsObjectNewFieldStep2.tsx to prevent form submission Current Behaviours: <img width="947" alt="Screenshot 2024-07-03 at 1 45 31 PM" src="https://github.com/twentyhq/twenty/assets/95612797/bef54bc4-fc83-48f3-894a-34445ec64723"> --------- Co-authored-by: Marie Stoppa <marie.stoppa@essec.edu>
This commit is contained in:
@ -6,7 +6,7 @@ describe('metadataLabelSchema', () => {
|
||||
const validMetadataLabel = 'Option 1';
|
||||
|
||||
// When
|
||||
const result = metadataLabelSchema.parse(validMetadataLabel);
|
||||
const result = metadataLabelSchema().parse(validMetadataLabel);
|
||||
|
||||
// Then
|
||||
expect(result).toEqual(validMetadataLabel);
|
||||
@ -16,7 +16,7 @@ describe('metadataLabelSchema', () => {
|
||||
const validMetadataLabel = 'עִבְרִי';
|
||||
|
||||
// When
|
||||
const result = metadataLabelSchema.parse(validMetadataLabel);
|
||||
const result = metadataLabelSchema().parse(validMetadataLabel);
|
||||
|
||||
// Then
|
||||
expect(result).toEqual(validMetadataLabel);
|
||||
|
||||
@ -10,97 +10,99 @@ import {
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { camelCaseStringSchema } from '~/utils/validation-schemas/camelCaseStringSchema';
|
||||
|
||||
export const fieldMetadataItemSchema = z.object({
|
||||
__typename: z.literal('field').optional(),
|
||||
createdAt: z.string().datetime(),
|
||||
defaultValue: z.any().optional(),
|
||||
description: z.string().trim().nullable().optional(),
|
||||
fromRelationMetadata: z
|
||||
.object({
|
||||
__typename: z.literal('relation').optional(),
|
||||
id: z.string().uuid(),
|
||||
relationType: z.nativeEnum(RelationMetadataType),
|
||||
toFieldMetadataId: z.string().uuid(),
|
||||
toObjectMetadata: z.object({
|
||||
__typename: z.literal('object').optional(),
|
||||
dataSourceId: z.string().uuid(),
|
||||
export const fieldMetadataItemSchema = (existingLabels?: string[]) => {
|
||||
return z.object({
|
||||
__typename: z.literal('field').optional(),
|
||||
createdAt: z.string().datetime(),
|
||||
defaultValue: z.any().optional(),
|
||||
description: z.string().trim().nullable().optional(),
|
||||
fromRelationMetadata: z
|
||||
.object({
|
||||
__typename: z.literal('relation').optional(),
|
||||
id: z.string().uuid(),
|
||||
isRemote: z.boolean(),
|
||||
isSystem: z.boolean(),
|
||||
namePlural: z.string().trim().min(1),
|
||||
nameSingular: z.string().trim().min(1),
|
||||
}),
|
||||
})
|
||||
.nullable()
|
||||
.optional(),
|
||||
icon: z.string().startsWith('Icon').trim().nullable(),
|
||||
id: z.string().uuid(),
|
||||
isActive: z.boolean(),
|
||||
isCustom: z.boolean(),
|
||||
isNullable: z.boolean(),
|
||||
isSystem: z.boolean(),
|
||||
label: metadataLabelSchema,
|
||||
name: camelCaseStringSchema,
|
||||
options: z
|
||||
.array(
|
||||
z.object({
|
||||
color: themeColorSchema,
|
||||
relationType: z.nativeEnum(RelationMetadataType),
|
||||
toFieldMetadataId: z.string().uuid(),
|
||||
toObjectMetadata: z.object({
|
||||
__typename: z.literal('object').optional(),
|
||||
dataSourceId: z.string().uuid(),
|
||||
id: z.string().uuid(),
|
||||
isRemote: z.boolean(),
|
||||
isSystem: z.boolean(),
|
||||
namePlural: z.string().trim().min(1),
|
||||
nameSingular: z.string().trim().min(1),
|
||||
}),
|
||||
})
|
||||
.nullable()
|
||||
.optional(),
|
||||
icon: z.string().startsWith('Icon').trim().nullable(),
|
||||
id: z.string().uuid(),
|
||||
isActive: z.boolean(),
|
||||
isCustom: z.boolean(),
|
||||
isNullable: z.boolean(),
|
||||
isSystem: z.boolean(),
|
||||
label: metadataLabelSchema(existingLabels),
|
||||
name: camelCaseStringSchema,
|
||||
options: z
|
||||
.array(
|
||||
z.object({
|
||||
color: themeColorSchema,
|
||||
id: z.string().uuid(),
|
||||
label: z.string().trim().min(1),
|
||||
position: z.number(),
|
||||
value: z.string().trim().min(1),
|
||||
}),
|
||||
)
|
||||
.nullable()
|
||||
.optional(),
|
||||
relationDefinition: z
|
||||
.object({
|
||||
__typename: z.literal('RelationDefinition').optional(),
|
||||
relationId: z.string().uuid(),
|
||||
direction: z.nativeEnum(RelationDefinitionType),
|
||||
sourceFieldMetadata: z.object({
|
||||
__typename: z.literal('field').optional(),
|
||||
id: z.string().uuid(),
|
||||
name: z.string().trim().min(1),
|
||||
}),
|
||||
sourceObjectMetadata: z.object({
|
||||
__typename: z.literal('object').optional(),
|
||||
id: z.string().uuid(),
|
||||
namePlural: z.string().trim().min(1),
|
||||
nameSingular: z.string().trim().min(1),
|
||||
}),
|
||||
targetFieldMetadata: z.object({
|
||||
__typename: z.literal('field').optional(),
|
||||
id: z.string().uuid(),
|
||||
name: z.string().trim().min(1),
|
||||
}),
|
||||
targetObjectMetadata: z.object({
|
||||
__typename: z.literal('object').optional(),
|
||||
id: z.string().uuid(),
|
||||
namePlural: z.string().trim().min(1),
|
||||
nameSingular: z.string().trim().min(1),
|
||||
}),
|
||||
})
|
||||
.nullable()
|
||||
.optional(),
|
||||
toRelationMetadata: z
|
||||
.object({
|
||||
__typename: z.literal('relation').optional(),
|
||||
id: z.string().uuid(),
|
||||
label: z.string().trim().min(1),
|
||||
position: z.number(),
|
||||
value: z.string().trim().min(1),
|
||||
}),
|
||||
)
|
||||
.nullable()
|
||||
.optional(),
|
||||
relationDefinition: z
|
||||
.object({
|
||||
__typename: z.literal('RelationDefinition').optional(),
|
||||
relationId: z.string().uuid(),
|
||||
direction: z.nativeEnum(RelationDefinitionType),
|
||||
sourceFieldMetadata: z.object({
|
||||
__typename: z.literal('field').optional(),
|
||||
id: z.string().uuid(),
|
||||
name: z.string().trim().min(1),
|
||||
}),
|
||||
sourceObjectMetadata: z.object({
|
||||
__typename: z.literal('object').optional(),
|
||||
id: z.string().uuid(),
|
||||
namePlural: z.string().trim().min(1),
|
||||
nameSingular: z.string().trim().min(1),
|
||||
}),
|
||||
targetFieldMetadata: z.object({
|
||||
__typename: z.literal('field').optional(),
|
||||
id: z.string().uuid(),
|
||||
name: z.string().trim().min(1),
|
||||
}),
|
||||
targetObjectMetadata: z.object({
|
||||
__typename: z.literal('object').optional(),
|
||||
id: z.string().uuid(),
|
||||
namePlural: z.string().trim().min(1),
|
||||
nameSingular: z.string().trim().min(1),
|
||||
}),
|
||||
})
|
||||
.nullable()
|
||||
.optional(),
|
||||
toRelationMetadata: z
|
||||
.object({
|
||||
__typename: z.literal('relation').optional(),
|
||||
id: z.string().uuid(),
|
||||
relationType: z.nativeEnum(RelationMetadataType),
|
||||
fromFieldMetadataId: z.string().uuid(),
|
||||
fromObjectMetadata: z.object({
|
||||
__typename: z.literal('object').optional(),
|
||||
id: z.string().uuid(),
|
||||
dataSourceId: z.string().uuid(),
|
||||
isRemote: z.boolean(),
|
||||
isSystem: z.boolean(),
|
||||
namePlural: z.string().trim().min(1),
|
||||
nameSingular: z.string().trim().min(1),
|
||||
}),
|
||||
})
|
||||
.nullable()
|
||||
.optional(),
|
||||
type: z.nativeEnum(FieldMetadataType),
|
||||
updatedAt: z.string().datetime(),
|
||||
}) satisfies z.ZodType<FieldMetadataItem>;
|
||||
relationType: z.nativeEnum(RelationMetadataType),
|
||||
fromFieldMetadataId: z.string().uuid(),
|
||||
fromObjectMetadata: z.object({
|
||||
__typename: z.literal('object').optional(),
|
||||
id: z.string().uuid(),
|
||||
dataSourceId: z.string().uuid(),
|
||||
isRemote: z.boolean(),
|
||||
isSystem: z.boolean(),
|
||||
namePlural: z.string().trim().min(1),
|
||||
nameSingular: z.string().trim().min(1),
|
||||
}),
|
||||
})
|
||||
.nullable()
|
||||
.optional(),
|
||||
type: z.nativeEnum(FieldMetadataType),
|
||||
updatedAt: z.string().datetime(),
|
||||
}) satisfies z.ZodType<FieldMetadataItem>;
|
||||
};
|
||||
|
||||
@ -1,23 +1,42 @@
|
||||
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';
|
||||
|
||||
export const metadataLabelSchema = z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1)
|
||||
.regex(METADATA_LABEL_VALID_PATTERN)
|
||||
.refine(
|
||||
(label) => {
|
||||
try {
|
||||
computeMetadataNameFromLabelOrThrow(label);
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
{
|
||||
message: 'Label is not formattable',
|
||||
},
|
||||
); // allows non-latin char
|
||||
export const metadataLabelSchema = (existingLabels?: string[]) => {
|
||||
return z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, errors.LabelEmpty)
|
||||
.regex(METADATA_LABEL_VALID_PATTERN, errors.LabelNotFormattable)
|
||||
.refine(
|
||||
(label) => {
|
||||
try {
|
||||
computeMetadataNameFromLabelOrThrow(label);
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
{
|
||||
message: errors.LabelNotFormattable,
|
||||
},
|
||||
)
|
||||
.refine(
|
||||
(label) => {
|
||||
try {
|
||||
if (!existingLabels || !label?.length) {
|
||||
return true;
|
||||
}
|
||||
return !existingLabels.includes(
|
||||
computeMetadataNameFromLabelOrThrow(label),
|
||||
);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
{
|
||||
message: errors.LabelNotUnique,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@ -10,7 +10,7 @@ export const objectMetadataItemSchema = z.object({
|
||||
createdAt: z.string().datetime(),
|
||||
dataSourceId: z.string().uuid(),
|
||||
description: z.string().trim().nullable().optional(),
|
||||
fields: z.array(fieldMetadataItemSchema),
|
||||
fields: z.array(fieldMetadataItemSchema()),
|
||||
icon: z.string().startsWith('Icon').trim(),
|
||||
id: z.string().uuid(),
|
||||
imageIdentifierFieldMetadataId: z.string().uuid().nullable(),
|
||||
@ -19,8 +19,8 @@ export const objectMetadataItemSchema = z.object({
|
||||
isRemote: z.boolean(),
|
||||
isSystem: z.boolean(),
|
||||
labelIdentifierFieldMetadataId: z.string().uuid().nullable(),
|
||||
labelPlural: metadataLabelSchema,
|
||||
labelSingular: metadataLabelSchema,
|
||||
labelPlural: metadataLabelSchema(),
|
||||
labelSingular: metadataLabelSchema(),
|
||||
namePlural: camelCaseStringSchema,
|
||||
nameSingular: camelCaseStringSchema,
|
||||
updatedAt: z.string().datetime(),
|
||||
|
||||
Reference in New Issue
Block a user