From a68a23f865abb8d4086cde12c866a52175cdf037 Mon Sep 17 00:00:00 2001 From: Renaud AMSELLEM Date: Fri, 8 Nov 2024 15:34:35 +0100 Subject: [PATCH] dev review --- .../RecordEdition/EditRecordContent/_types.ts | 4 +- .../standardFieldReducer.ts | 12 +- .../StandardFieldValue/DSBooleanWrapper.tsx | 4 + .../DSColorPickerWrapper.tsx | 4 + .../DSDatePickerWrapper.tsx | 4 + .../DSInputEncryptedWrapper.tsx | 4 + .../StandardFieldValue/DSInputWrapper.tsx | 4 + .../DSRangePickerWrapper.tsx | 4 + .../StandardFieldValue/DSRichTextWrapper.tsx | 4 + .../StandardFieldValueDisplayHandler.tsx | 2 +- .../ValuesList/MonoValueSelect.test.tsx | 124 ++++++++++++++++++ .../ValuesList/MonoValueSelect.tsx | 41 ++---- .../StandardFieldValue/ValuesList/_types.ts | 23 ++++ 13 files changed, 198 insertions(+), 36 deletions(-) create mode 100644 libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/ValuesList/_types.ts diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/_types.ts b/libs/ui/src/components/RecordEdition/EditRecordContent/_types.ts index a60bd2664..522caa1fb 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/_types.ts +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/_types.ts @@ -140,10 +140,10 @@ export enum VersionFieldScope { CURRENT = 'CURRENT' // values of "current" version, eg. the version selected in the form } -export interface ICommonFieldsReducerState { +export interface ICommonFieldsReducerState { record: IRecordIdentityWhoAmI; formElement: FormElement; - attribute: RecordFormAttributeFragment; + attribute: RecordFormAttributeFragmentType; isReadOnly: boolean; activeScope: VersionFieldScope; values: { diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/reducers/standardFieldReducer/standardFieldReducer.ts b/libs/ui/src/components/RecordEdition/EditRecordContent/reducers/standardFieldReducer/standardFieldReducer.ts index 909f8aa23..db7df00fb 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/reducers/standardFieldReducer/standardFieldReducer.ts +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/reducers/standardFieldReducer/standardFieldReducer.ts @@ -12,7 +12,12 @@ import { import {RecordFormElementsValueStandardValue} from '_ui/hooks/useGetRecordForm/useGetRecordForm'; import {IRecordIdentityWhoAmI} from '_ui/types/records'; import {IValueVersion} from '_ui/types/values'; -import {AttributeFormat, RecordFormAttributeFragment, ValueDetailsValueFragment} from '_ui/_gqlTypes'; +import { + AttributeFormat, + RecordFormAttributeFragment, + RecordFormAttributeStandardAttributeFragment, + ValueDetailsValueFragment +} from '_ui/_gqlTypes'; import {IRecordPropertyStandard} from '_ui/_queries/records/getRecordPropertiesQuery'; import {arrayValueVersionToObject} from '_ui/_utils'; @@ -85,7 +90,10 @@ interface INotCalculated { export type CalculatedFlags = INotCalculated | ICalculatedOverride | ICalculatedNotOverride; -export type IStandardFieldReducerState = ICommonFieldsReducerState & { +export type IStandardFieldReducerState = ICommonFieldsReducerState< + StandardFieldReducerValues, + RecordFormAttributeStandardAttributeFragment +> & { metadataEdit: boolean; } & InheritedFlags & CalculatedFlags; diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSBooleanWrapper.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSBooleanWrapper.tsx index 5d27a78f0..46edb3c6f 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSBooleanWrapper.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSBooleanWrapper.tsx @@ -35,6 +35,10 @@ const FontAwesomeIconStyled = styled(FontAwesomeIcon)` const _getBooleanValueAsStringForTranslation = (value: boolean): string => (value ? 'global.yes' : 'global.no'); export const DSBooleanWrapper: FunctionComponent = ({value, onChange, state, handleSubmit}) => { + if (!onChange) { + throw Error('DSBooleanWrapper should be used inside a antd Form.Item'); + } + const {t} = useSharedTranslation(); const {errors} = Form.Item.useStatus(); const {lang: availableLang} = useLang(); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSColorPickerWrapper.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSColorPickerWrapper.tsx index cc5884b7d..7c514501a 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSColorPickerWrapper.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSColorPickerWrapper.tsx @@ -46,6 +46,10 @@ export const DSColorPickerWrapper: FunctionComponent handleBlur, shouldShowValueDetailsButton = false }) => { + if (!onChange) { + throw Error('DSColorPickerWrapper should be used inside a antd Form.Item'); + } + const {t} = useSharedTranslation(); const {lang: availableLang} = useLang(); const [hasChanged, setHasChanged] = useState(false); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSDatePickerWrapper.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSDatePickerWrapper.tsx index 1a48c9105..8495e0f15 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSDatePickerWrapper.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSDatePickerWrapper.tsx @@ -41,6 +41,10 @@ export const DSDatePickerWrapper: FunctionComponent = handleSubmit, shouldShowValueDetailsButton = false }) => { + if (!onChange) { + throw Error('DSDatePickerWrapper should be used inside a antd Form.Item'); + } + const {t} = useSharedTranslation(); const {lang: availableLangs} = useLang(); const {errors} = Form.Item.useStatus(); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputEncryptedWrapper.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputEncryptedWrapper.tsx index 2b78c4df2..eb67db58e 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputEncryptedWrapper.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputEncryptedWrapper.tsx @@ -45,6 +45,10 @@ export const DSInputEncryptedWrapper: FunctionComponent { + if (!onChange) { + throw Error('DSInputEncryptedWrapper should be used inside a antd Form.Item'); + } + const {t} = useSharedTranslation(); const {errors} = Form.Item.useStatus(); const {onValueDetailsButtonClick} = useValueDetailsButton({ diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.tsx index e7989f6ee..f9e2c0ec0 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.tsx @@ -39,6 +39,10 @@ export const DSInputWrapper: FunctionComponent = ({ handleBlur, shouldShowValueDetailsButton = false }) => { + if (!onChange) { + throw Error('DSInputWrapper should be used inside a antd Form.Item'); + } + const {t} = useSharedTranslation(); const {errors} = Form.Item.useStatus(); const {onValueDetailsButtonClick} = useValueDetailsButton({ diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRangePickerWrapper.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRangePickerWrapper.tsx index 1ba93a3d3..cc3450338 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRangePickerWrapper.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRangePickerWrapper.tsx @@ -42,6 +42,10 @@ export const DSRangePickerWrapper: FunctionComponent handleBlur, shouldShowValueDetailsButton = false }) => { + if (!onChange) { + throw Error('DSRangePickerWrapper should be used inside a antd Form.Item'); + } + const {t} = useSharedTranslation(); const {lang: availableLangs} = useLang(); const {errors} = Form.Item.useStatus(); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRichTextWrapper.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRichTextWrapper.tsx index aadb93fef..026e4b0b8 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRichTextWrapper.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRichTextWrapper.tsx @@ -41,6 +41,10 @@ export const DSRichTextWrapper: FunctionComponent = ({ handleBlur, shouldShowValueDetailsButton = false }) => { + if (!onChange) { + throw Error('DSRichTextWrapper should be used inside a antd Form.Item'); + } + const {t} = useSharedTranslation(); const {errors} = Form.Item.useStatus(); const {onValueDetailsButtonClick} = useValueDetailsButton({ diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValueDisplayHandler/StandardFieldValueDisplayHandler.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValueDisplayHandler/StandardFieldValueDisplayHandler.tsx index cd161b968..94079a041 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValueDisplayHandler/StandardFieldValueDisplayHandler.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValueDisplayHandler/StandardFieldValueDisplayHandler.tsx @@ -1,4 +1,4 @@ -// Copyright LEAV Solutions 2017 +// Copyright LEAV Solutions 2017 until 2023/11/05, Copyright Aristid from 2023/11/06 // This file is released under LGPL V3 // License text available at https://www.gnu.org/licenses/lgpl-3.0.txt import {AttributeFormat, RecordFormAttributeStandardAttributeFragment} from '_ui/_gqlTypes'; diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/ValuesList/MonoValueSelect.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/ValuesList/MonoValueSelect.test.tsx index 9a86cd2f0..5dd6238df 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/ValuesList/MonoValueSelect.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/ValuesList/MonoValueSelect.test.tsx @@ -11,6 +11,8 @@ import userEvent from '@testing-library/user-event'; import {RecordFormAttributeStandardAttributeFragment, SortOrder} from '_ui/_gqlTypes'; import {VersionFieldScope} from '_ui/components/RecordEdition/EditRecordContent/_types'; import { + CalculatedFlags, + InheritedFlags, IStandardFieldReducerState, IStandardFieldValue } from '_ui/components/RecordEdition/EditRecordContent/reducers/standardFieldReducer/standardFieldReducer'; @@ -145,6 +147,128 @@ describe('', () => { expect(handleSubmitMock).toHaveBeenCalledWith('', attribute.id); }); + it.each` + calculatedValue | inheritedValue | displayedValue + ${'calculated'} | ${null} | ${'calculated'} + ${null} | ${'inherited'} | ${'inherited'} + ${'calculated'} | ${'inherited'} | ${'inherited'} + `( + 'should display calculated / inherited value in helper', + ({ + calculatedValue, + inheritedValue, + displayedValue + }: { + calculatedValue: string | null; + inheritedValue: string | null; + displayedValue: string; + }) => { + const stateWithInheritedValue: InheritedFlags = { + inheritedValue: {raw_value: inheritedValue}, + isInheritedValue: true, + isInheritedNotOverrideValue: false, + isInheritedOverrideValue: true + }; + const stateWithCalculatedValue: CalculatedFlags = { + calculatedValue: {raw_value: calculatedValue}, + isCalculatedValue: true, + isCalculatedNotOverrideValue: false, + isCalculatedOverrideValue: true + }; + + let newState = state; + if (inheritedValue) { + newState = {...newState, ...stateWithInheritedValue} as any; + } + + if (calculatedValue) { + newState = {...newState, ...stateWithCalculatedValue} as any; + } + + render( + + + + + + ); + + expect(screen.getByText(new RegExp(`${displayedValue}`))).toBeVisible(); + } + ); + + it.each` + calculatedValue | inheritedValue | displayedValue + ${'calculated'} | ${null} | ${'calculated'} + ${null} | ${'inherited'} | ${'inherited'} + ${'calculated'} | ${'inherited'} | ${'inherited'} + `( + 'should revert to calculated / inherited value on click on clear icon', + async ({ + calculatedValue, + inheritedValue, + displayedValue + }: { + calculatedValue: string | null; + inheritedValue: string | null; + displayedValue: string; + }) => { + const stateWithInheritedValue: InheritedFlags = { + inheritedValue: {raw_value: inheritedValue}, + isInheritedValue: true, + isInheritedNotOverrideValue: true, + isInheritedOverrideValue: false + }; + const stateWithCalculatedValue: CalculatedFlags = { + calculatedValue: {raw_value: calculatedValue}, + isCalculatedValue: true, + isCalculatedNotOverrideValue: true, + isCalculatedOverrideValue: false + }; + + let newState = state; + if (inheritedValue) { + newState = {...newState, ...stateWithInheritedValue} as any; + } + + if (calculatedValue) { + newState = {...newState, ...stateWithCalculatedValue} as any; + } + + render( + + + + + + ); + + expect(screen.queryByText(displayedValue)).not.toBeInTheDocument(); + const select = screen.getByRole('combobox'); + await userEvent.click(select); + + const green = screen.getAllByText('green').pop(); + await userEvent.click(green); + + const clearIcon = screen.getByLabelText('clear'); + await userEvent.click(clearIcon); + + expect(screen.getByTitle(displayedValue)).toBeVisible(); + } + ); + it('should display a specific text on search with results', async () => { render( diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/ValuesList/MonoValueSelect.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/ValuesList/MonoValueSelect.tsx index 9d7570809..79bba9b44 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/ValuesList/MonoValueSelect.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/ValuesList/MonoValueSelect.tsx @@ -2,34 +2,16 @@ // This file is released under LGPL V3 // License text available at https://www.gnu.org/licenses/lgpl-3.0.txt import {FunctionComponent, useEffect, useMemo, useRef, useState} from 'react'; -import {KitSelect, KitTypography} from 'aristid-ds'; +import {AntForm, KitSelect, KitTypography} from 'aristid-ds'; import useSharedTranslation from '_ui/hooks/useSharedTranslation/useSharedTranslation'; -import { - AttributeFormat, - RecordFormAttributeStandardAttributeFragment, - StandardValuesListFragmentStandardDateRangeValuesListConfFragment, - StandardValuesListFragmentStandardStringValuesListConfFragment -} from '_ui/_gqlTypes'; -import {Form, GetRef, SelectProps} from 'antd'; -import {IProvidedByAntFormItem} from '_ui/components/RecordEdition/EditRecordContent/_types'; +import {AttributeFormat} from '_ui/_gqlTypes'; +import {Form, GetRef} from 'antd'; import {useValueDetailsButton} from '_ui/components/RecordEdition/EditRecordContent/shared/ValueDetailsBtn/useValueDetailsButton'; -import { - IStandardFieldReducerState, - IStandardFieldValue -} from '_ui/components/RecordEdition/EditRecordContent/reducers/standardFieldReducer/standardFieldReducer'; import {useLang} from '_ui/hooks'; import {localizedTranslation} from '@leav/utils'; import moment from 'moment'; import {stringifyDateRangeValue} from '_ui/_utils'; - -interface IMonoValueSelectProps extends IProvidedByAntFormItem { - state: IStandardFieldReducerState; - attribute: RecordFormAttributeStandardAttributeFragment; - fieldValue: IStandardFieldValue; - handleSubmit: (value: string, id?: string) => void; - handleBlur: () => void; - shouldShowValueDetailsButton?: boolean; -} +import {IDateRangeValuesListConf, IMonoValueSelectProps, IStringValuesListConf} from './_types'; export const MonoValueSelect: FunctionComponent = ({ value, @@ -67,9 +49,6 @@ export const MonoValueSelect: FunctionComponent = ({ } }, [fieldValue.isEditing]); - type IStringValuesListConf = StandardValuesListFragmentStandardStringValuesListConfFragment; - type IDateRangeValuesListConf = StandardValuesListFragmentStandardDateRangeValuesListConfFragment; - const _getFilteredValuesList = () => { let values = []; @@ -104,9 +83,9 @@ export const MonoValueSelect: FunctionComponent = ({ const _resetToInheritedOrCalculatedValue = () => { if (state.isInheritedValue) { - onChange(state.inheritedValue.raw_value, options); + setTimeout(() => onChange(state.inheritedValue.raw_value, options), 0); } else if (state.isCalculatedValue) { - onChange(state.calculatedValue.raw_value, options); + setTimeout(() => onChange(state.calculatedValue.raw_value, options), 0); } handleSubmit('', attribute.id); }; @@ -129,8 +108,8 @@ export const MonoValueSelect: FunctionComponent = ({ }; const _handleOnClear = () => { - handleSubmit('', attribute.id); - _handleOnBlur(); + _handleOnChange(''); + handleBlur(); }; const helper = useMemo(() => { @@ -170,14 +149,14 @@ export const MonoValueSelect: FunctionComponent = ({ dropdownRender={menu => ( <> {searchedString !== '' && searchResultsCount > 0 && ( - <> +
{t('record_edition.press_enter_to')} {t('record_edition.select_this_value')} - +
)} {menu} diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/ValuesList/_types.ts b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/ValuesList/_types.ts new file mode 100644 index 000000000..4c6f6e0d9 --- /dev/null +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/ValuesList/_types.ts @@ -0,0 +1,23 @@ +import { + RecordFormAttributeStandardAttributeFragment, + StandardValuesListFragmentStandardDateRangeValuesListConfFragment, + StandardValuesListFragmentStandardStringValuesListConfFragment +} from '_ui/_gqlTypes'; +import {IProvidedByAntFormItem} from '_ui/components/RecordEdition/EditRecordContent/_types'; +import { + IStandardFieldReducerState, + IStandardFieldValue +} from '_ui/components/RecordEdition/EditRecordContent/reducers/standardFieldReducer/standardFieldReducer'; +import {SelectProps} from 'antd'; + +export interface IMonoValueSelectProps extends IProvidedByAntFormItem { + state: IStandardFieldReducerState; + attribute: RecordFormAttributeStandardAttributeFragment; + fieldValue: IStandardFieldValue; + handleSubmit: (value: string, id?: string) => void; + handleBlur: () => void; + shouldShowValueDetailsButton?: boolean; +} + +export type IStringValuesListConf = StandardValuesListFragmentStandardStringValuesListConfFragment; +export type IDateRangeValuesListConf = StandardValuesListFragmentStandardDateRangeValuesListConfFragment;