refactor: use react-hook-form to validate Settings/DataModel/Field (#4916)

Closes #4295
This commit is contained in:
Thaïs
2024-05-07 11:44:46 +02:00
committed by GitHub
parent 9c25c1beae
commit d0759ad7cc
18 changed files with 13234 additions and 13369 deletions

View File

@ -4,8 +4,7 @@ import { act, renderHook } from '@testing-library/react';
import { RecoilRoot } from 'recoil';
import { useCreateOneRelationMetadataItem } from '@/object-metadata/hooks/useCreateOneRelationMetadataItem';
import { FieldMetadataType } from '~/generated/graphql';
import { RelationMetadataType } from '~/generated-metadata/graphql';
import { RelationMetadataType } from '~/generated/graphql';
import {
query,
@ -46,7 +45,6 @@ describe('useCreateOneRelationMetadataItem', () => {
relationType: RelationMetadataType.OneToOne,
field: {
label: 'label',
type: FieldMetadataType.Relation,
},
objectMetadataId: 'objectMetadataId',
connect: {

View File

@ -9,7 +9,7 @@ import { formatFieldMetadataItemInput } from './formatFieldMetadataItemInput';
export type FormatRelationMetadataInputParams = {
relationType: RelationType;
field: Pick<Field, 'label' | 'icon' | 'description' | 'type'>;
field: Pick<Field, 'label' | 'icon' | 'description'>;
objectMetadataId: string;
connect: {
field: Pick<Field, 'label' | 'icon'>;

View File

@ -1,6 +1,3 @@
import { SafeParseSuccess } from 'zod';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { mockedCompanyObjectMetadataItem } from '~/testing/mock-data/metadata';
import { objectMetadataItemSchema } from '../objectMetadataItemSchema';
@ -11,13 +8,10 @@ describe('objectMetadataItemSchema', () => {
const validObjectMetadataItem = mockedCompanyObjectMetadataItem;
// When
const result = objectMetadataItemSchema.safeParse(validObjectMetadataItem);
const result = objectMetadataItemSchema.parse(validObjectMetadataItem);
// Then
expect(result.success).toBe(true);
expect((result as SafeParseSuccess<ObjectMetadataItem>).data).toEqual(
validObjectMetadataItem,
);
expect(result).toEqual(validObjectMetadataItem);
});
it('fails for an invalid object metadata item', () => {

View File

@ -1,6 +1,104 @@
import { z } from 'zod';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { metadataLabelSchema } from '@/object-metadata/validation-schemas/metadataLabelSchema';
import { themeColorSchema } from '@/ui/theme/utils/themeColorSchema';
import {
FieldMetadataType,
RelationDefinitionType,
RelationMetadataType,
} from '~/generated-metadata/graphql';
import { camelCaseStringSchema } from '~/utils/validation-schemas/camelCaseStringSchema';
// TODO: implement fieldMetadataItemSchema
export const fieldMetadataItemSchema: z.ZodType<FieldMetadataItem> = z.any();
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(),
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,
id: z.string().uuid(),
label: z.string().trim().min(1),
position: z.number(),
value: z.string().trim().min(1),
}),
)
.optional(),
relationDefinition: z
.object({
__typename: z.literal('RelationDefinition').optional(),
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>;

View File

@ -0,0 +1,7 @@
import { z } from 'zod';
export const metadataLabelSchema = z
.string()
.trim()
.min(1)
.regex(/^[a-zA-Z][a-zA-Z0-9 ()]*$/);

View File

@ -2,6 +2,7 @@ import { z } from 'zod';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { fieldMetadataItemSchema } from '@/object-metadata/validation-schemas/fieldMetadataItemSchema';
import { metadataLabelSchema } from '@/object-metadata/validation-schemas/metadataLabelSchema';
import { camelCaseStringSchema } from '~/utils/validation-schemas/camelCaseStringSchema';
export const objectMetadataItemSchema = z.object({
@ -18,8 +19,8 @@ export const objectMetadataItemSchema = z.object({
isRemote: z.boolean(),
isSystem: z.boolean(),
labelIdentifierFieldMetadataId: z.string().uuid().nullable(),
labelPlural: z.string().trim().min(1),
labelSingular: z.string().trim().min(1),
labelPlural: metadataLabelSchema,
labelSingular: metadataLabelSchema,
namePlural: camelCaseStringSchema,
nameSingular: camelCaseStringSchema,
updatedAt: z.string().datetime(),