Merge pull request #3672 from strapi/content-manager/group-layout-updates

Update content-manager schemas
This commit is contained in:
Alexandre BODIN 2019-07-24 13:59:11 +02:00 committed by GitHub
commit 175fba4441
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 270 additions and 365 deletions

View File

@ -12,8 +12,7 @@ module.exports = {
const userModels = Object.keys(strapi.models) const userModels = Object.keys(strapi.models)
.filter(key => key !== 'core_store') .filter(key => key !== 'core_store')
.map(uid => { .map(uid => {
const { info } = strapi.models[uid]; return service.formatContentType(uid, strapi.models[uid]);
return service.formatContentType({ uid, info });
}); });
const shouldDisplayPluginModel = uid => { const shouldDisplayPluginModel = uid => {
@ -28,11 +27,8 @@ module.exports = {
const plugin = strapi.plugins[pluginKey]; const plugin = strapi.plugins[pluginKey];
return Object.keys(plugin.models || {}).map(uid => { return Object.keys(plugin.models || {}).map(uid => {
const { info } = plugin.models[uid]; return service.formatContentType(uid, plugin.models[uid], {
return service.formatContentType({
uid, uid,
info,
isDisplayed: shouldDisplayPluginModel(uid), isDisplayed: shouldDisplayPluginModel(uid),
source: pluginKey, source: pluginKey,
}); });
@ -41,11 +37,7 @@ module.exports = {
.reduce((acc, models) => acc.concat(models), []); .reduce((acc, models) => acc.concat(models), []);
const adminModels = Object.keys(strapi.admin.models).map(uid => { const adminModels = Object.keys(strapi.admin.models).map(uid => {
const { info } = strapi.admin.models[uid]; return service.formatContentType(uid, strapi.admin.models[uid], {
return service.formatContentType({
uid,
info,
isDisplayed: false, isDisplayed: false,
source: 'admin', source: 'admin',
}); });

View File

@ -1,7 +1,5 @@
'use strict'; 'use strict';
const _ = require('lodash');
const pluralize = require('pluralize');
const { createModelConfigurationSchema } = require('./validation'); const { createModelConfigurationSchema } = require('./validation');
module.exports = { module.exports = {
@ -9,13 +7,11 @@ module.exports = {
* Returns the list of available groups * Returns the list of available groups
*/ */
async listGroups(ctx) { async listGroups(ctx) {
const data = Object.keys(strapi.groups).map(uid => ({ const ctService = strapi.plugins['content-manager'].services.contenttypes;
uid,
source: null, const data = Object.keys(strapi.groups).map(uid => {
isDisplayed: true, return ctService.formatContentType(uid, strapi.groups[uid]);
name: uid, });
label: _.upperFirst(pluralize(uid)),
}));
ctx.body = { data }; ctx.body = { data };
}, },
/** /**
@ -35,12 +31,13 @@ module.exports = {
return ctx.notFound('group.notFound'); return ctx.notFound('group.notFound');
} }
const ctService = strapi.plugins['content-manager'].services.contenttypes;
const groupService = strapi.plugins['content-manager'].services.groups; const groupService = strapi.plugins['content-manager'].services.groups;
const configurations = await groupService.getConfiguration(uid); const configurations = await groupService.getConfiguration(uid);
const data = { const data = {
uid, uid,
schema: groupService.formatGroupSchema(group), schema: ctService.formatContentTypeSchema(group),
...configurations, ...configurations,
}; };
@ -80,12 +77,12 @@ module.exports = {
const groupService = strapi.plugins['content-manager'].services.groups; const groupService = strapi.plugins['content-manager'].services.groups;
await groupService.setConfiguration(uid, input); await groupService.setConfiguration(uid, input);
const ctService = strapi.plugins['content-manager'].services.contenttypes;
const configurations = await groupService.getConfiguration(uid); const configurations = await groupService.getConfiguration(uid);
const data = { const data = {
uid, uid,
schema: ctService.formatContentTypeSchema(group),
schema: groupService.formatGroupSchema(group),
...configurations, ...configurations,
}; };

View File

@ -65,18 +65,19 @@ const createMetadasSchema = model => {
edit: yup edit: yup
.object() .object()
.shape({ .shape({
label: yup.string().required(), label: yup.string(),
description: yup.string(), description: yup.string(),
editable: yup.boolean().required(), placeholder: yup.string(),
visible: yup.boolean().required(), editable: yup.boolean(),
mainField: yup.string(), // only for relations. TODO: to reset when the relation changes visible: yup.boolean(),
mainField: yup.string(),
}) })
.noUnknown() .noUnknown()
.required(), .required(),
list: yup list: yup
.object() .object()
.shape({ .shape({
label: yup.string().required(), label: yup.string(),
searchable: yup.boolean(), searchable: yup.boolean(),
sortable: yup.boolean(), sortable: yup.boolean(),
}) })

View File

@ -40,15 +40,16 @@ module.exports = {
return storeUtils.deleteKey(storeKey); return storeUtils.deleteKey(storeKey);
}, },
formatContentType(opts) { formatContentType(uid, contentType, opts = {}) {
const { uid, info, source = null, isDisplayed = true } = opts; const { source = null, isDisplayed = true } = opts;
return { return {
uid, uid,
name: uid, name: uid,
label: formatContentTypeLabel(info.name || uid), label: formatContentTypeLabel(_.get(contentType, ['info', 'name'], uid)),
isDisplayed, isDisplayed,
source, source,
schema: this.formatContentTypeSchema(contentType),
}; };
}, },
@ -56,21 +57,41 @@ module.exports = {
const { associations, allAttributes } = contentType; const { associations, allAttributes } = contentType;
return { return {
...pickSchemaFields(contentType), ...pickSchemaFields(contentType),
attributes: Object.keys(allAttributes).reduce((acc, key) => { attributes: {
const attr = allAttributes[key]; [contentType.primaryKey]: {
type: contentType.primaryKeyType,
},
id: {
type: contentType.primaryKeyType,
},
...Object.keys(allAttributes).reduce((acc, key) => {
const attribute = allAttributes[key];
const assoc = associations.find(assoc => assoc.alias === key); const assoc = associations.find(assoc => assoc.alias === key);
if (assoc) { if (assoc) {
const { plugin } = attribute;
let targetEntity = attribute.model || attribute.collection;
if (plugin === 'upload' && targetEntity === 'file') {
acc[key] = { acc[key] = {
...attr, type: 'media',
type: 'relation', multiple: attribute.collection ? true : false,
targetModel: attr.model || attr.collection, required: attribute.required ? true : false,
relationType: assoc.nature,
}; };
} else { } else {
acc[key] = attr; acc[key] = {
...attribute,
type: 'relation',
targetModel: targetEntity,
relationType: assoc.nature,
};
}
} else {
acc[key] = attribute;
} }
return acc; return acc;
}, {}), }, {}),
},
}; };
}, },

View File

@ -1,7 +1,6 @@
'use strict'; 'use strict';
const storeUtils = require('./utils/store'); const storeUtils = require('./utils/store');
const { pickSchemaFields } = require('./utils/schema');
const uidToStoreKey = uid => `groups::${uid}`; const uidToStoreKey = uid => `groups::${uid}`;
@ -30,26 +29,4 @@ module.exports = {
const storeKey = uidToStoreKey(uid); const storeKey = uidToStoreKey(uid);
return storeUtils.deleteKey(storeKey); return storeUtils.deleteKey(storeKey);
}, },
formatGroupSchema(group) {
const { associations, allAttributes } = group;
return {
...pickSchemaFields(group),
attributes: Object.keys(allAttributes).reduce((acc, key) => {
const attr = allAttributes[key];
const assoc = associations.find(assoc => assoc.alias === key);
if (assoc) {
acc[key] = {
...attr,
type: 'relation',
targetModel: attr.model || attr.collection,
relationType: assoc.nature,
};
} else {
acc[key] = attr;
}
return acc;
}, {}),
};
},
}; };

View File

@ -1,217 +1,92 @@
const { const { isSortable, isVisible } = require('../attributes');
isSortable,
isEditable, const createMockSchema = (attrs, timestamps = true) => {
hasEditableAttribute, return {
hasListableAttribute, options: {
hasRelationAttribute, timestamps: timestamps ? ['createdAt', 'updatedAt'] : false,
} = require('../attributes'); },
attributes: {
id: {
type: 'integer',
},
...attrs,
...(timestamps
? {
createdAt: {
type: 'timestamp',
},
updatedAt: {
type: 'timestampUpdate',
},
}
: {}),
},
};
};
describe('attributesUtils', () => { describe('attributesUtils', () => {
describe('isSortable', () => { describe('isSortable', () => {
test('The id attribute is always sortable', () => { test('The id attribute is always sortable', () => {
expect(isSortable({}, 'id')).toBe(true); expect(isSortable(createMockSchema({}), 'id')).toBe(true);
});
test('Timestamps are sortable', () => {
expect(isSortable(createMockSchema({}, true), 'createdAt')).toBe(true);
expect(isSortable(createMockSchema({}, true), 'updatedAt')).toBe(true);
expect(isSortable(createMockSchema({}, false), 'createdAt')).toBe(false);
}); });
test('Group fields are not sortable', () => { test('Group fields are not sortable', () => {
expect( const schema = createMockSchema({
isSortable(
{
allAttributes: {
someGroup: { someGroup: {
type: 'group', type: 'group',
}, },
}, });
},
'someGroup' expect(isSortable(schema, 'someGroup')).toBe(false);
)
).toBe(false);
}); });
test('Json fields are not sortable', () => { test('Json fields are not sortable', () => {
expect( const schema = createMockSchema({
isSortable(
{
allAttributes: {
jsonInput: { jsonInput: {
type: 'json', type: 'json',
}, },
}, });
},
'jsonInput' expect(isSortable(schema, 'jsonInput')).toBe(false);
)
).toBe(false);
}); });
test('Relations are not sortable', () => { test('Relations are not sortable', () => {
expect( const schema = createMockSchema({
isSortable(
{
allAttributes: {
oneWayRel: { oneWayRel: {
model: 'someModel', type: 'relation',
targetModel: 'someModel',
}, },
},
},
'oneWayRel'
)
).toBe(false);
expect(
isSortable(
{
allAttributes: {
manyWayRel: { manyWayRel: {
collection: 'someModel', type: 'relation',
targetModel: 'someModel',
}, },
}, });
},
'manyWayRel' expect(isSortable(schema, 'oneWayRel')).toBe(false);
) expect(isSortable(schema, 'manyWayRel')).toBe(false);
).toBe(false);
}); });
}); });
describe('isEditable', () => { describe('isVisible', () => {
test('Check if the attribute is in a model attributes', () => { test('Check if the attribute is in a model attributes', () => {
expect( expect(
isEditable( isVisible(
{ createMockSchema({
attributes: {
field: { field: {
type: 'string', type: 'string',
}, },
}, }),
},
'field' 'field'
) )
).toBe(true); ).toBe(true);
expect( expect(isVisible(createMockSchema({}), 'createdAt')).toBe(false);
isEditable(
{
attributes: {
field: {
type: 'string',
},
},
},
'createdAt'
)
).toBe(false);
});
});
describe('hasEditableAttribute', () => {
test('Check if the attribute exists and is not a relation', () => {
const model = {
allAttributes: {
rel1: {
model: 'someModel',
},
rel2: {
collection: 'someModel',
},
title: {
type: 'string',
},
},
};
expect(hasEditableAttribute(model, 'rel1')).toBe(false);
expect(hasEditableAttribute(model, 'rel2')).toBe(false);
expect(hasEditableAttribute(model, 'unkown')).toBe(false);
expect(hasEditableAttribute(model, 'title')).toBe(true);
});
});
describe('hasListableAttribute', () => {
test('Ids are listable', () => {
expect(hasListableAttribute({}, 'id')).toBe(true);
});
test('Unknown attributes are not listable', () => {
const model = {
allAttributes: {
rel1: {
model: 'someModel',
},
rel2: {
collection: 'someModel',
},
title: {
type: 'string',
},
},
};
expect(hasListableAttribute(model, 'unkown')).toBe(false);
});
test('Group attributes are not listable', () => {
const model = {
allAttributes: {
someGroup: {
type: 'group',
},
},
};
expect(hasListableAttribute(model, 'someGroup')).toBe(false);
});
test('JSON attributes are not listable', () => {
const model = {
allAttributes: {
someJson: {
type: 'json',
},
},
};
expect(hasListableAttribute(model, 'someJson')).toBe(false);
});
test('Relations are not listable', () => {
const model = {
allAttributes: {
rel1: {
model: 'someModel',
},
rel2: {
collection: 'someModel',
},
title: {
type: 'string',
},
},
};
expect(hasListableAttribute(model, 'rel1')).toBe(false);
expect(hasListableAttribute(model, 'rel2')).toBe(false);
expect(hasListableAttribute(model, 'title')).toBe(true);
});
});
describe('hasRelationAttribute', () => {
test('Only validate relational attributes', () => {
const model = {
allAttributes: {
rel1: {
model: 'someModel',
},
rel2: {
collection: 'someModel',
},
title: {
type: 'string',
},
},
};
expect(hasRelationAttribute(model, 'rel1')).toBe(true);
expect(hasRelationAttribute(model, 'rel2')).toBe(true);
expect(hasRelationAttribute(model, 'unkown')).toBe(false);
expect(hasRelationAttribute(model, 'title')).toBe(false);
}); });
}); });
}); });

View File

@ -2,15 +2,13 @@
const _ = require('lodash'); const _ = require('lodash');
const NON_SORTABLES = ['group', 'json']; const NON_SORTABLES = ['group', 'json', 'relation'];
const isSortable = (model, name) => { const isSortable = (schema, name) => {
if (name === 'id') return true; if (!_.has(schema.attributes, name)) {
const attribute = model.allAttributes[name];
if (!_.has(attribute, 'type')) {
return false; return false;
} }
const attribute = schema.attributes[name];
if (NON_SORTABLES.includes(attribute.type)) { if (NON_SORTABLES.includes(attribute.type)) {
return false; return false;
} }
@ -18,51 +16,42 @@ const isSortable = (model, name) => {
return true; return true;
}; };
// check it is in the attributes not in allAttributes const isSearchable = (schema, name) => {
const isEditable = (model, name) => _.has(model.attributes, name); return isSortable(schema, name);
const hasRelationAttribute = (model, attr) => {
return (
_.has(model.allAttributes[attr], 'model') ||
_.has(model.allAttributes[attr], 'collection')
);
}; };
const hasEditableAttribute = (model, attr) => { const isVisible = (schema, name) => {
if (!_.has(model.allAttributes, attr)) { if (!_.has(schema.attributes, name)) {
return false; return false;
} }
if (!_.has(model.allAttributes[attr], 'type')) { if (isTimestamp(schema, name) || name === 'id') {
return false; return false;
} }
return true; return true;
}; };
const hasListableAttribute = (model, attr) => { const isTimestamp = (schema, name) => {
if (attr === 'id') return true; if (!_.has(schema.attributes, name)) {
if (!_.has(model.allAttributes, attr)) {
return false; return false;
} }
if (!_.has(model.allAttributes[attr], 'type')) { const timestampsOpt = _.get(schema, ['options', 'timestamps']);
return false; if (!timestampsOpt || !Array.isArray(timestampsOpt)) {
}
if (NON_SORTABLES.includes(model.allAttributes[attr].type)) {
return false; return false;
} }
if (timestampsOpt.includes(name)) {
return true; return true;
}
}; };
const isRelation = attribute => attribute.type === 'relation';
module.exports = { module.exports = {
isSortable, isSortable,
isEditable, isVisible,
isSearchable,
hasEditableAttribute, isRelation,
hasListableAttribute,
hasRelationAttribute,
}; };

View File

@ -1,20 +1,29 @@
const { createDefaultSettings, syncSettings } = require('./settings'); const { createDefaultSettings, syncSettings } = require('./settings');
const { createDefaultMetadatas, syncMetadatas } = require('./metadatas'); const { createDefaultMetadatas, syncMetadatas } = require('./metadatas');
const { createDefaultLayouts, syncLayouts } = require('./layouts'); const { createDefaultLayouts, syncLayouts } = require('./layouts');
const { formatContentTypeSchema } = require('../../ContentTypes');
async function createDefaultConfiguration(model) { async function createDefaultConfiguration(model) {
// convert model to schema
const schema = formatContentTypeSchema(model);
return { return {
settings: await createDefaultSettings(), settings: await createDefaultSettings(),
metadatas: await createDefaultMetadatas(model), metadatas: await createDefaultMetadatas(schema),
layouts: await createDefaultLayouts(model), layouts: await createDefaultLayouts(schema),
}; };
} }
async function syncConfiguration(conf, model) { async function syncConfiguration(conf, model) {
// convert model to schema
const schema = formatContentTypeSchema(model);
return { return {
settings: await syncSettings(conf, model), settings: await syncSettings(conf, schema),
layouts: await syncLayouts(conf, model), layouts: await syncLayouts(conf, schema),
metadatas: await syncMetadatas(conf, model), metadatas: await syncMetadatas(conf, schema),
}; };
} }

View File

@ -1,11 +1,7 @@
'use strict'; 'use strict';
const _ = require('lodash'); const _ = require('lodash');
const { const { isSortable, isVisible, isRelation } = require('./attributes');
hasListableAttribute,
hasRelationAttribute,
hasEditableAttribute,
} = require('./attributes');
const DEFAULT_LIST_LENGTH = 4; const DEFAULT_LIST_LENGTH = 4;
const MAX_ROW_SIZE = 12; const MAX_ROW_SIZE = 12;
@ -31,37 +27,39 @@ const typeToSize = type => {
} }
}; };
async function createDefaultLayouts(model) { async function createDefaultLayouts(schema) {
return { return {
list: createDefaultListLayout(model), list: createDefaultListLayout(schema),
editRelations: createDefaultEditRelationsLayout(model), editRelations: createDefaultEditRelationsLayout(schema),
edit: createDefaultEditLayout(model), edit: createDefaultEditLayout(schema),
}; };
} }
function createDefaultListLayout(model) { function createDefaultListLayout(schema) {
return ['id'] return Object.keys(schema.attributes)
.concat(Object.keys(model.allAttributes)) .filter(name => isSortable(schema, name))
.filter(name => hasListableAttribute(model, name))
.slice(0, DEFAULT_LIST_LENGTH); .slice(0, DEFAULT_LIST_LENGTH);
} }
function createDefaultEditRelationsLayout(model) { function createDefaultEditRelationsLayout(schema) {
return Object.keys(model.allAttributes).filter(name => if (schema.modelType === 'group') return [];
hasRelationAttribute(model, name)
return Object.keys(schema.attributes).filter(name =>
hasRelationAttribute(schema, name)
); );
} }
const rowSize = els => els.reduce((sum, el) => sum + el.size, 0); const rowSize = els => els.reduce((sum, el) => sum + el.size, 0);
function createDefaultEditLayout(model) {
const keys = Object.keys(model.attributes).filter(name => function createDefaultEditLayout(schema) {
hasEditableAttribute(model, name) const keys = Object.keys(schema.attributes).filter(name =>
hasEditableAttribute(schema, name)
); );
let layout = [[]]; let layout = [[]];
let currentRowIndex = 0; let currentRowIndex = 0;
for (let key of keys) { for (let key of keys) {
const attribute = model.attributes[key]; const attribute = schema.attributes[key];
const attributeSize = typeToSize(attribute.type); const attributeSize = typeToSize(attribute.type);
let currenRowSize = rowSize(layout[currentRowIndex]); let currenRowSize = rowSize(layout[currentRowIndex]);
@ -81,20 +79,22 @@ function createDefaultEditLayout(model) {
/** Synchronisation functions */ /** Synchronisation functions */
function syncLayouts(configuration, model) { function syncLayouts(configuration, schema) {
if (_.isEmpty(configuration.layouts)) return createDefaultLayouts(model); if (_.isEmpty(configuration.layouts)) return createDefaultLayouts(schema);
const { list = [], editRelations = [], edit = [] } = const { list = [], editRelations = [], edit = [] } =
configuration.layouts || {}; configuration.layouts || {};
const cleanList = list.filter(attr => hasListableAttribute(model, attr)); const cleanList = list.filter(attr => isSortable(schema, attr));
const cleanEditRelations = editRelations.filter(attr => const cleanEditRelations = editRelations.filter(attr =>
hasRelationAttribute(model, attr) hasRelationAttribute(schema, attr)
); );
const cleanEdit = edit.reduce((acc, row) => { const cleanEdit = edit.reduce((acc, row) => {
let newRow = row.filter(el => hasEditableAttribute(model, el.name)); let newRow = row.filter(el => hasEditableAttribute(schema, el.name));
// TODO: recompute row sizes
if (newRow.length > 0) { if (newRow.length > 0) {
acc.push(newRow); acc.push(newRow);
@ -103,16 +103,16 @@ function syncLayouts(configuration, model) {
}, []); }, []);
let layout = { let layout = {
list: cleanList.length > 0 ? cleanList : createDefaultListLayout(model), list: cleanList.length > 0 ? cleanList : createDefaultListLayout(schema),
editRelations: editRelations:
cleanEditRelations.length > 0 cleanEditRelations.length > 0
? cleanEditRelations ? cleanEditRelations
: createDefaultEditRelationsLayout(model), : createDefaultEditRelationsLayout(schema),
edit: cleanEdit.length > 0 ? cleanEdit : createDefaultEditLayout(model), edit: cleanEdit.length > 0 ? cleanEdit : createDefaultEditLayout(schema),
}; };
const newAttributes = _.difference( const newAttributes = _.difference(
Object.keys(model.allAttributes), Object.keys(schema.attributes),
Object.keys(configuration.metadatas) Object.keys(configuration.metadatas)
); );
@ -125,26 +125,28 @@ function syncLayouts(configuration, model) {
// only add valid listable attributes // only add valid listable attributes
layout.list = _.uniq( layout.list = _.uniq(
layout.list layout.list
.concat(newAttributes.filter(key => hasListableAttribute(model, key))) .concat(newAttributes.filter(key => isSortable(schema, key)))
.slice(0, DEFAULT_LIST_LENGTH) .slice(0, DEFAULT_LIST_LENGTH)
); );
} }
// add new relations to layout // add new relations to layout
if (schema.type !== 'group') {
const newRelations = newAttributes.filter(key => const newRelations = newAttributes.filter(key =>
hasRelationAttribute(model, key) hasRelationAttribute(schema, key)
); );
layout.editRelations = _.uniq(layout.editRelations.concat(newRelations)); layout.editRelations = _.uniq(layout.editRelations.concat(newRelations));
}
// add new attributes to edit view // add new attributes to edit view
const newEditAttributes = newAttributes.filter( const newEditAttributes = newAttributes.filter(
key => hasEditableAttribute(model, key) && _.has(model.attributes, key) key => hasEditableAttribute(schema, key) && isVisible(schema, key)
); );
let currentRowIndex = Math.max(layout.edit.length - 1, 0); let currentRowIndex = Math.max(layout.edit.length - 1, 0);
for (let key of newEditAttributes) { for (let key of newEditAttributes) {
const attribute = model.attributes[key]; const attribute = schema.attributes[key];
const attributeSize = typeToSize(attribute.type); const attributeSize = typeToSize(attribute.type);
let currenRowSize = rowSize(layout.edit[currentRowIndex]); let currenRowSize = rowSize(layout.edit[currentRowIndex]);
@ -162,6 +164,31 @@ function syncLayouts(configuration, model) {
return layout; return layout;
} }
const hasRelationAttribute = (schema, name) => {
if (!_.has(schema.attributes, name)) {
return false;
}
return isRelation(schema.attributes[name]);
};
const hasEditableAttribute = (schema, name) => {
if (!_.has(schema.attributes, name)) {
return false;
}
if (!isVisible(schema, name)) {
return false;
}
if (isRelation(schema.attributes[name])) {
if (schema.modelType === 'group') return true;
return false;
}
return true;
};
module.exports = { module.exports = {
createDefaultLayouts, createDefaultLayouts,
syncLayouts, syncLayouts,

View File

@ -2,13 +2,19 @@
const _ = require('lodash'); const _ = require('lodash');
const { const {
isEditable,
isSortable, isSortable,
hasListableAttribute, isSearchable,
isVisible,
isRelation,
} = require('./attributes'); } = require('./attributes');
const { formatContentTypeSchema } = require('../../ContentTypes');
function createDefaultMetadatas(model) { function createDefaultMetadatas(schema) {
return { return {
...Object.keys(schema.attributes).reduce((acc, name) => {
acc[name] = createDefaultMetadata(schema, name);
return acc;
}, {}),
id: { id: {
edit: {}, edit: {},
list: { list: {
@ -17,31 +23,26 @@ function createDefaultMetadatas(model) {
sortable: true, sortable: true,
}, },
}, },
...Object.keys(model.allAttributes).reduce((acc, name) => {
acc[name] = createDefaultMetadata(model, name);
return acc;
}, {}),
}; };
} }
function createDefaultMetadata(model, name) { function createDefaultMetadata(schema, name) {
const attr = model.allAttributes[name];
const edit = { const edit = {
label: name, label: _.upperFirst(name),
description: '', description: '',
placeholder: '', placeholder: '',
visible: true, visible: isVisible(schema, name),
editable: isEditable(model, name), editable: true,
}; };
if (_.has(attr, 'model') || _.has(attr, 'collection')) { if (isRelation(schema.attributes[name])) {
edit.mainField = 'id'; edit.mainField = 'id';
} }
const list = { const list = {
label: name, label: _.upperFirst(name),
searchable: true, searchable: isSearchable(schema, name),
sortable: isSortable(model, name), sortable: isSortable(schema, name),
}; };
return { edit, list }; return { edit, list };
@ -49,39 +50,44 @@ function createDefaultMetadata(model, name) {
/** Synchronisation functions */ /** Synchronisation functions */
async function syncMetadatas(configuration, model) { async function syncMetadatas(configuration, schema) {
// clear all keys that do not exist anymore // clear all keys that do not exist anymore
if (_.isEmpty(configuration.metadatas)) return createDefaultMetadatas(model); if (_.isEmpty(configuration.metadatas)) return createDefaultMetadatas(schema);
// remove old keys // remove old keys
const metasWithValidKeys = _.pick( const metasWithValidKeys = _.pick(
configuration.metadatas, configuration.metadatas,
['id'].concat(Object.keys(model.allAttributes)) Object.keys(schema.attributes)
); );
// add new keys and missing fields // add new keys and missing fields
const metasWithDefaults = _.merge( const metasWithDefaults = _.merge(
{}, {},
createDefaultMetadatas(model), createDefaultMetadatas(schema),
metasWithValidKeys metasWithValidKeys
); );
// clear the invalid mainFields // clear the invalid mainFields
const updatedMetas = Object.keys(metasWithDefaults).reduce((acc, key) => { const updatedMetas = Object.keys(metasWithDefaults).reduce((acc, key) => {
const meta = metasWithDefaults[key]; const { edit, list } = metasWithDefaults[key];
const { edit, list } = meta; const attr = schema.attributes[key];
let updatedMeta = { edit, list }; let updatedMeta = { edit, list };
// update sortable attr // update sortable attr
if (list.sortable && !isSortable(model, key)) { if (list.sortable && !isSortable(schema, key)) {
_.set(updatedMeta, ['list', 'sortable'], false); _.set(updatedMeta, ['list', 'sortable'], false);
_.set(acc, [key], updatedMeta); _.set(acc, [key], updatedMeta);
} }
if (list.searchable && !isSearchable(schema, key)) {
_.set(updatedMeta, ['list', 'searchable'], false);
_.set(acc, [key], updatedMeta);
}
if (!_.has(edit, 'mainField')) return acc; if (!_.has(edit, 'mainField')) return acc;
// remove mainField if the attribute is not a relation anymore // remove mainField if the attribute is not a relation anymore
if (_.has(model.allAttributes[key], 'type')) { if (!isRelation(attr)) {
_.set(updatedMeta, 'edit', _.omit(edit, ['mainField'])); _.set(updatedMeta, 'edit', _.omit(edit, ['mainField']));
_.set(acc, [key], updatedMeta); _.set(acc, [key], updatedMeta);
return acc; return acc;
@ -91,10 +97,11 @@ async function syncMetadatas(configuration, model) {
if (edit.mainField === 'id') return acc; if (edit.mainField === 'id') return acc;
// check the mainField in the targetModel // check the mainField in the targetModel
const attr = model.allAttributes[key]; const targetSchema = getTargetSchema(attr.targetModel, attr.plugin);
const target = strapi.getModel(attr.model || attr.collection, attr.plugin);
if (!hasListableAttribute(target, meta.mainField)) { if (!targetSchema) return acc;
if (!isSortable(targetSchema, edit.mainField)) {
_.set(updatedMeta, ['edit', 'mainField'], 'id'); _.set(updatedMeta, ['edit', 'mainField'], 'id');
_.set(acc, [key], updatedMeta); _.set(acc, [key], updatedMeta);
return acc; return acc;
@ -106,6 +113,13 @@ async function syncMetadatas(configuration, model) {
return _.assign(metasWithDefaults, updatedMetas); return _.assign(metasWithDefaults, updatedMetas);
} }
const getTargetSchema = (name, plugin) => {
const model = strapi.getModel(name, plugin);
if (!model) return null;
return formatContentTypeSchema(model);
};
module.exports = { module.exports = {
createDefaultMetadatas, createDefaultMetadatas,
syncMetadatas, syncMetadatas,

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const _ = require('lodash'); const _ = require('lodash');
const { hasListableAttribute } = require('./attributes'); const { isSortable } = require('./attributes');
/** /**
* Retunrs a configuration default settings * Retunrs a configuration default settings
@ -21,18 +21,16 @@ async function createDefaultSettings() {
/** Synchronisation functions */ /** Synchronisation functions */
async function syncSettings(configuration, model) { async function syncSettings(configuration, schema) {
if (_.isEmpty(configuration.settings)) return createDefaultSettings(model); if (_.isEmpty(configuration.settings)) return createDefaultSettings(schema);
const { mainField = 'id', defaultSortBy = 'id' } = const { mainField = 'id', defaultSortBy = 'id' } =
configuration.settings || {}; configuration.settings || {};
return { return {
...configuration.settings, ...configuration.settings,
mainField: hasListableAttribute(model, mainField) ? mainField : 'id', mainField: isSortable(schema, mainField) ? mainField : 'id',
defaultSortBy: hasListableAttribute(model, defaultSortBy) defaultSortBy: isSortable(schema, defaultSortBy) ? defaultSortBy : 'id',
? defaultSortBy
: 'id',
}; };
} }

View File

@ -51,6 +51,7 @@ module.exports = function(strapi) {
throw new Error(`Group ${key} is missing a collectionName attribute`); throw new Error(`Group ${key} is missing a collectionName attribute`);
return Object.assign(group, { return Object.assign(group, {
modelType: 'group',
globalId: group.globalId || _.upperFirst(_.camelCase(`group_${key}`)), globalId: group.globalId || _.upperFirst(_.camelCase(`group_${key}`)),
}); });
}); });
@ -61,6 +62,7 @@ module.exports = function(strapi) {
let model = strapi.api[key].models[index]; let model = strapi.api[key].models[index];
Object.assign(model, { Object.assign(model, {
modelType: 'contentType',
apiName: key, apiName: key,
globalId: model.globalId || _.upperFirst(_.camelCase(index)), globalId: model.globalId || _.upperFirst(_.camelCase(index)),
collectionName: model.collectionName || `${index}`.toLocaleLowerCase(), collectionName: model.collectionName || `${index}`.toLocaleLowerCase(),
@ -127,6 +129,7 @@ module.exports = function(strapi) {
let model = strapi.admin.models[key]; let model = strapi.admin.models[key];
Object.assign(model, { Object.assign(model, {
modelType: 'contentType',
identity: model.identity || _.upperFirst(key), identity: model.identity || _.upperFirst(key),
globalId: model.globalId || _.upperFirst(_.camelCase(`admin-${key}`)), globalId: model.globalId || _.upperFirst(_.camelCase(`admin-${key}`)),
connection: connection:
@ -155,6 +158,8 @@ module.exports = function(strapi) {
let model = plugin.models[key]; let model = plugin.models[key];
Object.assign(model, { Object.assign(model, {
modelType: 'contentType',
plugin: pluginName,
collectionName: collectionName:
model.collectionName || `${pluginName}_${key}`.toLowerCase(), model.collectionName || `${pluginName}_${key}`.toLowerCase(),
globalId: globalId: