Skip to content

Commit 338ab1c

Browse files
author
Georgi2704
committed
Validation error improvements
1 parent 6694d35 commit 338ab1c

File tree

4 files changed

+49
-28
lines changed

4 files changed

+49
-28
lines changed

frontend/packages/pydantic-forms/src/core/PydanticFormHandler.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ import { getHashForArray } from '@/utils';
1111
import { ReactHookForm } from './ReactHookForm';
1212

1313
export const PydanticFormHandler = ({
14-
formKey,
15-
onCancel,
16-
onSuccess,
17-
title,
18-
}: PydanticFormHandlerProps) => {
14+
formKey,
15+
onCancel,
16+
onSuccess,
17+
title,
18+
}: PydanticFormHandlerProps) => {
1919
const config = useGetConfig();
2020
const [formStep, setStep] = useState<FieldValues>();
2121
const formStepsRef = useRef<FieldValues[]>([]);
@@ -68,7 +68,7 @@ export const PydanticFormHandler = ({
6868
isLoading,
6969
pydanticFormSchema,
7070
defaultValues,
71-
handleRemoveValidationError
71+
handleRemoveValidationError,
7272
} = usePydanticForm(
7373
formKey,
7474
config,

frontend/packages/pydantic-forms/src/core/ReactHookForm.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*
66
* Here we define the outline of the form
77
*/
8-
import React, {useEffect} from 'react';
8+
import React, { useEffect } from 'react';
99
import type { FieldValues } from 'react-hook-form';
1010
import { FormProvider, useForm } from 'react-hook-form';
1111

@@ -36,7 +36,7 @@ export interface ReactHookFormProps {
3636
onPrevious: () => void;
3737
pydanticFormSchema?: PydanticFormSchema;
3838
title?: string;
39-
handleRemoveValidationError: (location: string[]) => void;
39+
handleRemoveValidationError: (location: string) => void;
4040
}
4141

4242
export const ReactHookForm = ({
@@ -52,7 +52,7 @@ export const ReactHookForm = ({
5252
onPrevious,
5353
pydanticFormSchema,
5454
title,
55-
handleRemoveValidationError
55+
handleRemoveValidationError,
5656
}: ReactHookFormProps) => {
5757
const config = useGetConfig();
5858
const t = useTranslations('renderForm');
@@ -76,8 +76,8 @@ export const ReactHookForm = ({
7676
});
7777

7878
useEffect(() => {
79-
const reactHookFormWatch = reactHookForm.watch((_, { name }) =>
80-
name && handleRemoveValidationError([name])
79+
const reactHookFormWatch = reactHookForm.watch(
80+
(_, { name }) => name && handleRemoveValidationError(name),
8181
);
8282
return reactHookFormWatch.unsubscribe;
8383
}, [handleRemoveValidationError, reactHookForm]);

frontend/packages/pydantic-forms/src/core/WrapFieldElement.tsx

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,21 @@ import React from 'react';
22
import { Controller, useFormContext } from 'react-hook-form';
33

44
import { FieldWrap } from '@/components/fields';
5-
import type { PydanticFormControlledElement, PydanticFormField } from '@/types';
5+
import { useGetValidationErrors } from '@/core/hooks';
6+
import {
7+
PydanticFormControlledElement,
8+
PydanticFormField,
9+
PydanticFormValidationErrorDetails,
10+
} from '@/types';
11+
12+
const getValidationErrorMsg = (
13+
errorResponse: PydanticFormValidationErrorDetails | null,
14+
path: string,
15+
): string | undefined => {
16+
return errorResponse?.source?.find(
17+
(err) => err.loc.map(String).join('.') === path,
18+
)?.msg;
19+
};
620

721
export const WrapFieldElement = ({
822
PydanticFormControlledElement,
@@ -14,6 +28,8 @@ export const WrapFieldElement = ({
1428
extraTriggerFields?: string[];
1529
}) => {
1630
const { control, trigger } = useFormContext();
31+
const validationErrorDetails = useGetValidationErrors();
32+
1733
return (
1834
<Controller
1935
name={pydanticFormField.id}
@@ -32,7 +48,12 @@ export const WrapFieldElement = ({
3248
<FieldWrap
3349
pydanticFormField={pydanticFormField}
3450
isInvalid={fieldState.invalid}
35-
frontendValidationMessage={fieldState.error?.message}
51+
frontendValidationMessage={
52+
getValidationErrorMsg(
53+
validationErrorDetails,
54+
pydanticFormField.id,
55+
) ?? fieldState.error?.message
56+
}
3657
>
3758
<PydanticFormControlledElement
3859
onChange={onChangeHandle}

frontend/packages/pydantic-forms/src/core/hooks/usePydanticForm.tsx

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,21 @@ export interface UsePydanticFormReturn {
2525
isSending: boolean;
2626
pydanticFormSchema?: PydanticFormSchema;
2727
defaultValues: FieldValues;
28-
handleRemoveValidationError: (location: string[]) => void;
28+
handleRemoveValidationError: (location: string) => void;
2929
}
3030

3131
const removeValidationErrorByLoc = (
3232
validationErrors: PydanticFormValidationErrorDetails | null,
33-
locToRemove: (string | number)[]
33+
locToRemove: string,
3434
): PydanticFormValidationErrorDetails | null => {
35-
3635
if (!validationErrors) return null;
3736

38-
const newSource = validationErrors.source.filter(
39-
(err) => JSON.stringify(err.loc) !== JSON.stringify(locToRemove)
40-
);
37+
const newSource = validationErrors.source.filter((err) => {
38+
const locPath = err.loc.join('.'); // e.g. "contact_persons.0.email"
39+
return locPath !== locToRemove;
40+
});
4141

42-
const topKey = locToRemove[0]?.toString();
42+
const [topKey] = locToRemove.split('.'); // e.g. "contact_persons"
4343
const newMapped = { ...validationErrors.mapped };
4444

4545
if (topKey && newMapped[topKey]) {
@@ -51,7 +51,7 @@ const removeValidationErrorByLoc = (
5151
source: newSource,
5252
mapped: newMapped,
5353
};
54-
}
54+
};
5555

5656
export function usePydanticForm(
5757
formKey: string,
@@ -63,7 +63,6 @@ export function usePydanticForm(
6363
response: PydanticFormSuccessResponse,
6464
) => void,
6565
formStep?: FieldValues,
66-
6766
): UsePydanticFormReturn {
6867
const emptyRawSchema: PydanticFormSchemaRawJson = useMemo(
6968
() => ({
@@ -158,11 +157,12 @@ export function usePydanticForm(
158157
// eslint-disable-next-line react-hooks/exhaustive-deps
159158
}, [apiResponse]);
160159

161-
const handleRemoveValidationError = (location: string[]) => {
162-
setValidationErrorsDetails((prev) =>
163-
removeValidationErrorByLoc(prev, location)
164-
);
165-
}
160+
const handleRemoveValidationError = (location: string) => {
161+
setValidationErrorsDetails((prev) => {
162+
const updatedErrors = removeValidationErrorByLoc(prev, location);
163+
return updatedErrors;
164+
});
165+
};
166166

167167
return {
168168
validationErrorsDetails,
@@ -173,6 +173,6 @@ export function usePydanticForm(
173173
pydanticFormSchema,
174174
defaultValues,
175175
isSending,
176-
handleRemoveValidationError
176+
handleRemoveValidationError,
177177
};
178178
}

0 commit comments

Comments
 (0)