From 482e69490a3e24a4078053cecda63a084baac137 Mon Sep 17 00:00:00 2001 From: Konstantin Markov Date: Tue, 10 Dec 2024 14:40:15 +0200 Subject: [PATCH] Changes after review --- .../field-adapters/custom-vocabularies.ts | 80 +++++++++++++++++++ .../planning-editor-standalone/profile.ts | 80 +++---------------- .../storage-adapter.ts | 24 ++---- 3 files changed, 96 insertions(+), 88 deletions(-) create mode 100644 client/components/planning-editor-standalone/field-adapters/custom-vocabularies.ts diff --git a/client/components/planning-editor-standalone/field-adapters/custom-vocabularies.ts b/client/components/planning-editor-standalone/field-adapters/custom-vocabularies.ts new file mode 100644 index 000000000..27e9089d6 --- /dev/null +++ b/client/components/planning-editor-standalone/field-adapters/custom-vocabularies.ts @@ -0,0 +1,80 @@ +import {IProfileSchemaTypeList} from 'interfaces'; +import {IDropdownConfigVocabulary, IAuthoringFieldV2, ISubject, IVocabularyItem} from 'superdesk-api'; +import {planningApi, superdeskApi} from 'superdeskApi'; +import {IFieldDefinition} from '../profile'; + +export const SUBJECT_PREFIX_ID = 'subject--'; +const getCustomVocabulariesId = (vocabularyId: string) => `${SUBJECT_PREFIX_ID}${vocabularyId}`; +const getStrippedCustomVocabularyId = (customVocabularyId: string) => customVocabularyId.replace(SUBJECT_PREFIX_ID, ''); + +export const getCustomVocabularyFields = () => { + const planningProfile = planningApi.contentProfiles.get('planning'); + const customVocabularyIds = + (planningProfile.schema?.['custom_vocabularies'] as IProfileSchemaTypeList)?.vocabularies; + const result: Array = []; + + if ((customVocabularyIds?.length ?? 0) > 0) { + const allVocabularies = superdeskApi.entities.vocabulary.getAll(); + + for (const id of customVocabularyIds) { + result.push({ + fieldId: getCustomVocabulariesId(id), + getField: ({required, id: _id}) => { + const fieldConfig: IDropdownConfigVocabulary = { + source: 'vocabulary', + vocabularyId: id, + multiple: true, + required: required, + }; + + const field: IAuthoringFieldV2 = { + id: _id, + name: id, + fieldType: 'dropdown', + fieldConfig: fieldConfig, + }; + + return field; + }, + storageAdapter: { + storeValue: (item, operationalValue: { + existing: Array; + fieldId: string; + value?: Array; + }) => { + const {existing = [], fieldId, value = []} = operationalValue; + const strippedId = getStrippedCustomVocabularyId(fieldId); + const vocabulary = allVocabularies.get(strippedId); + const vocabItems = vocabulary.items.filter((x) => value?.includes(x.qcode)) ?? []; + + // Subfield values + const itemsToSubject: Array = vocabItems.map((x) => ({ + name: x.name, + qcode: x.qcode, + scheme: vocabulary._id, + })); + + // Remove values that don't match the "subfield" ID, so there's no item duplication + const restOfValues = existing.filter((x) => x.scheme !== strippedId); + + return { + ...item, + subject: [ + ...itemsToSubject, + ...restOfValues, + ], + }; + }, + retrieveStoredValue: (storageValue: {fieldId: string; subject: Array;}) => { + const {fieldId, subject = []} = storageValue; + const strippedId = getStrippedCustomVocabularyId(fieldId); + + return subject.filter((x) => x.scheme === strippedId).map((x) => x.qcode); + }, + } + }); + } + } + + return result; +}; diff --git a/client/components/planning-editor-standalone/profile.ts b/client/components/planning-editor-standalone/profile.ts index 171f981ef..641c8c756 100644 --- a/client/components/planning-editor-standalone/profile.ts +++ b/client/components/planning-editor-standalone/profile.ts @@ -16,6 +16,7 @@ import { IAttachmentsFieldConfig, } from '../../planning-extension/src/authoring-react-fields/planning-attachments/interfaces'; import {IProfileSchemaTypeList} from 'interfaces'; +import {getCustomVocabularyFields} from './field-adapters/custom-vocabularies'; function getTextFieldConfig(options: {id: string; label: string, required: boolean}): IAuthoringFieldV2 { const editor3ConfigWithoutFormatting: IEditor3Config = { @@ -60,20 +61,17 @@ function getDateTimeField(options: {id: string; label: string, required: boolean return field; } -interface IFieldDefinition { +export interface IFieldDefinition { fieldId: string; getField: (options: {required: boolean, id: string}) => IAuthoringFieldV2; storageAdapter?: { - storeValue: (operationalValue) => unknown; // returns stored value + storeValue: (item, operationalValue) => T; // returns stored value retrieveStoredValue: (storageValue) => unknown; // returns operational value }; } type IFieldDefinitions = {[fieldId: string]: IFieldDefinition}; -export const SUBJECT_PREFIX_ID = 'subject--'; -const getCustomVocabulariesId = (vocabularyId: string) => `${SUBJECT_PREFIX_ID}${vocabularyId}`; -const getStrippedCustomVocabularyId = (customVocabularyId: string) => customVocabularyId.replace(SUBJECT_PREFIX_ID, ''); export function getFieldDefinitions(): IFieldDefinitions { const {gettext} = superdeskApi.localization; @@ -146,13 +144,16 @@ export function getFieldDefinitions(): IFieldDefinitions { return field; }, storageAdapter: { - storeValue: (operationalValue: Array): Array => { + storeValue: (item, operationalValue: Array) => { const vocabulary = superdeskApi.entities.vocabulary.getAll().get('locators'); const vocabularyItems = new Map( vocabulary.items.map((item) => [item.qcode, item]), ); - return operationalValue.map((qcode) => vocabularyItems.get(qcode)); + return { + ...item, + place: operationalValue.map((qcode) => vocabularyItems.get(qcode)), + }; }, retrieveStoredValue: (storageValue: Array) => storageValue.map(({qcode}) => qcode), }, @@ -175,69 +176,10 @@ export function getFieldDefinitions(): IFieldDefinitions { }, } ]; - const planningProfile = planningApi.contentProfiles.get('planning'); - const customVocabularyIds = - (planningProfile.schema?.['custom_vocabularies'] as IProfileSchemaTypeList)?.vocabularies; - - if ((customVocabularyIds?.length ?? 0) > 0) { - const allVocabularies = superdeskApi.entities.vocabulary.getAll(); - - for (const id of customVocabularyIds) { - result.push({ - fieldId: getCustomVocabulariesId(id), - getField: ({required, id: _id}) => { - const fieldConfig: IDropdownConfigVocabulary = { - source: 'vocabulary', - vocabularyId: id, - multiple: true, - required: required, - }; - const field: IAuthoringFieldV2 = { - id: _id, - name: id, - fieldType: 'dropdown', - fieldConfig: fieldConfig, - }; - - return field; - }, - storageAdapter: { - storeValue: (operationalValue: { - existing: Array; - fieldId: string; - value?: Array; - }) => { - const {existing = [], fieldId, value = []} = operationalValue; - const strippedId = getStrippedCustomVocabularyId(fieldId); - const vocabulary = allVocabularies.get(strippedId); - const vocabItems = vocabulary.items.filter((x) => value?.includes(x.qcode)) ?? []; - - // Subfield values - const itemsToSubject: Array = vocabItems.map((x) => ({ - name: x.name, - qcode: x.qcode, - scheme: vocabulary._id, - })); - - // Remove values that don't match the "subfield" ID, so there's no item duplication - const restOfValues = existing.filter((x) => x.scheme !== strippedId); - - return [ - ...itemsToSubject, - ...restOfValues, - ]; - }, - retrieveStoredValue: (storageValue: {fieldId: string; subject: Array;}) => { - const {fieldId, subject = []} = storageValue; - const strippedId = getStrippedCustomVocabularyId(fieldId); - - return subject.filter((x) => x.scheme === strippedId).map((x) => x.qcode); - }, - } - }); - } - } + result.push( + ...getCustomVocabularyFields(), + ); const resultObj = result.reduce((acc, item) => { acc[item.fieldId] = item; diff --git a/client/components/planning-editor-standalone/storage-adapter.ts b/client/components/planning-editor-standalone/storage-adapter.ts index d623491b0..2fc28df84 100644 --- a/client/components/planning-editor-standalone/storage-adapter.ts +++ b/client/components/planning-editor-standalone/storage-adapter.ts @@ -7,31 +7,17 @@ import { ISubject, } from 'superdesk-api'; import {superdeskApi} from '../../superdeskApi'; -import {getFieldDefinitions, SUBJECT_PREFIX_ID} from './profile'; +import {getFieldDefinitions} from './profile'; +import {SUBJECT_PREFIX_ID} from './field-adapters/custom-vocabularies'; export const storageAdapterPlanningItem: IStorageAdapter = { storeValue: (value, fieldId, item, config, fieldType) => { const {computeEditor3Output} = superdeskApi.helpers; - const fieldDefinitions = getFieldDefinitions(); const fieldStorageAdapter = fieldDefinitions[fieldId]?.storageAdapter; - if (fieldId.includes(SUBJECT_PREFIX_ID)) { - const computedValue = fieldStorageAdapter.storeValue({ - existing: item.subject, - fieldId: fieldId, - value: value, - }) as Array; - - return { - ...item, - subject: computedValue, - }; - } else if (fieldStorageAdapter != null) { - return { - ...item, - [fieldId]: fieldStorageAdapter.storeValue(value), - }; + if (fieldStorageAdapter != null) { + return fieldStorageAdapter.storeValue(item, value); } else if (fieldType === 'editor3') { const editor3Config = config as IEditor3Config; const rawState = (value as IEditor3ValueStorage).rawContentState; @@ -60,7 +46,7 @@ export const storageAdapterPlanningItem: IStorageAdapter = { const fieldDefinitions = getFieldDefinitions(); const fieldStorageAdapter = fieldDefinitions[fieldId]?.storageAdapter; - if (fieldId.includes(SUBJECT_PREFIX_ID)) { + if (fieldId.startsWith(SUBJECT_PREFIX_ID)) { return fieldStorageAdapter.retrieveStoredValue({fieldId: fieldId, subject: item.subject}); } else if (fieldStorageAdapter != null) { return fieldStorageAdapter.retrieveStoredValue(value);