From d0803e2f4cb6900957d6408af5eb7f34f8514a9e Mon Sep 17 00:00:00 2001 From: Konstantin Markov Date: Fri, 13 Dec 2024 13:33:46 +0200 Subject: [PATCH] Refactor structure & categories field (#2156) --- .../field-definitions/agendas-field.ts | 33 +++ .../field-definitions/date-time-config.ts | 19 ++ .../field-definitions/index.ts | 99 ++++++++ .../field-definitions/interfaces.ts | 13 ++ .../field-definitions/place-field.ts | 38 +++ .../field-definitions/text-field-config.ts | 26 +++ .../planning-editor-standalone/profile.ts | 216 +----------------- .../storage-adapter.ts | 2 +- 8 files changed, 231 insertions(+), 215 deletions(-) create mode 100644 client/components/planning-editor-standalone/field-definitions/agendas-field.ts create mode 100644 client/components/planning-editor-standalone/field-definitions/date-time-config.ts create mode 100644 client/components/planning-editor-standalone/field-definitions/index.ts create mode 100644 client/components/planning-editor-standalone/field-definitions/interfaces.ts create mode 100644 client/components/planning-editor-standalone/field-definitions/place-field.ts create mode 100644 client/components/planning-editor-standalone/field-definitions/text-field-config.ts diff --git a/client/components/planning-editor-standalone/field-definitions/agendas-field.ts b/client/components/planning-editor-standalone/field-definitions/agendas-field.ts new file mode 100644 index 000000000..9281f7017 --- /dev/null +++ b/client/components/planning-editor-standalone/field-definitions/agendas-field.ts @@ -0,0 +1,33 @@ +import {IAgenda} from 'interfaces'; +import {IDropdownConfigManualSource, IAuthoringFieldV2} from 'superdesk-api'; +import {planningApi} from 'superdeskApi'; +import {gettext} from 'utils'; +import {IFieldDefinition} from './interfaces'; + +export const getAgendasField = (): IFieldDefinition => ({ + fieldId: 'agendas', + getField: ({id, required}) => { + const fieldConfig: IDropdownConfigManualSource = { + source: 'manual-entry', + options: ((planningApi.redux.store.getState().agenda.agendas ?? []) as Array) + .filter((item) => item.is_enabled) + .map((item) => ({ + id: item._id, + label: item.name, + })), + roundCorners: true, + type: 'text', + multiple: true, + required: required, + }; + + const field: IAuthoringFieldV2 = { + id: id, + name: gettext('Agendas'), + fieldType: 'dropdown', + fieldConfig: fieldConfig, + }; + + return field; + }, +}); diff --git a/client/components/planning-editor-standalone/field-definitions/date-time-config.ts b/client/components/planning-editor-standalone/field-definitions/date-time-config.ts new file mode 100644 index 000000000..03a170b5a --- /dev/null +++ b/client/components/planning-editor-standalone/field-definitions/date-time-config.ts @@ -0,0 +1,19 @@ +import {IAuthoringFieldV2, IDateTimeFieldConfig} from 'superdesk-api'; + +export function getDateTimeField(options: {id: string; label: string, required: boolean}): IAuthoringFieldV2 { + const config: IDateTimeFieldConfig = { + allowSeconds: false, + }; + + const field: IAuthoringFieldV2 = { + id: options.id, + name: options.label, + fieldType: 'datetime', + fieldConfig: { + ...config, + required: options.required, + }, + }; + + return field; +} diff --git a/client/components/planning-editor-standalone/field-definitions/index.ts b/client/components/planning-editor-standalone/field-definitions/index.ts new file mode 100644 index 000000000..b71d36fe6 --- /dev/null +++ b/client/components/planning-editor-standalone/field-definitions/index.ts @@ -0,0 +1,99 @@ +import { + IAttachmentsFieldConfig, +} from '../../../planning-extension/src/authoring-react-fields/planning-attachments/interfaces'; +import { + IAuthoringFieldV2, + ICommonFieldConfig, +} from 'superdesk-api'; +import {superdeskApi} from '../../../superdeskApi'; +import {getCustomVocabularyFields} from '../field-adapters/custom-vocabularies'; +import {getDateTimeField} from './date-time-config'; +import {IFieldDefinitions, IFieldDefinition} from './interfaces'; +import {getTextFieldConfig} from './text-field-config'; +import {getPlaceField} from './place-field'; +import {getAgendasField} from './agendas-field'; + +export function getFieldDefinitions(): IFieldDefinitions { + const {gettext} = superdeskApi.localization; + const result: Array = [ + { + fieldId: 'ednote', + getField: ({required, id}) => getTextFieldConfig({id: id, label: gettext('Ed Note'), required: required}), + }, + { + fieldId: 'internal_note', + getField: ({required, id}) => + getTextFieldConfig({id: id, label: gettext('Internal Note'), required: required}), + }, + { + fieldId: 'name', + getField: ({required, id}) => getTextFieldConfig({id: id, label: gettext('Name'), required: required}), + }, + { + fieldId: 'slugline', + getField: ({required, id}) => getTextFieldConfig({id: id, label: gettext('Slugline'), required: required}), + }, + { + fieldId: 'description_text', + getField: ({required, id}) => + getTextFieldConfig({id: id, label: gettext('Description'), required: required}), + }, + { + fieldId: 'headline', + getField: ({required, id}) => getTextFieldConfig({id: id, label: gettext('Headline'), required: required}), + }, + { + fieldId: 'planning_date', + getField: ({required, id}) => + getDateTimeField({id: id, label: gettext('Planning date'), required: required}), + }, + { + fieldId: 'files', + getField: ({required, id}) => { + const fieldConfig: IAttachmentsFieldConfig = { + required, + }; + + const field: IAuthoringFieldV2 = { + id: id, + name: gettext('Attached files'), + fieldType: 'files', + fieldConfig: fieldConfig, + }; + + return field; + }, + }, + getPlaceField(), + getAgendasField(), + { + fieldId: 'coverages', + getField: ({id, required}) => { + const fieldConfig: ICommonFieldConfig = { + required, + }; + + const field: IAuthoringFieldV2 = { + id: id, + name: gettext('Coverages'), + fieldType: 'coverages', + fieldConfig: fieldConfig, + }; + + return field; + }, + } + ]; + + result.push( + ...getCustomVocabularyFields(), + ); + + const resultObj = result.reduce((acc, item) => { + acc[item.fieldId] = item; + + return acc; + }, {} as IFieldDefinitions); + + return resultObj; +} diff --git a/client/components/planning-editor-standalone/field-definitions/interfaces.ts b/client/components/planning-editor-standalone/field-definitions/interfaces.ts new file mode 100644 index 000000000..8921178fc --- /dev/null +++ b/client/components/planning-editor-standalone/field-definitions/interfaces.ts @@ -0,0 +1,13 @@ +import {IAuthoringFieldV2} from 'superdesk-api'; + +export interface IFieldDefinition { + fieldId: string; + getField: (options: {required: boolean, id: string}) => IAuthoringFieldV2; + storageAdapter?: { + storeValue: (item: T, operationalValue: unknown) => T; // returns stored value + retrieveStoredValue: + (item: T, fieldId: string) => unknown; // returns operational value + }; +} + +export type IFieldDefinitions = {[fieldId: string]: IFieldDefinition}; diff --git a/client/components/planning-editor-standalone/field-definitions/place-field.ts b/client/components/planning-editor-standalone/field-definitions/place-field.ts new file mode 100644 index 000000000..28df5ef8a --- /dev/null +++ b/client/components/planning-editor-standalone/field-definitions/place-field.ts @@ -0,0 +1,38 @@ +import {IDropdownConfigVocabulary, IAuthoringFieldV2, IVocabularyItem} from 'superdesk-api'; +import {superdeskApi} from '../../../superdeskApi'; +import {IFieldDefinition} from './interfaces'; + +export const getPlaceField = (): IFieldDefinition => ({ + fieldId: 'place', + getField: ({id, required}) => { + const fieldConfig: IDropdownConfigVocabulary = { + source: 'vocabulary', + vocabularyId: 'locators', + multiple: true, + required: required, + }; + + const field: IAuthoringFieldV2 = { + id: id, + name: superdeskApi.localization.gettext('Place'), + fieldType: 'dropdown', + fieldConfig: fieldConfig, + }; + + return field; + }, + storageAdapter: { + storeValue: (item, operationalValue: Array) => { + const vocabulary = superdeskApi.entities.vocabulary.getAll().get('locators'); + const vocabularyItems = new Map( + vocabulary.items.map((item) => [item.qcode, item]), + ); + + return { + ...item, + place: operationalValue.map((qcode) => vocabularyItems.get(qcode)), + }; + }, + retrieveStoredValue: (item, fieldId) => item[fieldId].map(({qcode}) => qcode), + }, +}); diff --git a/client/components/planning-editor-standalone/field-definitions/text-field-config.ts b/client/components/planning-editor-standalone/field-definitions/text-field-config.ts new file mode 100644 index 000000000..1c9b4caf0 --- /dev/null +++ b/client/components/planning-editor-standalone/field-definitions/text-field-config.ts @@ -0,0 +1,26 @@ +import {IAuthoringFieldV2, IEditor3Config} from 'superdesk-api'; + +export function getTextFieldConfig(options: {id: string; label: string, required: boolean}): IAuthoringFieldV2 { + const editor3ConfigWithoutFormatting: IEditor3Config = { + editorFormat: [], + minLength: undefined, + maxLength: undefined, + cleanPastedHtml: false, + singleLine: true, + disallowedCharacters: [], + showStatistics: false, + width: 100, + }; + + const field: IAuthoringFieldV2 = { + id: options.id, + name: options.label, + fieldType: 'editor3', + fieldConfig: { + ...editor3ConfigWithoutFormatting, + required: options.required, + }, + }; + + return field; +} diff --git a/client/components/planning-editor-standalone/profile.ts b/client/components/planning-editor-standalone/profile.ts index 15595cbef..c73e127c3 100644 --- a/client/components/planning-editor-standalone/profile.ts +++ b/client/components/planning-editor-standalone/profile.ts @@ -1,220 +1,8 @@ import {OrderedMap} from 'immutable'; -import { - IAuthoringFieldV2, - ICommonFieldConfig, - IContentProfileV2, - IDateTimeFieldConfig, - IDropdownConfigManualSource, - IDropdownConfigVocabulary, - IEditor3Config, - IVocabularyItem, -} from 'superdesk-api'; -import {planningApi, superdeskApi} from '../../superdeskApi'; -import { - IAttachmentsFieldConfig, -} from '../../planning-extension/src/authoring-react-fields/planning-attachments/interfaces'; -import {getCustomVocabularyFields} from './field-adapters/custom-vocabularies'; +import {IContentProfileV2} from 'superdesk-api'; import {getPlanningProfileFields} from './profile-fields'; -import {IAgenda} from 'interfaces'; - -function getTextFieldConfig(options: {id: string; label: string, required: boolean}): IAuthoringFieldV2 { - const editor3ConfigWithoutFormatting: IEditor3Config = { - editorFormat: [], - minLength: undefined, - maxLength: undefined, - cleanPastedHtml: false, - singleLine: true, - disallowedCharacters: [], - showStatistics: false, - }; - - const field: IAuthoringFieldV2 = { - id: options.id, - name: options.label, - fieldType: 'editor3', - fieldConfig: { - ...editor3ConfigWithoutFormatting, - required: options.required, - }, - }; - - return field; -} - -function getDateTimeField(options: {id: string; label: string, required: boolean}): IAuthoringFieldV2 { - const config: IDateTimeFieldConfig = { - allowSeconds: false, - }; - - const field: IAuthoringFieldV2 = { - id: options.id, - name: options.label, - fieldType: 'datetime', - fieldConfig: { - ...config, - required: options.required, - }, - }; - - return field; -} - -export interface IFieldDefinition { - fieldId: string; - getField: (options: {required: boolean, id: string}) => IAuthoringFieldV2; - storageAdapter?: { - storeValue: (item: T, operationalValue: unknown) => T; // returns stored value - retrieveStoredValue: - (item: T, fieldId: string) => unknown; // returns operational value - }; -} - -type IFieldDefinitions = {[fieldId: string]: IFieldDefinition}; - -export function getFieldDefinitions(): IFieldDefinitions { - const {gettext} = superdeskApi.localization; - const result: Array = [ - { - fieldId: 'ednote', - getField: ({required, id}) => getTextFieldConfig({id: id, label: gettext('Ed Note'), required: required}), - }, - { - fieldId: 'internal_note', - getField: ({required, id}) => - getTextFieldConfig({id: id, label: gettext('Internal Note'), required: required}), - }, - { - fieldId: 'name', - getField: ({required, id}) => getTextFieldConfig({id: id, label: gettext('Name'), required: required}), - }, - { - fieldId: 'slugline', - getField: ({required, id}) => getTextFieldConfig({id: id, label: gettext('Slugline'), required: required}), - }, - { - fieldId: 'description_text', - getField: ({required, id}) => - getTextFieldConfig({id: id, label: gettext('Description'), required: required}), - }, - { - fieldId: 'headline', - getField: ({required, id}) => getTextFieldConfig({id: id, label: gettext('Headline'), required: required}), - }, - { - fieldId: 'planning_date', - getField: ({required, id}) => - getDateTimeField({id: id, label: gettext('Planning date'), required: required}), - }, - { - fieldId: 'files', - getField: ({required, id}) => { - const fieldConfig: IAttachmentsFieldConfig = { - required, - }; - - const field: IAuthoringFieldV2 = { - id: id, - name: gettext('Attached files'), - fieldType: 'files', - fieldConfig: fieldConfig, - }; - - return field; - }, - }, - { - fieldId: 'place', - getField: ({id, required}) => { - const fieldConfig: IDropdownConfigVocabulary = { - source: 'vocabulary', - vocabularyId: 'locators', - multiple: true, - required: required, - }; - - const field: IAuthoringFieldV2 = { - id: id, - name: gettext('Place'), - fieldType: 'dropdown', - fieldConfig: fieldConfig, - }; - - return field; - }, - storageAdapter: { - storeValue: (item, operationalValue: Array) => { - const vocabulary = superdeskApi.entities.vocabulary.getAll().get('locators'); - const vocabularyItems = new Map( - vocabulary.items.map((item) => [item.qcode, item]), - ); - - return { - ...item, - place: operationalValue.map((qcode) => vocabularyItems.get(qcode)), - }; - }, - retrieveStoredValue: (item, fieldId) => item[fieldId].map(({qcode}) => qcode), - }, - }, - { - fieldId: 'coverages', - getField: ({id, required}) => { - const fieldConfig: ICommonFieldConfig = { - required, - }; - - const field: IAuthoringFieldV2 = { - id: id, - name: gettext('Coverages'), - fieldType: 'coverages', - fieldConfig: fieldConfig, - }; - - return field; - }, - }, - { - fieldId: 'agendas', - getField: ({id, required}) => { - const fieldConfig: IDropdownConfigManualSource = { - source: 'manual-entry', - options: ((planningApi.redux.store.getState().agenda.agendas ?? []) as Array) - .filter((item) => item.is_enabled) - .map((item) => ({ - id: item._id, - label: item.name, - })), - roundCorners: true, - type: 'text', - multiple: true, - required: required, - }; - - const field: IAuthoringFieldV2 = { - id: id, - name: gettext('Agendas'), - fieldType: 'dropdown', - fieldConfig: fieldConfig, - }; - - return field; - }, - }, - ]; - - result.push( - ...getCustomVocabularyFields(), - ); - - const resultObj = result.reduce((acc, item) => { - acc[item.fieldId] = item; - - return acc; - }, {} as IFieldDefinitions); - - return resultObj; -} +import {getFieldDefinitions} from './field-definitions/index'; export function getProfile() { const planningFieldIds = getPlanningProfileFields(); diff --git a/client/components/planning-editor-standalone/storage-adapter.ts b/client/components/planning-editor-standalone/storage-adapter.ts index 663746422..53ccfcb52 100644 --- a/client/components/planning-editor-standalone/storage-adapter.ts +++ b/client/components/planning-editor-standalone/storage-adapter.ts @@ -6,7 +6,7 @@ import { IStorageAdapter, } from 'superdesk-api'; import {superdeskApi} from '../../superdeskApi'; -import {getFieldDefinitions} from './profile'; +import {getFieldDefinitions} from './field-definitions'; export const storageAdapterPlanningItem: IStorageAdapter = { storeValue: (value, fieldId, item, config, fieldType) => {