UNPKG

strapi-plugin-content-manager

Version:

A powerful UI to easily manage your data.

243 lines (202 loc) 7.79 kB
const _ = require('lodash'); const pluralize = require('pluralize'); module.exports = async cb => { const pickData = (model) => _.pick(model, [ 'info', 'connection', 'collectionName', 'attributes', 'identity', 'globalId', 'globalName', 'orm', 'loadedModel', 'primaryKey', 'associations' ]); const models = _.mapValues(strapi.models, pickData); delete models['core_store']; const pluginsModel = Object.keys(strapi.plugins).reduce((acc, current) => { acc[current] = { models: _.mapValues(strapi.plugins[current].models, pickData), }; return acc; }, {}); // Init schema const schema = { generalSettings: { search: true, filters: true, bulkActions: true, pageEntries: 10, }, models: { plugins: {}, }, }; const buildSchema = (model, name, plugin = false) => { // Model data const schemaModel = Object.assign({ label: _.upperFirst(name), labelPlural: _.upperFirst(pluralize(name)), orm: model.orm || 'mongoose', search: true, filters: true, bulkActions: true, pageEntries: 10, defaultSort: model.primaryKey, sort: 'ASC', }, model); // Fields (non relation) schemaModel.fields = _.mapValues(_.pickBy(model.attributes, attribute => !attribute.model && !attribute.collection ), (value, attribute) => ({ label: _.upperFirst(attribute), description: '', type: value.type || 'string', })); // Select fields displayed in list view // schemaModel.list = _.slice(_.keys(schemaModel.fields), 0, 4); schemaModel.listDisplay = Object.keys(schemaModel.fields) // Construct Array of attr ex { type: 'string', label: 'Foo', name: 'Foo', description: '' } // NOTE: Do we allow sort on boolean? .map(attr => { const attrType = schemaModel.fields[attr].type; const sortable = attrType !== 'json' && attrType !== 'array'; return Object.assign(schemaModel.fields[attr], { name: attr, sortable, searchable: sortable }); }) // Retrieve only the fourth first items .slice(0, 4); schemaModel.listDisplay.splice(0, 0, { name: model.primaryKey || 'id', label: 'Id', type: 'string', sortable: true, searchable: true, }); if (model.associations) { // Model relations schemaModel.relations = model.associations.reduce((acc, current) => { const displayedAttribute = current.plugin ? _.get(pluginsModel, [current.plugin, 'models', current.model || current.collection, 'info', 'mainField']) || _.findKey(_.get(pluginsModel, [current.plugin, 'models', current.model || current.collection, 'attributes']), { type : 'string'}) || 'id' : _.get(models, [current.model || current.collection, 'info', 'mainField']) || _.findKey(_.get(models, [current.model || current.collection, 'attributes']), { type : 'string'}) || 'id'; acc[current.alias] = { ...current, description: '', displayedAttribute, }; return acc; }, {}); } if (plugin) { return _.set(schema.models.plugins, `${plugin}.${name}`, schemaModel); } // Set the formatted model to the schema schema.models[name] = schemaModel; }; _.forEach(pluginsModel, (plugin, pluginName) => { _.forEach(plugin.models, (model, name) => { buildSchema(model, name, pluginName); }); }); // Generate schema for models. _.forEach(models, (model, name) => { buildSchema(model, name); }); const pluginStore = strapi.store({ environment: '', type: 'plugin', name: 'content-manager' }); const getApis = (data) => Object.keys(data).reduce((acc, curr) => { if (data[curr].fields) { return acc.concat([curr]); } if (curr === 'plugins') { Object.keys(data[curr]).map(plugin => { Object.keys(data[curr][plugin]).map(api => { acc = acc.concat([`${curr}.${plugin}.${api}`]); }); }); } return acc; }, []); const getApisKeys = (data, sameArray) => sameArray.map(apiPath => { const fields = Object.keys(_.get(data.models, apiPath.concat(['fields']))); return fields.map(field => `${apiPath.join('.')}.fields.${field}`); }); try { const prevSchema = await pluginStore.get({ key: 'schema' }); if (!prevSchema) { pluginStore.set({ key: 'schema', value: schema }); return cb(); } const splitted = str => str.split('.'); const prevSchemaApis = getApis(prevSchema.models); const schemaApis = getApis(schema.models); const apisToAdd = schemaApis.filter(api => prevSchemaApis.indexOf(api) === -1).map(splitted); const apisToRemove = prevSchemaApis.filter(api => schemaApis.indexOf(api) === -1).map(splitted); const sameApis = schemaApis.filter(api => prevSchemaApis.indexOf(api) !== -1).map(splitted); const schemaSameApisKeys = _.flattenDeep(getApisKeys(schema, sameApis)); const prevSchemaSameApisKeys = _.flattenDeep(getApisKeys(prevSchema, sameApis)); const sameApisAttrToAdd = schemaSameApisKeys.filter(attr => prevSchemaSameApisKeys.indexOf(attr) === -1).map(splitted); const sameApisAttrToRemove = prevSchemaSameApisKeys.filter(attr => schemaSameApisKeys.indexOf(attr) === -1).map(splitted); // Remove api apisToRemove.map(apiPath => { _.unset(prevSchema.models, apiPath); }); // Remove API attribute sameApisAttrToRemove.map(attrPath => { // Check default sort and change it if needed _.unset(prevSchema.models, attrPath); const apiPath = attrPath.length > 3 ? _.take(attrPath, 3) : _.take(attrPath, 1); const listDisplayPath = apiPath.concat('listDisplay'); const prevListDisplay = _.get(prevSchema.models, listDisplayPath); const defaultSortPath = apiPath.concat('defaultSort'); const currentAttr = attrPath.slice(-1); const defaultSort = _.get(prevSchema.models, defaultSortPath); if (_.includes(currentAttr, defaultSort)) { _.set(prevSchema.models, defaultSortPath, _.get(schema.models, defaultSortPath)); } // Update the displayed fields const updatedListDisplay = prevListDisplay.filter(obj => obj.name !== currentAttr.join()); if (updatedListDisplay.length === 0) { // Update it with the one from the generaeted schema _.set(prevSchema.models, listDisplayPath, _.get(schema.models, listDisplayPath, [])); } else { _.set(prevSchema.models, listDisplayPath, updatedListDisplay); } }); // Add API apisToAdd.map(apiPath => { const api = _.get(schema.models, apiPath); const { search, filters, bulkActions, pageEntries } = _.get(prevSchema, 'generalSettings'); _.set(api, 'filters', filters); _.set(api, 'search', search); _.set(api, 'bulkActions', bulkActions); _.set(api, 'pageEntries', pageEntries); _.set(prevSchema.models, apiPath, api); }); // Add attribute to existing API sameApisAttrToAdd.map(attrPath => { const attr = _.get(schema.models, attrPath); _.set(prevSchema.models, attrPath, attr); }); // Update other keys sameApis.map(apiPath => { const keysToUpdate = ['relations', 'loadedModel', 'associations', 'attributes'].map(key => apiPath.concat(key)); keysToUpdate.map(keyPath => { const newValue = _.get(schema.models, keyPath); _.set(prevSchema.models, keyPath, newValue); }); }); await pluginStore.set({ key: 'schema', value: prevSchema }); } catch(err) { console.log('error', err); } cb(); };