From 17cb8d7713c8232c7ad637fd06d763765f1cd998 Mon Sep 17 00:00:00 2001 From: Arno Date: Thu, 7 Mar 2024 09:59:37 +0100 Subject: [PATCH 01/16] --wip-- [skip ci] polish: ds input period field refacto(Input): add information button on text and range picker input feat(Input): make input reset value if required and empty --- .../attributes/attributeDetailsFragment.ts | 1 + .../RecordEdition/EditRecord/EditRecord.tsx | 14 +--- .../EditRecordContent/EditRecordContent.tsx | 65 +++++++++++++--- .../RecordEdition/EditRecordContent/_types.ts | 5 +- .../StandardFieldValue/DSInputWrapper.tsx | 69 +++++++++++++++++ .../DSRangePickerWrapper.tsx | 74 ++++++++++++++++++ .../StandardFieldValue/StandardFieldValue.tsx | 76 ++++++++++++++++--- .../EditRecordModal/EditRecordModal.tsx | 2 +- .../EditRecordPage/EditRecordPage.tsx | 2 +- libs/ui/src/locales/en/shared.json | 1 + libs/ui/src/locales/fr/shared.json | 1 + libs/utils/dist/cjs/types/applications.d.ts | 2 +- libs/utils/dist/cjs/types/attributes.js | 3 + libs/utils/dist/cjs/types/attributes.js.map | 2 +- libs/utils/dist/cjs/types/errors.d.ts | 6 +- libs/utils/dist/cjs/types/events.d.ts | 58 +++++++------- libs/utils/dist/cjs/types/forms.d.ts | 35 +++++---- libs/utils/dist/cjs/types/forms.js.map | 2 +- libs/utils/dist/esm/types/applications.d.ts | 2 +- libs/utils/dist/esm/types/attributes.js | 3 + libs/utils/dist/esm/types/attributes.js.map | 2 +- libs/utils/dist/esm/types/errors.d.ts | 6 +- libs/utils/dist/esm/types/events.d.ts | 58 +++++++------- libs/utils/dist/esm/types/forms.d.ts | 35 +++++---- libs/utils/dist/esm/types/forms.js.map | 2 +- libs/utils/dist/esm/utils.d.ts | 57 ++++---------- libs/utils/src/types/forms.ts | 4 + 27 files changed, 404 insertions(+), 183 deletions(-) create mode 100644 libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.tsx create mode 100644 libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRangePickerWrapper.tsx diff --git a/libs/ui/src/_queries/attributes/attributeDetailsFragment.ts b/libs/ui/src/_queries/attributes/attributeDetailsFragment.ts index 013ee0a1f..e9a2750ba 100644 --- a/libs/ui/src/_queries/attributes/attributeDetailsFragment.ts +++ b/libs/ui/src/_queries/attributes/attributeDetailsFragment.ts @@ -11,6 +11,7 @@ export const attributeDetailsFragment = gql` system readonly label + required description multiple_values metadata_fields { diff --git a/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx b/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx index 53e695ed0..9bd6d27ef 100644 --- a/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx @@ -58,7 +58,6 @@ interface IEditRecordProps { // Here we're not in charge of buttons position. It might on a modal footer or pretty much anywhere. // We're using refs to still be able to handle the click on the buttons buttonsRefs: { - submit?: React.RefObject; close?: React.RefObject; refresh?: React.RefObject; valuesVersions?: React.RefObject; @@ -163,15 +162,6 @@ export const EditRecord: FunctionComponent = ({ }; }, [buttonsRefs]); - // Handle state (disabled or not) of submit button - useEffect(() => { - if (!buttonsRefs?.submit?.current) { - return; - } - - buttonsRefs.submit.current.disabled = !hasPendingValues; - }, [hasPendingValues, buttonsRefs.submit]); - // Keep pendingValuesRef in sync with the state useEffect(() => { pendingValuesRef.current = pendingValues; @@ -330,7 +320,7 @@ export const EditRecord: FunctionComponent = ({ /** * Submit the whole record: create record and batch save all stored values */ - const _handleRecordSubmit = async () => { + const handleRecordSubmit = async () => { const currentPendingValues = pendingValuesRef.current ?? {}; if (!!!Object.keys(currentPendingValues).length) { return; @@ -439,7 +429,6 @@ export const EditRecord: FunctionComponent = ({ }; const listenersByButtonsName: Record void> = { - submit: _handleRecordSubmit, close: onClose, refresh: () => { dispatch({ @@ -466,6 +455,7 @@ export const EditRecord: FunctionComponent = ({ void; onValueSubmit: SubmitValueFunc; onValueDelete: DeleteValueFunc; onDeleteMultipleValues: DeleteMultipleValuesFunc; @@ -30,6 +37,7 @@ interface IEditRecordContentProps { function EditRecordContent({ record, library, + handleRecordSubmit, onValueSubmit, onValueDelete, onDeleteMultipleValues, @@ -38,6 +46,7 @@ function EditRecordContent({ const formId = record ? 'edition' : 'creation'; const {t} = useSharedTranslation(); const {state, dispatch} = useEditRecordReducer(); + const [antForm] = useForm(); useRecordsConsultationHistory(record?.library?.id ?? null, record?.id ?? null); @@ -123,17 +132,49 @@ function EditRecordContent({ uiElement: formComponents[FormUIElementTypes.FIELDS_CONTAINER] }; + const antdFormInitialValues = {}; + recordForm.elements.forEach(element => { + const {attribute, values} = element; + const fieldValue = values[0] as RecordFormElementsValueStandardValue; + if (attribute.format === AttributeFormat.text) { + antdFormInitialValues[attribute.id] = fieldValue?.raw_value || ''; + } + + const hasDateRangeValues = (dateRange: unknown): dateRange is IDateRangeValue => { + return (dateRange as IDateRangeValue).from !== undefined; + }; + + if (attribute.format === AttributeFormat.date_range) { + if (fieldValue?.raw_value) { + if (hasDateRangeValues(fieldValue.raw_value)) { + antdFormInitialValues[attribute.id] = [ + dayjs.unix(Number(fieldValue.raw_value.from)), + dayjs.unix(Number(fieldValue.raw_value.to)) + ]; + } else if (typeof fieldValue.raw_value === 'string') { + const convertedFieldValue = JSON.parse(fieldValue.raw_value); + antdFormInitialValues[attribute.id] = [ + dayjs.unix(Number(convertedFieldValue.from)), + dayjs.unix(Number(convertedFieldValue.to)) + ]; + } + } + } + }); + // Use a hash of record form as a key to force a full re-render when the form changes return ( - - - +
+ + + +
); } diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/_types.ts b/libs/ui/src/components/RecordEdition/EditRecordContent/_types.ts index e1a788ae7..0f3d5cf3f 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/_types.ts +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/_types.ts @@ -6,6 +6,7 @@ import { FormFieldTypes, FormUIElementTypes, ICommonFieldsSettings, + IRequiredFieldsSettings, IDateRangeValue, IKeyValue, Override @@ -126,7 +127,7 @@ export interface IStandardInputProps { onChange: (value: string) => void; onSubmit: (valueToSave: StandardValueTypes) => void; onPressEnter?: () => void; - settings: ICommonFieldsSettings; + settings: IRequiredFieldsSettings; inputRef: MutableRefObject; } @@ -141,7 +142,7 @@ export enum FieldScope { export interface ICommonFieldsReducerState { record: IRecordIdentityWhoAmI; - formElement: FormElement; + formElement: FormElement; attribute: IRecordPropertyAttribute; isReadOnly: boolean; activeScope: FieldScope; 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 new file mode 100644 index 000000000..fdbc4ea32 --- /dev/null +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.tsx @@ -0,0 +1,69 @@ +import {KitInput} from 'aristid-ds'; +import {FocusEvent, FunctionComponent, ReactNode} from 'react'; +import {IStandardFieldReducerState} from '../../../reducers/standardFieldReducer/standardFieldReducer'; + +import {Form} from 'antd'; +import styled from 'styled-components'; + +interface IDSInputWrapperProps { + state: IStandardFieldReducerState; + infoButton: ReactNode; + value?: string; + onChange?: () => void; + _handleSubmit: (value: string, id?: string) => void; + resetField: () => void; +} + +const InputContainer = styled.div` + position: relative; + + .actions { + position: absolute; + top: 55%; + right: 38px; + display: none; + z-index: 1000; + } + + &:hover .actions { + display: block; + } +`; + +export const DSInputWrapper: FunctionComponent = ({ + state, + value, + infoButton, + onChange, + _handleSubmit, + resetField +}) => { + const {errors} = Form.Item.useStatus(); + const isRequired = state.formElement.settings.required; + + const handleBlur = (e: FocusEvent) => { + let valuetoSubmit = e.target.value; + if (isRequired && valuetoSubmit === '' && state.formElement.values[0]) { + valuetoSubmit = (state.formElement.values[0] as any).raw_value; + resetField(); + } + _handleSubmit(valuetoSubmit, state.attribute.id); + }; + + return ( + + 0 ? 'error' : undefined} + disabled={state.isReadOnly} + onBlur={handleBlur} + allowClear={false} + /> + {/*TODO : Move actions inside KitInput when DS is updated*/} +
{infoButton}
+
+ ); +}; 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 new file mode 100644 index 000000000..46c5fa6c4 --- /dev/null +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRangePickerWrapper.tsx @@ -0,0 +1,74 @@ +import {KitDatePicker} from 'aristid-ds'; +import {FocusEvent, FunctionComponent, ReactNode} from 'react'; +import {IStandardFieldReducerState} from '../../../reducers/standardFieldReducer/standardFieldReducer'; +import {Form} from 'antd'; +import dayjs from 'dayjs'; +import {StandardValueTypes} from '../../../_types'; +import {styled} from 'styled-components'; + +interface IDSRangePickerWrapperProps { + state: IStandardFieldReducerState; + infoButton: ReactNode; + value?: string; + onChange?: (e) => void; + _handleSubmit: (value: StandardValueTypes, id?: string) => void; +} + +const InputContainer = styled.div` + position: relative; + + .actions { + position: absolute; + top: 53%; + right: 38px; + display: none; + z-index: 1000; + } + + &:hover .actions { + display: block; + } +`; + +export const DSRangePickerWrapper: FunctionComponent = ({ + state, + infoButton, + value, + onChange, + _handleSubmit +}) => { + const {errors} = Form.Item.useStatus(); + const isRequired = state.formElement.settings.required; + + const _handleDateChange: (daysjsDates: [dayjs.Dayjs, dayjs.Dayjs]) => void = daysjsDates => { + let dateToSave = {from: null, to: null}; + if (daysjsDates) { + const [dateFrom, dateTo] = daysjsDates; + dateToSave = {from: String(dateFrom.unix()), to: String(dateTo.unix())}; + } + + onChange(daysjsDates); + + if (isRequired && dateToSave.from === null) { + return; + } + + _handleSubmit(dateToSave, state.attribute.id); + }; + + return ( + + 0 ? 'error' : undefined} + disabled={state.isReadOnly} + allowClear={false} + /> + {/*TODO : Move actions inside KitInput when DS is updated*/} +
{infoButton}
+
+ ); +}; diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx index f1ac1f977..4061395ff 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx @@ -7,6 +7,8 @@ import {Button, Form, Input, InputRef, Popover, Space, theme} from 'antd'; import moment from 'moment'; import React, {MutableRefObject, useEffect, useRef} from 'react'; import styled, {CSSObject} from 'styled-components'; +import {DSInputWrapper} from './DSInputWrapper'; +import {DSRangePickerWrapper} from './DSRangePickerWrapper'; import {themeVars} from '_ui/antdTheme'; import {FloatingMenu, FloatingMenuAction} from '_ui/components'; import Dimmer from '_ui/components/Dimmer'; @@ -50,6 +52,8 @@ import NumberInput from './Inputs/NumberInput'; import TextInput from './Inputs/TextInput'; import ValuesList from './ValuesList'; import {IValueOfValuesList} from './ValuesList/ValuesList'; +import {useForm} from 'antd/es/form/Form'; +import dayjs from 'dayjs'; const ErrorMessage = styled.div` color: ${themeVars.errorColor}; @@ -252,13 +256,13 @@ function StandardFieldValue({ } }, [fieldValue.isEditing, fieldValue.editingValue]); - const _handleSubmit = async (valueToSave: StandardValueTypes) => { + const _handleSubmit = async (valueToSave: StandardValueTypes, id?: string) => { if (valueToSave === '') { return _handleDelete(); } const convertedValue = typeof valueToSave === 'object' ? JSON.stringify(valueToSave) : valueToSave; - onSubmit(fieldValue.idValue, convertedValue); + onSubmit(fieldValue.idValue ?? id, convertedValue); }; const _handlePressEnter = async () => { @@ -581,12 +585,66 @@ function StandardFieldValue({ borderRadius: hasMultipleValuesDisplay ? 'none' : token.borderRadius }; + const attributeFormatsWithoutDS = [ + AttributeFormat.boolean, + AttributeFormat.color, + AttributeFormat.date, + AttributeFormat.encrypted, + AttributeFormat.extended, + AttributeFormat.numeric, + AttributeFormat.rich_text + ]; + + // const resetField = () => { + // antForm.resetFields(); + // }; + return ( <> - {fieldValue.isEditing && } - -
- + + {attribute.format === AttributeFormat.text && ( + + } + // resetField={resetField} + /> + )} + {attribute.format === AttributeFormat.date_range && ( + + } + /> + )} + + + {attributeFormatsWithoutDS.includes(attribute.format) && ( + <> + {fieldValue.isEditing && } + )} - -
-
+ + + )} ); } diff --git a/libs/ui/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx b/libs/ui/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx index 7db2c5539..85cb94995 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx @@ -79,6 +79,7 @@ export const EditRecordModal: FunctionComponent = ({ if (isCreationMode) { footerButtons.push( = ({ afterCreate={afterCreate} valuesVersion={valuesVersion} buttonsRefs={{ - submit: submitButtonRef, close: closeButtonRef, refresh: refreshButtonRef, valuesVersions: valuesVersionsButtonRef diff --git a/libs/ui/src/components/RecordEdition/EditRecordPage/EditRecordPage.tsx b/libs/ui/src/components/RecordEdition/EditRecordPage/EditRecordPage.tsx index c7b985eee..aed4c7f28 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordPage/EditRecordPage.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordPage/EditRecordPage.tsx @@ -74,7 +74,7 @@ export const EditRecordPage: FunctionComponent = ({ library={library} valuesVersion={valuesVersion} afterCreate={afterCreate} - buttonsRefs={{submit: submitButtonRef, close: closeButtonRef, refresh: refreshButtonRef}} + buttonsRefs={{close: closeButtonRef, refresh: refreshButtonRef}} onClose={onClose} /> diff --git a/libs/ui/src/locales/en/shared.json b/libs/ui/src/locales/en/shared.json index 65a4f1f70..d5ef4068e 100644 --- a/libs/ui/src/locales/en/shared.json +++ b/libs/ui/src/locales/en/shared.json @@ -33,6 +33,7 @@ }, "errors": { "default_language_required": "The default language is required", + "standard_field_required": "This field is required", "field_required": "The field {{fieldName}} is required", "invalid_id_format": "The identifier must contain only letters, numbers, and underscores (eg. \"my_id\")", "invalid_endpoint_format": "The endpoint must contain only letters, numbers, and dashes (eg. \"my-app\")", diff --git a/libs/ui/src/locales/fr/shared.json b/libs/ui/src/locales/fr/shared.json index 2dde2f3b6..41989a323 100644 --- a/libs/ui/src/locales/fr/shared.json +++ b/libs/ui/src/locales/fr/shared.json @@ -33,6 +33,7 @@ }, "errors": { "default_language_required": "La langue par défaut est requise", + "standard_field_required": "Ce champ est requis", "field_required": "Le champ {{fieldName}} est requis", "invalid_id_format": "L'identifiant peut être composé uniquement de lettres minuscules, de chiffres et du caractère \"_\" (ex: \"mon_id\")", "invalid_endpoint_format": "Le point d'accès peut être composé uniquement de lettres minuscules, de chiffres et du caractère \"-\" (ex: \"mon-app\")", diff --git a/libs/utils/dist/cjs/types/applications.d.ts b/libs/utils/dist/cjs/types/applications.d.ts index 7c8650363..777eef2f9 100644 --- a/libs/utils/dist/cjs/types/applications.d.ts +++ b/libs/utils/dist/cjs/types/applications.d.ts @@ -1 +1 @@ -export declare const CONSULTED_APPS_KEY = 'applications_consultation'; +export declare const CONSULTED_APPS_KEY = "applications_consultation"; diff --git a/libs/utils/dist/cjs/types/attributes.js b/libs/utils/dist/cjs/types/attributes.js index 75a0e5af8..de7420d9b 100644 --- a/libs/utils/dist/cjs/types/attributes.js +++ b/libs/utils/dist/cjs/types/attributes.js @@ -1,6 +1,9 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AttributeType = void 0; +// Copyright LEAV Solutions 2017 +// This file is released under LGPL V3 +// License text available at https://www.gnu.org/licenses/lgpl-3.0.txt var AttributeType; (function (AttributeType) { AttributeType["advanced"] = "advanced"; diff --git a/libs/utils/dist/cjs/types/attributes.js.map b/libs/utils/dist/cjs/types/attributes.js.map index d43bdd51c..f7871f80f 100644 --- a/libs/utils/dist/cjs/types/attributes.js.map +++ b/libs/utils/dist/cjs/types/attributes.js.map @@ -1 +1 @@ -{"version":3,"file":"attributes.js","sourceRoot":"","sources":["../../../src/types/attributes.ts"],"names":[],"mappings":";;;AAAA,IAAY,aAMX;AAND,WAAY,aAAa;IACrB,sCAAqB,CAAA;IACrB,gDAA+B,CAAA;IAC/B,kCAAiB,CAAA;IACjB,4CAA2B,CAAA;IAC3B,8BAAa,CAAA;AACjB,CAAC,EANW,aAAa,GAAb,qBAAa,KAAb,qBAAa,QAMxB"} \ No newline at end of file +{"version":3,"file":"attributes.js","sourceRoot":"","sources":["../../../src/types/attributes.ts"],"names":[],"mappings":";;;AAAA,gCAAgC;AAChC,sCAAsC;AACtC,sEAAsE;AACtE,IAAY,aAMX;AAND,WAAY,aAAa;IACrB,sCAAqB,CAAA;IACrB,gDAA+B,CAAA;IAC/B,kCAAiB,CAAA;IACjB,4CAA2B,CAAA;IAC3B,8BAAa,CAAA;AACjB,CAAC,EANW,aAAa,GAAb,qBAAa,KAAb,qBAAa,QAMxB"} \ No newline at end of file diff --git a/libs/utils/dist/cjs/types/errors.d.ts b/libs/utils/dist/cjs/types/errors.d.ts index 12290268b..78a92613d 100644 --- a/libs/utils/dist/cjs/types/errors.d.ts +++ b/libs/utils/dist/cjs/types/errors.d.ts @@ -1,5 +1,5 @@ export declare enum ErrorTypes { - VALIDATION_ERROR = 'VALIDATION_ERROR', - PERMISSION_ERROR = 'PERMISSION_ERROR', - INTERNAL_ERROR = 'INTERNAL_ERROR' + VALIDATION_ERROR = "VALIDATION_ERROR", + PERMISSION_ERROR = "PERMISSION_ERROR", + INTERNAL_ERROR = "INTERNAL_ERROR" } diff --git a/libs/utils/dist/cjs/types/events.d.ts b/libs/utils/dist/cjs/types/events.d.ts index a08d31d8f..da911fb97 100644 --- a/libs/utils/dist/cjs/types/events.d.ts +++ b/libs/utils/dist/cjs/types/events.d.ts @@ -7,35 +7,35 @@ export interface IEvent { } /*** Database events ***/ export declare enum EventAction { - API_KEY_DELETE = 'API_KEY_DELETE', - API_KEY_SAVE = 'API_KEY_SAVE', - APP_DELETE = 'APP_DELETE', - APP_SAVE = 'APP_SAVE', - ATTRIBUTE_DELETE = 'ATTRIBUTE_DELETE', - ATTRIBUTE_SAVE = 'ATTRIBUTE_SAVE', - EXPORT_START = 'EXPORT_START', - EXPORT_END = 'EXPORT_END', - DATA_IMPORT_START = 'DATA_IMPORT_START', - DATA_IMPORT_END = 'DATA_IMPORT_END', - CONFIG_IMPORT_START = 'CONFIG_IMPORT_START', - CONFIG_IMPORT_END = 'CONFIG_IMPORT_END', - GLOBAL_SETTINGS_SAVE = 'GLOBAL_SETTINGS_SAVE', - LIBRARY_DELETE = 'LIBRARY_DELETE', - LIBRARY_PURGE = 'LIBRARY_PURGE', - LIBRARY_SAVE = 'LIBRARY_SAVE', - TASKS_DELETE = 'TASKS_DELETE', - PERMISSION_SAVE = 'PERMISSION_SAVE', - RECORD_DELETE = 'RECORD_DELETE', - RECORD_SAVE = 'RECORD_SAVE', - TREE_ADD_ELEMENT = 'TREE_ADD_ELEMENT', - TREE_DELETE = 'TREE_DELETE', - TREE_DELETE_ELEMENT = 'TREE_DELETE_ELEMENT', - TREE_MOVE_ELEMENT = 'TREE_MOVE_ELEMENT', - TREE_SAVE = 'TREE_SAVE', - VALUE_DELETE = 'VALUE_DELETE', - VALUE_SAVE = 'VALUE_SAVE', - VERSION_PROFILE_DELETE = 'VERSION_PROFILE_DELETE', - VERSION_PROFILE_SAVE = 'VERSION_PROFILE_SAVE' + API_KEY_DELETE = "API_KEY_DELETE", + API_KEY_SAVE = "API_KEY_SAVE", + APP_DELETE = "APP_DELETE", + APP_SAVE = "APP_SAVE", + ATTRIBUTE_DELETE = "ATTRIBUTE_DELETE", + ATTRIBUTE_SAVE = "ATTRIBUTE_SAVE", + EXPORT_START = "EXPORT_START", + EXPORT_END = "EXPORT_END", + DATA_IMPORT_START = "DATA_IMPORT_START", + DATA_IMPORT_END = "DATA_IMPORT_END", + CONFIG_IMPORT_START = "CONFIG_IMPORT_START", + CONFIG_IMPORT_END = "CONFIG_IMPORT_END", + GLOBAL_SETTINGS_SAVE = "GLOBAL_SETTINGS_SAVE", + LIBRARY_DELETE = "LIBRARY_DELETE", + LIBRARY_PURGE = "LIBRARY_PURGE", + LIBRARY_SAVE = "LIBRARY_SAVE", + TASKS_DELETE = "TASKS_DELETE", + PERMISSION_SAVE = "PERMISSION_SAVE", + RECORD_DELETE = "RECORD_DELETE", + RECORD_SAVE = "RECORD_SAVE", + TREE_ADD_ELEMENT = "TREE_ADD_ELEMENT", + TREE_DELETE = "TREE_DELETE", + TREE_DELETE_ELEMENT = "TREE_DELETE_ELEMENT", + TREE_MOVE_ELEMENT = "TREE_MOVE_ELEMENT", + TREE_SAVE = "TREE_SAVE", + VALUE_DELETE = "VALUE_DELETE", + VALUE_SAVE = "VALUE_SAVE", + VERSION_PROFILE_DELETE = "VERSION_PROFILE_DELETE", + VERSION_PROFILE_SAVE = "VERSION_PROFILE_SAVE" } export interface IDbPayload { trigger?: string; diff --git a/libs/utils/dist/cjs/types/forms.d.ts b/libs/utils/dist/cjs/types/forms.d.ts index 5e1c269bf..bca724c1d 100644 --- a/libs/utils/dist/cjs/types/forms.d.ts +++ b/libs/utils/dist/cjs/types/forms.d.ts @@ -1,28 +1,31 @@ -import {IKeyValue} from './helpers'; +import { IKeyValue } from './helpers'; export declare enum FormUIElementTypes { - DIVIDER = 'divider', - FIELDS_CONTAINER = 'fields_container', - TAB_FIELDS_CONTAINER = 'tab_fields_container', - TEXT_BLOCK = 'text_block', - TABS = 'tabs' + DIVIDER = "divider", + FIELDS_CONTAINER = "fields_container", + TAB_FIELDS_CONTAINER = "tab_fields_container", + TEXT_BLOCK = "text_block", + TABS = "tabs" } export declare enum FormFieldTypes { - TEXT_INPUT = 'input_field', - DATE = 'date', - CHECKBOX = 'checkbox', - ENCRYPTED = 'encrypted', - DROPDOWN = 'dropdown', - LINK = 'link', - TREE = 'tree' + TEXT_INPUT = "input_field", + DATE = "date", + CHECKBOX = "checkbox", + ENCRYPTED = "encrypted", + DROPDOWN = "dropdown", + LINK = "link", + TREE = "tree" } export declare enum TabsDirection { - HORIZONTAL = 'horizontal', - VERTICAL = 'vertical' + HORIZONTAL = "horizontal", + VERTICAL = "vertical" } export interface ICommonFieldsSettings { label?: string; attribute?: string; } +export interface IRequiredFieldsSettings extends ICommonFieldsSettings { + required?: boolean; +} export interface IFormDividerSettings { title?: string; } @@ -47,4 +50,4 @@ export interface IFormLinkFieldSettings extends ICommonFieldsSettings { }>; displayRecordIdentity: boolean; } -export declare const FORM_ROOT_CONTAINER_ID = '__root'; +export declare const FORM_ROOT_CONTAINER_ID = "__root"; diff --git a/libs/utils/dist/cjs/types/forms.js.map b/libs/utils/dist/cjs/types/forms.js.map index 32811476c..99553fbb3 100644 --- a/libs/utils/dist/cjs/types/forms.js.map +++ b/libs/utils/dist/cjs/types/forms.js.map @@ -1 +1 @@ -{"version":3,"file":"forms.js","sourceRoot":"","sources":["../../../src/types/forms.ts"],"names":[],"mappings":";;;AAKA,IAAY,kBAMX;AAND,WAAY,kBAAkB;IAC1B,yCAAmB,CAAA;IACnB,2DAAqC,CAAA;IACrC,mEAA6C,CAAA;IAC7C,+CAAyB,CAAA;IACzB,mCAAa,CAAA;AACjB,CAAC,EANW,kBAAkB,GAAlB,0BAAkB,KAAlB,0BAAkB,QAM7B;AAED,IAAY,cAQX;AARD,WAAY,cAAc;IACtB,4CAA0B,CAAA;IAC1B,+BAAa,CAAA;IACb,uCAAqB,CAAA;IACrB,yCAAuB,CAAA;IACvB,uCAAqB,CAAA;IACrB,+BAAa,CAAA;IACb,+BAAa,CAAA;AACjB,CAAC,EARW,cAAc,GAAd,sBAAc,KAAd,sBAAc,QAQzB;AAED,IAAY,aAGX;AAHD,WAAY,aAAa;IACrB,0CAAyB,CAAA;IACzB,sCAAqB,CAAA;AACzB,CAAC,EAHW,aAAa,GAAb,qBAAa,KAAb,qBAAa,QAGxB;AAqCY,QAAA,sBAAsB,GAAG,QAAQ,CAAC"} \ No newline at end of file +{"version":3,"file":"forms.js","sourceRoot":"","sources":["../../../src/types/forms.ts"],"names":[],"mappings":";;;AAKA,IAAY,kBAMX;AAND,WAAY,kBAAkB;IAC1B,yCAAmB,CAAA;IACnB,2DAAqC,CAAA;IACrC,mEAA6C,CAAA;IAC7C,+CAAyB,CAAA;IACzB,mCAAa,CAAA;AACjB,CAAC,EANW,kBAAkB,GAAlB,0BAAkB,KAAlB,0BAAkB,QAM7B;AAED,IAAY,cAQX;AARD,WAAY,cAAc;IACtB,4CAA0B,CAAA;IAC1B,+BAAa,CAAA;IACb,uCAAqB,CAAA;IACrB,yCAAuB,CAAA;IACvB,uCAAqB,CAAA;IACrB,+BAAa,CAAA;IACb,+BAAa,CAAA;AACjB,CAAC,EARW,cAAc,GAAd,sBAAc,KAAd,sBAAc,QAQzB;AAED,IAAY,aAGX;AAHD,WAAY,aAAa;IACrB,0CAAyB,CAAA;IACzB,sCAAqB,CAAA;AACzB,CAAC,EAHW,aAAa,GAAb,qBAAa,KAAb,qBAAa,QAGxB;AAyCY,QAAA,sBAAsB,GAAG,QAAQ,CAAC"} \ No newline at end of file diff --git a/libs/utils/dist/esm/types/applications.d.ts b/libs/utils/dist/esm/types/applications.d.ts index 7c8650363..777eef2f9 100644 --- a/libs/utils/dist/esm/types/applications.d.ts +++ b/libs/utils/dist/esm/types/applications.d.ts @@ -1 +1 @@ -export declare const CONSULTED_APPS_KEY = 'applications_consultation'; +export declare const CONSULTED_APPS_KEY = "applications_consultation"; diff --git a/libs/utils/dist/esm/types/attributes.js b/libs/utils/dist/esm/types/attributes.js index 45eed1345..5c53c7f9a 100644 --- a/libs/utils/dist/esm/types/attributes.js +++ b/libs/utils/dist/esm/types/attributes.js @@ -1,3 +1,6 @@ +// Copyright LEAV Solutions 2017 +// This file is released under LGPL V3 +// License text available at https://www.gnu.org/licenses/lgpl-3.0.txt export var AttributeType; (function (AttributeType) { AttributeType["advanced"] = "advanced"; diff --git a/libs/utils/dist/esm/types/attributes.js.map b/libs/utils/dist/esm/types/attributes.js.map index e3c7bf2b4..99766e6ca 100644 --- a/libs/utils/dist/esm/types/attributes.js.map +++ b/libs/utils/dist/esm/types/attributes.js.map @@ -1 +1 @@ -{"version":3,"file":"attributes.js","sourceRoot":"","sources":["../../../src/types/attributes.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,aAMX;AAND,WAAY,aAAa;IACrB,sCAAqB,CAAA;IACrB,gDAA+B,CAAA;IAC/B,kCAAiB,CAAA;IACjB,4CAA2B,CAAA;IAC3B,8BAAa,CAAA;AACjB,CAAC,EANW,aAAa,KAAb,aAAa,QAMxB"} \ No newline at end of file +{"version":3,"file":"attributes.js","sourceRoot":"","sources":["../../../src/types/attributes.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,sCAAsC;AACtC,sEAAsE;AACtE,MAAM,CAAN,IAAY,aAMX;AAND,WAAY,aAAa;IACrB,sCAAqB,CAAA;IACrB,gDAA+B,CAAA;IAC/B,kCAAiB,CAAA;IACjB,4CAA2B,CAAA;IAC3B,8BAAa,CAAA;AACjB,CAAC,EANW,aAAa,KAAb,aAAa,QAMxB"} \ No newline at end of file diff --git a/libs/utils/dist/esm/types/errors.d.ts b/libs/utils/dist/esm/types/errors.d.ts index 12290268b..78a92613d 100644 --- a/libs/utils/dist/esm/types/errors.d.ts +++ b/libs/utils/dist/esm/types/errors.d.ts @@ -1,5 +1,5 @@ export declare enum ErrorTypes { - VALIDATION_ERROR = 'VALIDATION_ERROR', - PERMISSION_ERROR = 'PERMISSION_ERROR', - INTERNAL_ERROR = 'INTERNAL_ERROR' + VALIDATION_ERROR = "VALIDATION_ERROR", + PERMISSION_ERROR = "PERMISSION_ERROR", + INTERNAL_ERROR = "INTERNAL_ERROR" } diff --git a/libs/utils/dist/esm/types/events.d.ts b/libs/utils/dist/esm/types/events.d.ts index a08d31d8f..da911fb97 100644 --- a/libs/utils/dist/esm/types/events.d.ts +++ b/libs/utils/dist/esm/types/events.d.ts @@ -7,35 +7,35 @@ export interface IEvent { } /*** Database events ***/ export declare enum EventAction { - API_KEY_DELETE = 'API_KEY_DELETE', - API_KEY_SAVE = 'API_KEY_SAVE', - APP_DELETE = 'APP_DELETE', - APP_SAVE = 'APP_SAVE', - ATTRIBUTE_DELETE = 'ATTRIBUTE_DELETE', - ATTRIBUTE_SAVE = 'ATTRIBUTE_SAVE', - EXPORT_START = 'EXPORT_START', - EXPORT_END = 'EXPORT_END', - DATA_IMPORT_START = 'DATA_IMPORT_START', - DATA_IMPORT_END = 'DATA_IMPORT_END', - CONFIG_IMPORT_START = 'CONFIG_IMPORT_START', - CONFIG_IMPORT_END = 'CONFIG_IMPORT_END', - GLOBAL_SETTINGS_SAVE = 'GLOBAL_SETTINGS_SAVE', - LIBRARY_DELETE = 'LIBRARY_DELETE', - LIBRARY_PURGE = 'LIBRARY_PURGE', - LIBRARY_SAVE = 'LIBRARY_SAVE', - TASKS_DELETE = 'TASKS_DELETE', - PERMISSION_SAVE = 'PERMISSION_SAVE', - RECORD_DELETE = 'RECORD_DELETE', - RECORD_SAVE = 'RECORD_SAVE', - TREE_ADD_ELEMENT = 'TREE_ADD_ELEMENT', - TREE_DELETE = 'TREE_DELETE', - TREE_DELETE_ELEMENT = 'TREE_DELETE_ELEMENT', - TREE_MOVE_ELEMENT = 'TREE_MOVE_ELEMENT', - TREE_SAVE = 'TREE_SAVE', - VALUE_DELETE = 'VALUE_DELETE', - VALUE_SAVE = 'VALUE_SAVE', - VERSION_PROFILE_DELETE = 'VERSION_PROFILE_DELETE', - VERSION_PROFILE_SAVE = 'VERSION_PROFILE_SAVE' + API_KEY_DELETE = "API_KEY_DELETE", + API_KEY_SAVE = "API_KEY_SAVE", + APP_DELETE = "APP_DELETE", + APP_SAVE = "APP_SAVE", + ATTRIBUTE_DELETE = "ATTRIBUTE_DELETE", + ATTRIBUTE_SAVE = "ATTRIBUTE_SAVE", + EXPORT_START = "EXPORT_START", + EXPORT_END = "EXPORT_END", + DATA_IMPORT_START = "DATA_IMPORT_START", + DATA_IMPORT_END = "DATA_IMPORT_END", + CONFIG_IMPORT_START = "CONFIG_IMPORT_START", + CONFIG_IMPORT_END = "CONFIG_IMPORT_END", + GLOBAL_SETTINGS_SAVE = "GLOBAL_SETTINGS_SAVE", + LIBRARY_DELETE = "LIBRARY_DELETE", + LIBRARY_PURGE = "LIBRARY_PURGE", + LIBRARY_SAVE = "LIBRARY_SAVE", + TASKS_DELETE = "TASKS_DELETE", + PERMISSION_SAVE = "PERMISSION_SAVE", + RECORD_DELETE = "RECORD_DELETE", + RECORD_SAVE = "RECORD_SAVE", + TREE_ADD_ELEMENT = "TREE_ADD_ELEMENT", + TREE_DELETE = "TREE_DELETE", + TREE_DELETE_ELEMENT = "TREE_DELETE_ELEMENT", + TREE_MOVE_ELEMENT = "TREE_MOVE_ELEMENT", + TREE_SAVE = "TREE_SAVE", + VALUE_DELETE = "VALUE_DELETE", + VALUE_SAVE = "VALUE_SAVE", + VERSION_PROFILE_DELETE = "VERSION_PROFILE_DELETE", + VERSION_PROFILE_SAVE = "VERSION_PROFILE_SAVE" } export interface IDbPayload { trigger?: string; diff --git a/libs/utils/dist/esm/types/forms.d.ts b/libs/utils/dist/esm/types/forms.d.ts index 5e1c269bf..bca724c1d 100644 --- a/libs/utils/dist/esm/types/forms.d.ts +++ b/libs/utils/dist/esm/types/forms.d.ts @@ -1,28 +1,31 @@ -import {IKeyValue} from './helpers'; +import { IKeyValue } from './helpers'; export declare enum FormUIElementTypes { - DIVIDER = 'divider', - FIELDS_CONTAINER = 'fields_container', - TAB_FIELDS_CONTAINER = 'tab_fields_container', - TEXT_BLOCK = 'text_block', - TABS = 'tabs' + DIVIDER = "divider", + FIELDS_CONTAINER = "fields_container", + TAB_FIELDS_CONTAINER = "tab_fields_container", + TEXT_BLOCK = "text_block", + TABS = "tabs" } export declare enum FormFieldTypes { - TEXT_INPUT = 'input_field', - DATE = 'date', - CHECKBOX = 'checkbox', - ENCRYPTED = 'encrypted', - DROPDOWN = 'dropdown', - LINK = 'link', - TREE = 'tree' + TEXT_INPUT = "input_field", + DATE = "date", + CHECKBOX = "checkbox", + ENCRYPTED = "encrypted", + DROPDOWN = "dropdown", + LINK = "link", + TREE = "tree" } export declare enum TabsDirection { - HORIZONTAL = 'horizontal', - VERTICAL = 'vertical' + HORIZONTAL = "horizontal", + VERTICAL = "vertical" } export interface ICommonFieldsSettings { label?: string; attribute?: string; } +export interface IRequiredFieldsSettings extends ICommonFieldsSettings { + required?: boolean; +} export interface IFormDividerSettings { title?: string; } @@ -47,4 +50,4 @@ export interface IFormLinkFieldSettings extends ICommonFieldsSettings { }>; displayRecordIdentity: boolean; } -export declare const FORM_ROOT_CONTAINER_ID = '__root'; +export declare const FORM_ROOT_CONTAINER_ID = "__root"; diff --git a/libs/utils/dist/esm/types/forms.js.map b/libs/utils/dist/esm/types/forms.js.map index 2128d0060..41eef5268 100644 --- a/libs/utils/dist/esm/types/forms.js.map +++ b/libs/utils/dist/esm/types/forms.js.map @@ -1 +1 @@ -{"version":3,"file":"forms.js","sourceRoot":"","sources":["../../../src/types/forms.ts"],"names":[],"mappings":"AAKA,MAAM,CAAN,IAAY,kBAMX;AAND,WAAY,kBAAkB;IAC1B,yCAAmB,CAAA;IACnB,2DAAqC,CAAA;IACrC,mEAA6C,CAAA;IAC7C,+CAAyB,CAAA;IACzB,mCAAa,CAAA;AACjB,CAAC,EANW,kBAAkB,KAAlB,kBAAkB,QAM7B;AAED,MAAM,CAAN,IAAY,cAQX;AARD,WAAY,cAAc;IACtB,4CAA0B,CAAA;IAC1B,+BAAa,CAAA;IACb,uCAAqB,CAAA;IACrB,yCAAuB,CAAA;IACvB,uCAAqB,CAAA;IACrB,+BAAa,CAAA;IACb,+BAAa,CAAA;AACjB,CAAC,EARW,cAAc,KAAd,cAAc,QAQzB;AAED,MAAM,CAAN,IAAY,aAGX;AAHD,WAAY,aAAa;IACrB,0CAAyB,CAAA;IACzB,sCAAqB,CAAA;AACzB,CAAC,EAHW,aAAa,KAAb,aAAa,QAGxB;AAqCD,MAAM,CAAC,MAAM,sBAAsB,GAAG,QAAQ,CAAC"} \ No newline at end of file +{"version":3,"file":"forms.js","sourceRoot":"","sources":["../../../src/types/forms.ts"],"names":[],"mappings":"AAKA,MAAM,CAAN,IAAY,kBAMX;AAND,WAAY,kBAAkB;IAC1B,yCAAmB,CAAA;IACnB,2DAAqC,CAAA;IACrC,mEAA6C,CAAA;IAC7C,+CAAyB,CAAA;IACzB,mCAAa,CAAA;AACjB,CAAC,EANW,kBAAkB,KAAlB,kBAAkB,QAM7B;AAED,MAAM,CAAN,IAAY,cAQX;AARD,WAAY,cAAc;IACtB,4CAA0B,CAAA;IAC1B,+BAAa,CAAA;IACb,uCAAqB,CAAA;IACrB,yCAAuB,CAAA;IACvB,uCAAqB,CAAA;IACrB,+BAAa,CAAA;IACb,+BAAa,CAAA;AACjB,CAAC,EARW,cAAc,KAAd,cAAc,QAQzB;AAED,MAAM,CAAN,IAAY,aAGX;AAHD,WAAY,aAAa;IACrB,0CAAyB,CAAA;IACzB,sCAAqB,CAAA;AACzB,CAAC,EAHW,aAAa,KAAb,aAAa,QAGxB;AAyCD,MAAM,CAAC,MAAM,sBAAsB,GAAG,QAAQ,CAAC"} \ No newline at end of file diff --git a/libs/utils/dist/esm/utils.d.ts b/libs/utils/dist/esm/utils.d.ts index 2707f149a..fb6d824c1 100644 --- a/libs/utils/dist/esm/utils.d.ts +++ b/libs/utils/dist/esm/utils.d.ts @@ -1,18 +1,10 @@ -import {AttributeType} from './types/attributes'; -import {FileType} from './types/files'; -import {IKeyValue} from './types/helpers'; +import { AttributeType } from './types/attributes'; +import { FileType } from './types/files'; +import { IKeyValue } from './types/helpers'; export declare const getGraphqlTypeFromLibraryName: (library: string) => string; export declare const getGraphqlQueryNameFromLibraryName: (library: string) => string; -export declare const isFileAllowed: ( - fsPath: string, - allowList: string[], - ignoreList: string[], - filePath: string -) => boolean; -export declare const localizedTranslation: ( - translations: Record, - availableLanguages: string[] -) => string; +export declare const isFileAllowed: (fsPath: string, allowList: string[], ignoreList: string[], filePath: string) => boolean; +export declare const localizedTranslation: (translations: Record, availableLanguages: string[]) => string; /** * * @param str @@ -20,12 +12,7 @@ export declare const localizedTranslation: ( * @param saturation in percent, default to 30 * @param luminosity in percent, default to 80 */ -export declare const stringToColor: ( - str?: string | null, - format?: string, - saturation?: number, - luminosity?: number -) => string; +export declare const stringToColor: (str?: string | null, format?: string, saturation?: number, luminosity?: number) => string; export declare const getInvertColor: (color: string) => string; /** * Parse string to extract args. @@ -35,22 +22,14 @@ export declare const getInvertColor: (color: string) => string; * eg. "-library product -type link" => {library: product, type: link} * @param mapping */ -export declare const extractArgsFromString: ( - mapping: string -) => { +export declare const extractArgsFromString: (mapping: string) => { [arg: string]: string; }; -export declare const objectToNameValueArray: ( - obj: IKeyValue -) => { +export declare const objectToNameValueArray: (obj: IKeyValue) => { name: string; value: T; }[]; -export declare const nameValArrayToObj: ( - arr?: Array<{}>, - keyFieldName?: string, - valueFieldName?: string -) => { +export declare const nameValArrayToObj: (arr?: Array<{}>, keyFieldName?: string, valueFieldName?: string) => { [key: string]: any; }; export declare const getFileType: (fileName: string) => FileType; @@ -77,23 +56,13 @@ export declare const slugifyString: (id: string, separator?: '-' | '_') => strin export declare const simpleStringHash: (str: string) => number; export declare const getFlagByLang: (lang: string) => string; export declare const getLogsIndexName: (instanceId: string) => string; -export declare const waitFor: ( - predicate: () => Promise | boolean, - options?: { - timeout?: number; - interval?: number; - } -) => Promise; +export declare const waitFor: (predicate: () => Promise | boolean, options?: { + timeout?: number; + interval?: number; +}) => Promise; export declare const isTypeLink: (type: AttributeType) => boolean; export declare const isTypeStandard: (type: AttributeType) => boolean; /** * Return a new object without the keys passed in parameter */ export declare const omit: (obj: T, ...keys: K[]) => Omit; -export declare const waitFor: ( - predicate: () => Promise | boolean, - options?: { - timeout?: number; - interval?: number; - } -) => Promise; diff --git a/libs/utils/src/types/forms.ts b/libs/utils/src/types/forms.ts index a9948a1cb..ad3744739 100644 --- a/libs/utils/src/types/forms.ts +++ b/libs/utils/src/types/forms.ts @@ -31,6 +31,10 @@ export interface ICommonFieldsSettings { attribute?: string; } +export interface IRequiredFieldsSettings extends ICommonFieldsSettings { + required?: boolean; +} + export interface IFormDividerSettings { title?: string; } From 87a798c5ccdd1143f48190288e90db1a9d3b59f2 Mon Sep 17 00:00:00 2001 From: Renaud AMSELLEM Date: Wed, 13 Mar 2024 09:59:29 +0100 Subject: [PATCH 02/16] add submit button in form --- .../RecordEdition/EditRecordContent/EditRecordContent.tsx | 7 ++++++- .../RecordEdition/EditRecordModal/EditRecordModal.tsx | 4 +--- .../RecordEdition/EditRecordPage/EditRecordPage.tsx | 7 +++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx index f3463fd49..d9ea88474 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx @@ -164,7 +164,12 @@ function EditRecordContent({ // Use a hash of record form as a key to force a full re-render when the form changes return ( -
+ = ({ const isCreationMode = !record; // Create refs for the buttons to pass them to the EditRecord component - const submitButtonRef = useRef(null); const closeButtonRef = useRef(null); const refreshButtonRef = useRef(null); const valuesVersionsButtonRef = useRef(null); @@ -81,9 +80,8 @@ export const EditRecordModal: FunctionComponent = ({ } > {t('global.submit')} diff --git a/libs/ui/src/components/RecordEdition/EditRecordPage/EditRecordPage.tsx b/libs/ui/src/components/RecordEdition/EditRecordPage/EditRecordPage.tsx index aed4c7f28..84916246a 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordPage/EditRecordPage.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordPage/EditRecordPage.tsx @@ -45,7 +45,6 @@ export const EditRecordPage: FunctionComponent = ({ const isInCreateMode = !record; // Create refs for the buttons to pass them to the EditRecord component - const submitButtonRef = useRef(null); const closeButtonRef = useRef(null); const refreshButtonRef = useRef(null); @@ -63,7 +62,11 @@ export const EditRecordPage: FunctionComponent = ({ {closeButtonLabel} {isInCreateMode && ( - }> + } + > {t('global.submit')} )} From 707cd1d55e53ea1c624fa32c5b03780d3db26fe0 Mon Sep 17 00:00:00 2001 From: Delmotte-Vincent Date: Wed, 13 Mar 2024 11:50:25 +0100 Subject: [PATCH 03/16] WIP --- libs/ui/src/__mocks__/common/attribute.ts | 2 +- .../EditRecordContent/EditRecordContent.tsx | 2 +- .../StandardFieldValue/DSInputWrapper.tsx | 15 ++-- .../DSRangePickerWrapper.tsx | 8 ++- .../Inputs/DateRangeInput.tsx | 69 ------------------- .../StandardFieldValue/StandardFieldValue.tsx | 12 +--- .../EditRecordModal/EditRecordModal.tsx | 1 + 7 files changed, 19 insertions(+), 90 deletions(-) delete mode 100644 libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/Inputs/DateRangeInput.tsx diff --git a/libs/ui/src/__mocks__/common/attribute.ts b/libs/ui/src/__mocks__/common/attribute.ts index b25a91f49..69bb26ab7 100644 --- a/libs/ui/src/__mocks__/common/attribute.ts +++ b/libs/ui/src/__mocks__/common/attribute.ts @@ -103,7 +103,7 @@ export const mockAttributeVersionable: AttributeDetailsFragment = { export const mockFormAttribute: RecordFormAttributeFragment = { id: 'test_attribute', type: AttributeType.simple, - format: AttributeFormat.text, + format: AttributeFormat.extended, label: { fr: 'test', en: 'test' diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx index d9ea88474..f489f31c6 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx @@ -21,7 +21,7 @@ import {RecordEditionContext} from './hooks/useRecordEditionContext'; import {formComponents} from './uiElements'; import {DeleteMultipleValuesFunc, DeleteValueFunc, FormElement, SubmitValueFunc} from './_types'; import {Form} from 'antd'; -import {useForm} from 'antd/es/form/Form'; +import {useForm} from 'antd/lib/form/Form'; import dayjs from 'dayjs'; interface IEditRecordContentProps { 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 fdbc4ea32..f1e3c6a62 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 @@ -1,3 +1,6 @@ +// Copyright LEAV Solutions 2017 +// This file is released under LGPL V3 +// License text available at https://www.gnu.org/licenses/lgpl-3.0.txt import {KitInput} from 'aristid-ds'; import {FocusEvent, FunctionComponent, ReactNode} from 'react'; import {IStandardFieldReducerState} from '../../../reducers/standardFieldReducer/standardFieldReducer'; @@ -11,7 +14,6 @@ interface IDSInputWrapperProps { value?: string; onChange?: () => void; _handleSubmit: (value: string, id?: string) => void; - resetField: () => void; } const InputContainer = styled.div` @@ -20,7 +22,7 @@ const InputContainer = styled.div` .actions { position: absolute; top: 55%; - right: 38px; + right: 36px; display: none; z-index: 1000; } @@ -35,17 +37,19 @@ export const DSInputWrapper: FunctionComponent = ({ value, infoButton, onChange, - _handleSubmit, - resetField + _handleSubmit }) => { const {errors} = Form.Item.useStatus(); + const form = Form.useFormInstance(); + const isRequired = state.formElement.settings.required; const handleBlur = (e: FocusEvent) => { let valuetoSubmit = e.target.value; if (isRequired && valuetoSubmit === '' && state.formElement.values[0]) { valuetoSubmit = (state.formElement.values[0] as any).raw_value; - resetField(); + form.setFieldValue(state.attribute.id, valuetoSubmit); + form.validateFields(); } _handleSubmit(valuetoSubmit, state.attribute.id); }; @@ -60,7 +64,6 @@ export const DSInputWrapper: FunctionComponent = ({ status={errors.length > 0 ? 'error' : undefined} disabled={state.isReadOnly} onBlur={handleBlur} - allowClear={false} /> {/*TODO : Move actions inside KitInput when DS is updated*/}
{infoButton}
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 46c5fa6c4..7b5689329 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 @@ -1,5 +1,8 @@ +// Copyright LEAV Solutions 2017 +// This file is released under LGPL V3 +// License text available at https://www.gnu.org/licenses/lgpl-3.0.txt import {KitDatePicker} from 'aristid-ds'; -import {FocusEvent, FunctionComponent, ReactNode} from 'react'; +import {FunctionComponent, ReactNode} from 'react'; import {IStandardFieldReducerState} from '../../../reducers/standardFieldReducer/standardFieldReducer'; import {Form} from 'antd'; import dayjs from 'dayjs'; @@ -20,7 +23,7 @@ const InputContainer = styled.div` .actions { position: absolute; top: 53%; - right: 38px; + right: 36px; display: none; z-index: 1000; } @@ -65,7 +68,6 @@ export const DSRangePickerWrapper: FunctionComponent onChange={_handleDateChange} status={errors.length > 0 ? 'error' : undefined} disabled={state.isReadOnly} - allowClear={false} /> {/*TODO : Move actions inside KitInput when DS is updated*/}
{infoButton}
diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/Inputs/DateRangeInput.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/Inputs/DateRangeInput.tsx deleted file mode 100644 index ae0f85f7b..000000000 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/Inputs/DateRangeInput.tsx +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright LEAV Solutions 2017 -// This file is released under LGPL V3 -// License text available at https://www.gnu.org/licenses/lgpl-3.0.txt -import {IDateRangeValue, IFormDateFieldSettings} from '@leav/utils'; -import {DatePicker, Input} from 'antd'; -import dayjs from 'dayjs'; -import {ComponentProps} from 'react'; -import {themeVars} from '_ui/antdTheme'; -import {IStandardInputProps} from '_ui/components/RecordEdition/EditRecordContent/_types'; -import {useSharedTranslation} from '_ui/hooks/useSharedTranslation'; -import {RecordFormAttributeStandardAttributeFragment} from '_ui/_gqlTypes'; -import {stringifyDateRangeValue} from '_ui/_utils'; - -function DateRangeInput({state, fieldValue, onFocus, onSubmit, settings}: IStandardInputProps): JSX.Element { - const {editingValue, displayValue} = fieldValue; - const {t} = useSharedTranslation(); - - const attribute = state.formElement.attribute as RecordFormAttributeStandardAttributeFragment; - const isValuesListEnabled = !!attribute?.values_list?.enable; - const isValuesListOpen = !!attribute?.values_list?.allowFreeEntry; - - const _handleDateChange: (dates: [dayjs.Dayjs, dayjs.Dayjs]) => void = selectedDates => { - const [dateFrom, dateTo] = selectedDates; - const dateToSave = selectedDates ? {from: String(dateFrom.unix()), to: String(dateTo.unix())} : null; - onSubmit(dateToSave); - }; - - const isParsable = typeof editingValue === 'string' && editingValue.length > 0; - const editingRangeValue = isParsable ? JSON.parse(editingValue) : (editingValue as IDateRangeValue); - const rangeValue: [dayjs.Dayjs, dayjs.Dayjs] = editingRangeValue - ? [dayjs(Number(editingRangeValue.from) * 1000), dayjs(Number(editingRangeValue.to) * 1000)] - : null; - - // If we have a values list, picker must be on top to keep list readable - const pickerPosition = isValuesListEnabled ? 'topLeft' : null; - - const rangeDisplayValue = displayValue as IDateRangeValue; - - return !isValuesListEnabled || isValuesListOpen ? ( - ['onOk']} - popupStyle={{background: themeVars.defaultBg}} - style={{background: themeVars.defaultBg, width: '100%'}} - allowClear={false} - placement={pickerPosition} - /> - ) : ( - - ); -} - -export default DateRangeInput; diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx index 4061395ff..6c7aa880c 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx @@ -46,14 +46,11 @@ import { import CheckboxInput from './Inputs/CheckboxInput'; import ColorInput from './Inputs/ColorInput'; import DateInput from './Inputs/DateInput'; -import DateRangeInput from './Inputs/DateRangeInput'; import EncryptedInput from './Inputs/EncryptedInput'; import NumberInput from './Inputs/NumberInput'; import TextInput from './Inputs/TextInput'; import ValuesList from './ValuesList'; import {IValueOfValuesList} from './ValuesList/ValuesList'; -import {useForm} from 'antd/es/form/Form'; -import dayjs from 'dayjs'; const ErrorMessage = styled.div` color: ${themeVars.errorColor}; @@ -185,9 +182,9 @@ const FormItem = styled(Form.Item)` const RichTextEditorInput = React.lazy(() => import('./Inputs/RichTextEditorInput')); const inputComponentByFormat: {[format in AttributeFormat]: (props: IStandardInputProps) => JSX.Element} = { - [AttributeFormat.text]: TextInput, + [AttributeFormat.text]: null, [AttributeFormat.date]: DateInput, - [AttributeFormat.date_range]: DateRangeInput, + [AttributeFormat.date_range]: null, [AttributeFormat.boolean]: CheckboxInput, [AttributeFormat.numeric]: NumberInput, [AttributeFormat.encrypted]: EncryptedInput, @@ -595,10 +592,6 @@ function StandardFieldValue({ AttributeFormat.rich_text ]; - // const resetField = () => { - // antForm.resetFields(); - // }; - return ( <> } - // resetField={resetField} /> )} {attribute.format === AttributeFormat.date_range && ( diff --git a/libs/ui/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx b/libs/ui/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx index be9e4371e..53226646c 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx @@ -78,6 +78,7 @@ export const EditRecordModal: FunctionComponent = ({ if (isCreationMode) { footerButtons.push( Date: Wed, 13 Mar 2024 14:52:37 +0100 Subject: [PATCH 04/16] text(@leav/ui): add await before getElementBy --- .../uiElements/StandardField/StandardField.test.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardField.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardField.test.tsx index 1174488b7..169520401 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardField.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardField.test.tsx @@ -484,9 +484,7 @@ describe('StandardField', () => { const submitBtn = await screen.findByRole('button', {name: 'global.submit'}); await userEvent.click(submitBtn); - await waitFor(() => { - expect(screen.getByText('ERROR_MESSAGE')).toBeInTheDocument(); - }); + expect(screen.getByText('ERROR_MESSAGE')).toBeInTheDocument(); }); test('Delete value', async () => { @@ -504,9 +502,7 @@ describe('StandardField', () => { await userEvent.click(confirmDeleteBtn); - await waitFor(() => { - expect(mockHandleDelete).toHaveBeenCalled(); - }); + expect(mockHandleDelete).toHaveBeenCalled(); }); test('On multiple-values attribute, can delete all values', async () => { From 6a9f86e9f989ccf456a06492d73e88c9a12a7eb2 Mon Sep 17 00:00:00 2001 From: Delmotte-Vincent Date: Wed, 13 Mar 2024 16:51:00 +0100 Subject: [PATCH 05/16] test(@leav/ui): split standard field test --- .../StandardField/StandardField.test.tsx | 10 +- .../StandardField/StandardFieldColor.test.tsx | 109 ++++++++++++++++ .../StandardField/StandardFieldDate.test.tsx | 100 ++++++++++++++ .../StandardFieldEncrypted.test.tsx | 101 +++++++++++++++ .../StandardFieldNumeric.test.tsx | 99 ++++++++++++++ .../StandardFieldRichText.test.tsx | 122 ++++++++++++++++++ .../StandardField/StandardFieldText.test.tsx | 90 +++++++++++++ 7 files changed, 627 insertions(+), 4 deletions(-) create mode 100644 libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldColor.test.tsx create mode 100644 libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldDate.test.tsx create mode 100644 libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldEncrypted.test.tsx create mode 100644 libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldNumeric.test.tsx create mode 100644 libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldRichText.test.tsx create mode 100644 libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldText.test.tsx diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardField.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardField.test.tsx index 169520401..c03bf788e 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardField.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardField.test.tsx @@ -106,12 +106,9 @@ describe('StandardField', () => { disconnect: jest.fn() })); - const waitForOption: waitForOptions = { - timeout: 5000 - }; - beforeEach(() => jest.clearAllMocks()); +<<<<<<< HEAD test('Render text field, type value and submit', async () => { render(); @@ -143,6 +140,8 @@ describe('StandardField', () => { }); }); +======= +>>>>>>> bf2a1819 (test(@leav/ui): split standard field test) test('Display informations about value', async () => { render(); @@ -211,6 +210,7 @@ describe('StandardField', () => { expect(inputElem).toBeDisabled(); }); +<<<<<<< HEAD test('Render date field', async () => { const recordValuesDate = [ { @@ -471,6 +471,8 @@ describe('StandardField', () => { }); }); +======= +>>>>>>> bf2a1819 (test(@leav/ui): split standard field test) test('Display error message', async () => { const onSubmitFail: SubmitValueFunc = jest.fn().mockReturnValue({ status: APICallStatus.ERROR, diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldColor.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldColor.test.tsx new file mode 100644 index 000000000..856bf10b1 --- /dev/null +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldColor.test.tsx @@ -0,0 +1,109 @@ +import {render, screen, waitFor} from '_ui/_tests/testUtils'; +import userEvent from '@testing-library/user-event'; +import StandardField from './StandardField'; +import { + APICallStatus, + DeleteMultipleValuesFunc, + DeleteValueFunc, + ISubmitMultipleResult, + SubmitValueFunc +} from '../../_types'; +import {mockModifier} from '_ui/__mocks__/common/value'; +import {AttributeFormat, AttributeType, ValueDetailsValueFragment} from '_ui/_gqlTypes'; +import {IRecordPropertyAttribute} from '_ui/_queries/records/getRecordPropertiesQuery'; +import {mockFormElementInput} from '_ui/__mocks__/common/form'; +import {mockFormAttribute} from '_ui/__mocks__/common/attribute'; + +describe('StandardField, Color input', () => { + const mockRecordValuesCommon = { + created_at: 123456789, + modified_at: 123456789, + created_by: mockModifier, + modified_by: mockModifier, + id_value: null, + metadata: null, + version: null + }; + + const mockAttribute: IRecordPropertyAttribute = { + id: 'test_attribute', + label: {en: 'Test Attribute'}, + format: AttributeFormat.color, + type: AttributeType.simple, + system: false + }; + + const mockSubmitRes: ISubmitMultipleResult = { + status: APICallStatus.SUCCESS, + values: [ + { + id_value: null, + created_at: 1234567890, + created_by: { + ...mockModifier + }, + modified_at: 1234567890, + modified_by: { + ...mockModifier + }, + value: 'new value', + raw_value: 'new raw value', + version: null, + attribute: mockAttribute as ValueDetailsValueFragment['attribute'], + metadata: null + } + ] + }; + + const mockHandleSubmit: SubmitValueFunc = jest.fn().mockReturnValue(mockSubmitRes); + const mockHandleDelete: DeleteValueFunc = jest.fn().mockReturnValue({status: APICallStatus.SUCCESS}); + const mockHandleMultipleValues: DeleteMultipleValuesFunc = jest + .fn() + .mockReturnValue({status: APICallStatus.SUCCESS}); + + const baseProps = { + onValueSubmit: mockHandleSubmit, + onValueDelete: mockHandleDelete, + onDeleteMultipleValues: mockHandleMultipleValues + }; + + window.HTMLElement.prototype.scrollIntoView = jest.fn(); + test('Render color field', async () => { + const colorValue = 'FFFFFF'; + const newColorValue = '000000'; + const recordValuesDate = [ + { + ...mockRecordValuesCommon, + value: colorValue, + raw_value: colorValue + } + ]; + render( + + ); + // Open ColorPicker Element + const colorElem = screen.getByRole('textbox'); + userEvent.click(colorElem); + + const colorPickerElem = screen.getByRole('textbox'); + expect(colorPickerElem).toBeInTheDocument(); + + // Update color value + colorPickerElem.focus(); + userEvent.clear(colorPickerElem); + userEvent.type(colorPickerElem, newColorValue); + userEvent.click(screen.getByRole('button', {name: 'global.submit'})); + + expect(colorPickerElem).not.toBeInTheDocument(); + await waitFor(() => { + expect(mockHandleSubmit).toHaveBeenCalled(); + }); + }); +}); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldDate.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldDate.test.tsx new file mode 100644 index 000000000..f9e860f19 --- /dev/null +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldDate.test.tsx @@ -0,0 +1,100 @@ +import {mockFormElementInput} from '_ui/__mocks__/common/form'; +import userEvent from '@testing-library/user-event'; +import {render, screen, waitFor} from '_ui/_tests/testUtils'; +import StandardField from './StandardField'; +import {mockFormAttribute} from '_ui/__mocks__/common/attribute'; +import {mockModifier} from '_ui/__mocks__/common/value'; +import { + APICallStatus, + DeleteMultipleValuesFunc, + DeleteValueFunc, + ISubmitMultipleResult, + SubmitValueFunc +} from '../../_types'; +import {AttributeFormat, AttributeType, ValueDetailsValueFragment} from '_ui/_gqlTypes'; +import {IRecordPropertyAttribute} from '_ui/_queries/records/getRecordPropertiesQuery'; +describe('StandardField, Date Input', () => { + window.HTMLElement.prototype.scrollIntoView = jest.fn(); + + const mockAttribute: IRecordPropertyAttribute = { + id: 'test_attribute', + label: {en: 'Test Attribute'}, + format: AttributeFormat.text, + type: AttributeType.simple, + system: false + }; + + const mockRecordValuesCommon = { + created_at: 123456789, + modified_at: 123456789, + created_by: mockModifier, + modified_by: mockModifier, + id_value: null, + metadata: null, + version: null + }; + + const mockSubmitRes: ISubmitMultipleResult = { + status: APICallStatus.SUCCESS, + values: [ + { + id_value: null, + created_at: 1234567890, + created_by: { + ...mockModifier + }, + modified_at: 1234567890, + modified_by: { + ...mockModifier + }, + value: 'new value', + raw_value: 'new raw value', + version: null, + attribute: mockAttribute as ValueDetailsValueFragment['attribute'], + metadata: null + } + ] + }; + + const mockHandleSubmit: SubmitValueFunc = jest.fn().mockReturnValue(mockSubmitRes); + const mockHandleDelete: DeleteValueFunc = jest.fn().mockReturnValue({status: APICallStatus.SUCCESS}); + const mockHandleMultipleValues: DeleteMultipleValuesFunc = jest + .fn() + .mockReturnValue({status: APICallStatus.SUCCESS}); + + const baseProps = { + onValueSubmit: mockHandleSubmit, + onValueDelete: mockHandleDelete, + onDeleteMultipleValues: mockHandleMultipleValues + }; + test('Render date field', async () => { + const recordValuesDate = [ + { + ...mockRecordValuesCommon, + value: '2021-03-19T17:24:00', + raw_value: '1616174663' + } + ]; + render( + + ); + + const inputElem = screen.getByRole('textbox'); + userEvent.click(inputElem); + const calendarElem = await screen.findByTestId('datepicker'); + expect(calendarElem).toBeInTheDocument(); + + await userEvent.click(screen.getByRole('cell', {name: '2021-03-11'})); + + await waitFor(() => { + expect(mockHandleSubmit).toHaveBeenCalled(); + }); + }); +}); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldEncrypted.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldEncrypted.test.tsx new file mode 100644 index 000000000..ddd510fd4 --- /dev/null +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldEncrypted.test.tsx @@ -0,0 +1,101 @@ +import {render, screen} from '_ui/_tests/testUtils'; +import userEvent from '@testing-library/user-event'; +import StandardField from '../StandardField'; +import {mockModifier} from '_ui/__mocks__/common/value'; +import {AttributeFormat, AttributeType, ValueDetailsValueFragment} from '_ui/_gqlTypes'; +import {IRecordPropertyAttribute} from '_ui/_queries/records/getRecordPropertiesQuery'; +import {mockFormElementInput} from '_ui/__mocks__/common/form'; +import {mockFormAttribute} from '_ui/__mocks__/common/attribute'; +import { + APICallStatus, + DeleteMultipleValuesFunc, + DeleteValueFunc, + ISubmitMultipleResult, + SubmitValueFunc +} from '../../_types'; + +describe('StandardField, Color input', () => { + const mockRecordValuesCommon = { + created_at: 123456789, + modified_at: 123456789, + created_by: mockModifier, + modified_by: mockModifier, + id_value: null, + metadata: null, + version: null + }; + + const mockAttribute: IRecordPropertyAttribute = { + id: 'test_attribute', + label: {en: 'Test Attribute'}, + format: AttributeFormat.color, + type: AttributeType.simple, + system: false + }; + + const mockSubmitRes: ISubmitMultipleResult = { + status: APICallStatus.SUCCESS, + values: [ + { + id_value: null, + created_at: 1234567890, + created_by: { + ...mockModifier + }, + modified_at: 1234567890, + modified_by: { + ...mockModifier + }, + value: 'new value', + raw_value: 'new raw value', + version: null, + attribute: mockAttribute as ValueDetailsValueFragment['attribute'], + metadata: null + } + ] + }; + + const mockHandleSubmit: SubmitValueFunc = jest.fn().mockReturnValue(mockSubmitRes); + const mockHandleDelete: DeleteValueFunc = jest.fn().mockReturnValue({status: APICallStatus.SUCCESS}); + const mockHandleMultipleValues: DeleteMultipleValuesFunc = jest + .fn() + .mockReturnValue({status: APICallStatus.SUCCESS}); + + const baseProps = { + onValueSubmit: mockHandleSubmit, + onValueDelete: mockHandleDelete, + onDeleteMultipleValues: mockHandleMultipleValues + }; + + window.HTMLElement.prototype.scrollIntoView = jest.fn(); + test('Render encrypted field', async () => { + const recordValuesEncrypted = [ + { + ...mockRecordValuesCommon, + value: 'my_hashed_pwd', + raw_value: 'my_hashed_pwd' + } + ]; + render( + + ); + + const inputElem = screen.getByRole('textbox'); + expect(inputElem).toHaveValue(); + expect(inputElem).not.toHaveValue('my_hashed_pwd'); + + userEvent.click(inputElem); + + const pwdElem = await screen.findByTestId('encrypted-input'); + + expect(pwdElem).toBeInTheDocument(); + expect(pwdElem).toHaveValue(''); + }); +}); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldNumeric.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldNumeric.test.tsx new file mode 100644 index 000000000..a3160bc57 --- /dev/null +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldNumeric.test.tsx @@ -0,0 +1,99 @@ +import {render, screen, waitFor} from '_ui/_tests/testUtils'; +import userEvent from '@testing-library/user-event'; +import StandardField from '../StandardField'; +import {mockModifier} from '_ui/__mocks__/common/value'; +import {AttributeFormat, AttributeType, ValueDetailsValueFragment} from '_ui/_gqlTypes'; +import {IRecordPropertyAttribute} from '_ui/_queries/records/getRecordPropertiesQuery'; +import {mockFormElementInput} from '_ui/__mocks__/common/form'; +import {mockFormAttribute} from '_ui/__mocks__/common/attribute'; +import { + APICallStatus, + DeleteMultipleValuesFunc, + DeleteValueFunc, + ISubmitMultipleResult, + SubmitValueFunc +} from '../../_types'; + +describe('StandardField, Numeric input', () => { + const mockRecordValuesCommon = { + created_at: 123456789, + modified_at: 123456789, + created_by: mockModifier, + modified_by: mockModifier, + id_value: null, + metadata: null, + version: null + }; + + const mockAttribute: IRecordPropertyAttribute = { + id: 'test_attribute', + label: {en: 'Test Attribute'}, + format: AttributeFormat.color, + type: AttributeType.simple, + system: false + }; + + const mockSubmitRes: ISubmitMultipleResult = { + status: APICallStatus.SUCCESS, + values: [ + { + id_value: null, + created_at: 1234567890, + created_by: { + ...mockModifier + }, + modified_at: 1234567890, + modified_by: { + ...mockModifier + }, + value: 'new value', + raw_value: 'new raw value', + version: null, + attribute: mockAttribute as ValueDetailsValueFragment['attribute'], + metadata: null + } + ] + }; + + const mockHandleSubmit: SubmitValueFunc = jest.fn().mockReturnValue(mockSubmitRes); + const mockHandleDelete: DeleteValueFunc = jest.fn().mockReturnValue({status: APICallStatus.SUCCESS}); + const mockHandleMultipleValues: DeleteMultipleValuesFunc = jest + .fn() + .mockReturnValue({status: APICallStatus.SUCCESS}); + + const baseProps = { + onValueSubmit: mockHandleSubmit, + onValueDelete: mockHandleDelete, + onDeleteMultipleValues: mockHandleMultipleValues + }; + + window.HTMLElement.prototype.scrollIntoView = jest.fn(); + + test('Render numeric input', async () => { + const recordValuesNumeric = [ + { + ...mockRecordValuesCommon, + value: '123456', + raw_value: '123456' + } + ]; + + render( + + ); + + const inputElem = screen.getByRole('textbox'); + expect(inputElem).toHaveValue('123456'); + + userEvent.click(inputElem); + + expect(await screen.findByRole('spinbutton')).toBeInTheDocument(); + }); +}); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldRichText.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldRichText.test.tsx new file mode 100644 index 000000000..ddc47db9b --- /dev/null +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldRichText.test.tsx @@ -0,0 +1,122 @@ +import {render, screen, waitFor} from '_ui/_tests/testUtils'; +import userEvent from '@testing-library/user-event'; +import StandardField from '../StandardField'; +import { + APICallStatus, + DeleteMultipleValuesFunc, + DeleteValueFunc, + ISubmitMultipleResult, + SubmitValueFunc +} from '../../_types'; +import {mockModifier} from '_ui/__mocks__/common/value'; +import {AttributeFormat, AttributeType, ValueDetailsValueFragment} from '_ui/_gqlTypes'; +import {IRecordPropertyAttribute} from '_ui/_queries/records/getRecordPropertiesQuery'; +import {mockFormElementInput} from '_ui/__mocks__/common/form'; +import {mockFormAttribute} from '_ui/__mocks__/common/attribute'; +import {Suspense} from 'react'; + +describe('StandardField, Rich Text input', () => { + const mockRecordValuesCommon = { + created_at: 123456789, + modified_at: 123456789, + created_by: mockModifier, + modified_by: mockModifier, + id_value: null, + metadata: null, + version: null + }; + + const mockAttribute: IRecordPropertyAttribute = { + id: 'test_attribute', + label: {en: 'Test Attribute'}, + format: AttributeFormat.color, + type: AttributeType.simple, + system: false + }; + + const mockSubmitRes: ISubmitMultipleResult = { + status: APICallStatus.SUCCESS, + values: [ + { + id_value: null, + created_at: 1234567890, + created_by: { + ...mockModifier + }, + modified_at: 1234567890, + modified_by: { + ...mockModifier + }, + value: 'new value', + raw_value: 'new raw value', + version: null, + attribute: mockAttribute as ValueDetailsValueFragment['attribute'], + metadata: null + } + ] + }; + + const mockHandleSubmit: SubmitValueFunc = jest.fn().mockReturnValue(mockSubmitRes); + const mockHandleDelete: DeleteValueFunc = jest.fn().mockReturnValue({status: APICallStatus.SUCCESS}); + const mockHandleMultipleValues: DeleteMultipleValuesFunc = jest + .fn() + .mockReturnValue({status: APICallStatus.SUCCESS}); + + const baseProps = { + onValueSubmit: mockHandleSubmit, + onValueDelete: mockHandleDelete, + onDeleteMultipleValues: mockHandleMultipleValues + }; + + global.ResizeObserver = jest.fn().mockImplementation(() => ({ + observe: jest.fn(), + unobserve: jest.fn(), + disconnect: jest.fn() + })); + + window.HTMLElement.prototype.scrollIntoView = jest.fn(); + test('Render Rich Text field', async () => { + const recordValuesRichText = [ + { + ...mockRecordValuesCommon, + value: '

rich text editor test

', + raw_value: 'new rich text editor test' + } + ]; + render( + Loading}> + + + ); + + await waitFor( + () => { + screen.getByTestId('ckeditor'); + }, + {timeout: 5000} + ); + + const richTextElem = screen.getByTestId('ckeditor'); + await userEvent.click(richTextElem); + + const richTextElemOpen = screen.getByRole('textbox'); + expect(richTextElemOpen).toBeInTheDocument(); + + await userEvent.click(richTextElemOpen); + + const toolBarElem = await screen.findByRole('toolbar'); + expect(toolBarElem).toBeInTheDocument(); + + await userEvent.click(screen.getByRole('button', {name: 'global.submit'})); + await waitFor(() => { + expect(mockHandleSubmit).toHaveBeenCalled(); + }); + }); +}); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldText.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldText.test.tsx new file mode 100644 index 000000000..88ecf2fe4 --- /dev/null +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldText.test.tsx @@ -0,0 +1,90 @@ +import {render, screen, waitFor} from '_ui/_tests/testUtils'; +import StandardField from './StandardField'; +import userEvent from '@testing-library/user-event'; +import {mockFormElementInput} from '_ui/__mocks__/common/form'; +import { + APICallStatus, + DeleteMultipleValuesFunc, + DeleteValueFunc, + ISubmitMultipleResult, + SubmitValueFunc +} from '../../_types'; +import {mockModifier} from '_ui/__mocks__/common/value'; +import {AttributeFormat, AttributeType, ValueDetailsValueFragment} from '_ui/_gqlTypes'; +import {IRecordPropertyAttribute} from '_ui/_queries/records/getRecordPropertiesQuery'; + +describe('StandardField, Text input', () => { + const mockAttribute: IRecordPropertyAttribute = { + id: 'test_attribute', + label: {en: 'Test Attribute'}, + format: AttributeFormat.text, + type: AttributeType.simple, + system: false + }; + + const mockSubmitRes: ISubmitMultipleResult = { + status: APICallStatus.SUCCESS, + values: [ + { + id_value: null, + created_at: 1234567890, + created_by: { + ...mockModifier + }, + modified_at: 1234567890, + modified_by: { + ...mockModifier + }, + value: 'new value', + raw_value: 'new raw value', + version: null, + attribute: mockAttribute as ValueDetailsValueFragment['attribute'], + metadata: null + } + ] + }; + + const mockHandleSubmit: SubmitValueFunc = jest.fn().mockReturnValue(mockSubmitRes); + const mockHandleDelete: DeleteValueFunc = jest.fn().mockReturnValue({status: APICallStatus.SUCCESS}); + const mockHandleMultipleValues: DeleteMultipleValuesFunc = jest + .fn() + .mockReturnValue({status: APICallStatus.SUCCESS}); + + const baseProps = { + onValueSubmit: mockHandleSubmit, + onValueDelete: mockHandleDelete, + onDeleteMultipleValues: mockHandleMultipleValues + }; + + window.HTMLElement.prototype.scrollIntoView = jest.fn(); + test('Render text field, type value and submit', async () => { + render(); + + const inputElem = screen.getByRole('textbox'); + expect(inputElem).toBeInTheDocument(); + expect(inputElem).toHaveValue('My value formatted'); + + await userEvent.click(inputElem); + + // When editing, input is a new component, thus we have to get it again + const editingInputElem = screen.getByRole('textbox'); + await waitFor(() => { + expect(editingInputElem).toHaveValue('my_raw_value'); + }); + + const submitBtn = screen.getByRole('button', {name: 'global.submit'}); + expect(submitBtn).toBeVisible(); + + await userEvent.clear(editingInputElem); + await userEvent.type(editingInputElem, 'value modified'); + await waitFor(() => { + expect(editingInputElem).toHaveValue('value modified'); + }); + + userEvent.click(submitBtn); + + await waitFor(() => { + expect(mockHandleSubmit).toHaveBeenCalled(); + }); + }); +}); From 353609f0941ab5b8304fb85fc4ec9618d934b044 Mon Sep 17 00:00:00 2001 From: Renaud AMSELLEM Date: Thu, 14 Mar 2024 10:57:51 +0100 Subject: [PATCH 06/16] add test for rangepicker --- .../DSDateRangePicker.test.tsx | 184 ++++++++++++++++++ .../StandardFieldValue/DSInputWrapper.tsx | 6 +- .../DSRangePickerWrapper.tsx | 14 +- 3 files changed, 196 insertions(+), 8 deletions(-) create mode 100644 libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSDateRangePicker.test.tsx diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSDateRangePicker.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSDateRangePicker.test.tsx new file mode 100644 index 000000000..3528b3b8a --- /dev/null +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSDateRangePicker.test.tsx @@ -0,0 +1,184 @@ +import {render, screen, fireEvent} from '_ui/_tests/testUtils'; +import {DSRangePickerWrapper} from './DSRangePickerWrapper'; +import {FieldScope} from '../../../_types'; +import { + IStandardFieldReducerState, + StandardFieldValueState +} from '../../../reducers/standardFieldReducer/standardFieldReducer'; +import {mockRecord} from '_ui/__mocks__/common/record'; +import {mockFormElementInput} from '_ui/__mocks__/common/form'; +import {mockAttributeLink} from '_ui/__mocks__/common/attribute'; +import userEvent from '@testing-library/user-event'; +import {Form} from 'antd'; +import dayjs from 'dayjs'; + +const label = 'label'; +const idValue = '123'; +const mockValue = { + index: 0, + displayValue: 'my value', + editingValue: 'my raw value', + originRawValue: 'my raw value', + idValue: null, + isEditing: false, + isErrorDisplayed: false, + value: { + id_value: null, + value: 'my value', + raw_value: 'my raw value', + modified_at: null, + created_at: null, + created_by: null, + modified_by: null + }, + version: null, + error: '', + state: StandardFieldValueState.PRISTINE +}; + +const getInitialState = (required: boolean): IStandardFieldReducerState => ({ + record: mockRecord, + formElement: { + ...mockFormElementInput, + settings: { + label, + required + } + }, + attribute: mockAttributeLink, + isReadOnly: false, + activeScope: FieldScope.CURRENT, + values: { + [FieldScope.CURRENT]: { + version: null, + values: {[idValue]: mockValue} + }, + [FieldScope.INHERITED]: null + }, + metadataEdit: false +}); + +describe('DSRangePickerWrapper', () => { + const mockOnChange = jest.fn(); + const mockHandleSubmit = jest.fn(); + let user!: ReturnType; + + beforeEach(() => { + user = userEvent.setup({}); + jest.resetAllMocks(); + }); + + describe('without required field', () => { + test('should call onChange with value', async () => { + const state = getInitialState(false); + render( + + + + + + ); + + const rangePickerInputs = screen.getAllByRole('textbox'); + await user.click(rangePickerInputs[0]); + const currentDate = dayjs().format('YYYY-MM-DD'); + await user.click(screen.getByTitle(currentDate)); + await user.click(screen.getByTitle(currentDate)); + + expect(mockOnChange).toHaveBeenCalled(); + expect(mockHandleSubmit).toHaveBeenCalledWith(expect.anything(), state.attribute.id); + }); + + test('should not save to LEAV if field becomes empty', async () => { + const state = getInitialState(false); + render( +

+ + + +
+ ); + + const rangePickerInputs = screen.getAllByRole('textbox'); + await user.click(rangePickerInputs[0]); + const currentDate = dayjs().format('YYYY-MM-DD'); + await user.click(screen.getByTitle(currentDate)); + await user.click(screen.getByTitle(currentDate)); + + expect(mockOnChange).toHaveBeenCalled(); + expect(mockHandleSubmit).toHaveBeenCalled(); + + await user.click(screen.getByRole('button')); + + expect(mockOnChange).toHaveBeenCalledTimes(2); + expect(mockHandleSubmit).toHaveBeenCalledTimes(2); + }); + }); + + describe('with required field', () => { + test('should submit the value if field is not empty', async () => { + const state = getInitialState(true); + render( +
+ + + +
+ ); + + const rangePickerInputs = screen.getAllByRole('textbox'); + await user.click(rangePickerInputs[0]); + const currentDate = dayjs().format('YYYY-MM-DD'); + await user.click(screen.getByTitle(currentDate)); + await user.click(screen.getByTitle(currentDate)); + + expect(mockOnChange).toHaveBeenCalled(); + expect(mockHandleSubmit).toHaveBeenCalledWith(expect.anything(), state.attribute.id); + }); + + test('should not save to LEAV if field becomes empty', async () => { + const state = getInitialState(true); + render( +
+ + + +
+ ); + + const rangePickerInputs = screen.getAllByRole('textbox'); + await user.click(rangePickerInputs[0]); + const currentDate = dayjs().format('YYYY-MM-DD'); + await user.click(screen.getByTitle(currentDate)); + await user.click(screen.getByTitle(currentDate)); + + expect(mockOnChange).toHaveBeenCalled(); + expect(mockHandleSubmit).toHaveBeenCalled(); + + await user.click(screen.getByRole('button')); + + expect(mockOnChange).toHaveBeenCalledTimes(2); + expect(mockHandleSubmit).toHaveBeenCalledTimes(1); + }); + }); +}); 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 f1e3c6a62..e390c304d 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 @@ -4,15 +4,15 @@ import {KitInput} from 'aristid-ds'; import {FocusEvent, FunctionComponent, ReactNode} from 'react'; import {IStandardFieldReducerState} from '../../../reducers/standardFieldReducer/standardFieldReducer'; - import {Form} from 'antd'; import styled from 'styled-components'; +import {InputProps} from 'antd/lib'; interface IDSInputWrapperProps { state: IStandardFieldReducerState; infoButton: ReactNode; - value?: string; - onChange?: () => void; + value?: InputProps['value']; + onChange?: InputProps['onChange']; _handleSubmit: (value: string, id?: string) => void; } 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 7b5689329..d0d468b24 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 @@ -8,12 +8,13 @@ import {Form} from 'antd'; import dayjs from 'dayjs'; import {StandardValueTypes} from '../../../_types'; import {styled} from 'styled-components'; +import {RangePickerProps} from 'antd/lib/date-picker'; interface IDSRangePickerWrapperProps { state: IStandardFieldReducerState; infoButton: ReactNode; - value?: string; - onChange?: (e) => void; + value?: RangePickerProps['value']; + onChange?: RangePickerProps['onChange']; _handleSubmit: (value: StandardValueTypes, id?: string) => void; } @@ -43,14 +44,17 @@ export const DSRangePickerWrapper: FunctionComponent const {errors} = Form.Item.useStatus(); const isRequired = state.formElement.settings.required; - const _handleDateChange: (daysjsDates: [dayjs.Dayjs, dayjs.Dayjs]) => void = daysjsDates => { + const _handleDateChange: (daysjsDates: [dayjs.Dayjs, dayjs.Dayjs], dateStrings: [string, string]) => void = ( + daysjsDates, + dateStrings + ) => { let dateToSave = {from: null, to: null}; if (daysjsDates) { const [dateFrom, dateTo] = daysjsDates; dateToSave = {from: String(dateFrom.unix()), to: String(dateTo.unix())}; } - onChange(daysjsDates); + onChange(daysjsDates, dateStrings); if (isRequired && dateToSave.from === null) { return; @@ -69,7 +73,7 @@ export const DSRangePickerWrapper: FunctionComponent status={errors.length > 0 ? 'error' : undefined} disabled={state.isReadOnly} /> - {/*TODO : Move actions inside KitInput when DS is updated*/} + {/*TODO : Move actions inside KitRangePicker when DS is updated*/}
{infoButton}
); From acb1c59743e5604a064a4649d5a4cf53f1ce823b Mon Sep 17 00:00:00 2001 From: Renaud AMSELLEM Date: Thu, 14 Mar 2024 11:45:42 +0100 Subject: [PATCH 07/16] fix --- .../RecordEdition/EditRecordContent/EditRecordContent.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx index f489f31c6..322e37f63 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx @@ -135,6 +135,9 @@ function EditRecordContent({ const antdFormInitialValues = {}; recordForm.elements.forEach(element => { const {attribute, values} = element; + if (!attribute) { + return; + } const fieldValue = values[0] as RecordFormElementsValueStandardValue; if (attribute.format === AttributeFormat.text) { antdFormInitialValues[attribute.id] = fieldValue?.raw_value || ''; From 2f407e70f523dfa40b6ad63ecd81b15b77d535aa Mon Sep 17 00:00:00 2001 From: Renaud AMSELLEM Date: Thu, 14 Mar 2024 12:07:01 +0100 Subject: [PATCH 08/16] fix test --- .../RecordEdition/EditRecord/EditRecord.tsx | 1 - .../StandardFieldValue/StandardFieldValue.tsx | 24 +------------------ 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx b/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx index 9bd6d27ef..fcaf1f0eb 100644 --- a/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx @@ -107,7 +107,6 @@ export const EditRecord: FunctionComponent = ({ containerStyle, buttonsRefs }) => { - const {t} = useSharedTranslation(); const isCreationMode = !record; const [state, dispatch] = useReducer(editRecordReducer, { diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx index 6c7aa880c..afe75a78a 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx @@ -259,7 +259,7 @@ function StandardFieldValue({ } const convertedValue = typeof valueToSave === 'object' ? JSON.stringify(valueToSave) : valueToSave; - onSubmit(fieldValue.idValue ?? id, convertedValue); + onSubmit(id ?? fieldValue.idValue, convertedValue); }; const _handlePressEnter = async () => { @@ -359,28 +359,6 @@ function StandardFieldValue({ if (hasValue) { switch (attribute.format) { - case AttributeFormat.date_range: - const {editingValue} = fieldValue; - const isCreation = typeof editingValue === 'string' && editingValue.length > 0; - let dateRangeValue = null; - - if (isCreation) { - const convertedFieldValue: IDateRangeValue = JSON.parse(editingValue); - dateRangeValue = { - from: new Date(Number(convertedFieldValue.from) * 1000).toLocaleDateString( - i18n.language - ), - to: new Date(Number(convertedFieldValue.to) * 1000).toLocaleDateString(i18n.language) - }; - } else { - dateRangeValue = fieldValue.displayValue as IDateRangeValue; - } - - displayedValue = - dateRangeValue?.from && dateRangeValue?.to - ? stringifyDateRangeValue(dateRangeValue, t) - : ''; - break; case AttributeFormat.encrypted: displayedValue = '•••••••••'; break; From 2db5e8fa49709e4cb2ba9a3809b454a4194d6f87 Mon Sep 17 00:00:00 2001 From: Delmotte-Vincent Date: Thu, 14 Mar 2024 13:59:59 +0100 Subject: [PATCH 09/16] fix(@leav/ui): rebase error --- .../StandardField/StandardField.test.tsx | 297 ------------------ 1 file changed, 297 deletions(-) diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardField.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardField.test.tsx index c03bf788e..37e50620f 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardField.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardField.test.tsx @@ -108,40 +108,6 @@ describe('StandardField', () => { beforeEach(() => jest.clearAllMocks()); -<<<<<<< HEAD - test('Render text field, type value and submit', async () => { - render(); - - const inputElem = screen.getByRole('textbox'); - expect(inputElem).toBeInTheDocument(); - expect(inputElem).toHaveValue('My value formatted'); - - await userEvent.click(inputElem); - - // When editing, input is a new component, thus we have to get it again - const editingInputElem = screen.getByRole('textbox'); - await waitFor(() => { - expect(editingInputElem).toHaveValue('my_raw_value'); - }); - - const submitBtn = screen.getByRole('button', {name: 'global.submit'}); - expect(submitBtn).toBeVisible(); - - await userEvent.clear(editingInputElem); - await userEvent.type(editingInputElem, 'value modified'); - await waitFor(() => { - expect(editingInputElem).toHaveValue('value modified'); - }); - - await userEvent.click(submitBtn); - - await waitFor(() => { - expect(mockHandleSubmit).toHaveBeenCalled(); - }); - }); - -======= ->>>>>>> bf2a1819 (test(@leav/ui): split standard field test) test('Display informations about value', async () => { render(); @@ -210,269 +176,6 @@ describe('StandardField', () => { expect(inputElem).toBeDisabled(); }); -<<<<<<< HEAD - test('Render date field', async () => { - const recordValuesDate = [ - { - ...mockRecordValuesCommon, - value: '2021-03-19T17:24:00', - raw_value: '1616174663' - } - ]; - render( - - ); - - const inputElem = screen.getByRole('textbox'); - await userEvent.click(inputElem); - const calendarElem = await screen.findByTestId('datepicker'); - expect(calendarElem).toBeInTheDocument(); - - await userEvent.click(screen.getByRole('cell', {name: '2021-03-11'})); - - await waitFor(() => { - expect(mockHandleSubmit).toHaveBeenCalled(); - }); - }); - - test('Render range date field', async () => { - const recordValuesRangeDate = [ - { - ...mockRecordValuesCommon, - value: { - from: '2024-02-05T08:30:50+00:00', - to: '2024-03-08T08:30:50+00:00' - }, - raw_value: { - from: 1707121850, - to: 1709886650 - } - } - ]; - - const onValueSubmitMock: SubmitValueFunc = jest.fn().mockReturnValue({ - ...mockSubmitRes, - values: [ - { - ...mockSubmitRes.values[0], - value: { - from: '2024-02-10T08:30:50+00:00', - to: '2024-02-15T08:30:50+00:00' - }, - raw_value: { - from: 1707523200, - to: 1707955200 - } - } - ] - }); - - render( - - ); - - const inputElem = screen.getByRole('textbox'); - await userEvent.click(inputElem); - - const calendarElem = screen.getAllByTestId('datepicker'); - expect(calendarElem).toHaveLength(2); - - await userEvent.click(screen.getByTitle('2024-02-10')); - await userEvent.click(screen.getByTitle('2024-02-15')); - - expect(onValueSubmitMock).toHaveBeenCalled(); - - await userEvent.click(screen.getByRole('textbox')); - expect(screen.getByPlaceholderText('Start date')).toHaveValue('2024-02-10'); - expect(screen.getByPlaceholderText('End date')).toHaveValue('2024-02-15'); - }); - - test('Render color field', async () => { - const colorValue = 'FFFFFF'; - const newColorValue = '000000'; - const recordValuesDate = [ - { - ...mockRecordValuesCommon, - value: colorValue, - raw_value: colorValue - } - ]; - render( - - ); - // Open ColorPicker Element - const colorElem = screen.getByRole('textbox'); - userEvent.click(colorElem); - - const colorPickerElem = screen.getByRole('textbox'); - expect(colorPickerElem).toBeInTheDocument(); - - // Update color value - colorPickerElem.focus(); - userEvent.clear(colorPickerElem); - userEvent.type(colorPickerElem, newColorValue); - userEvent.click(screen.getByRole('button', {name: 'global.submit'})); - - expect(colorPickerElem).not.toBeInTheDocument(); - await waitFor(() => { - expect(mockHandleSubmit).toHaveBeenCalled(); - }); - }); - - test('Render checkbox', async () => { - const recordValuesBoolean = [ - { - ...mockRecordValuesCommon, - value: 'true', - raw_value: 'true' - } - ]; - - render( - - ); - - const inputElem = screen.getByRole('checkbox'); - - await userEvent.click(inputElem); - - await waitFor(() => { - expect(mockHandleSubmit).toHaveBeenCalled(); - }); - }); - - test('Render encrypted field', async () => { - const recordValuesEncrypted = [ - { - ...mockRecordValuesCommon, - value: 'my_hashed_pwd', - raw_value: 'my_hashed_pwd' - } - ]; - render( - - ); - - const inputElem = screen.getByRole('textbox'); - expect(inputElem).toHaveValue(); - expect(inputElem).not.toHaveValue('my_hashed_pwd'); - - userEvent.click(inputElem); - - const pwdElem = await screen.findByTestId('encrypted-input'); - - expect(pwdElem).toBeInTheDocument(); - expect(pwdElem).toHaveValue(''); - }); - - test('Render numeric input', async () => { - const recordValuesNumeric = [ - { - ...mockRecordValuesCommon, - value: '123456', - raw_value: '123456' - } - ]; - - render( - - ); - - const inputElem = screen.getByRole('textbox'); - expect(inputElem).toHaveValue('123456'); - - await userEvent.click(inputElem); - - expect(await screen.findByRole('spinbutton')).toBeInTheDocument(); - }); - - test('Render Rich Text field', async () => { - const recordValuesRichText = [ - { - ...mockRecordValuesCommon, - value: '

rich text editor test

', - raw_value: 'new rich text editor test' - } - ]; - render( - Loading}> - - - ); - - await waitFor(() => { - screen.getByTestId('ckeditor'); - }, waitForOption); - - const richTextElem = screen.getByTestId('ckeditor'); - await userEvent.click(richTextElem); - - const richTextElemOpen = screen.getByRole('textbox'); - expect(richTextElemOpen).toBeInTheDocument(); - - await userEvent.click(richTextElemOpen); - - const toolBarElem = await screen.findByRole('toolbar'); - expect(toolBarElem).toBeInTheDocument(); - - await userEvent.click(screen.getByRole('button', {name: 'global.submit'})); - await waitFor(() => { - expect(mockHandleSubmit).toHaveBeenCalled(); - }); - }); - -======= ->>>>>>> bf2a1819 (test(@leav/ui): split standard field test) test('Display error message', async () => { const onSubmitFail: SubmitValueFunc = jest.fn().mockReturnValue({ status: APICallStatus.ERROR, From 666e55635b33d503efd1cde3da89823478ed0d65 Mon Sep 17 00:00:00 2001 From: Renaud AMSELLEM Date: Thu, 14 Mar 2024 14:28:14 +0100 Subject: [PATCH 10/16] fix tscheck with new ds version --- apps/data-studio/package.json | 2 +- apps/login/package.json | 2 +- apps/portal/package.json | 2 +- libs/ui/package.json | 2 +- yarn.lock | 16 ++++++++-------- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/data-studio/package.json b/apps/data-studio/package.json index a4d7d0754..fa1ca1db2 100644 --- a/apps/data-studio/package.json +++ b/apps/data-studio/package.json @@ -13,7 +13,7 @@ "antd": "5.14.0", "apollo-cache-inmemory": "1.6.6", "apollo-upload-client": "14.1.3", - "aristid-ds": "2.0.0-ae6eeaa", + "aristid-ds": "2.0.0-60b909d", "dayjs": "1.11.10", "graphql": "15.0.0", "graphql-tag": "2.12.6", diff --git a/apps/login/package.json b/apps/login/package.json index 41fd89a52..e71fcfc05 100644 --- a/apps/login/package.json +++ b/apps/login/package.json @@ -7,7 +7,7 @@ "@ant-design/icons": "5.2.6", "@leav/ui": "workspace:libs/ui", "antd": "5.14.0", - "aristid-ds": "2.0.0-ae6eeaa", + "aristid-ds": "2.0.0-60b909d", "i18next": "22.5.0", "i18next-browser-languagedetector": "7.0.2", "i18next-http-backend": "2.1.1", diff --git a/apps/portal/package.json b/apps/portal/package.json index f38053703..b88658cce 100644 --- a/apps/portal/package.json +++ b/apps/portal/package.json @@ -8,7 +8,7 @@ "@leav/ui": "workspace:libs/ui", "@leav/utils": "workspace:libs/utils", "antd": "5.14.0", - "aristid-ds": "2.0.0-ae6eeaa", + "aristid-ds": "2.0.0-60b909d", "cross-fetch": "3.1.5", "graphql-ws": "5.12.0", "i18next": "22.5.0", diff --git a/libs/ui/package.json b/libs/ui/package.json index 41656e110..457751079 100644 --- a/libs/ui/package.json +++ b/libs/ui/package.json @@ -62,7 +62,7 @@ "@ckeditor/ckeditor5-build-inline": "39.0.1", "@ckeditor/ckeditor5-react": "6.1.0", "@leav/utils": "0.0.1", - "aristid-ds": "2.0.0-ae6eeaa", + "aristid-ds": "2.0.0-60b909d", "dayjs": "1.11.10", "dompurify": "3.0.5", "html-react-parser": "4.2.2", diff --git a/yarn.lock b/yarn.lock index ccbbbec7e..4e2f2323a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7872,7 +7872,7 @@ __metadata: "@types/react-beautiful-dnd": "npm:13.1.2" "@types/react-table": "npm:7.7.12" "@types/uuid": "npm:^9" - aristid-ds: "npm:2.0.0-ae6eeaa" + aristid-ds: "npm:2.0.0-60b909d" babel-jest: "npm:29.3.1" commander: "npm:9.5.0" dayjs: "npm:1.11.10" @@ -11843,9 +11843,9 @@ __metadata: languageName: node linkType: hard -"aristid-ds@npm:2.0.0-ae6eeaa": - version: 2.0.0-ae6eeaa - resolution: "aristid-ds@npm:2.0.0-ae6eeaa" +"aristid-ds@npm:2.0.0-60b909d": + version: 2.0.0-60b909d + resolution: "aristid-ds@npm:2.0.0-60b909d" dependencies: "@dnd-kit/core": "npm:^6.1.0" "@dnd-kit/modifiers": "npm:^7.0.0" @@ -11888,7 +11888,7 @@ __metadata: react-uuid: ^2.0.0 remark-gfm: ^3.0.1 styled-components: ^6.0.7 - checksum: dad51247f954837c55e077e89bb97a85ca5b75151312f3b390690eea0451103c1e783fb92a77bbf578e04d5c27afba422218e9d896a25a1c630609334a906f4f + checksum: aad634976d8bb695e4f39205115f363598bb69cbedca5a9edf68f315e6c74128df4f3ed3de87921fb795822f8404a584dd937a525ca7c7e2da4e1f3161dc5106 languageName: node linkType: hard @@ -14761,7 +14761,7 @@ __metadata: apollo: "npm:2.34.0" apollo-cache-inmemory: "npm:1.6.6" apollo-upload-client: "npm:14.1.3" - aristid-ds: "npm:2.0.0-ae6eeaa" + aristid-ds: "npm:2.0.0-60b909d" commander: "npm:5.1.0" dayjs: "npm:1.11.10" graphql: "npm:15.0.0" @@ -22417,7 +22417,7 @@ __metadata: "@types/react-dom": "npm:18.2.6" "@vitejs/plugin-react": "npm:3.1.0" antd: "npm:5.14.0" - aristid-ds: "npm:2.0.0-ae6eeaa" + aristid-ds: "npm:2.0.0-60b909d" i18next: "npm:22.5.0" i18next-browser-languagedetector: "npm:7.0.2" i18next-http-backend: "npm:2.1.1" @@ -24974,7 +24974,7 @@ __metadata: "@vitejs/plugin-react": "npm:3.1.0" antd: "npm:5.14.0" apollo: "npm:2.34.0" - aristid-ds: "npm:2.0.0-ae6eeaa" + aristid-ds: "npm:2.0.0-60b909d" commander: "npm:10.0.0" cross-fetch: "npm:3.1.5" graphql-ws: "npm:5.12.0" From 41e174b6aaa6b4e8188166d9a10e48308d4ef29b Mon Sep 17 00:00:00 2001 From: Renaud AMSELLEM Date: Thu, 14 Mar 2024 14:52:35 +0100 Subject: [PATCH 11/16] final review for the pair --- .../EditRecordContent/EditRecordContent.tsx | 32 +++---- .../RecordEdition/EditRecordContent/_types.ts | 1 - .../RecordEdition/EditRecordContent/formId.ts | 1 + .../StandardFieldValue/DSInputWrapper.tsx | 6 +- .../DSRangePickerWrapper.tsx | 6 +- .../StandardFieldValue/StandardFieldValue.tsx | 90 ++++++++++--------- .../EditRecordModal/EditRecordModal.tsx | 3 +- .../EditRecordPage/EditRecordPage.tsx | 3 +- 8 files changed, 74 insertions(+), 68 deletions(-) create mode 100644 libs/ui/src/components/RecordEdition/EditRecordContent/formId.ts diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx index 322e37f63..a73c56278 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx @@ -4,10 +4,7 @@ import {FormUIElementTypes, FORM_ROOT_CONTAINER_ID, simpleStringHash, IDateRangeValue} from '@leav/utils'; import {useEffect, useMemo} from 'react'; import {ErrorDisplay} from '_ui/components'; -import useGetRecordForm, { - RecordFormElementsValue, - RecordFormElementsValueStandardValue -} from '_ui/hooks/useGetRecordForm'; +import useGetRecordForm, {RecordFormElementsValueStandardValue} from '_ui/hooks/useGetRecordForm'; import {useGetRecordUpdatesSubscription} from '_ui/hooks/useGetRecordUpdatesSubscription'; import useRecordsConsultationHistory from '_ui/hooks/useRecordsConsultationHistory'; import {useSharedTranslation} from '_ui/hooks/useSharedTranslation'; @@ -23,6 +20,7 @@ import {DeleteMultipleValuesFunc, DeleteValueFunc, FormElement, SubmitValueFunc} import {Form} from 'antd'; import {useForm} from 'antd/lib/form/Form'; import dayjs from 'dayjs'; +import {EDIT_OR_CREATE_RECORD_FORM_ID} from './formId'; interface IEditRecordContentProps { record: IRecordIdentityWhoAmI | null; @@ -132,43 +130,45 @@ function EditRecordContent({ uiElement: formComponents[FormUIElementTypes.FIELDS_CONTAINER] }; - const antdFormInitialValues = {}; - recordForm.elements.forEach(element => { + const hasDateRangeValues = (dateRange: unknown): dateRange is IDateRangeValue => { + return (dateRange as IDateRangeValue).from !== undefined; + }; + + const antdFormInitialValues = recordForm.elements.reduce((acc, element) => { const {attribute, values} = element; if (!attribute) { - return; + return acc; } + const fieldValue = values[0] as RecordFormElementsValueStandardValue; if (attribute.format === AttributeFormat.text) { - antdFormInitialValues[attribute.id] = fieldValue?.raw_value || ''; + acc[attribute.id] = fieldValue?.raw_value || ''; } - const hasDateRangeValues = (dateRange: unknown): dateRange is IDateRangeValue => { - return (dateRange as IDateRangeValue).from !== undefined; - }; - if (attribute.format === AttributeFormat.date_range) { if (fieldValue?.raw_value) { if (hasDateRangeValues(fieldValue.raw_value)) { - antdFormInitialValues[attribute.id] = [ + acc[attribute.id] = [ dayjs.unix(Number(fieldValue.raw_value.from)), dayjs.unix(Number(fieldValue.raw_value.to)) ]; } else if (typeof fieldValue.raw_value === 'string') { const convertedFieldValue = JSON.parse(fieldValue.raw_value); - antdFormInitialValues[attribute.id] = [ + acc[attribute.id] = [ dayjs.unix(Number(convertedFieldValue.from)), dayjs.unix(Number(convertedFieldValue.to)) ]; } } } - }); + + return acc; + }, {}); // Use a hash of record form as a key to force a full re-render when the form changes return (

void; + handleSubmit: (value: string, id?: string) => void; } const InputContainer = styled.div` @@ -37,7 +37,7 @@ export const DSInputWrapper: FunctionComponent = ({ value, infoButton, onChange, - _handleSubmit + handleSubmit }) => { const {errors} = Form.Item.useStatus(); const form = Form.useFormInstance(); @@ -51,7 +51,7 @@ export const DSInputWrapper: FunctionComponent = ({ form.setFieldValue(state.attribute.id, valuetoSubmit); form.validateFields(); } - _handleSubmit(valuetoSubmit, state.attribute.id); + handleSubmit(valuetoSubmit, state.attribute.id); }; return ( 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 d0d468b24..f3d4cbfa2 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 @@ -15,7 +15,7 @@ interface IDSRangePickerWrapperProps { infoButton: ReactNode; value?: RangePickerProps['value']; onChange?: RangePickerProps['onChange']; - _handleSubmit: (value: StandardValueTypes, id?: string) => void; + handleSubmit: (value: StandardValueTypes, id?: string) => void; } const InputContainer = styled.div` @@ -39,7 +39,7 @@ export const DSRangePickerWrapper: FunctionComponent infoButton, value, onChange, - _handleSubmit + handleSubmit }) => { const {errors} = Form.Item.useStatus(); const isRequired = state.formElement.settings.required; @@ -60,7 +60,7 @@ export const DSRangePickerWrapper: FunctionComponent return; } - _handleSubmit(dateToSave, state.attribute.id); + handleSubmit(dateToSave, state.attribute.id); }; return ( diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx index afe75a78a..677c14c1a 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx @@ -253,7 +253,7 @@ function StandardFieldValue({ } }, [fieldValue.isEditing, fieldValue.editingValue]); - const _handleSubmit = async (valueToSave: StandardValueTypes, id?: string) => { + const handleSubmit = async (valueToSave: StandardValueTypes, id?: string) => { if (valueToSave === '') { return _handleDelete(); } @@ -264,7 +264,7 @@ function StandardFieldValue({ const _handlePressEnter = async () => { if (!isValuesListEnabled) { - return _handleSubmit(fieldValue.editingValue); + return handleSubmit(fieldValue.editingValue); } const valuesList = _getFilteredValuesList(); @@ -272,7 +272,7 @@ function StandardFieldValue({ return; } - return _handleSubmit(valuesList[0].value); + return handleSubmit(valuesList[0].value); }; const _handleDelete = async () => { @@ -331,7 +331,7 @@ function StandardFieldValue({ }; const _handleClickSubmit = () => { - _handleSubmit(fieldValue.editingValue); + handleSubmit(fieldValue.editingValue); }; const _handleValueCopy = (value: AnyPrimitive | IDateRangeValue) => { @@ -405,7 +405,7 @@ function StandardFieldValue({ fieldValue={fieldValue} onChange={_handleValueChange} onFocus={_handleFocus} - onSubmit={_handleSubmit} + onSubmit={handleSubmit} onPressEnter={_handlePressEnter} settings={state.formElement.settings} inputRef={inputRef} @@ -560,6 +560,8 @@ function StandardFieldValue({ borderRadius: hasMultipleValuesDisplay ? 'none' : token.borderRadius }; + const attributeFormatsWithDS = [AttributeFormat.text, AttributeFormat.date_range]; + const attributeFormatsWithoutDS = [ AttributeFormat.boolean, AttributeFormat.color, @@ -572,44 +574,46 @@ function StandardFieldValue({ return ( <> - - {attribute.format === AttributeFormat.text && ( - - } - /> - )} - {attribute.format === AttributeFormat.date_range && ( - + {attributeFormatsWithDS && ( + - )} - + ]} + > + {attribute.format === AttributeFormat.text && ( + + } + /> + )} + {attribute.format === AttributeFormat.date_range && ( + + } + /> + )} + + )} {attributeFormatsWithoutDS.includes(attribute.format) && ( <> @@ -645,7 +649,7 @@ function StandardFieldValue({ )} diff --git a/libs/ui/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx b/libs/ui/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx index 53226646c..3c3f1a562 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx @@ -12,6 +12,7 @@ import {RecordIdentityFragment} from '_ui/_gqlTypes'; import {EditRecord} from '../EditRecord'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {faXmark, faFloppyDisk, faRotateRight, faLayerGroup} from '@fortawesome/free-solid-svg-icons'; +import {EDIT_OR_CREATE_RECORD_FORM_ID} from '../EditRecordContent/formId'; interface IEditRecordModalProps { open: boolean; @@ -81,7 +82,7 @@ export const EditRecordModal: FunctionComponent = ({ key="submit" htmlType="submit" type="primary" - form="createAndEditRecordForm" + form={EDIT_OR_CREATE_RECORD_FORM_ID} aria-label={t('global.submit')} icon={} > diff --git a/libs/ui/src/components/RecordEdition/EditRecordPage/EditRecordPage.tsx b/libs/ui/src/components/RecordEdition/EditRecordPage/EditRecordPage.tsx index 84916246a..03c037da4 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordPage/EditRecordPage.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordPage/EditRecordPage.tsx @@ -11,6 +11,7 @@ import {RecordIdentityFragment} from '_ui/_gqlTypes'; import {EditRecord} from '../EditRecord'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {faXmark, faFloppyDisk, faRotateRight} from '@fortawesome/free-solid-svg-icons'; +import {EDIT_OR_CREATE_RECORD_FORM_ID} from '../EditRecordContent/formId'; interface IEditRecordPageProps { record: RecordIdentityFragment['whoAmI'] | null; @@ -63,7 +64,7 @@ export const EditRecordPage: FunctionComponent = ({ {isInCreateMode && ( } > From 54916e29e1b0bd39a3e625c79704a7984226aa16 Mon Sep 17 00:00:00 2001 From: Renaud AMSELLEM Date: Thu, 14 Mar 2024 15:05:02 +0100 Subject: [PATCH 12/16] some commit --- .../EditRecord/EditRecord.test.tsx | 2 - .../EditRecordContent.test.tsx | 2 + .../DSDateRangePicker.test.tsx | 8 +- .../DSInputWrapper.test.tsx | 123 ++++++++++++++++++ 4 files changed, 129 insertions(+), 6 deletions(-) create mode 100644 libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.test.tsx diff --git a/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.test.tsx b/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.test.tsx index ad2d818b3..1878cdbad 100644 --- a/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.test.tsx @@ -66,7 +66,6 @@ describe('EditRecord', () => { record={mockRecord} onClose={_handleClose} buttonsRefs={{ - submit: submitButtonRef, close: closeButtonRef }} /> @@ -96,7 +95,6 @@ describe('EditRecord', () => { record={mockRecord} onClose={_handleClose} buttonsRefs={{ - submit: submitButtonRef, close: closeButtonRef }} /> diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.test.tsx index 86d5b9f6c..0c7e2d398 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.test.tsx @@ -91,6 +91,7 @@ describe('EditRecordContent', () => { library={mockRecord.library.id} onValueDelete={jest.fn()} onValueSubmit={jest.fn()} + handleRecordSubmit={jest.fn()} onDeleteMultipleValues={jest.fn()} readonly={false} />, @@ -121,6 +122,7 @@ describe('EditRecordContent', () => { { state={state} infoButton="" onChange={mockOnChange} - _handleSubmit={mockHandleSubmit} + handleSubmit={mockHandleSubmit} /> @@ -103,7 +103,7 @@ describe('DSRangePickerWrapper', () => { state={state} infoButton="" onChange={mockOnChange} - _handleSubmit={mockHandleSubmit} + handleSubmit={mockHandleSubmit} />
@@ -135,7 +135,7 @@ describe('DSRangePickerWrapper', () => { state={state} infoButton="" onChange={mockOnChange} - _handleSubmit={mockHandleSubmit} + handleSubmit={mockHandleSubmit} /> @@ -160,7 +160,7 @@ describe('DSRangePickerWrapper', () => { state={state} infoButton="" onChange={mockOnChange} - _handleSubmit={mockHandleSubmit} + handleSubmit={mockHandleSubmit} /> diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.test.tsx new file mode 100644 index 000000000..30aac6385 --- /dev/null +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.test.tsx @@ -0,0 +1,123 @@ +import {render, screen} from '_ui/_tests/testUtils'; +import {DSInputWrapper} from './DSInputWrapper'; +import {FieldScope} from '../../../_types'; +import { + IStandardFieldReducerState, + StandardFieldValueState +} from '../../../reducers/standardFieldReducer/standardFieldReducer'; +import {mockRecord} from '_ui/__mocks__/common/record'; +import {mockFormElementInput} from '_ui/__mocks__/common/form'; +import {mockAttributeLink} from '_ui/__mocks__/common/attribute'; +import userEvent from '@testing-library/user-event'; +import {Form} from 'antd'; + +const label = 'label'; +const idValue = '123'; +const mockValue = { + index: 0, + displayValue: 'my value', + editingValue: 'my raw value', + originRawValue: 'my raw value', + idValue: null, + isEditing: false, + isErrorDisplayed: false, + value: { + id_value: null, + value: 'my value', + raw_value: 'my raw value', + modified_at: null, + created_at: null, + created_by: null, + modified_by: null + }, + version: null, + error: '', + state: StandardFieldValueState.PRISTINE +}; + +const getInitialState = (required: boolean): IStandardFieldReducerState => ({ + record: mockRecord, + formElement: { + ...mockFormElementInput, + settings: { + label, + required + } + }, + attribute: mockAttributeLink, + isReadOnly: false, + activeScope: FieldScope.CURRENT, + values: { + [FieldScope.CURRENT]: { + version: null, + values: {[idValue]: mockValue} + }, + [FieldScope.INHERITED]: null + }, + metadataEdit: false +}); + +describe('DSInputWrapper', () => { + const mockHandleSubmit = jest.fn(); + let user!: ReturnType; + + beforeEach(() => { + user = userEvent.setup({}); + jest.resetAllMocks(); + }); + + test('should not submit default value if field is not required', async () => { + const state = getInitialState(false); + render( +
+ + + +
+ ); + + const input = screen.getByRole('textbox'); + await user.click(input); + await user.tab(); + + expect(mockHandleSubmit).toHaveBeenCalledWith('', state.attribute.id); + }); + + describe('with required input', () => { + test('should submit the value if field is not empty', async () => { + const state = getInitialState(true); + render( +
+ + + +
+ ); + + const text = 'text'; + const input = screen.getByRole('textbox'); + await user.click(input); + await user.type(input, text); + await user.tab(); + + expect(mockHandleSubmit).toHaveBeenCalledWith(text, state.attribute.id); + }); + + test('should submit the default value if field is empty', async () => { + const state = getInitialState(true); + render( +
+ + + +
+ ); + + const input = screen.getByRole('textbox'); + await user.click(input); + await user.tab(); + + expect(mockHandleSubmit).toHaveBeenCalledWith('my_raw_value', state.attribute.id); + }); + }); +}); From b9b2a4b9292a59405537e8bd6920a1df6b171560 Mon Sep 17 00:00:00 2001 From: Renaud AMSELLEM Date: Thu, 14 Mar 2024 18:14:28 +0100 Subject: [PATCH 13/16] review --- libs/ui/src/__mocks__/common/form.tsx | 2 +- .../RecordEdition/EditRecord/EditRecord.tsx | 6 ++--- .../EditRecordContent/EditRecordContent.tsx | 2 +- .../StandardField/StandardFieldColor.test.tsx | 10 +++---- .../StandardField/StandardFieldDate.test.tsx | 6 ++--- .../StandardFieldEncrypted.test.tsx | 4 +-- .../StandardFieldNumeric.test.tsx | 4 +-- .../StandardFieldRichText.test.tsx | 6 ++--- .../DSInputWrapper.test.tsx | 12 ++++----- .../StandardFieldValue/DSInputWrapper.tsx | 3 +-- ...test.tsx => DSRangePickerWrapper.test.tsx} | 20 ++++++++------ .../DSRangePickerWrapper.tsx | 27 ++++++++++--------- .../StandardFieldValue/StandardFieldValue.tsx | 11 +++----- 13 files changed, 54 insertions(+), 59 deletions(-) rename libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/{DSDateRangePicker.test.tsx => DSRangePickerWrapper.test.tsx} (90%) diff --git a/libs/ui/src/__mocks__/common/form.tsx b/libs/ui/src/__mocks__/common/form.tsx index b56559bca..2be166ce5 100644 --- a/libs/ui/src/__mocks__/common/form.tsx +++ b/libs/ui/src/__mocks__/common/form.tsx @@ -18,7 +18,7 @@ import {mockAttributeSimple, mockFormAttribute} from './attribute'; import {mockModifier} from './value'; import {mockVersionProfile} from './versionProfile'; -const formElementBase = { +export const formElementBase = { type: FormElementTypes.layout, attribute: null, valueError: null, diff --git a/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx b/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx index fcaf1f0eb..04ae93306 100644 --- a/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx @@ -132,7 +132,7 @@ export const EditRecord: FunctionComponent = ({ const [pendingValues, setPendingValues] = useState({}); - // As _handleRecordSubmit is called via the callback of an event listener, it won't have access to the latest state. + // As __handleRecordSubmit is called via the callback of an event listener, it won't have access to the latest state. // We use a ref to store the latest state and access it in the callback const pendingValuesRef = useRef(pendingValues); @@ -319,7 +319,7 @@ export const EditRecord: FunctionComponent = ({ /** * Submit the whole record: create record and batch save all stored values */ - const handleRecordSubmit = async () => { + const _handleRecordSubmit = async () => { const currentPendingValues = pendingValuesRef.current ?? {}; if (!!!Object.keys(currentPendingValues).length) { return; @@ -454,7 +454,7 @@ export const EditRecord: FunctionComponent = ({ { - return (dateRange as IDateRangeValue).from !== undefined; + return (dateRange as IDateRangeValue).from !== undefined && (dateRange as IDateRangeValue).to !== undefined; }; const antdFormInitialValues = recordForm.elements.reduce((acc, element) => { diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldColor.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldColor.test.tsx index 856bf10b1..e96f47367 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldColor.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldColor.test.tsx @@ -97,13 +97,11 @@ describe('StandardField, Color input', () => { // Update color value colorPickerElem.focus(); - userEvent.clear(colorPickerElem); - userEvent.type(colorPickerElem, newColorValue); - userEvent.click(screen.getByRole('button', {name: 'global.submit'})); + await userEvent.clear(colorPickerElem); + await userEvent.type(colorPickerElem, newColorValue); + await userEvent.click(screen.getByRole('button', {name: 'global.submit'})); expect(colorPickerElem).not.toBeInTheDocument(); - await waitFor(() => { - expect(mockHandleSubmit).toHaveBeenCalled(); - }); + expect(mockHandleSubmit).toHaveBeenCalled(); }); }); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldDate.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldDate.test.tsx index f9e860f19..62e230026 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldDate.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldDate.test.tsx @@ -87,14 +87,12 @@ describe('StandardField, Date Input', () => { ); const inputElem = screen.getByRole('textbox'); - userEvent.click(inputElem); + await userEvent.click(inputElem); const calendarElem = await screen.findByTestId('datepicker'); expect(calendarElem).toBeInTheDocument(); await userEvent.click(screen.getByRole('cell', {name: '2021-03-11'})); - await waitFor(() => { - expect(mockHandleSubmit).toHaveBeenCalled(); - }); + expect(mockHandleSubmit).toHaveBeenCalled(); }); }); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldEncrypted.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldEncrypted.test.tsx index ddd510fd4..45bc10734 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldEncrypted.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldEncrypted.test.tsx @@ -91,9 +91,9 @@ describe('StandardField, Color input', () => { expect(inputElem).toHaveValue(); expect(inputElem).not.toHaveValue('my_hashed_pwd'); - userEvent.click(inputElem); + await userEvent.click(inputElem); - const pwdElem = await screen.findByTestId('encrypted-input'); + const pwdElem = screen.getByTestId('encrypted-input'); expect(pwdElem).toBeInTheDocument(); expect(pwdElem).toHaveValue(''); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldNumeric.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldNumeric.test.tsx index a3160bc57..7284dd4a6 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldNumeric.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldNumeric.test.tsx @@ -92,8 +92,8 @@ describe('StandardField, Numeric input', () => { const inputElem = screen.getByRole('textbox'); expect(inputElem).toHaveValue('123456'); - userEvent.click(inputElem); + await userEvent.click(inputElem); - expect(await screen.findByRole('spinbutton')).toBeInTheDocument(); + expect(screen.getByRole('spinbutton')).toBeInTheDocument(); }); }); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldRichText.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldRichText.test.tsx index ddc47db9b..c97a46ebb 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldRichText.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldRichText.test.tsx @@ -111,12 +111,10 @@ describe('StandardField, Rich Text input', () => { await userEvent.click(richTextElemOpen); - const toolBarElem = await screen.findByRole('toolbar'); + const toolBarElem = screen.getByRole('toolbar'); expect(toolBarElem).toBeInTheDocument(); await userEvent.click(screen.getByRole('button', {name: 'global.submit'})); - await waitFor(() => { - expect(mockHandleSubmit).toHaveBeenCalled(); - }); + expect(mockHandleSubmit).toHaveBeenCalled(); }); }); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.test.tsx index 30aac6385..9df2f517c 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.test.tsx @@ -6,7 +6,7 @@ import { StandardFieldValueState } from '../../../reducers/standardFieldReducer/standardFieldReducer'; import {mockRecord} from '_ui/__mocks__/common/record'; -import {mockFormElementInput} from '_ui/__mocks__/common/form'; +import {formElementBase, mockFormElementInput} from '_ui/__mocks__/common/form'; import {mockAttributeLink} from '_ui/__mocks__/common/attribute'; import userEvent from '@testing-library/user-event'; import {Form} from 'antd'; @@ -66,7 +66,7 @@ describe('DSInputWrapper', () => { jest.resetAllMocks(); }); - test('should not submit default value if field is not required', async () => { + test('Should submit empty value if field is not required', async () => { const state = getInitialState(false); render(
@@ -83,8 +83,8 @@ describe('DSInputWrapper', () => { expect(mockHandleSubmit).toHaveBeenCalledWith('', state.attribute.id); }); - describe('with required input', () => { - test('should submit the value if field is not empty', async () => { + describe('With required input', () => { + test('Should submit the value if field is not empty', async () => { const state = getInitialState(true); render( @@ -103,7 +103,7 @@ describe('DSInputWrapper', () => { expect(mockHandleSubmit).toHaveBeenCalledWith(text, state.attribute.id); }); - test('should submit the default value if field is empty', async () => { + test('Should submit the default value if field is empty', async () => { const state = getInitialState(true); render( @@ -117,7 +117,7 @@ describe('DSInputWrapper', () => { await user.click(input); await user.tab(); - expect(mockHandleSubmit).toHaveBeenCalledWith('my_raw_value', state.attribute.id); + expect(mockHandleSubmit).toHaveBeenCalledWith(formElementBase.values[0].raw_value, state.attribute.id); }); }); }); 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 307007bb3..325600ace 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 @@ -4,9 +4,8 @@ import {KitInput} from 'aristid-ds'; import {FocusEvent, FunctionComponent, ReactNode} from 'react'; import {IStandardFieldReducerState} from '../../../reducers/standardFieldReducer/standardFieldReducer'; -import {Form} from 'antd'; +import {Form, InputProps} from 'antd'; import styled from 'styled-components'; -import {InputProps} from 'antd/lib'; interface IDSInputWrapperProps { state: IStandardFieldReducerState; diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSDateRangePicker.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRangePickerWrapper.test.tsx similarity index 90% rename from libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSDateRangePicker.test.tsx rename to libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRangePickerWrapper.test.tsx index d6b8b3353..cc171183f 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSDateRangePicker.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRangePickerWrapper.test.tsx @@ -65,11 +65,12 @@ describe('DSRangePickerWrapper', () => { beforeEach(() => { user = userEvent.setup({}); - jest.resetAllMocks(); + mockOnChange.mockReset(); + mockHandleSubmit.mockReset(); }); - describe('without required field', () => { - test('should call onChange with value', async () => { + describe('Without required field', () => { + test('Should call onChange with value', async () => { const state = getInitialState(false); render( @@ -90,11 +91,14 @@ describe('DSRangePickerWrapper', () => { await user.click(screen.getByTitle(currentDate)); await user.click(screen.getByTitle(currentDate)); - expect(mockOnChange).toHaveBeenCalled(); + expect(mockOnChange).toHaveBeenCalledWith( + [dayjs(currentDate), dayjs(currentDate)], + [currentDate, currentDate] + ); expect(mockHandleSubmit).toHaveBeenCalledWith(expect.anything(), state.attribute.id); }); - test('should not save to LEAV if field becomes empty', async () => { + test('Should save to LEAV if field becomes empty', async () => { const state = getInitialState(false); render( @@ -125,8 +129,8 @@ describe('DSRangePickerWrapper', () => { }); }); - describe('with required field', () => { - test('should submit the value if field is not empty', async () => { + describe('With required field', () => { + test('Should submit the value if field is not empty', async () => { const state = getInitialState(true); render( @@ -151,7 +155,7 @@ describe('DSRangePickerWrapper', () => { expect(mockHandleSubmit).toHaveBeenCalledWith(expect.anything(), state.attribute.id); }); - test('should not save to LEAV if field becomes empty', async () => { + test('Should not save to LEAV if field becomes empty', async () => { const state = getInitialState(true); render( 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 f3d4cbfa2..8736b2d3e 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 @@ -44,23 +44,24 @@ export const DSRangePickerWrapper: FunctionComponent const {errors} = Form.Item.useStatus(); const isRequired = state.formElement.settings.required; - const _handleDateChange: (daysjsDates: [dayjs.Dayjs, dayjs.Dayjs], dateStrings: [string, string]) => void = ( - daysjsDates, - dateStrings - ) => { - let dateToSave = {from: null, to: null}; - if (daysjsDates) { - const [dateFrom, dateTo] = daysjsDates; - dateToSave = {from: String(dateFrom.unix()), to: String(dateTo.unix())}; - } - - onChange(daysjsDates, dateStrings); + const _handleDateChange: ( + rangePickerDates: [dayjs.Dayjs, dayjs.Dayjs] | null, + rangePickerDatesStrings: [string, string] | null + ) => void = (rangePickerDates, rangePickerDatesStrings) => { + onChange(rangePickerDates, rangePickerDatesStrings); - if (isRequired && dateToSave.from === null) { + if (isRequired && rangePickerDates === null) { return; } - handleSubmit(dateToSave, state.attribute.id); + const datesToSave = {from: null, to: null}; + if (rangePickerDates !== null) { + const [dateFrom, dateTo] = rangePickerDates; + datesToSave.from = String(dateFrom.unix()); + datesToSave.to = String(dateTo.unix()); + } + + handleSubmit(datesToSave, state.attribute.id); }; return ( diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx index 677c14c1a..03cf16c95 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx @@ -173,12 +173,6 @@ const ButtonsWrapper = styled.div` } `; -const FormItem = styled(Form.Item)` - && { - margin: 0; - } -`; - const RichTextEditorInput = React.lazy(() => import('./Inputs/RichTextEditorInput')); const inputComponentByFormat: {[format in AttributeFormat]: (props: IStandardInputProps) => JSX.Element} = { @@ -618,7 +612,10 @@ function StandardFieldValue({ {attributeFormatsWithoutDS.includes(attribute.format) && ( <> {fieldValue.isEditing && } - + Date: Fri, 15 Mar 2024 10:24:29 +0100 Subject: [PATCH 14/16] review --- .../RecordEdition/EditRecord/EditRecord.tsx | 2 +- .../EditRecordContent.test.tsx | 4 +- .../EditRecordContent/EditRecordContent.tsx | 37 ++++++++++--------- .../{formId.ts => formConstants.ts} | 0 .../StandardFieldValue/DSInputWrapper.tsx | 3 +- .../DSRangePickerWrapper.test.tsx | 35 +++++++++++++----- .../EditRecordModal/EditRecordModal.tsx | 2 +- .../EditRecordPage/EditRecordPage.tsx | 2 +- 8 files changed, 52 insertions(+), 33 deletions(-) rename libs/ui/src/components/RecordEdition/EditRecordContent/{formId.ts => formConstants.ts} (100%) diff --git a/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx b/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx index 04ae93306..9d708a8d0 100644 --- a/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx @@ -454,7 +454,7 @@ export const EditRecord: FunctionComponent = ({ { , @@ -122,7 +122,7 @@ describe('EditRecordContent', () => { void; + onRecordSubmit: () => void; onValueSubmit: SubmitValueFunc; onValueDelete: DeleteValueFunc; onDeleteMultipleValues: DeleteMultipleValuesFunc; @@ -35,7 +35,7 @@ interface IEditRecordContentProps { function EditRecordContent({ record, library, - handleRecordSubmit, + onRecordSubmit, onValueSubmit, onValueDelete, onDeleteMultipleValues, @@ -141,24 +141,27 @@ function EditRecordContent({ } const fieldValue = values[0] as RecordFormElementsValueStandardValue; + if (attribute.format === AttributeFormat.text) { acc[attribute.id] = fieldValue?.raw_value || ''; } if (attribute.format === AttributeFormat.date_range) { - if (fieldValue?.raw_value) { - if (hasDateRangeValues(fieldValue.raw_value)) { - acc[attribute.id] = [ - dayjs.unix(Number(fieldValue.raw_value.from)), - dayjs.unix(Number(fieldValue.raw_value.to)) - ]; - } else if (typeof fieldValue.raw_value === 'string') { - const convertedFieldValue = JSON.parse(fieldValue.raw_value); - acc[attribute.id] = [ - dayjs.unix(Number(convertedFieldValue.from)), - dayjs.unix(Number(convertedFieldValue.to)) - ]; - } + if (!fieldValue?.raw_value) { + return acc; + } + + if (hasDateRangeValues(fieldValue.raw_value)) { + acc[attribute.id] = [ + dayjs.unix(Number(fieldValue.raw_value.from)), + dayjs.unix(Number(fieldValue.raw_value.to)) + ]; + } else if (typeof fieldValue.raw_value === 'string') { + const convertedFieldValue = JSON.parse(fieldValue.raw_value); + acc[attribute.id] = [ + dayjs.unix(Number(convertedFieldValue.from)), + dayjs.unix(Number(convertedFieldValue.to)) + ]; } } @@ -171,7 +174,7 @@ function EditRecordContent({ id={EDIT_OR_CREATE_RECORD_FORM_ID} form={antForm} initialValues={antdFormInitialValues} - onFinish={handleRecordSubmit} + onFinish={onRecordSubmit} > = ({ const handleBlur = (e: FocusEvent) => { let valuetoSubmit = e.target.value; if (isRequired && valuetoSubmit === '' && state.formElement.values[0]) { - valuetoSubmit = (state.formElement.values[0] as any).raw_value; + valuetoSubmit = (state.formElement.values[0] as RecordFormElementsValueStandardValue).raw_value; form.setFieldValue(state.attribute.id, valuetoSubmit); form.validateFields(); } diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRangePickerWrapper.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRangePickerWrapper.test.tsx index cc171183f..a962b5456 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRangePickerWrapper.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRangePickerWrapper.test.tsx @@ -87,15 +87,22 @@ describe('DSRangePickerWrapper', () => { const rangePickerInputs = screen.getAllByRole('textbox'); await user.click(rangePickerInputs[0]); - const currentDate = dayjs().format('YYYY-MM-DD'); - await user.click(screen.getByTitle(currentDate)); - await user.click(screen.getByTitle(currentDate)); + const startRangeDate = dayjs().format('YYYY-MM-DD'); + const endRangeDate = dayjs().add(1, 'day').format('YYYY-MM-DD'); + await user.click(screen.getByTitle(startRangeDate)); + await user.click(screen.getByTitle(endRangeDate)); + + const unixStartRangeDate = dayjs(startRangeDate).unix().toString(); + const unixEndRangeDate = dayjs(endRangeDate).unix().toString(); expect(mockOnChange).toHaveBeenCalledWith( - [dayjs(currentDate), dayjs(currentDate)], - [currentDate, currentDate] + [dayjs(startRangeDate), dayjs(endRangeDate)], + [startRangeDate, endRangeDate] + ); + expect(mockHandleSubmit).toHaveBeenCalledWith( + {from: unixStartRangeDate, to: unixEndRangeDate}, + state.attribute.id ); - expect(mockHandleSubmit).toHaveBeenCalledWith(expect.anything(), state.attribute.id); }); test('Should save to LEAV if field becomes empty', async () => { @@ -147,12 +154,20 @@ describe('DSRangePickerWrapper', () => { const rangePickerInputs = screen.getAllByRole('textbox'); await user.click(rangePickerInputs[0]); - const currentDate = dayjs().format('YYYY-MM-DD'); - await user.click(screen.getByTitle(currentDate)); - await user.click(screen.getByTitle(currentDate)); + const startRangeDate = dayjs().format('YYYY-MM-DD'); + const endRangeDate = dayjs().add(1, 'day').format('YYYY-MM-DD'); + + await user.click(screen.getByTitle(startRangeDate)); + await user.click(screen.getByTitle(endRangeDate)); + + const unixStartRangeDate = dayjs(startRangeDate).unix().toString(); + const unixEndRangeDate = dayjs(endRangeDate).unix().toString(); expect(mockOnChange).toHaveBeenCalled(); - expect(mockHandleSubmit).toHaveBeenCalledWith(expect.anything(), state.attribute.id); + expect(mockHandleSubmit).toHaveBeenCalledWith( + {from: unixStartRangeDate, to: unixEndRangeDate}, + state.attribute.id + ); }); test('Should not save to LEAV if field becomes empty', async () => { diff --git a/libs/ui/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx b/libs/ui/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx index 3c3f1a562..e8098edb0 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx @@ -12,7 +12,7 @@ import {RecordIdentityFragment} from '_ui/_gqlTypes'; import {EditRecord} from '../EditRecord'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {faXmark, faFloppyDisk, faRotateRight, faLayerGroup} from '@fortawesome/free-solid-svg-icons'; -import {EDIT_OR_CREATE_RECORD_FORM_ID} from '../EditRecordContent/formId'; +import {EDIT_OR_CREATE_RECORD_FORM_ID} from '../EditRecordContent/formConstants'; interface IEditRecordModalProps { open: boolean; diff --git a/libs/ui/src/components/RecordEdition/EditRecordPage/EditRecordPage.tsx b/libs/ui/src/components/RecordEdition/EditRecordPage/EditRecordPage.tsx index 03c037da4..6d0e5cb38 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordPage/EditRecordPage.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordPage/EditRecordPage.tsx @@ -11,7 +11,7 @@ import {RecordIdentityFragment} from '_ui/_gqlTypes'; import {EditRecord} from '../EditRecord'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {faXmark, faFloppyDisk, faRotateRight} from '@fortawesome/free-solid-svg-icons'; -import {EDIT_OR_CREATE_RECORD_FORM_ID} from '../EditRecordContent/formId'; +import {EDIT_OR_CREATE_RECORD_FORM_ID} from '../EditRecordContent/formConstants'; interface IEditRecordPageProps { record: RecordIdentityFragment['whoAmI'] | null; From 467b6e315fd1d51d98f36254aeabd090a25e0d93 Mon Sep 17 00:00:00 2001 From: Renaud AMSELLEM Date: Fri, 15 Mar 2024 14:26:26 +0100 Subject: [PATCH 15/16] review --- libs/ui/src/__mocks__/common/form.tsx | 2 +- .../RecordEdition/EditRecord/EditRecord.tsx | 4 ++-- .../EditRecordContent/EditRecordContent.tsx | 11 +++++------ .../StandardField/StandardFieldColor.test.tsx | 2 +- .../StandardField/StandardFieldDate.test.tsx | 3 +-- .../StandardFieldValue/DSInputWrapper.test.tsx | 10 +++++++--- .../DSRangePickerWrapper.test.tsx | 14 +++++++------- .../DSRangePickerWrapper.tsx | 8 ++++---- .../StandardFieldValue/StandardFieldValue.tsx | 18 +++++++++--------- 9 files changed, 37 insertions(+), 35 deletions(-) diff --git a/libs/ui/src/__mocks__/common/form.tsx b/libs/ui/src/__mocks__/common/form.tsx index 2be166ce5..b56559bca 100644 --- a/libs/ui/src/__mocks__/common/form.tsx +++ b/libs/ui/src/__mocks__/common/form.tsx @@ -18,7 +18,7 @@ import {mockAttributeSimple, mockFormAttribute} from './attribute'; import {mockModifier} from './value'; import {mockVersionProfile} from './versionProfile'; -export const formElementBase = { +const formElementBase = { type: FormElementTypes.layout, attribute: null, valueError: null, diff --git a/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx b/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx index 9d708a8d0..9dc67f02e 100644 --- a/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecord/EditRecord.tsx @@ -124,7 +124,7 @@ export const EditRecord: FunctionComponent = ({ record?.id ); - const {saveValues, loading: saveValuesLoading} = useSaveValueBatchMutation(); + const {saveValues} = useSaveValueBatchMutation(); const {deleteValue} = useExecuteDeleteValueMutation(record); const [createRecord] = useCreateRecordMutation(); @@ -132,7 +132,7 @@ export const EditRecord: FunctionComponent = ({ const [pendingValues, setPendingValues] = useState({}); - // As __handleRecordSubmit is called via the callback of an event listener, it won't have access to the latest state. + // As _handleRecordSubmit is called via the callback of an event listener, it won't have access to the latest state. // We use a ref to store the latest state and access it in the callback const pendingValuesRef = useRef(pendingValues); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx index 65136d655..1d924300e 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/EditRecordContent.tsx @@ -19,6 +19,7 @@ import {formComponents} from './uiElements'; import {DeleteMultipleValuesFunc, DeleteValueFunc, FormElement, SubmitValueFunc} from './_types'; import {Form} from 'antd'; import {useForm} from 'antd/lib/form/Form'; +import {Store} from 'antd/lib/form/interface'; import dayjs from 'dayjs'; import {EDIT_OR_CREATE_RECORD_FORM_ID} from './formConstants'; @@ -130,12 +131,10 @@ function EditRecordContent({ uiElement: formComponents[FormUIElementTypes.FIELDS_CONTAINER] }; - const hasDateRangeValues = (dateRange: unknown): dateRange is IDateRangeValue => { - return (dateRange as IDateRangeValue).from !== undefined && (dateRange as IDateRangeValue).to !== undefined; - }; + const hasDateRangeValues = (dateRange: unknown): dateRange is IDateRangeValue => + (dateRange as IDateRangeValue).from !== undefined && (dateRange as IDateRangeValue).to !== undefined; - const antdFormInitialValues = recordForm.elements.reduce((acc, element) => { - const {attribute, values} = element; + const antdFormInitialValues = recordForm.elements.reduce((acc, {attribute, values}) => { if (!attribute) { return acc; } @@ -143,7 +142,7 @@ function EditRecordContent({ const fieldValue = values[0] as RecordFormElementsValueStandardValue; if (attribute.format === AttributeFormat.text) { - acc[attribute.id] = fieldValue?.raw_value || ''; + acc[attribute.id] = fieldValue?.raw_value ?? ''; } if (attribute.format === AttributeFormat.date_range) { diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldColor.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldColor.test.tsx index e96f47367..3fbcd5949 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldColor.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldColor.test.tsx @@ -90,7 +90,7 @@ describe('StandardField, Color input', () => { ); // Open ColorPicker Element const colorElem = screen.getByRole('textbox'); - userEvent.click(colorElem); + await userEvent.click(colorElem); const colorPickerElem = screen.getByRole('textbox'); expect(colorPickerElem).toBeInTheDocument(); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldDate.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldDate.test.tsx index 62e230026..7c316cd88 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldDate.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldDate.test.tsx @@ -88,8 +88,7 @@ describe('StandardField, Date Input', () => { const inputElem = screen.getByRole('textbox'); await userEvent.click(inputElem); - const calendarElem = await screen.findByTestId('datepicker'); - expect(calendarElem).toBeInTheDocument(); + expect(screen.getByTestId('datepicker')).toBeInTheDocument(); await userEvent.click(screen.getByRole('cell', {name: '2021-03-11'})); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.test.tsx index 9df2f517c..c2e43f27c 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSInputWrapper.test.tsx @@ -6,10 +6,11 @@ import { StandardFieldValueState } from '../../../reducers/standardFieldReducer/standardFieldReducer'; import {mockRecord} from '_ui/__mocks__/common/record'; -import {formElementBase, mockFormElementInput} from '_ui/__mocks__/common/form'; +import {mockFormElementInput} from '_ui/__mocks__/common/form'; import {mockAttributeLink} from '_ui/__mocks__/common/attribute'; import userEvent from '@testing-library/user-event'; import {Form} from 'antd'; +import {RecordFormElementsValueStandardValue} from '_ui/hooks/useGetRecordForm'; const label = 'label'; const idValue = '123'; @@ -63,7 +64,7 @@ describe('DSInputWrapper', () => { beforeEach(() => { user = userEvent.setup({}); - jest.resetAllMocks(); + mockHandleSubmit.mockReset(); }); test('Should submit empty value if field is not required', async () => { @@ -117,7 +118,10 @@ describe('DSInputWrapper', () => { await user.click(input); await user.tab(); - expect(mockHandleSubmit).toHaveBeenCalledWith(formElementBase.values[0].raw_value, state.attribute.id); + expect(mockHandleSubmit).toHaveBeenCalledWith( + (state.formElement.values[0] as RecordFormElementsValueStandardValue).raw_value, + state.attribute.id + ); }); }); }); diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRangePickerWrapper.test.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRangePickerWrapper.test.tsx index a962b5456..ecfded11e 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRangePickerWrapper.test.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/DSRangePickerWrapper.test.tsx @@ -126,10 +126,10 @@ describe('DSRangePickerWrapper', () => { await user.click(screen.getByTitle(currentDate)); await user.click(screen.getByTitle(currentDate)); - expect(mockOnChange).toHaveBeenCalled(); - expect(mockHandleSubmit).toHaveBeenCalled(); + expect(mockOnChange).toHaveBeenCalledTimes(1); + expect(mockHandleSubmit).toHaveBeenCalledTimes(1); - await user.click(screen.getByRole('button')); + await user.click(screen.getByRole('button')); // click on clear icon expect(mockOnChange).toHaveBeenCalledTimes(2); expect(mockHandleSubmit).toHaveBeenCalledTimes(2); @@ -137,7 +137,7 @@ describe('DSRangePickerWrapper', () => { }); describe('With required field', () => { - test('Should submit the value if field is not empty', async () => { + test('Should save to LEAV if field is not empty', async () => { const state = getInitialState(true); render( @@ -191,10 +191,10 @@ describe('DSRangePickerWrapper', () => { await user.click(screen.getByTitle(currentDate)); await user.click(screen.getByTitle(currentDate)); - expect(mockOnChange).toHaveBeenCalled(); - expect(mockHandleSubmit).toHaveBeenCalled(); + expect(mockOnChange).toHaveBeenCalledTimes(1); + expect(mockHandleSubmit).toHaveBeenCalledTimes(1); - await user.click(screen.getByRole('button')); + await user.click(screen.getByRole('button')); // click on clear icon expect(mockOnChange).toHaveBeenCalledTimes(2); expect(mockHandleSubmit).toHaveBeenCalledTimes(1); 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 8736b2d3e..f19aaad84 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 @@ -45,10 +45,10 @@ export const DSRangePickerWrapper: FunctionComponent const isRequired = state.formElement.settings.required; const _handleDateChange: ( - rangePickerDates: [dayjs.Dayjs, dayjs.Dayjs] | null, - rangePickerDatesStrings: [string, string] | null - ) => void = (rangePickerDates, rangePickerDatesStrings) => { - onChange(rangePickerDates, rangePickerDatesStrings); + rangePickerDates: [from: dayjs.Dayjs, to: dayjs.Dayjs] | null, + antOnChangeParams: [from: string, to: string] | null + ) => void = (rangePickerDates, ...antOnChangeParams) => { + onChange(rangePickerDates, ...antOnChangeParams); if (isRequired && rangePickerDates === null) { return; diff --git a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx index 03cf16c95..b394597f5 100644 --- a/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx +++ b/libs/ui/src/components/RecordEdition/EditRecordContent/uiElements/StandardField/StandardFieldValue/StandardFieldValue.tsx @@ -247,7 +247,7 @@ function StandardFieldValue({ } }, [fieldValue.isEditing, fieldValue.editingValue]); - const handleSubmit = async (valueToSave: StandardValueTypes, id?: string) => { + const _handleSubmit = async (valueToSave: StandardValueTypes, id?: string) => { if (valueToSave === '') { return _handleDelete(); } @@ -258,7 +258,7 @@ function StandardFieldValue({ const _handlePressEnter = async () => { if (!isValuesListEnabled) { - return handleSubmit(fieldValue.editingValue); + return _handleSubmit(fieldValue.editingValue); } const valuesList = _getFilteredValuesList(); @@ -266,7 +266,7 @@ function StandardFieldValue({ return; } - return handleSubmit(valuesList[0].value); + return _handleSubmit(valuesList[0].value); }; const _handleDelete = async () => { @@ -325,7 +325,7 @@ function StandardFieldValue({ }; const _handleClickSubmit = () => { - handleSubmit(fieldValue.editingValue); + _handleSubmit(fieldValue.editingValue); }; const _handleValueCopy = (value: AnyPrimitive | IDateRangeValue) => { @@ -399,7 +399,7 @@ function StandardFieldValue({ fieldValue={fieldValue} onChange={_handleValueChange} onFocus={_handleFocus} - onSubmit={handleSubmit} + onSubmit={_handleSubmit} onPressEnter={_handlePressEnter} settings={state.formElement.settings} inputRef={inputRef} @@ -568,7 +568,7 @@ function StandardFieldValue({ return ( <> - {attributeFormatsWithDS && ( + {attributeFormatsWithDS.includes(attribute.format) && ( )} From 68ed59170e05e9ff41c8f95b9d32914acf5ef454 Mon Sep 17 00:00:00 2001 From: Renaud AMSELLEM Date: Fri, 15 Mar 2024 17:30:19 +0100 Subject: [PATCH 16/16] up ds --- apps/data-studio/package.json | 2 +- apps/login/package.json | 2 +- apps/portal/package.json | 2 +- libs/ui/package.json | 2 +- yarn.lock | 26 ++++++++++++++++++-------- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/apps/data-studio/package.json b/apps/data-studio/package.json index fa1ca1db2..13f36d052 100644 --- a/apps/data-studio/package.json +++ b/apps/data-studio/package.json @@ -13,7 +13,7 @@ "antd": "5.14.0", "apollo-cache-inmemory": "1.6.6", "apollo-upload-client": "14.1.3", - "aristid-ds": "2.0.0-60b909d", + "aristid-ds": "3.0.0-66e1ba6", "dayjs": "1.11.10", "graphql": "15.0.0", "graphql-tag": "2.12.6", diff --git a/apps/login/package.json b/apps/login/package.json index e71fcfc05..fb495227f 100644 --- a/apps/login/package.json +++ b/apps/login/package.json @@ -7,7 +7,7 @@ "@ant-design/icons": "5.2.6", "@leav/ui": "workspace:libs/ui", "antd": "5.14.0", - "aristid-ds": "2.0.0-60b909d", + "aristid-ds": "3.0.0-66e1ba6", "i18next": "22.5.0", "i18next-browser-languagedetector": "7.0.2", "i18next-http-backend": "2.1.1", diff --git a/apps/portal/package.json b/apps/portal/package.json index b88658cce..3a8d34d2e 100644 --- a/apps/portal/package.json +++ b/apps/portal/package.json @@ -8,7 +8,7 @@ "@leav/ui": "workspace:libs/ui", "@leav/utils": "workspace:libs/utils", "antd": "5.14.0", - "aristid-ds": "2.0.0-60b909d", + "aristid-ds": "3.0.0-66e1ba6", "cross-fetch": "3.1.5", "graphql-ws": "5.12.0", "i18next": "22.5.0", diff --git a/libs/ui/package.json b/libs/ui/package.json index 457751079..4491929d5 100644 --- a/libs/ui/package.json +++ b/libs/ui/package.json @@ -62,7 +62,7 @@ "@ckeditor/ckeditor5-build-inline": "39.0.1", "@ckeditor/ckeditor5-react": "6.1.0", "@leav/utils": "0.0.1", - "aristid-ds": "2.0.0-60b909d", + "aristid-ds": "3.0.0-66e1ba6", "dayjs": "1.11.10", "dompurify": "3.0.5", "html-react-parser": "4.2.2", diff --git a/yarn.lock b/yarn.lock index 4e2f2323a..106fee7f1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7872,7 +7872,7 @@ __metadata: "@types/react-beautiful-dnd": "npm:13.1.2" "@types/react-table": "npm:7.7.12" "@types/uuid": "npm:^9" - aristid-ds: "npm:2.0.0-60b909d" + aristid-ds: "npm:3.0.0-66e1ba6" babel-jest: "npm:29.3.1" commander: "npm:9.5.0" dayjs: "npm:1.11.10" @@ -11843,9 +11843,9 @@ __metadata: languageName: node linkType: hard -"aristid-ds@npm:2.0.0-60b909d": - version: 2.0.0-60b909d - resolution: "aristid-ds@npm:2.0.0-60b909d" +"aristid-ds@npm:3.0.0-66e1ba6": + version: 3.0.0-66e1ba6 + resolution: "aristid-ds@npm:3.0.0-66e1ba6" dependencies: "@dnd-kit/core": "npm:^6.1.0" "@dnd-kit/modifiers": "npm:^7.0.0" @@ -11866,6 +11866,7 @@ __metadata: rc-util: "npm:^5.37.0" react: "npm:^18.2.0" react-dom: "npm:^18.2.0" + react-flag-kit: "npm:^1.1.1" react-hot-toast: "npm:^2.4.1" react-modal: "npm:^3.16.1" react-resize-detector: "npm:^9.1.0" @@ -11888,7 +11889,7 @@ __metadata: react-uuid: ^2.0.0 remark-gfm: ^3.0.1 styled-components: ^6.0.7 - checksum: aad634976d8bb695e4f39205115f363598bb69cbedca5a9edf68f315e6c74128df4f3ed3de87921fb795822f8404a584dd937a525ca7c7e2da4e1f3161dc5106 + checksum: 55c41c0d8891fcf5fbbe5ec0a8342b79e6c6215b73456a5292b6f50372be727bf8d24b468fa66f99876438b612818aca8de52f11a3598a4eb1a8b87788cd5dfe languageName: node linkType: hard @@ -14761,7 +14762,7 @@ __metadata: apollo: "npm:2.34.0" apollo-cache-inmemory: "npm:1.6.6" apollo-upload-client: "npm:14.1.3" - aristid-ds: "npm:2.0.0-60b909d" + aristid-ds: "npm:3.0.0-66e1ba6" commander: "npm:5.1.0" dayjs: "npm:1.11.10" graphql: "npm:15.0.0" @@ -22417,7 +22418,7 @@ __metadata: "@types/react-dom": "npm:18.2.6" "@vitejs/plugin-react": "npm:3.1.0" antd: "npm:5.14.0" - aristid-ds: "npm:2.0.0-60b909d" + aristid-ds: "npm:3.0.0-66e1ba6" i18next: "npm:22.5.0" i18next-browser-languagedetector: "npm:7.0.2" i18next-http-backend: "npm:2.1.1" @@ -24974,7 +24975,7 @@ __metadata: "@vitejs/plugin-react": "npm:3.1.0" antd: "npm:5.14.0" apollo: "npm:2.34.0" - aristid-ds: "npm:2.0.0-60b909d" + aristid-ds: "npm:3.0.0-66e1ba6" commander: "npm:10.0.0" cross-fetch: "npm:3.1.5" graphql-ws: "npm:5.12.0" @@ -26629,6 +26630,15 @@ __metadata: languageName: node linkType: hard +"react-flag-kit@npm:^1.1.1": + version: 1.1.1 + resolution: "react-flag-kit@npm:1.1.1" + peerDependencies: + react: ^16.6.0 || ^17.0.0 || ^18.0.0 + checksum: 8bc4c28d74b6e1bfbe647a5fb64bf99b47c7a5315efb0ea234fb065aa0f87a87a562d103d5e147c4975a25d1a9502e50f432d036312382f89262b7e82a71102f + languageName: node + linkType: hard + "react-hot-toast@npm:^2.4.1": version: 2.4.1 resolution: "react-hot-toast@npm:2.4.1"