mirror of
https://github.com/strapi/strapi.git
synced 2025-11-01 18:33:55 +00:00
Update displayed fields when removing a field from the content type builder
This commit is contained in:
parent
54aef15b75
commit
6bf3ddeea9
@ -326,7 +326,9 @@ module.exports = async cb => {
|
||||
|
||||
// Update other keys
|
||||
sameApis.map(apiPath => {
|
||||
const keysToUpdate = ['relations', 'loadedModel', 'associations', 'attributes'].map(key => apiPath.concat(key));
|
||||
// This doesn't keep the prevSettings for the relations, the user will have to reset it.
|
||||
// We might have to improve this if we want the order of the relations to be kept
|
||||
const keysToUpdate = ['relations', 'loadedModel', 'associations', 'attributes', ['editDisplay', 'relations']].map(key => apiPath.concat(key));
|
||||
|
||||
keysToUpdate.map(keyPath => {
|
||||
const newValue = _.get(schema.models, keyPath);
|
||||
|
||||
@ -111,7 +111,7 @@ module.exports = {
|
||||
await Service.generateAPI(name, description, connection, collectionName, []);
|
||||
}
|
||||
|
||||
await Service.appearance(formatedAttributes, name);
|
||||
await Service.appearance(formatedAttributes, name, plugin);
|
||||
|
||||
try {
|
||||
const modelJSON = _.cloneDeep(require(modelFilePath));
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
"prepublishOnly": "IS_MONOREPO=true npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"immutable": "^3.8.2",
|
||||
"pluralize": "^7.0.0",
|
||||
"strapi-generate": "3.0.0-alpha.13.0.1",
|
||||
"strapi-generate-api": "3.0.0-alpha.13.0.1"
|
||||
@ -50,4 +51,4 @@
|
||||
"npm": ">= 5.0.0"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,9 +4,11 @@ const path = require('path');
|
||||
const fs = require('fs');
|
||||
const _ = require('lodash');
|
||||
const generator = require('strapi-generate');
|
||||
const { fromJS } = require('immutable');
|
||||
const Manager = require('../utils/Manager.js');
|
||||
|
||||
module.exports = {
|
||||
appearance: async (attributes, model) => {
|
||||
appearance: async (attributes, model, plugin) => {
|
||||
const pluginStore = strapi.store({
|
||||
environment: '',
|
||||
type: 'plugin',
|
||||
@ -17,6 +19,107 @@ module.exports = {
|
||||
|
||||
const layout = _.get(schema.layout, model, {});
|
||||
|
||||
// If updating a content-type
|
||||
if (!_.isEmpty(layout)) {
|
||||
const state = fromJS({
|
||||
schema: fromJS(schema),
|
||||
});
|
||||
const schemaPath = plugin ? ['models', 'plugins', plugin, model] : ['models', model];
|
||||
const keys = plugin ? `plugins.${plugin}.${model}.editDisplay` : `${model}.editDisplay`;
|
||||
const prevList = state.getIn(['schema', ...schemaPath, 'editDisplay', 'fields']);
|
||||
const prevFields = Object.keys(state.getIn(['schema', ...schemaPath, 'editDisplay', 'availableFields']).toJS());
|
||||
const currentFields = Object.keys(attributes);
|
||||
const fieldsToRemove = _.difference(prevFields, currentFields);
|
||||
let newList = prevList;
|
||||
|
||||
fieldsToRemove.forEach((field) => {
|
||||
const index = newList.indexOf(field);
|
||||
const manager = new Manager(state, prevList, keys, index, fromJS(layout.attributes || {}));
|
||||
const attrToRemoveInfos = manager.attrToRemoveInfos; // Retrieve the removed item infos
|
||||
const arrayOfLastLineElements = manager.arrayOfEndLineElements;
|
||||
const isRemovingAFullWidthNode = attrToRemoveInfos.bootstrapCol === 12;
|
||||
|
||||
if (isRemovingAFullWidthNode) {
|
||||
const currentNodeLine = _.findIndex(arrayOfLastLineElements, ['index', attrToRemoveInfos.index]); // Used only to know if removing a full size element on the first line
|
||||
if (currentNodeLine === 0) {
|
||||
newList = newList
|
||||
.delete(index);
|
||||
} else {
|
||||
const previousNodeLine = currentNodeLine - 1;
|
||||
const firstElementOnLine = previousNodeLine === 0 ? 0 : arrayOfLastLineElements[previousNodeLine - 1].index + 1;
|
||||
const lastElementOnLine = arrayOfLastLineElements[previousNodeLine].index + 1;
|
||||
const previousLineRangeIndexes = firstElementOnLine === lastElementOnLine ? [firstElementOnLine] : _.range(firstElementOnLine, lastElementOnLine);
|
||||
const elementsOnLine = manager.getElementsOnALine(previousLineRangeIndexes);
|
||||
const previousLineColNumber = manager.getLineSize(elementsOnLine);
|
||||
|
||||
if (previousLineColNumber >= 10) {
|
||||
newList = newList
|
||||
.delete(index);
|
||||
} else {
|
||||
const colNumberToAdd = 12 - previousLineColNumber;
|
||||
const colsToAdd = manager.getColsToAdd(colNumberToAdd);
|
||||
newList = newList
|
||||
.delete(index)
|
||||
.insert(index, colsToAdd[0]);
|
||||
|
||||
if (colsToAdd.length > 1) {
|
||||
newList = newList
|
||||
.insert(index, colsToAdd[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const nodeBounds = { left: manager.getBound(false), right: manager.getBound(true) }; // Retrieve the removed element's bounds
|
||||
const leftBoundIndex = _.get(nodeBounds, ['left', 'index'], 0) + 1;
|
||||
const rightBoundIndex = _.get(nodeBounds, ['right', 'index'], prevList.size -1);
|
||||
const elementsOnLine = manager.getElementsOnALine(_.range(leftBoundIndex - 1, rightBoundIndex + 1));
|
||||
const currentLineColSize = manager.getLineSize(elementsOnLine);
|
||||
const isRemovingLine = currentLineColSize - attrToRemoveInfos.bootstrapCol === 0;
|
||||
|
||||
if (isRemovingLine) {
|
||||
newList = newList
|
||||
.delete(attrToRemoveInfos.index);
|
||||
} else {
|
||||
const random = Math.floor(Math.random() * 1000);
|
||||
newList = newList
|
||||
.delete(attrToRemoveInfos.index)
|
||||
.insert(rightBoundIndex, `__col-md-${attrToRemoveInfos.bootstrapCol}__${random}`);
|
||||
}
|
||||
}
|
||||
|
||||
const newState = state.updateIn(['schema', 'models', ...keys.split('.'), 'fields'], () => newList);
|
||||
const newManager = new Manager(newState, newList, keys, index, fromJS(layout));
|
||||
const lastListItem = newManager.getAttrInfos(newList.size - 1);
|
||||
const isLastItemFullSize = lastListItem.bootstrapCol === 12;
|
||||
const newArrayOfLastLineElements = newManager.arrayOfEndLineElements
|
||||
.concat({ name: lastListItem.name, index: lastListItem.index, isFullSize: isLastItemFullSize });
|
||||
// Array of element's index to remove from the new list
|
||||
let addedElementsToRemove = [];
|
||||
|
||||
newArrayOfLastLineElements.forEach((item, i) => {
|
||||
if (i < newArrayOfLastLineElements.length) {
|
||||
const firstElementOnLine = i === 0 ? 0 : newArrayOfLastLineElements[i - 1].index + 1;
|
||||
const lastElementOnLine = newArrayOfLastLineElements[i].index;
|
||||
const rangeIndex = _.range(firstElementOnLine, lastElementOnLine + 1);
|
||||
const elementsOnLine = newManager.getElementsOnALine(rangeIndex)
|
||||
.filter(name => !name.includes('__col'));
|
||||
|
||||
if (elementsOnLine.length === 0) {
|
||||
addedElementsToRemove = addedElementsToRemove.concat(rangeIndex);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
newList = newList.filter((item, index) => { // Remove the unnecessary divs
|
||||
const indexToKeep = addedElementsToRemove.indexOf(index) === -1;
|
||||
|
||||
return indexToKeep;
|
||||
});
|
||||
});
|
||||
|
||||
_.set(schema, [...schemaPath, 'editDisplay', 'fields'], newList.toJS());
|
||||
}
|
||||
|
||||
Object.keys(attributes).map(attribute => {
|
||||
const appearances = _.get(attributes, [attribute, 'appearance'], {});
|
||||
Object.keys(appearances).map(appearance => {
|
||||
|
||||
228
packages/strapi-plugin-content-type-builder/utils/Manager.js
Normal file
228
packages/strapi-plugin-content-type-builder/utils/Manager.js
Normal file
@ -0,0 +1,228 @@
|
||||
const { findIndex, pullAt, range } = require('lodash');
|
||||
const { List } = require('immutable');
|
||||
|
||||
class Manager {
|
||||
constructor(state, list, keys, index, layout) {
|
||||
this.state = state;
|
||||
this.keys = keys.split('.');
|
||||
this.layout = layout;
|
||||
this.list = list;
|
||||
this.index = index;
|
||||
this.arrayOfEndLineElements = this.getLinesBound();
|
||||
this.attrToRemoveInfos = this.attrToRemoveInfos();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the bootstrap col index, name and type of a field
|
||||
* @param {Number} index
|
||||
* @returns {Object}
|
||||
*/
|
||||
getAttrInfos(index) {
|
||||
const name = this.getAttrName(index);
|
||||
const appearance = this.layout.getIn([name, 'appearance']);
|
||||
const type = appearance !== '' && appearance !== undefined ? appearance : this.getType(name);
|
||||
const bootstrapCol = this.getBootStrapCol(type);
|
||||
|
||||
const infos = {
|
||||
bootstrapCol,
|
||||
index,
|
||||
name,
|
||||
type,
|
||||
};
|
||||
|
||||
return infos;
|
||||
}
|
||||
|
||||
getColsToAdd(number) {
|
||||
let ret;
|
||||
|
||||
switch(number) {
|
||||
case 9:
|
||||
ret = ['__col-md-3__', '__col-md-6__'];
|
||||
break;
|
||||
case 8:
|
||||
ret = ['__col-md-4__', '__col-md-4__'];
|
||||
break;
|
||||
case 4:
|
||||
ret = ['__col-md-4__'];
|
||||
break;
|
||||
case 6:
|
||||
ret = ['__col-md-6__'];
|
||||
break;
|
||||
default:
|
||||
ret = ['__col-md-3__'];
|
||||
}
|
||||
const random = Math.floor(Math.random() * 1000);
|
||||
|
||||
return ret.map(v => `${v}${random}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field default bootstrap col
|
||||
* NOTE: will change if we add the customisation of an input's width
|
||||
* @param {String} type
|
||||
* @returns {Number}
|
||||
*/
|
||||
getBootStrapCol(type) {
|
||||
switch(type) {
|
||||
case 'checkbox':
|
||||
case 'boolean':
|
||||
case 'date':
|
||||
return 4;
|
||||
case 'json':
|
||||
case 'wysiwyg':
|
||||
case 'WYSIWYG':
|
||||
return 12;
|
||||
default:
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
getElementsOnALine(itemsToPull, arr = this.list) {
|
||||
const array = List.isList(arr) ? arr.toJS() : arr;
|
||||
|
||||
return pullAt(array, itemsToPull);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the field to remove infos
|
||||
* @returns {Object}
|
||||
*/
|
||||
attrToRemoveInfos() {
|
||||
return this.getAttrInfos(this.index);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Retrieve the last element of each bootstrap line
|
||||
* @returns {Array}
|
||||
*/
|
||||
getLinesBound() { // NOTE: doesn't work for the last element if the line is not full!
|
||||
const array = [];
|
||||
let sum = 0;
|
||||
|
||||
this.list.forEach((item, i) => {
|
||||
let { bootstrapCol, index, name, type } = this.getAttrInfos(i);
|
||||
|
||||
if (!type && name.includes('__col')) {
|
||||
bootstrapCol = parseInt(name.split('__')[1].split('-')[2], 10);
|
||||
}
|
||||
|
||||
sum += bootstrapCol;
|
||||
|
||||
if (sum === 12 || bootstrapCol === 12) {
|
||||
const isFullSize = bootstrapCol === 12;
|
||||
array.push({ name, index, isFullSize });
|
||||
sum = 0;
|
||||
}
|
||||
|
||||
if (sum > 12) {
|
||||
sum = 0;
|
||||
}
|
||||
|
||||
if (i < this.list.size - 1) {
|
||||
let { bootstrapCol: nextBootstrapCol, name: nextName, type: nextType } = this.getAttrInfos(i + 1);
|
||||
|
||||
if (!nextType && nextName.includes('__col')) {
|
||||
nextBootstrapCol = parseInt(nextName.split('__')[1].split('-')[2], 10);
|
||||
}
|
||||
|
||||
if (sum + nextBootstrapCol > 12) {
|
||||
const isFullSize = bootstrapCol === 12;
|
||||
array.push({ name, index, isFullSize });
|
||||
sum = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Retrieve the field's type depending on its name
|
||||
* @param {String} itemName
|
||||
* @returns {String}
|
||||
*/
|
||||
getType(itemName) {
|
||||
return this.state
|
||||
.getIn(['schema', 'models', ...this.keys, 'availableFields', itemName, 'type']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field name depending on its index
|
||||
* @param {Number} itemIndex
|
||||
* @returns {String}
|
||||
*/
|
||||
getAttrName(itemIndex){
|
||||
return this.state
|
||||
.getIn(['schema', 'models', ...this.keys, 'fields', itemIndex]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the line bootstrap col sum
|
||||
* @param {Number} leftBound
|
||||
* @param {Number} rightBound
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
getLineSize(elements) {
|
||||
return elements.reduce((acc, current) => {
|
||||
const appearance = this.layout.getIn([current, 'appearance']);
|
||||
const type = appearance !== '' && appearance !== undefined ? appearance : this.getType(current);
|
||||
const col = current.includes('__col') ? parseInt(current.split('__')[1].split('-')[2], 10) : this.getBootStrapCol(type);
|
||||
|
||||
return acc += col;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Bool} dir sup or min
|
||||
* @param {Number} pivot the center
|
||||
* @returns {Object} the first sup or last sup
|
||||
*/
|
||||
getBound(dir, pivot = this.index) {
|
||||
let result = {};
|
||||
let hasResult = false;
|
||||
|
||||
this.arrayOfEndLineElements.forEach(item => {
|
||||
const rightBondCond = findIndex(this.arrayOfEndLineElements, ['index', pivot]) !== -1 ? item.index < pivot : item.index <= pivot;
|
||||
const cond = dir === true ? item.index >= pivot && !hasResult : rightBondCond;
|
||||
|
||||
if (cond) {
|
||||
hasResult = true;
|
||||
result = dir === true ? item : { name: this.list.get(item.index + 1), index: item.index + 1, isFullSize: false };
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
getLayout() {
|
||||
let newList = this.list;
|
||||
let sum = 0;
|
||||
|
||||
this.arrayOfEndLineElements.forEach((item, i) => {
|
||||
const firstLineItem = i === 0 ? 0 : this.arrayOfEndLineElements[i - 1].index +1;
|
||||
const lastLineItem = item.index + 1;
|
||||
const lineRange = firstLineItem === lastLineItem ? [firstLineItem] : range(firstLineItem, lastLineItem);
|
||||
const lineItems = this.getElementsOnALine(lineRange);
|
||||
const lineSize = this.getLineSize(lineItems);
|
||||
|
||||
if (lineSize < 10 && i < this.arrayOfEndLineElements.length - 1) {
|
||||
const colsToAdd = this.getColsToAdd(12 - lineSize);
|
||||
newList = newList.insert(lastLineItem + sum, colsToAdd[0]);
|
||||
|
||||
if (colsToAdd.length > 1) {
|
||||
newList = newList.insert(lastLineItem + sum, colsToAdd[1]);
|
||||
}
|
||||
sum += 1;
|
||||
}
|
||||
});
|
||||
|
||||
return newList;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Manager;
|
||||
@ -28,9 +28,6 @@
|
||||
"model": "role",
|
||||
"via": "users",
|
||||
"plugin": "users-permissions"
|
||||
},
|
||||
"newField": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"collectionName": "users-permissions_user"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user