Migrate from Zod v3 to v4 (#14639)
Closes [#1526](https://github.com/twentyhq/core-team-issues/issues/1526) --------- Co-authored-by: Félix Malfait <felix@twenty.com> Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
+18
-18
@@ -39,56 +39,56 @@ const isUniqueFieldFormSchema = z.object({
|
||||
|
||||
const booleanFieldFormSchema = z
|
||||
.object({ type: z.literal(FieldMetadataType.BOOLEAN) })
|
||||
.merge(settingsDataModelFieldBooleanFormSchema);
|
||||
.extend(settingsDataModelFieldBooleanFormSchema.shape);
|
||||
|
||||
const currencyFieldFormSchema = z
|
||||
.object({ type: z.literal(FieldMetadataType.CURRENCY) })
|
||||
.merge(settingsDataModelFieldCurrencyFormSchema);
|
||||
.extend(settingsDataModelFieldCurrencyFormSchema.shape);
|
||||
|
||||
const dateFieldFormSchema = z
|
||||
.object({ type: z.literal(FieldMetadataType.DATE) })
|
||||
.merge(settingsDataModelFieldDateFormSchema)
|
||||
.merge(isUniqueFieldFormSchema);
|
||||
.extend(settingsDataModelFieldDateFormSchema.shape)
|
||||
.extend(isUniqueFieldFormSchema.shape);
|
||||
|
||||
const dateTimeFieldFormSchema = z
|
||||
.object({ type: z.literal(FieldMetadataType.DATE_TIME) })
|
||||
.merge(settingsDataModelFieldDateFormSchema)
|
||||
.merge(isUniqueFieldFormSchema);
|
||||
.extend(settingsDataModelFieldDateFormSchema.shape)
|
||||
.extend(isUniqueFieldFormSchema.shape);
|
||||
|
||||
const relationFieldFormSchema = z
|
||||
.object({ type: z.literal(FieldMetadataType.RELATION) })
|
||||
.merge(settingsDataModelFieldRelationFormSchema);
|
||||
.extend(settingsDataModelFieldRelationFormSchema.shape);
|
||||
|
||||
const morphRelationFieldFormSchema = z
|
||||
.object({ type: z.literal(FieldMetadataType.MORPH_RELATION) })
|
||||
.merge(settingsDataModelFieldMorphRelationFormSchema);
|
||||
.extend(settingsDataModelFieldMorphRelationFormSchema.shape);
|
||||
|
||||
const selectFieldFormSchema = z
|
||||
.object({ type: z.literal(FieldMetadataType.SELECT) })
|
||||
.merge(settingsDataModelFieldSelectFormSchema);
|
||||
.extend(settingsDataModelFieldSelectFormSchema.shape);
|
||||
|
||||
const multiSelectFieldFormSchema = z
|
||||
.object({ type: z.literal(FieldMetadataType.MULTI_SELECT) })
|
||||
.merge(settingsDataModelFieldMultiSelectFormSchema);
|
||||
.extend(settingsDataModelFieldMultiSelectFormSchema.shape);
|
||||
|
||||
const numberFieldFormSchema = z
|
||||
.object({ type: z.literal(FieldMetadataType.NUMBER) })
|
||||
.merge(settingsDataModelFieldNumberFormSchema)
|
||||
.merge(isUniqueFieldFormSchema);
|
||||
.extend(settingsDataModelFieldNumberFormSchema.shape)
|
||||
.extend(isUniqueFieldFormSchema.shape);
|
||||
|
||||
const textFieldFormSchema = z
|
||||
.object({ type: z.literal(FieldMetadataType.TEXT) })
|
||||
.merge(settingsDataModelFieldTextFormSchema)
|
||||
.merge(isUniqueFieldFormSchema);
|
||||
.extend(settingsDataModelFieldTextFormSchema.shape)
|
||||
.extend(isUniqueFieldFormSchema.shape);
|
||||
|
||||
const addressFieldFormSchema = z
|
||||
.object({ type: z.literal(FieldMetadataType.ADDRESS) })
|
||||
.merge(settingsDataModelFieldAddressFormSchema);
|
||||
.extend(settingsDataModelFieldAddressFormSchema.shape);
|
||||
|
||||
const phonesFieldFormSchema = z
|
||||
.object({ type: z.literal(FieldMetadataType.PHONES) })
|
||||
.merge(settingsDataModelFieldPhonesFormSchema)
|
||||
.merge(isUniqueFieldFormSchema);
|
||||
.extend(settingsDataModelFieldPhonesFormSchema.shape)
|
||||
.extend(isUniqueFieldFormSchema.shape);
|
||||
|
||||
const otherFieldsFormSchema = z
|
||||
.object({
|
||||
@@ -111,7 +111,7 @@ const otherFieldsFormSchema = z
|
||||
) as [FieldMetadataType, ...FieldMetadataType[]],
|
||||
),
|
||||
})
|
||||
.merge(isUniqueFieldFormSchema);
|
||||
.extend(isUniqueFieldFormSchema.shape);
|
||||
|
||||
export const settingsDataModelFieldSettingsFormSchema = z.discriminatedUnion(
|
||||
'type',
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
import { RelationType } from '~/generated-metadata/graphql';
|
||||
|
||||
export const settingsDataModelFieldMorphRelationFormSchema = z.object({
|
||||
morphRelationObjectMetadataIds: z.array(z.string().uuid()).min(2),
|
||||
morphRelationObjectMetadataIds: z.array(z.uuid()).min(2),
|
||||
relationType: z.enum(
|
||||
Object.keys(RELATION_TYPES) as [RelationType, ...RelationType[]],
|
||||
),
|
||||
|
||||
+3
-3
@@ -25,15 +25,15 @@ export const settingsDataModelFieldRelationFormSchema = z.object({
|
||||
label: true,
|
||||
})
|
||||
// NOT SURE IF THIS IS CORRECT
|
||||
.merge(
|
||||
.extend(
|
||||
fieldMetadataItemSchema()
|
||||
.pick({
|
||||
name: true,
|
||||
isLabelSyncedWithName: true,
|
||||
})
|
||||
.partial(),
|
||||
.partial().shape,
|
||||
),
|
||||
objectMetadataId: z.string().uuid(),
|
||||
objectMetadataId: z.uuid(),
|
||||
type: z.enum(
|
||||
Object.keys(RELATION_TYPES) as [RelationType, ...RelationType[]],
|
||||
),
|
||||
|
||||
+5
-3
@@ -7,8 +7,10 @@ import { settingsDataModelFieldTypeFormSchema } from '~/pages/settings/data-mode
|
||||
export const settingsFieldFormSchema = (existingOtherLabels?: string[]) => {
|
||||
return z
|
||||
.object({})
|
||||
.merge(settingsDataModelFieldIconLabelFormSchema(existingOtherLabels))
|
||||
.merge(settingsDataModelFieldDescriptionFormSchema())
|
||||
.merge(settingsDataModelFieldTypeFormSchema)
|
||||
.extend(
|
||||
settingsDataModelFieldIconLabelFormSchema(existingOtherLabels).shape,
|
||||
)
|
||||
.extend(settingsDataModelFieldDescriptionFormSchema().shape)
|
||||
.extend(settingsDataModelFieldTypeFormSchema.shape)
|
||||
.and(settingsDataModelFieldSettingsFormSchema);
|
||||
};
|
||||
|
||||
+3
-2
@@ -27,8 +27,9 @@ export const getMultiSelectFieldPreviewValue = ({
|
||||
|
||||
return multiSelectFieldDefaultValueSchema(fieldMetadataItem.options)
|
||||
.refine(isDefined)
|
||||
.transform((value) =>
|
||||
value.map(stripSimpleQuotesFromString).filter(isNonEmptyString),
|
||||
.transform(
|
||||
(value) =>
|
||||
value?.map(stripSimpleQuotesFromString).filter(isNonEmptyString) ?? [],
|
||||
)
|
||||
.refine(isNonEmptyArray)
|
||||
.catch(allOptionValues)
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ export const getSelectFieldPreviewValue = ({
|
||||
|
||||
return selectFieldDefaultValueSchema(fieldMetadataItem.options)
|
||||
.refine(isDefined)
|
||||
.transform(stripSimpleQuotesFromString)
|
||||
.transform((value) => stripSimpleQuotesFromString(value ?? ''))
|
||||
.refine(isNonEmptyString)
|
||||
.catch(firstOptionValue)
|
||||
.parse(fieldMetadataItem.defaultValue);
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useMemo } from 'react';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { ZodError, isDirty, type z } from 'zod';
|
||||
import { ZodError, type z } from 'zod';
|
||||
|
||||
import { useUpdateOneObjectMetadataItem } from '@/object-metadata/hooks/useUpdateOneObjectMetadataItem';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
@@ -54,7 +54,7 @@ export const SettingsDataModelObjectIdentifiersForm = ({
|
||||
const handleSave = async (
|
||||
formValues: SettingsDataModelObjectIdentifiersFormValues,
|
||||
) => {
|
||||
if (!isDirty) {
|
||||
if (!formConfig.formState.isDirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+20
-27
@@ -3,13 +3,12 @@
|
||||
exports[`settingsDataModelObjectAboutFormSchema fails when isLabelSyncedWithName is not a boolean 1`] = `
|
||||
[ZodError: [
|
||||
{
|
||||
"code": "invalid_type",
|
||||
"expected": "boolean",
|
||||
"received": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
"isLabelSyncedWithName"
|
||||
],
|
||||
"message": "Expected boolean, received string"
|
||||
"message": "Invalid input: expected boolean, received string"
|
||||
}
|
||||
]]
|
||||
`;
|
||||
@@ -17,26 +16,24 @@ exports[`settingsDataModelObjectAboutFormSchema fails when isLabelSyncedWithName
|
||||
exports[`settingsDataModelObjectAboutFormSchema fails when labels are empty strings 1`] = `
|
||||
[ZodError: [
|
||||
{
|
||||
"origin": "string",
|
||||
"code": "too_small",
|
||||
"minimum": 1,
|
||||
"type": "string",
|
||||
"inclusive": true,
|
||||
"exact": false,
|
||||
"message": "String must contain at least 1 character(s)",
|
||||
"path": [
|
||||
"labelSingular"
|
||||
]
|
||||
],
|
||||
"message": "Too small: expected string to have >=1 characters"
|
||||
},
|
||||
{
|
||||
"origin": "string",
|
||||
"code": "too_small",
|
||||
"minimum": 1,
|
||||
"type": "string",
|
||||
"inclusive": true,
|
||||
"exact": false,
|
||||
"message": "String must contain at least 1 character(s)",
|
||||
"path": [
|
||||
"labelPlural"
|
||||
]
|
||||
],
|
||||
"message": "Too small: expected string to have >=1 characters"
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
@@ -59,17 +56,17 @@ exports[`settingsDataModelObjectAboutFormSchema fails when names are not in came
|
||||
[ZodError: [
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "String should be camel case",
|
||||
"path": [
|
||||
"namePlural"
|
||||
]
|
||||
],
|
||||
"message": "String should be camel case"
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "String should be camel case",
|
||||
"path": [
|
||||
"nameSingular"
|
||||
]
|
||||
],
|
||||
"message": "String should be camel case"
|
||||
}
|
||||
]]
|
||||
`;
|
||||
@@ -77,22 +74,20 @@ exports[`settingsDataModelObjectAboutFormSchema fails when names are not in came
|
||||
exports[`settingsDataModelObjectAboutFormSchema fails when required fields are missing 1`] = `
|
||||
[ZodError: [
|
||||
{
|
||||
"code": "invalid_type",
|
||||
"expected": "string",
|
||||
"received": "undefined",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
"labelSingular"
|
||||
],
|
||||
"message": "Required"
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
},
|
||||
{
|
||||
"code": "invalid_type",
|
||||
"expected": "string",
|
||||
"received": "undefined",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
"labelPlural"
|
||||
],
|
||||
"message": "Required"
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
}
|
||||
]]
|
||||
`;
|
||||
@@ -138,22 +133,20 @@ exports[`settingsDataModelObjectAboutFormSchema fails when singular and plural n
|
||||
exports[`settingsDataModelObjectAboutFormSchema fails with invalid types for optional fields 1`] = `
|
||||
[ZodError: [
|
||||
{
|
||||
"code": "invalid_type",
|
||||
"expected": "string",
|
||||
"received": "number",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
"description"
|
||||
],
|
||||
"message": "Expected string, received number"
|
||||
"message": "Invalid input: expected string, received number"
|
||||
},
|
||||
{
|
||||
"code": "invalid_type",
|
||||
"expected": "string",
|
||||
"received": "boolean",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
"icon"
|
||||
],
|
||||
"message": "Expected string, received boolean"
|
||||
"message": "Invalid input: expected string, received boolean"
|
||||
}
|
||||
]]
|
||||
`;
|
||||
|
||||
+2
-2
@@ -39,7 +39,7 @@ export const settingsDataModelObjectAboutFormSchema =
|
||||
];
|
||||
labelFields.forEach((field) =>
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: 'custom',
|
||||
message: t`Singular and plural labels must be different`,
|
||||
path: [field],
|
||||
}),
|
||||
@@ -55,7 +55,7 @@ export const settingsDataModelObjectAboutFormSchema =
|
||||
];
|
||||
nameFields.forEach((field) =>
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: 'custom',
|
||||
message: t`Singular and plural names must be different`,
|
||||
path: [field],
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user