import CrudStoreModel, { BaseSchemaModel, CrudStoreItemsModel, CrudStoreSchemaModel, CrudStoreSchemaPropertiesModel } from "../stores/types/CrudStoreModel"; import store from '../stores/index'; export default class CrudHelpers { public static initialValues(schema: CrudStoreSchemaModel, query?: { [k: string]: string }): CrudStoreItemsModel | undefined { // Initialize abstract types with first derived type by default const properties = { ...schema.properties, ...schema.oneOf ? schema.oneOf[0].properties : {} }; let item = this.initialValueForObject(properties); if (item && query) { item = this.populateQueryIntoCrudItem(properties, item, query); } return item; } private static initialValueForObject(properties: CrudStoreSchemaPropertiesModel | undefined): CrudStoreItemsModel | undefined { if (!properties) { return; } const item: CrudStoreItemsModel = { $type: properties.$type.enum[0] }; for (const [property, value] of Object.entries(properties)) { const typedValue = value as BaseSchemaModel; switch (typedValue.type) { case 'string': item[property] = this.initialStringValues(typedValue); break; case 'integer': case 'number': item[property] = this.initialNumberValues(typedValue); break; case 'boolean': item[property] = this.initialBooleanValues(typedValue); break; case 'array': item[property] = this.initialArrayValues(typedValue); break; case 'object': item[property] = this.initialObjectValues(typedValue); } } return item; } private static initialStringValues(property: BaseSchemaModel): string | Date | undefined { if (property.default && typeof property.default === 'string') { return property.default; } if (!property.required || property.isHidden) { return; } if (property.format === 'datetime-picker') { return new Date(); } return ''; } private static initialNumberValues(property: BaseSchemaModel): number | undefined { if (property.default && !isNaN(parseFloat(property.default))) { return parseFloat(property.default); } if (!property.required) { return; } return 0; } private static initialBooleanValues(property: BaseSchemaModel): boolean { if (property.default && property.default.toLowerCase() === 'true') { return true; } return false; } private static initialArrayValues(property: BaseSchemaModel): any[] { if (property.default && JSON.parse(property.default) instanceof Array) { return JSON.parse(property.default) as []; } if (!property.minLength || !property.items) { return []; } if (property.items.oneOf || property.items.$ref) { return []; } return Array(property.minLength).fill(0).map(() => this.initialValueForObject(property.items?.properties)) } private static initialObjectValues(property: BaseSchemaModel): CrudStoreItemsModel | undefined { if (property.default && typeof property.default === 'object') { console.warn('Object default values are not supported. You might be able to use a workaround with a JSON value'); return property.default; } if (!property.required) { return; } if (property.oneOf) { return; } if (property.$ref) { return; } if (!property.properties) { return; } return this.initialValueForObject(property.properties) } private static populateQueryIntoCrudItem(properties: CrudStoreSchemaPropertiesModel, item: CrudStoreItemsModel, query: { [k: string]: string }): CrudStoreItemsModel { for (const [property, value] of Object.entries(query)) { if (!Object.keys(properties).includes(property)) { continue; } item[property] = this.convertQueryValueToType(properties[property] as BaseSchemaModel, value); } return item; } private static convertQueryValueToType(property: BaseSchemaModel, value: string) { switch (property.type) { case 'string': if (property.format === 'datetime-picker') { return new Date(value); } return value; case 'boolean': return value.toLowerCase() === 'true'; case 'number': return Number.parseFloat(value); case 'array': return []; default: return; } } public static getDisplayFieldForSchemaProperties(schemaProperties: Object | undefined): string | null { if (!schemaProperties) { return null; } for (const entry of Object.entries(schemaProperties)) { const [ key, value ] = entry; const keyDenyList = ['modifiedBy', 'createdBy', 'language']; if (!keyDenyList.includes(key) && value.format === 'string-input') { return key; } } // fallback to Guid of a CmsItem return 'id'; } public static getStoreNameForReference(reference: string): string | null { const matches = reference.match(/\/items\/(.*)\/schema/); return matches && matches[1] ? matches[1] : null; } public static getDisplayFieldValueForReference(store: any, reference: string, guid: string) { const storeName = this.getStoreNameForReference(reference); if (!storeName || !store.state[storeName]) { return guid; } const getterName = `${storeName}/getItemByGuid`; const foundItem = typeof store.getters[getterName] === 'function' ? store.getters[getterName](guid) : null; const crudState = store.state[storeName] as CrudStoreModel; if (this.hasUnfetchedData(crudState)) { store.dispatch(`${storeName}/fetchCrudData`); } const displayField = this.getDisplayFieldForSchemaProperties(store.state[storeName].schema?.properties); return foundItem && displayField ? foundItem[displayField] : guid; } // Fetch and populate specified crud store with its data and subscribe to // crud store language change for multi-language support to refresh crud data public static async subscribeCrudData(module: string): Promise<() => void> { const crudState = store.state[module] as CrudStoreModel; if (this.hasUnfetchedData(crudState)) { await store.dispatch(`${module}/fetchCrudData`); } return store.subscribe(async (mutation) => { if (mutation.type === 'languages/setSelected' && !crudState.loading) { await store.dispatch(`${module}/fetchCrudData`); } }); } public static hasUnfetchedData(crudState: CrudStoreModel): boolean { if (crudState.loading) { return false; } if (store.state.languages.useMultiLanguage && store.state.languages.selected?.key !== crudState.language) { return true; } return !crudState.initialized; } }