From ddd37930c30875cef903d121b628e94e26e14c24 Mon Sep 17 00:00:00 2001 From: Teddy Date: Fri, 25 Aug 2023 14:56:41 +0200 Subject: [PATCH] Fix metadata handling on value save --- apps/core/src/domain/record/recordDomain.ts | 36 ++- apps/core/src/domain/value/valueDomain.ts | 224 ++++++++++-------- .../StandardField/StandardField.tsx | 6 +- .../EditRecordModal/EditRecordModal.tsx | 9 +- .../ValueMetadata/ValueMetadata.tsx | 12 +- 5 files changed, 174 insertions(+), 113 deletions(-) diff --git a/apps/core/src/domain/record/recordDomain.ts b/apps/core/src/domain/record/recordDomain.ts index 1d9d3fd1f..ef19ff7e5 100644 --- a/apps/core/src/domain/record/recordDomain.ts +++ b/apps/core/src/domain/record/recordDomain.ts @@ -18,7 +18,7 @@ import {IUtils} from 'utils/utils'; import * as Config from '_types/config'; import {IListWithCursor} from '_types/list'; import {IPreview} from '_types/preview'; -import {IValue, IValuesOptions} from '_types/value'; +import {IStandardValue, IValue, IValuesOptions} from '_types/value'; import PermissionError from '../../errors/PermissionError'; import ValidationError from '../../errors/ValidationError'; import {getPreviewUrl} from '../../utils/preview/preview'; @@ -1072,8 +1072,40 @@ export default function({ const forceArray = options?.forceArray ?? false; + //TODO: fix "[object]" on input after edit let formattedValues = await Promise.all( - values.map(v => valueDomain.formatValue({attribute: attrProps, value: v, record, library, ctx})) + values.map(async v => { + const formattedValue = await valueDomain.formatValue({ + attribute: attrProps, + value: v, + record, + library, + ctx + }); + + if (attrProps.metadata_fields && formattedValue.metadata) { + for (const metadataField of attrProps.metadata_fields) { + if (!formattedValue.metadata[metadataField]) { + continue; + } + + const metadataAttributeProps = await attributeDomain.getAttributeProperties({ + id: metadataField, + ctx + }); + + formattedValue.metadata[metadataField] = await valueDomain.runActionsList({ + listName: ActionsListEvents.GET_VALUE, + attribute: metadataAttributeProps, + library, + value: formattedValue.metadata[metadataField] as IStandardValue, + ctx + }); + } + } + + return formattedValue; + }) ); // sort of flatMap cause _formatRecordValue can return multiple values for 1 input val (think heritage) diff --git a/apps/core/src/domain/value/valueDomain.ts b/apps/core/src/domain/value/valueDomain.ts index f56f1c68c..85c1829c4 100644 --- a/apps/core/src/domain/value/valueDomain.ts +++ b/apps/core/src/domain/value/valueDomain.ts @@ -123,7 +123,7 @@ interface IDeps { 'core.domain.tree'?: ITreeDomain; } -const valueDomain = function ({ +const valueDomain = function({ config = null, 'core.domain.actionsList': actionsListDomain = null, 'core.domain.attribute': attributeDomain = null, @@ -187,6 +187,57 @@ const valueDomain = function ({ } }; + const _formatValue = async ({attribute, value, record, library, ctx}) => { + let processedValue = {...value}; // Don't mutate given value + + const isLinkAttribute = + attribute.type === AttributeTypes.SIMPLE_LINK || attribute.type === AttributeTypes.ADVANCED_LINK; + + if (isLinkAttribute && attribute.linked_library) { + const linkValue = processedValue.value + ? {...processedValue.value, library: processedValue.value.library ?? attribute.linked_library} + : null; + processedValue = {...value, value: linkValue}; + } + + processedValue.attribute = attribute.id; + + // Format metadata values as well + if ((attribute.metadata_fields ?? []).length) { + const metadataValuesFormatted = await attribute.metadata_fields.reduce( + async (allValuesProm, metadataField) => { + const allValues = await allValuesProm; + try { + const metadataAttributeProps = await attributeDomain.getAttributeProperties({ + id: metadataField, + ctx + }); + + allValues[metadataField] = + typeof value.metadata?.[metadataField] !== 'undefined' + ? await _formatValue({ + attribute: metadataAttributeProps, + value: {value: value.metadata?.[metadataField]}, + record, + library, + ctx + }) + : null; + } catch (err) { + logger.error(err); + allValues[metadataField] = null; + } + + return allValues; + }, + Promise.resolve({}) + ); + processedValue.metadata = metadataValuesFormatted; + } + + return processedValue; + }; + const _executeDeleteValue = async ({library, recordId, attribute, value, ctx}: IDeleteValueParams) => { // Check permission const canUpdateRecord = await recordPermissionDomain.getRecordPermission({ @@ -303,6 +354,71 @@ const valueDomain = function ({ return res; }; + const _executeSaveValue = async ( + library: string, + record: IRecord, + attribute: IAttribute, + value: IValue, + ctx: IQueryInfos + ) => { + const savedVal = await saveOneValue( + library, + record.id, + attribute, + value, + { + valueRepo, + recordRepo, + treeRepo, + getDefaultElementHelper, + actionsListDomain, + attributeDomain, + versionProfileDomain + }, + ctx + ); + + // Apply actions list on value + + let processedValue = await _runActionsList({ + listName: ActionsListEvents.GET_VALUE, + value: savedVal, + attribute, + record, + library, + ctx + }); + + processedValue = await _formatValue({ + attribute, + value: processedValue, + record, + library, + ctx + }); + + // Runs actionsList on metadata values as well + if (attribute.metadata_fields?.length && processedValue.metadata) { + for (const metadataField of attribute.metadata_fields) { + const metadataAttributeProps = await attributeDomain.getAttributeProperties({ + id: metadataField, + ctx + }); + + processedValue.metadata[metadataField] = await _runActionsList({ + listName: ActionsListEvents.GET_VALUE, + value: processedValue.metadata[metadataField] as IStandardValue, + attribute: metadataAttributeProps, + record, + library, + ctx + }); + } + } + + return savedVal; + }; + return { async getValues({library, recordId, attribute, options, ctx}): Promise { await validate.validateLibrary(library, ctx); @@ -472,22 +588,7 @@ const valueDomain = function ({ ctx }); - const savedVal = await saveOneValue( - library, - recordId, - attributeProps, - valueToSave, - { - valueRepo, - recordRepo, - treeRepo, - getDefaultElementHelper, - actionsListDomain, - attributeDomain, - versionProfileDomain - }, - ctx - ); + const savedVal = await _executeSaveValue(library, record, attributeProps, valueToSave, ctx); await eventsManager.sendDatabaseEvent( { @@ -515,7 +616,7 @@ const valueDomain = function ({ }); // Apply formating - processedValue = await this.formatValue({ + processedValue = await _formatValue({ attribute: attributeProps, value: processedValue, record, @@ -629,22 +730,7 @@ const valueDomain = function ({ value: valToSave, ctx }) - : await saveOneValue( - library, - recordId, - attributeProps, - valToSave, - { - valueRepo, - recordRepo, - treeRepo, - getDefaultElementHelper, - actionsListDomain, - attributeDomain, - versionProfileDomain - }, - ctx - ); + : await _executeSaveValue(library, record, attributeProps, valToSave, ctx); // TODO: get old value ? await eventsManager.sendDatabaseEvent( @@ -660,24 +746,7 @@ const valueDomain = function ({ ctx ); - let processedValue = await _runActionsList({ - listName: ActionsListEvents.GET_VALUE, - value: savedVal, - attribute: attributeProps, - record: {id: recordId}, - library, - ctx - }); - - processedValue = await this.formatValue({ - attribute: attributeProps, - value: processedValue, - record, - library, - ctx - }); - - prevRes.values.push(processedValue); + prevRes.values.push(savedVal); } catch (e) { if ( !e.type || @@ -717,56 +786,7 @@ const valueDomain = function ({ return _executeDeleteValue({library, recordId, attribute, value, ctx}); }, - async formatValue({attribute, value, record, library, ctx}) { - let processedValue = {...value}; // Don't mutate given value - - const isLinkAttribute = - attribute.type === AttributeTypes.SIMPLE_LINK || attribute.type === AttributeTypes.ADVANCED_LINK; - - if (isLinkAttribute && attribute.linked_library) { - const linkValue = processedValue.value - ? {...processedValue.value, library: processedValue.value.library ?? attribute.linked_library} - : null; - processedValue = {...value, value: linkValue}; - } - - processedValue.attribute = attribute.id; - - // Format metadata values as well - if ((attribute.metadata_fields ?? []).length) { - const metadataValuesFormatted = await attribute.metadata_fields.reduce( - async (allValuesProm, metadataField) => { - const allValues = await allValuesProm; - try { - const metadataAttributeProps = await attributeDomain.getAttributeProperties({ - id: metadataField, - ctx - }); - - allValues[metadataField] = - typeof value.metadata?.[metadataField] !== 'undefined' - ? await this.formatValue({ - attribute: metadataAttributeProps, - value: {value: value.metadata?.[metadataField]}, - record, - library, - ctx - }) - : null; - } catch (err) { - logger.error(err); - allValues[metadataField] = null; - } - - return allValues; - }, - Promise.resolve({}) - ); - processedValue.metadata = metadataValuesFormatted; - } - - return processedValue; - }, + formatValue: _formatValue, runActionsList: _runActionsList }; }; diff --git a/apps/data-studio/src/components/RecordEdition/EditRecord/uiElements/StandardField/StandardField.tsx b/apps/data-studio/src/components/RecordEdition/EditRecord/uiElements/StandardField/StandardField.tsx index 5c0543c81..4edb9bb77 100644 --- a/apps/data-studio/src/components/RecordEdition/EditRecord/uiElements/StandardField/StandardField.tsx +++ b/apps/data-studio/src/components/RecordEdition/EditRecord/uiElements/StandardField/StandardField.tsx @@ -115,7 +115,7 @@ function StandardField({ let resultValue; if (state.metadataEdit) { - const value = + const metadataValue = (submitResValue.metadata ?? []).find(({name}) => name === element.attribute.id)?.value ?? null; resultValue = { id_value: null, @@ -124,8 +124,8 @@ function StandardField({ created_by: null, modified_by: null, version: null, - raw_value: value, - value, + raw_value: metadataValue.raw_value ?? metadataValue.value, + value: metadataValue.value, metadata: null, attribute }; diff --git a/apps/data-studio/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx b/apps/data-studio/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx index 1d2b0ce4d..79cf8086f 100644 --- a/apps/data-studio/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx +++ b/apps/data-studio/src/components/RecordEdition/EditRecordModal/EditRecordModal.tsx @@ -218,7 +218,14 @@ function EditRecordModal({ attribute: value.attribute, metadata: value.metadata ? Object.keys(value.metadata).reduce((metadata, metadataAttributeId) => { - metadata.push({name: metadataAttributeId, value: value.metadata[metadataAttributeId]}); + metadata.push({ + name: metadataAttributeId, + value: { + id_value: null, + value: value.metadata[metadataAttributeId], + raw_value: value.metadata[metadataAttributeId] + } + }); return metadata; }, []) : null diff --git a/apps/data-studio/src/components/RecordEdition/EditRecordSidebar/ValueDetails/ValueMetadata/ValueMetadata.tsx b/apps/data-studio/src/components/RecordEdition/EditRecordSidebar/ValueDetails/ValueMetadata/ValueMetadata.tsx index 5289752cc..28fd8a726 100644 --- a/apps/data-studio/src/components/RecordEdition/EditRecordSidebar/ValueDetails/ValueMetadata/ValueMetadata.tsx +++ b/apps/data-studio/src/components/RecordEdition/EditRecordSidebar/ValueDetails/ValueMetadata/ValueMetadata.tsx @@ -41,13 +41,13 @@ const _inputTypeByFormat: {[format in AttributeFormat]: FormFieldTypes} = { [AttributeFormat.color]: FormFieldTypes.TEXT_INPUT }; -function ValueMetadata({value, attribute, onMetadataSubmit}: IValueMetadataProps): JSX.Element { +function ValueMetadata({value: parentValue, attribute, onMetadataSubmit}: IValueMetadataProps): JSX.Element { const {lang} = useLang(); const _handleValueSubmit: (field: MetadataField) => SubmitValueFunc = field => ( values ): Promise => { - return onMetadataSubmit(value, attribute, { + return onMetadataSubmit(parentValue, attribute, { [field.id]: (values[0] as ISubmittedValueStandard).value }); }; @@ -55,7 +55,7 @@ function ValueMetadata({value, attribute, onMetadataSubmit}: IValueMetadataProps const _handleValueDelete: (field: MetadataField) => DeleteValueFunc = field => ( values ): Promise => { - return onMetadataSubmit(value, attribute, { + return onMetadataSubmit(parentValue, attribute, { [field.id]: null }); }; @@ -71,7 +71,9 @@ function ValueMetadata({value, attribute, onMetadataSubmit}: IValueMetadataProps uiElementType: _inputTypeByFormat[field.format], valueError: null, values: - [value?.metadata?.find(({name}) => name === field.id)?.value as RecordFormElementsValue] ?? [], + [ + parentValue?.metadata?.find(({name}) => name === field.id)?.value as RecordFormElementsValue + ] ?? [], settings: { label: localizedTranslation(field.label, lang) }, @@ -80,7 +82,7 @@ function ValueMetadata({value, attribute, onMetadataSubmit}: IValueMetadataProps return (