184 lines
4.4 KiB
JavaScript

'use strict';
const _ = require('lodash');
const {
isListable,
hasEditableAttribute,
hasRelationAttribute,
} = require('./attributes');
const DEFAULT_LIST_LENGTH = 4;
const MAX_ROW_SIZE = 12;
const typeToSize = type => {
switch (type) {
case 'checkbox':
case 'boolean':
case 'date':
case 'biginteger':
case 'decimal':
case 'float':
case 'integer':
case 'number':
return MAX_ROW_SIZE / 3;
case 'json':
case 'group':
case 'richtext':
return MAX_ROW_SIZE;
default:
return MAX_ROW_SIZE / 2;
}
};
async function createDefaultLayouts(schema) {
return {
list: createDefaultListLayout(schema),
editRelations: createDefaultEditRelationsLayout(schema),
edit: createDefaultEditLayout(schema),
..._.pick(_.get(schema, ['config', 'layouts'], {}), [
'list',
'edit',
'editRelations',
]),
};
}
function createDefaultListLayout(schema) {
return Object.keys(schema.attributes)
.filter(name => isListable(schema, name))
.slice(0, DEFAULT_LIST_LENGTH);
}
function createDefaultEditRelationsLayout(schema) {
if (schema.modelType === 'group') return [];
return Object.keys(schema.attributes).filter(name =>
hasRelationAttribute(schema, name)
);
}
const rowSize = els => els.reduce((sum, el) => sum + el.size, 0);
function createDefaultEditLayout(schema) {
const keys = Object.keys(schema.attributes).filter(name =>
hasEditableAttribute(schema, name)
);
return appendToEditLayout([], keys, schema);
}
/** Synchronisation functions */
function syncLayouts(configuration, schema) {
if (_.isEmpty(configuration.layouts)) return createDefaultLayouts(schema);
const { list = [], editRelations = [], edit = [] } =
configuration.layouts || {};
let cleanList = list.filter(attr => isListable(schema, attr));
let cleanEditRelations = editRelations.filter(attr =>
hasRelationAttribute(schema, attr)
);
let elementsToReAppend = [];
let cleanEdit = [];
for (let row of edit) {
let newRow = [];
for (let el of row) {
if (!hasEditableAttribute(schema, el.name)) continue;
// if size of the element has changed (type changes)
if (typeToSize(schema.attributes[el.name].type) !== el.size) {
elementsToReAppend.push(el.name);
continue;
}
newRow.push(el);
}
if (newRow.length > 0) {
cleanEdit.push(newRow);
}
}
cleanEdit = appendToEditLayout(cleanEdit, elementsToReAppend, schema);
const newAttributes = _.difference(
Object.keys(schema.attributes),
Object.keys(configuration.metadatas)
);
/** Add new attributes where they belong */
if (cleanList.length < DEFAULT_LIST_LENGTH) {
// add newAttributes
// only add valid listable attributes
cleanList = _.uniq(
cleanList
.concat(newAttributes.filter(key => isListable(schema, key)))
.slice(0, DEFAULT_LIST_LENGTH)
);
}
// add new relations to layout
if (schema.modelType !== 'group') {
const newRelations = newAttributes.filter(key =>
hasRelationAttribute(schema, key)
);
cleanEditRelations = _.uniq(cleanEditRelations.concat(newRelations));
}
// add new attributes to edit view
const newEditAttributes = newAttributes.filter(key =>
hasEditableAttribute(schema, key)
);
cleanEdit = appendToEditLayout(cleanEdit, newEditAttributes, schema);
return {
list: cleanList.length > 0 ? cleanList : createDefaultListLayout(schema),
edit: cleanEdit.length > 0 ? cleanEdit : createDefaultEditLayout(schema),
editRelations:
cleanEditRelations.length > 0
? cleanEditRelations
: createDefaultEditRelationsLayout(schema),
};
}
const appendToEditLayout = (layout = [], keysToAppend, schema) => {
if (keysToAppend.length === 0) return layout;
let currentRowIndex = Math.max(layout.length - 1, 0);
// init currentRow if necessary
if (!layout[currentRowIndex]) {
layout[currentRowIndex] = [];
}
for (let key of keysToAppend) {
const attribute = schema.attributes[key];
const attributeSize = typeToSize(attribute.type);
let currenRowSize = rowSize(layout[currentRowIndex]);
if (currenRowSize + attributeSize > MAX_ROW_SIZE) {
currentRowIndex += 1;
layout[currentRowIndex] = [];
}
layout[currentRowIndex].push({
name: key,
size: attributeSize,
});
}
return layout;
};
module.exports = {
createDefaultLayouts,
syncLayouts,
};