Skip to content

Commit

Permalink
Changes after review
Browse files Browse the repository at this point in the history
  • Loading branch information
thecalcc committed Dec 10, 2024
1 parent 625185a commit 482e694
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 88 deletions.
Original file line number Diff line number Diff line change
@@ -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<IFieldDefinition> = [];

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<ISubject>;
fieldId: string;
value?: Array<IVocabularyItem['qcode']>;
}) => {
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<ISubject> = 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<ISubject>;}) => {
const {fieldId, subject = []} = storageValue;
const strippedId = getStrippedCustomVocabularyId(fieldId);

return subject.filter((x) => x.scheme === strippedId).map((x) => x.qcode);
},
}
});
}
}

return result;
};
80 changes: 11 additions & 69 deletions client/components/planning-editor-standalone/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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: <T>(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;
Expand Down Expand Up @@ -146,13 +144,16 @@ export function getFieldDefinitions(): IFieldDefinitions {
return field;
},
storageAdapter: {
storeValue: (operationalValue: Array<string>): Array<IVocabularyItem> => {
storeValue: (item, operationalValue: Array<string>) => {
const vocabulary = superdeskApi.entities.vocabulary.getAll().get('locators');
const vocabularyItems = new Map<IVocabularyItem['qcode'], IVocabularyItem>(
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<IVocabularyItem>) => storageValue.map(({qcode}) => qcode),
},
Expand All @@ -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<ISubject>;
fieldId: string;
value?: Array<IVocabularyItem['qcode']>;
}) => {
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<ISubject> = 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<ISubject>;}) => {
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;
Expand Down
24 changes: 5 additions & 19 deletions client/components/planning-editor-standalone/storage-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<IPlanningItem> = {
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<ISubject>;

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;
Expand Down Expand Up @@ -60,7 +46,7 @@ export const storageAdapterPlanningItem: IStorageAdapter<IPlanningItem> = {
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);
Expand Down

0 comments on commit 482e694

Please sign in to comment.