fix: content manager error management

This commit is contained in:
Alexandre Bodin 2024-06-24 22:30:43 +02:00
parent 6529e2bd50
commit 068381c9c9
6 changed files with 19 additions and 52 deletions

View File

@ -670,45 +670,16 @@ const useField = <TValue = any,>(path: string): FieldValue<TValue | undefined> =
const handleChange = useForm('useField', (state) => state.onChange); const handleChange = useForm('useField', (state) => state.onChange);
const formatNestedErrorMessages = (stateErrors: FormErrors<FormValues>) => { const error = useForm('useField', (state) => {
const nestedErrors: Record<string, any> = {}; const error = getIn(state.errors, path);
Object.entries(stateErrors).forEach(([key, value]) => { if (isErrorMessageDescriptor(error)) {
let current = nestedErrors; const { values, ...message } = error;
return formatMessage(message, values);
const pathParts = key.split('.');
pathParts.forEach((part, index) => {
const isLastPart = index === pathParts.length - 1;
if (isLastPart) {
if (typeof value === 'string') {
// If the value is a translation message object or a string, it should be nested as is
current[part] = value;
} else if (isErrorMessageDescriptor(value)) {
// If the value is a plain object, it should be converted to a string message
current[part] = formatMessage(value);
} else {
// If the value is not an object, it may be an array or a message
setIn(current, part, value);
}
} else {
// Ensure nested structure exists
if (!current[part]) {
const isArray = !isNaN(Number(pathParts[index + 1]));
current[part] = isArray ? [] : {};
} }
current = current[part]; return error;
}
}); });
});
return nestedErrors;
};
const error = useForm('useField', (state) =>
getIn(formatNestedErrorMessages(state.errors), path)
);
return { return {
initialValue, initialValue,

View File

@ -46,11 +46,6 @@ const Initializer = ({ disabled, name, onClick }: InitializerProps) => {
</Flex> </Flex>
</Flex> </Flex>
</Box> </Box>
{field.error && (
<Typography textColor="danger600" variant="pi">
{field.error}
</Typography>
)}
</> </>
); );
}; };

View File

@ -1,5 +1,3 @@
import { useState } from 'react';
import { Box, Checkbox, Field, Flex, NumberInput, TextInput } from '@strapi/design-system'; import { Box, Checkbox, Field, Flex, NumberInput, TextInput } from '@strapi/design-system';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
@ -23,7 +21,6 @@ export const CheckboxWithNumberField = ({
value = null, value = null,
}: CheckboxWithNumberFieldProps) => { }: CheckboxWithNumberFieldProps) => {
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const [showInput, setShowInput] = useState(!!value || value === 0);
const label = intlLabel.id const label = intlLabel.id
? formatMessage( ? formatMessage(
{ id: intlLabel.id, defaultMessage: intlLabel.defaultMessage }, { id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
@ -46,13 +43,12 @@ export const CheckboxWithNumberField = ({
const nextValue = value ? initValue : null; const nextValue = value ? initValue : null;
onChange({ target: { name, value: nextValue } }); onChange({ target: { name, value: nextValue } });
setShowInput((prev) => !prev);
}} }}
checked={showInput} checked={value !== null}
> >
{label} {label}
</Checkbox> </Checkbox>
{showInput && ( {value !== null && (
<Box paddingLeft={6} style={{ maxWidth: '200px' }}> <Box paddingLeft={6} style={{ maxWidth: '200px' }}>
{type === 'text' ? ( {type === 'text' ? (
<Field.Root error={errorMessage} name={name}> <Field.Root error={errorMessage} name={name}>
@ -70,7 +66,7 @@ export const CheckboxWithNumberField = ({
aria-label={label} aria-label={label}
disabled={disabled} disabled={disabled}
onValueChange={(value: any) => { onValueChange={(value: any) => {
onChange({ target: { name, value, type } }); onChange({ target: { name, value: value ?? 0, type } });
}} }}
value={value || 0} value={value || 0}
/> />

View File

@ -81,7 +81,7 @@ const validators = {
yup yup
.number() .number()
.integer() .integer()
.min(0) .min(1)
.when('maxLength', (maxLength, schema) => { .when('maxLength', (maxLength, schema) => {
if (maxLength) { if (maxLength) {
return schema.max(maxLength, getTrad('error.validation.minSupMax')); return schema.max(maxLength, getTrad('error.validation.minSupMax'));
@ -118,7 +118,11 @@ const createTextShape = (usedAttributeNames: Array<string>, reservedNames: Array
name: 'isValidRegExpPattern', name: 'isValidRegExpPattern',
message: getTrad('error.validation.regex'), message: getTrad('error.validation.regex'),
test(value) { test(value) {
try {
return new RegExp(value || '') !== null; return new RegExp(value || '') !== null;
} catch (e) {
return false;
}
}, },
}) })
.nullable(), .nullable(),

View File

@ -42,6 +42,7 @@ export const TabForm = ({
<Grid.Root gap={4}> <Grid.Root gap={4}>
{section.items.map((input: any, i: number) => { {section.items.map((input: any, i: number) => {
const key = `${sectionIndex}.${i}`; const key = `${sectionIndex}.${i}`;
/** /**
* Use undefined as the default value because not every input wants a string e.g. Date pickers * Use undefined as the default value because not every input wants a string e.g. Date pickers
*/ */

View File

@ -64,7 +64,7 @@
"error.validation.enum-duplicate": "Duplicate values are not allowed (only alphanumeric characters are taken into account).", "error.validation.enum-duplicate": "Duplicate values are not allowed (only alphanumeric characters are taken into account).",
"error.validation.enum-empty-string": "Empty strings are not allowed", "error.validation.enum-empty-string": "Empty strings are not allowed",
"error.validation.enum-regex": "At least one value is invalid. Values should have at least one alphabetical character preceding the first occurence of a number.", "error.validation.enum-regex": "At least one value is invalid. Values should have at least one alphabetical character preceding the first occurence of a number.",
"error.validation.minSupMax": "Can't be superior", "error.validation.minSupMax": "min can't be superior to max",
"error.validation.positive": "Must be a positive number", "error.validation.positive": "Must be a positive number",
"error.validation.regex": "Regex pattern is invalid", "error.validation.regex": "Regex pattern is invalid",
"error.validation.relation.targetAttribute-taken": "This name exists in the target", "error.validation.relation.targetAttribute-taken": "This name exists in the target",