From 2aace648271c05af8ee05cdb0d54420c50762105 Mon Sep 17 00:00:00 2001 From: Matthias GOUPIL Date: Wed, 12 Jun 2024 10:54:06 +0200 Subject: [PATCH] fix(#1282746): [Grid] Add error validation in grid --- .../components/public/locales/en/common.json | 1 + .../components/public/locales/fr/common.json | 1 + .../atoms/form/DoubleDatePickerError.test.tsx | 15 ++++++ .../atoms/form/DoubleDatePickerError.tsx | 11 +++- .../atoms/form/DropDownError.test.tsx | 15 ++++++ .../components/atoms/form/DropDownError.tsx | 11 +++- .../atoms/form/InputTextError.test.tsx | 17 +++++++ .../components/atoms/form/InputTextError.tsx | 11 +++- .../components/atoms/form/RangeError.test.tsx | 20 ++++++-- .../src/components/atoms/form/RangeError.tsx | 11 +++- .../CustomTable/StickyBar/StickyBar.tsx | 2 +- .../__snapshots__/StickyBar.test.tsx.snap | 2 +- .../ResourceTable/ResourceTable.tsx | 13 +++-- .../FieldGuesser/EditableDropDownGuesser.tsx | 2 + .../FieldGuesser/EditableFieldGuesser.tsx | 5 ++ .../stateful/TableGuesser/TableGuesser.tsx | 14 +++++- .../TableStickyBar/TableStickyBar.tsx | 33 ++++++++---- packages/components/src/hooks/useApi.ts | 48 ++++++++++-------- packages/components/src/hooks/useFormError.ts | 10 ++-- packages/shared/src/services/table.test.ts | 12 +++-- packages/shared/src/services/table.ts | 50 +++++++++++++++++-- packages/shared/src/types/api.ts | 8 ++- packages/shared/src/types/field.ts | 2 + packages/shared/src/types/hydra.ts | 3 +- 24 files changed, 256 insertions(+), 61 deletions(-) diff --git a/packages/components/public/locales/en/common.json b/packages/components/public/locales/en/common.json index 89f40756..864b9066 100644 --- a/packages/components/public/locales/en/common.json +++ b/packages/components/public/locales/en/common.json @@ -52,6 +52,7 @@ "formError.synonymTermsSizeInvalid": "Please provide at least two values in all \"synonyms\" fields.", "formError.synonymTermsDuplicate": "There are duplicates among the \"synonyms\", please remove them.", "formError.expansionTermsDuplicate": "There are duplicates among the \"expansion terms\", please remove them.", + "formError.prompt": "The prompt must contain a single occurrence of \"%s\".", "field.productImage": "Product image", "default.undefined": "empty", "log.out": "Log out", diff --git a/packages/components/public/locales/fr/common.json b/packages/components/public/locales/fr/common.json index e4d0ebe1..794a336b 100644 --- a/packages/components/public/locales/fr/common.json +++ b/packages/components/public/locales/fr/common.json @@ -53,6 +53,7 @@ "formError.synonymTermsDuplicate": "Il y a des doublons parmi les \"synonymes\", veuillez les retirer.", "formError.expansionTermsDuplicate": "Il y a des doublons parmi les \"termes étendus\", veuillez les retirer.", "field.productImage": "Image produit", + "formError.prompt": "Le prompt doit contenir une seule occurrence de \"%s\".", "default.undefined": "vide", "log.out": "Déconnexion", "entity": "Entité", diff --git a/packages/components/src/components/atoms/form/DoubleDatePickerError.test.tsx b/packages/components/src/components/atoms/form/DoubleDatePickerError.test.tsx index 3888d8db..843036a3 100644 --- a/packages/components/src/components/atoms/form/DoubleDatePickerError.test.tsx +++ b/packages/components/src/components/atoms/form/DoubleDatePickerError.test.tsx @@ -95,4 +95,19 @@ describe('RangeError', () => { ) expect(screen.getByText('formError.erreur')).toBeInTheDocument() }) + + it('should display a replacement error message with replacementErrorsMessages prop when the field has an error', () => { + renderWithProviders( + + ) + expect(screen.getByText('formError.customError')).toBeInTheDocument() + }) }) diff --git a/packages/components/src/components/atoms/form/DoubleDatePickerError.tsx b/packages/components/src/components/atoms/form/DoubleDatePickerError.tsx index e1d9c293..3e576f33 100644 --- a/packages/components/src/components/atoms/form/DoubleDatePickerError.tsx +++ b/packages/components/src/components/atoms/form/DoubleDatePickerError.tsx @@ -47,7 +47,13 @@ export function doubleDateValidator( function DoubleDatePickerError( props: IDoubleDatePickerErrorProps ): JSX.Element { - const { onChange, showError, additionalValidator, ...inputProps } = props + const { + onChange, + showError, + additionalValidator, + replacementErrorsMessages, + ...inputProps + } = props const validator = useCallback( (value: IDoubleDatePickerValues, event) => { @@ -66,7 +72,8 @@ function DoubleDatePickerError( inputProps.value, showError, validator, - inputProps.disabled + inputProps.disabled, + replacementErrorsMessages ) return ( diff --git a/packages/components/src/components/atoms/form/DropDownError.test.tsx b/packages/components/src/components/atoms/form/DropDownError.test.tsx index e72ae1ef..f26506d9 100644 --- a/packages/components/src/components/atoms/form/DropDownError.test.tsx +++ b/packages/components/src/components/atoms/form/DropDownError.test.tsx @@ -64,4 +64,19 @@ describe('DropDownError', () => { ) expect(screen.getByText('formError.erreur')).toBeInTheDocument() }) + + it('should display a replacement error message with replacementErrorsMessages prop when the field has an error', () => { + renderWithProviders( + 'erreur'} + replacementErrorsMessages={{ + erreur: 'customError', + }} + /> + ) + expect(screen.getByText('formError.customError')).toBeInTheDocument() + }) }) diff --git a/packages/components/src/components/atoms/form/DropDownError.tsx b/packages/components/src/components/atoms/form/DropDownError.tsx index 9913cfff..83de20bf 100644 --- a/packages/components/src/components/atoms/form/DropDownError.tsx +++ b/packages/components/src/components/atoms/form/DropDownError.tsx @@ -7,7 +7,13 @@ import Dropdown, { IDropDownProps } from './DropDown' interface IDropDownErrorProps extends IFieldErrorProps, IDropDownProps {} function DropdownError(props: IDropDownErrorProps): JSX.Element { - const { onChange, showError, additionalValidator, ...inputProps } = props + const { + onChange, + showError, + additionalValidator, + replacementErrorsMessages, + ...inputProps + } = props const validator = useCallback( (value, event) => { @@ -30,7 +36,8 @@ function DropdownError(props: IDropDownErrorProps): JSX.Element { inputProps.value, showError, validator, - inputProps.disabled + inputProps.disabled, + replacementErrorsMessages ) return ( diff --git a/packages/components/src/components/atoms/form/InputTextError.test.tsx b/packages/components/src/components/atoms/form/InputTextError.test.tsx index f8e598c9..f81f96fa 100644 --- a/packages/components/src/components/atoms/form/InputTextError.test.tsx +++ b/packages/components/src/components/atoms/form/InputTextError.test.tsx @@ -78,4 +78,21 @@ describe('InputTextError', () => { ) expect(screen.getByText('formError.erreur')).toBeInTheDocument() }) + + it('should display a replacement error message with replacementErrorsMessages prop when the field has an error', () => { + renderWithProviders( + + ) + expect(screen.getByText('formError.customError')).toBeInTheDocument() + }) }) diff --git a/packages/components/src/components/atoms/form/InputTextError.tsx b/packages/components/src/components/atoms/form/InputTextError.tsx index 0ec4ce99..a06ccba3 100644 --- a/packages/components/src/components/atoms/form/InputTextError.tsx +++ b/packages/components/src/components/atoms/form/InputTextError.tsx @@ -7,7 +7,13 @@ import InputText, { IInputTextProps } from './InputText' interface IInputTextErrorProps extends IFieldErrorProps, IInputTextProps {} function InputTextError(props: IInputTextErrorProps): JSX.Element { - const { onChange, showError, additionalValidator, ...inputProps } = props + const { + onChange, + showError, + additionalValidator, + replacementErrorsMessages, + ...inputProps + } = props const validator = useCallback( (value, event) => { if (additionalValidator) return additionalValidator(value, event) @@ -21,7 +27,8 @@ function InputTextError(props: IInputTextErrorProps): JSX.Element { inputProps.value, showError, validator, - inputProps.disabled + inputProps.disabled, + replacementErrorsMessages ) return ( diff --git a/packages/components/src/components/atoms/form/RangeError.test.tsx b/packages/components/src/components/atoms/form/RangeError.test.tsx index 07c3642d..ead995d2 100644 --- a/packages/components/src/components/atoms/form/RangeError.test.tsx +++ b/packages/components/src/components/atoms/form/RangeError.test.tsx @@ -42,11 +42,25 @@ describe('RangeError', () => { showError required value={[1, null]} - additionalValidator={(): string => { - return 'erreur' - }} + additionalValidator={(): string => 'erreur'} /> ) expect(screen.getByText('formError.erreur')).toBeInTheDocument() }) + + it('should display a replacement error message with replacementErrorsMessages prop when the field has an error', () => { + renderWithProviders( + 'erreur'} + replacementErrorsMessages={{ + erreur: 'customError', + }} + /> + ) + expect(screen.getByText('formError.customError')).toBeInTheDocument() + }) }) diff --git a/packages/components/src/components/atoms/form/RangeError.tsx b/packages/components/src/components/atoms/form/RangeError.tsx index 864b2723..e72782f2 100644 --- a/packages/components/src/components/atoms/form/RangeError.tsx +++ b/packages/components/src/components/atoms/form/RangeError.tsx @@ -7,7 +7,13 @@ import Range, { IRangeProps } from './Range' interface IRangeErrorProps extends IFieldErrorProps, IRangeProps {} function RangeError(props: IRangeErrorProps): JSX.Element { - const { onChange, showError, additionalValidator, ...inputProps } = props + const { + onChange, + showError, + additionalValidator, + replacementErrorsMessages, + ...inputProps + } = props const validator = useCallback( (value: [number | string | null, number | string | null], event) => { @@ -28,7 +34,8 @@ function RangeError(props: IRangeErrorProps): JSX.Element { inputProps.value, showError, validator, - inputProps.disabled + inputProps.disabled, + replacementErrorsMessages ) return ( diff --git a/packages/components/src/components/molecules/CustomTable/StickyBar/StickyBar.tsx b/packages/components/src/components/molecules/CustomTable/StickyBar/StickyBar.tsx index 676f03f4..57380de6 100644 --- a/packages/components/src/components/molecules/CustomTable/StickyBar/StickyBar.tsx +++ b/packages/components/src/components/molecules/CustomTable/StickyBar/StickyBar.tsx @@ -19,7 +19,7 @@ const StickyActions = styled(Box)(({ theme }) => ({ backgroundColor: theme.palette.colors.white, minHeight: '64px', width: '100%', - margin: '32px 16px 16px 16px', + margin: '0px 16px 16px 16px', border: 'solid', borderColor: theme.palette.colors.neutral[300], borderWidth: '1px', diff --git a/packages/components/src/components/molecules/CustomTable/StickyBar/__snapshots__/StickyBar.test.tsx.snap b/packages/components/src/components/molecules/CustomTable/StickyBar/__snapshots__/StickyBar.test.tsx.snap index fa9921a5..e034c13b 100644 --- a/packages/components/src/components/molecules/CustomTable/StickyBar/__snapshots__/StickyBar.test.tsx.snap +++ b/packages/components/src/components/molecules/CustomTable/StickyBar/__snapshots__/StickyBar.test.tsx.snap @@ -8,7 +8,7 @@ exports[`StickyBar should match snapshot 1`] = ` style="left: 0px;" >
Hello Sticky diff --git a/packages/components/src/components/stateful-pages/ResourceTable/ResourceTable.tsx b/packages/components/src/components/stateful-pages/ResourceTable/ResourceTable.tsx index 5379bf66..db9eb408 100644 --- a/packages/components/src/components/stateful-pages/ResourceTable/ResourceTable.tsx +++ b/packages/components/src/components/stateful-pages/ResourceTable/ResourceTable.tsx @@ -2,6 +2,7 @@ import React, { Dispatch, FunctionComponent, SetStateAction, + SyntheticEvent, useEffect, useMemo, useState, @@ -216,12 +217,18 @@ function ResourceTable(props: IResourceTable): JSX.Element { function handleRowChange( id: string | number, name: string, - value: boolean | number | string + value: boolean | number | string, + event: SyntheticEvent, + showError: boolean ): void { + const validity = (event.target as HTMLInputElement)?.checkValidity() if (update) { - update(id, { [name]: value }) + update(id, { [name]: value }, !showError || validity) } else if (replace) { - replace({ id, [name]: value } as unknown as ISourceField) + replace( + { id, [name]: value } as unknown as ISourceField, + !showError || validity + ) } } diff --git a/packages/components/src/components/stateful/FieldGuesser/EditableDropDownGuesser.tsx b/packages/components/src/components/stateful/FieldGuesser/EditableDropDownGuesser.tsx index d6ec72d4..1f06bf84 100644 --- a/packages/components/src/components/stateful/FieldGuesser/EditableDropDownGuesser.tsx +++ b/packages/components/src/components/stateful/FieldGuesser/EditableDropDownGuesser.tsx @@ -39,6 +39,7 @@ function EditableDropDownGuesser(props: IProps): JSX.Element { helperText, helperIcon, showError, + replacementErrorsMessages, } = props const { t } = useTranslation('common') @@ -94,6 +95,7 @@ function EditableDropDownGuesser(props: IProps): JSX.Element { } objectKeyValue={field?.gally?.options?.objectKeyValue} sx={{ minWidth: '230.667px' }} + replacementErrorsMessages={replacementErrorsMessages} /> ) } diff --git a/packages/components/src/components/stateful/FieldGuesser/EditableFieldGuesser.tsx b/packages/components/src/components/stateful/FieldGuesser/EditableFieldGuesser.tsx index f40323e1..e4409be0 100644 --- a/packages/components/src/components/stateful/FieldGuesser/EditableFieldGuesser.tsx +++ b/packages/components/src/components/stateful/FieldGuesser/EditableFieldGuesser.tsx @@ -54,6 +54,7 @@ function EditableFieldGuesser(props: IFieldGuesserProps): JSX.Element { placeholder, error, helperText, + replacementErrorsMessages, } = props const { t } = useTranslation('common') @@ -120,6 +121,7 @@ function EditableFieldGuesser(props: IFieldGuesserProps): JSX.Element { type={input === DataContentType.NUMBER ? 'number' : 'text'} value={value as string | number | null} placeholder={placeholder} + replacementErrorsMessages={replacementErrorsMessages} /> ) } @@ -141,6 +143,7 @@ function EditableFieldGuesser(props: IFieldGuesserProps): JSX.Element { showError={showError} suffix={suffix} value={value as (string | number | null)[]} + replacementErrorsMessages={replacementErrorsMessages} /> ) } @@ -267,6 +270,7 @@ function EditableFieldGuesser(props: IFieldGuesserProps): JSX.Element { multiple={Boolean(value instanceof Array)} error={error} helperText={helperText} + replacementErrorsMessages={replacementErrorsMessages} /> ) } @@ -295,6 +299,7 @@ function EditableFieldGuesser(props: IFieldGuesserProps): JSX.Element { placeholder={placeholder} error={error} showError={showError} + replacementErrorsMessages={replacementErrorsMessages} /> ) } diff --git a/packages/components/src/components/stateful/TableGuesser/TableGuesser.tsx b/packages/components/src/components/stateful/TableGuesser/TableGuesser.tsx index 3eb22718..e0fd018d 100644 --- a/packages/components/src/components/stateful/TableGuesser/TableGuesser.tsx +++ b/packages/components/src/components/stateful/TableGuesser/TableGuesser.tsx @@ -38,7 +38,8 @@ interface IProps { id: string | number, name: string, value: boolean | number | string, - event: SyntheticEvent + event: SyntheticEvent, + showError?: boolean ) => void resource: IResource rowsPerPage?: number @@ -128,6 +129,15 @@ function TableGuesser(props: IProps): JSX.Element { } } + function handleRowUpdate( + id: string | number, + name: string, + value: boolean | number | string, + event: SyntheticEvent + ): void { + const field = tableHeaders.find((field) => field.name === name) + onRowUpdate(id, name, value, event, field?.showError) + } return ( <> (props: IProps): JSX.Element { massiveSelectionState={massiveSelectionState} massiveSelectionIndeterminate={massiveSelectionIndeterminate} onPageChange={onPageChange} - onRowUpdate={onRowUpdate} + onRowUpdate={handleRowUpdate} onSelection={handleSelection} ref={tableRef} rowsPerPage={rowsPerPage ?? defaultPageSize} diff --git a/packages/components/src/components/stateful/TableStickyBar/TableStickyBar.tsx b/packages/components/src/components/stateful/TableStickyBar/TableStickyBar.tsx index 7bd0c8bb..2efee0b7 100644 --- a/packages/components/src/components/stateful/TableStickyBar/TableStickyBar.tsx +++ b/packages/components/src/components/stateful/TableStickyBar/TableStickyBar.tsx @@ -1,4 +1,4 @@ -import React, { ChangeEvent, FormEvent } from 'react' +import React, { ChangeEvent, FormEvent, useState } from 'react' import { useTranslation } from 'next-i18next' import { Box, Checkbox } from '@mui/material' import { styled } from '@mui/system' @@ -13,16 +13,17 @@ import Button from '../../atoms/buttons/Button' import Dropdown from '../../atoms/form/DropDown' import FieldGuesser from '../FieldGuesser/FieldGuesser' +import Form from '../../atoms/form/Form' const ActionsButtonsContainer = styled(Box)({ marginLeft: 'auto', }) -const Form = styled('form')({ - display: 'flex', - alignItems: 'center', - flex: 1, -}) +// const Form = styled('form')({ +// display: 'flex', +// alignItems: 'center', +// flex: 1, +// }) interface IProps { field: IField | '' @@ -56,9 +57,13 @@ function TableStickyBar(props: IProps): JSX.Element { const { t: tApi } = useTranslation('api') const header = field ? getFieldHeader(field, tApi) : null - function handleSubmit(event: FormEvent): void { + function handleSubmit( + event: FormEvent, + formIsValid: boolean + ): void { event.preventDefault() - onApply() + if (!formIsValid) setShowError(true) + else onApply() } function handleSelection(event: ChangeEvent): void { @@ -69,8 +74,17 @@ function TableStickyBar(props: IProps): JSX.Element { onSelection(false) } + const [showError, setShowError] = useState(false) + return ( -
+ {Boolean(withSelection) && ( )} diff --git a/packages/components/src/hooks/useApi.ts b/packages/components/src/hooks/useApi.ts index 54181489..df08a124 100644 --- a/packages/components/src/hooks/useApi.ts +++ b/packages/components/src/hooks/useApi.ts @@ -191,22 +191,24 @@ export function useApiEditableList( const debouncedUpdate = useMemo( () => - debounce(async (): Promise => { - const promises = Object.entries(itemsToUpdate.current).map( - ([id, updatedItems]) => { - delete itemsToUpdate.current[id] - return update(id, updatedItems) - } - ) + debounce(async (isValid = true): Promise => { + if (isValid) { + const promises = Object.entries(itemsToUpdate.current).map( + ([id, updatedItems]) => { + delete itemsToUpdate.current[id] + return update(id, updatedItems) + } + ) - await Promise.all(promises) - load() + await Promise.all(promises) + load() + } }, debounceDelay), [load, update] ) const editableUpdate = useCallback( - (id: string | number, updatedItem: Partial) => { + (id: string | number, updatedItem: Partial, isValid = true) => { if (id in itemsToUpdate.current) { itemsToUpdate.current[id] = { ...itemsToUpdate.current[id], @@ -221,7 +223,7 @@ export function useApiEditableList( item.id === id ? { ...item, ...updatedItem } : item ) ) - debouncedUpdate() + debouncedUpdate(isValid) }, [debouncedUpdate, updateList] ) @@ -279,22 +281,24 @@ export function useApiEditableList( const debouncedReplace = useMemo( () => - debounce(async (): Promise => { - const promises = Object.entries(itemsToUpdate.current).map( - ([id, replacedItem]) => { - delete itemsToUpdate.current[id] - return replace(replacedItem) - } - ) + debounce(async (isValid = true): Promise => { + if (isValid) { + const promises = Object.entries(itemsToUpdate.current).map( + ([id, replacedItem]) => { + delete itemsToUpdate.current[id] + return replace(replacedItem) + } + ) - await Promise.all(promises) - load() + await Promise.all(promises) + load() + } }, debounceDelay), [load, replace] ) const editableReplace = useCallback( - (replacedItem: Partial) => { + (replacedItem: Partial, isValid = true) => { const id = replacedItem.id as string if (id in itemsToUpdate.current) { itemsToUpdate.current[id] = { @@ -310,7 +314,7 @@ export function useApiEditableList( item.id === replacedItem.id ? { ...item, ...replacedItem } : item ) ) - debouncedReplace() + debouncedReplace(isValid) }, [debouncedReplace, updateList] ) diff --git a/packages/components/src/hooks/useFormError.ts b/packages/components/src/hooks/useFormError.ts index 39c580c9..399ff4c0 100644 --- a/packages/components/src/hooks/useFormError.ts +++ b/packages/components/src/hooks/useFormError.ts @@ -21,6 +21,7 @@ export type IValidator = ( export interface IFieldErrorProps { showError?: boolean additionalValidator?: IValidator + replacementErrorsMessages?: Record } export interface IFormErrorProps { error: boolean @@ -35,7 +36,8 @@ export function useFormError( value: unknown, showError = false, validator?: IValidator, - disabled = false + disabled = false, + replacementErrorsMessages?: Record ): [IFormErrorProps, Dispatch>] { const [error, setError] = useState('') const ref = useRef(null) @@ -99,7 +101,9 @@ export function useFormError( props.helperText = '' } else if (error && showError) { props.helperIcon = 'close' - props.helperText = t(`formError.${error}`) + props.helperText = t( + `formError.${replacementErrorsMessages?.[error] || error}` + ) } return [ props, @@ -108,5 +112,5 @@ export function useFormError( ref.current?.setCustomValidity(error) }, ] - }, [error, handleChange, t, disabled, showError]) + }, [error, handleChange, t, disabled, showError, replacementErrorsMessages]) } diff --git a/packages/shared/src/services/table.test.ts b/packages/shared/src/services/table.test.ts index 9c5323c2..5eb96011 100644 --- a/packages/shared/src/services/table.test.ts +++ b/packages/shared/src/services/table.test.ts @@ -55,7 +55,9 @@ describe('Table service', () => { type: DataContentType.STRING, editable: false, required: true, - validation: undefined, + validation: {}, + replacementErrorsMessages: {}, + showError: false, }) expect(getFieldHeader(fieldDropdown, (x: T): T => x)).toEqual({ depends: undefined, @@ -68,7 +70,9 @@ describe('Table service', () => { type: DataContentType.STRING, editable: false, required: true, - validation: undefined, + validation: {}, + replacementErrorsMessages: {}, + showError: false, }) }) }) @@ -133,7 +137,9 @@ describe('Table service', () => { required: false, suffix: '', type: DataContentType.STRING, - validation: undefined, + validation: {}, + replacementErrorsMessages: {}, + showError: false, }) }) }) diff --git a/packages/shared/src/services/table.ts b/packages/shared/src/services/table.ts index bfbc4682..9244bd90 100644 --- a/packages/shared/src/services/table.ts +++ b/packages/shared/src/services/table.ts @@ -47,14 +47,59 @@ export function getFieldInput( return fallback } +const customValidations: Record< + string, + { + attribute: string + value: string | number + error: { + name: string + message: string + } + } +> = { + prompt: { + attribute: 'pattern', + value: '^(?:(?!%)[\\s\\S])*%s(?:(?!%)[\\s\\S])*$', + error: { + name: 'patternMismatch', + message: 'prompt', + }, + }, +} + export function getFieldConfig( field: IField -): Pick { +): Pick< + IFieldConfig, + | 'depends' + | 'field' + | 'suffix' + | 'validation' + | 'showError' + | 'replacementErrorsMessages' +> { + const validation: Record = {} + const replacementErrorsMessages: Record = {} + let showError = false + Object.entries(field.gally?.validation || {}).forEach(([key, value]) => { + if (customValidations[key] && value) { + validation[customValidations[key].attribute] = + customValidations[key].value + replacementErrorsMessages[customValidations[key].error.name] = + customValidations[key].error.message + showError = true + } else if (!customValidations[key] && typeof value !== 'boolean') { + validation[key] = value + } + }) return { depends: field.gally?.depends, field, suffix: field.gally?.input === 'percentage' ? '%' : '', - validation: field.gally?.validation, + validation, + showError, + replacementErrorsMessages, } } @@ -63,7 +108,6 @@ export function getFieldHeader(field: IField, t: TFunction): IFieldConfig { const type = getFieldDataContentType(field) const id = field.title const input = getFieldInput(field, type) - return { ...fieldConfig, editable: field.gally?.editable && field.writeable, diff --git a/packages/shared/src/types/api.ts b/packages/shared/src/types/api.ts index 4cfd767f..b69a69ef 100644 --- a/packages/shared/src/types/api.ts +++ b/packages/shared/src/types/api.ts @@ -68,10 +68,14 @@ export type IResourceEditableMassReplace = ( item: Omit ) => Promise export type IResourceEditableRemove = (id: string | number) => Promise -export type IResourceEditableReplace = (item: Partial) => void +export type IResourceEditableReplace = ( + item: Partial, + isValid?: boolean +) => void export type IResourceEditableUpdate = ( id: string | number, - item: Partial + item: Partial, + isValid?: boolean ) => void export interface IResourceEditableOperations { diff --git a/packages/shared/src/types/field.ts b/packages/shared/src/types/field.ts index 85330c0e..36131f3d 100644 --- a/packages/shared/src/types/field.ts +++ b/packages/shared/src/types/field.ts @@ -40,6 +40,8 @@ export interface IFieldConfig extends IFieldState { error?: boolean headerStyle?: CSSProperties cellsStyle?: CSSProperties + showError?: boolean + replacementErrorsMessages?: Record } export interface IFieldConfigFormWithFieldset { diff --git a/packages/shared/src/types/hydra.ts b/packages/shared/src/types/hydra.ts index afbc4dca..92b756e5 100644 --- a/packages/shared/src/types/hydra.ts +++ b/packages/shared/src/types/hydra.ts @@ -118,7 +118,7 @@ export interface IGallyProperty { position?: number required?: boolean type?: string - validation?: Record + validation?: Record visible?: boolean alias?: string multipleValueFormat?: IMultipleValueFormat @@ -132,6 +132,7 @@ export interface IGallyProperty { multipleInputConfiguration?: IMultipleInputConfiguration placeholder?: string defaultValue?: unknown + showError?: boolean } export interface IDropdownOptions { objectKeyValue?: string