diff --git a/application/Espo/Modules/Crm/Resources/metadata/app/entityManagerParams.json b/application/Espo/Modules/Crm/Resources/metadata/app/entityManagerParams.json index b7bf6abbd2..ffb25ed25d 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/app/entityManagerParams.json +++ b/application/Espo/Modules/Crm/Resources/metadata/app/entityManagerParams.json @@ -5,7 +5,8 @@ "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 3 }, "duplicateCheckFieldList": { "location": "scopes", @@ -13,35 +14,40 @@ "type": "multiEnum", "tooltip": true, "view": "views/admin/entity-manager/fields/duplicate-check-field-list" - } + }, + "groupIndex": 3 }, "collaborators": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "assignedUsers": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "lockable": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 }, "transactionalSave": { "location": "entityDefs", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 } }, "Contact": { @@ -50,7 +56,8 @@ "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 3 }, "duplicateCheckFieldList": { "location": "scopes", @@ -58,35 +65,40 @@ "type": "multiEnum", "tooltip": true, "view": "views/admin/entity-manager/fields/duplicate-check-field-list" - } + }, + "groupIndex": 3 }, "collaborators": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "assignedUsers": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "lockable": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 }, "transactionalSave": { "location": "entityDefs", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 } }, "Lead": { @@ -95,7 +107,8 @@ "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 3 }, "duplicateCheckFieldList": { "location": "scopes", @@ -103,35 +116,40 @@ "type": "bool", "tooltip": true, "view": "views/admin/entity-manager/fields/duplicate-check-field-list" - } + }, + "groupIndex": 3 }, "collaborators": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "assignedUsers": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "lockable": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 }, "transactionalSave": { "location": "entityDefs", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 } }, "Opportunity": { @@ -140,28 +158,32 @@ "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "assignedUsers": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "lockable": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 }, "transactionalSave": { "location": "entityDefs", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 } }, "Document": { @@ -170,28 +192,32 @@ "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "assignedUsers": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "lockable": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 }, "transactionalSave": { "location": "entityDefs", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 } }, "Case": { @@ -200,28 +226,32 @@ "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "assignedUsers": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "lockable": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 }, "transactionalSave": { "location": "entityDefs", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 } }, "KnowledgeBaseArticle": { @@ -230,28 +260,32 @@ "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "assignedUsers": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "lockable": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 }, "transactionalSave": { "location": "entityDefs", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 } }, "Meeting": { @@ -296,14 +330,16 @@ "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 }, "transactionalSave": { "location": "entityDefs", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 } }, "Call": { @@ -348,14 +384,16 @@ "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 }, "transactionalSave": { "location": "entityDefs", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 } }, "Task": { @@ -382,28 +420,32 @@ "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "assignedUsers": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "lockable": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 }, "transactionalSave": { "location": "entityDefs", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 } }, "TargetList": { @@ -412,21 +454,24 @@ "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "lockable": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 }, "transactionalSave": { "location": "entityDefs", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 } }, "@Event": { @@ -471,14 +516,16 @@ "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "assignedUsers": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "aclContactLink": { "location": "aclDefs", @@ -487,7 +534,8 @@ "type": "enum", "tooltip": true, "view": "views/admin/entity-manager/fields/acl-contact-link" - } + }, + "groupIndex": 4 }, "aclAccountLink": { "location": "aclDefs", @@ -496,21 +544,24 @@ "type": "enum", "tooltip": true, "view": "views/admin/entity-manager/fields/acl-account-link" - } + }, + "groupIndex": 4 }, "lockable": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 }, "transactionalSave": { "location": "entityDefs", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 } } } diff --git a/application/Espo/Resources/metadata/app/entityManagerParams.json b/application/Espo/Resources/metadata/app/entityManagerParams.json index 7c30ee2b16..6dbd3f30b8 100644 --- a/application/Espo/Resources/metadata/app/entityManagerParams.json +++ b/application/Espo/Resources/metadata/app/entityManagerParams.json @@ -28,7 +28,8 @@ "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 3 }, "duplicateCheckFieldList": { "location": "scopes", @@ -36,21 +37,24 @@ "type": "multiEnum", "tooltip": true, "view": "views/admin/entity-manager/fields/duplicate-check-field-list" - } + }, + "groupIndex": 3 }, "collaborators": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "assignedUsers": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "aclContactLink": { "location": "aclDefs", @@ -59,7 +63,8 @@ "type": "enum", "tooltip": true, "view": "views/admin/entity-manager/fields/acl-contact-link" - } + }, + "groupIndex": 4 }, "aclAccountLink": { "location": "aclDefs", @@ -68,21 +73,24 @@ "type": "enum", "tooltip": true, "view": "views/admin/entity-manager/fields/acl-account-link" - } + }, + "groupIndex": 4 }, "lockable": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 }, "transactionalSave": { "location": "entityDefs", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 } }, "@Person": { @@ -91,7 +99,8 @@ "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 3 }, "duplicateCheckFieldList": { "location": "scopes", @@ -99,21 +108,24 @@ "type": "multiEnum", "tooltip": true, "view": "views/admin/entity-manager/fields/duplicate-check-field-list" - } + }, + "groupIndex": 3 }, "collaborators": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "assignedUsers": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "aclContactLink": { "location": "aclDefs", @@ -122,7 +134,8 @@ "type": "enum", "tooltip": true, "view": "views/admin/entity-manager/fields/acl-contact-link" - } + }, + "groupIndex": 4 }, "aclAccountLink": { "location": "aclDefs", @@ -131,21 +144,24 @@ "type": "enum", "tooltip": true, "view": "views/admin/entity-manager/fields/acl-account-link" - } + }, + "groupIndex": 4 }, "lockable": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 }, "transactionalSave": { "location": "entityDefs", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 } }, "@Base": { @@ -154,7 +170,8 @@ "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 3 }, "duplicateCheckFieldList": { "location": "scopes", @@ -162,21 +179,24 @@ "type": "multiEnum", "tooltip": true, "view": "views/admin/entity-manager/fields/duplicate-check-field-list" - } + }, + "groupIndex": 3 }, "collaborators": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "assignedUsers": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "aclContactLink": { "location": "aclDefs", @@ -185,7 +205,8 @@ "type": "enum", "tooltip": true, "view": "views/admin/entity-manager/fields/acl-contact-link" - } + }, + "groupIndex": 4 }, "aclAccountLink": { "location": "aclDefs", @@ -194,28 +215,32 @@ "type": "enum", "tooltip": true, "view": "views/admin/entity-manager/fields/acl-account-link" - } + }, + "groupIndex": 4 }, "categories": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "lockable": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 }, "transactionalSave": { "location": "entityDefs", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 } }, "@BasePlus": { @@ -224,7 +249,8 @@ "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 3 }, "duplicateCheckFieldList": { "location": "scopes", @@ -232,21 +258,24 @@ "type": "multiEnum", "tooltip": true, "view": "views/admin/entity-manager/fields/duplicate-check-field-list" - } + }, + "groupIndex": 3 }, "collaborators": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "assignedUsers": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "aclContactLink": { "location": "aclDefs", @@ -255,7 +284,8 @@ "type": "enum", "tooltip": true, "view": "views/admin/entity-manager/fields/acl-contact-link" - } + }, + "groupIndex": 4 }, "aclAccountLink": { "location": "aclDefs", @@ -264,28 +294,32 @@ "type": "enum", "tooltip": true, "view": "views/admin/entity-manager/fields/acl-account-link" - } + }, + "groupIndex": 4 }, "categories": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 1 }, "lockable": { "location": "scopes", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 }, "transactionalSave": { "location": "entityDefs", "fieldDefs": { "type": "bool", "tooltip": true - } + }, + "groupIndex": 2 } } } diff --git a/client/src/views/admin/entity-manager/edit.js b/client/src/views/admin/entity-manager/edit.js index 1bcb11a004..7e9e64e76a 100644 --- a/client/src/views/admin/entity-manager/edit.js +++ b/client/src/views/admin/entity-manager/edit.js @@ -38,6 +38,7 @@ class EntityManagerEditView extends View { * string: { * fieldDefs: Object., * location?: string, + * groupIndex?: number, * } * }} */ @@ -50,6 +51,12 @@ class EntityManagerEditView extends View { */ enumFieldList + /** + * @private + * @type {string|null} + */ + scope + data() { return { isNew: this.isNew, @@ -77,66 +84,9 @@ class EntityManagerEditView extends View { this.hasColorField = !this.getConfig().get('scopeColorsDisabled'); if (scope) { - this.additionalParams = Espo.Utils.cloneDeep({ - ...this.getMetadata().get(['app', 'entityManagerParams', 'Global']), - ...this.getMetadata().get(['app', 'entityManagerParams', '@' + (templateType || '_')]), - ...this.getMetadata().get(['app', 'entityManagerParams', scope]), - }); + this.setupAdditionalParams(templateType, scope); + this.setupModelValues(scope); - this.model.set('name', scope); - this.model.set('labelSingular', this.translate(scope, 'scopeNames')); - this.model.set('labelPlural', this.translate(scope, 'scopeNamesPlural')); - this.model.set('type', this.getMetadata().get('scopes.' + scope + '.type') || ''); - this.model.set('stream', this.getMetadata().get('scopes.' + scope + '.stream') || false); - this.model.set('disabled', this.getMetadata().get('scopes.' + scope + '.disabled') || false); - - this.model.set('sortBy', this.getMetadata().get('entityDefs.' + scope + '.collection.orderBy')); - this.model.set('sortDirection', this.getMetadata().get('entityDefs.' + scope + '.collection.order')); - - this.model.set('textFilterFields', - this.getMetadata().get(['entityDefs', scope, 'collection', 'textFilterFields']) || ['name'] - ); - - this.model.set('fullTextSearch', - this.getMetadata().get(['entityDefs', scope, 'collection', 'fullTextSearch']) || false - ); - - this.model.set('countDisabled', - this.getMetadata().get(['entityDefs', scope, 'collection', 'countDisabled']) || false - ); - - this.model.set('statusField', this.getMetadata().get('scopes.' + scope + '.statusField') || null); - - if (this.hasColorField) { - this.model.set('color', this.getMetadata().get(['clientDefs', scope, 'color']) || null); - } - - this.model.set('iconClass', this.getMetadata().get(['clientDefs', scope, 'iconClass']) || null); - - this.model.set( - 'kanbanViewMode', - this.getMetadata().get(['clientDefs', scope, 'kanbanViewMode']) || false - ); - - this.model.set( - 'kanbanStatusIgnoreList', - this.getMetadata().get(['scopes', scope, 'kanbanStatusIgnoreList']) || [] - ); - - for (const param in this.additionalParams) { - /** @type {{fieldDefs: Object, location?: string, param?: string}} */ - const defs = this.additionalParams[param]; - const location = defs.location || this.defaultParamLocation; - const defaultValue = defs.fieldDefs.type === 'bool' ? false : null; - const actualParam = defs.param || param; - - const value = this.getMetadata().get([location, scope, actualParam]) || defaultValue; - - this.model.set(param, value); - } - } - - if (scope) { /** @type {Record.} */ const fieldDefs = this.getMetadata().get(`entityDefs.${scope}.fields`) || {}; @@ -221,6 +171,13 @@ class EntityManagerEditView extends View { this.translatedStatusOptions = {}; } + this.setupDetailLayout(); + } + + /** + * @private + */ + setupDetailLayout() { this.detailLayout = [ { rows: [ @@ -307,50 +264,146 @@ class EntityManagerEditView extends View { }, ]; - if (this.scope) { - const rows1 = []; - const rows2 = []; + if (!this.scope) { + return; + } - const paramList1 = Object.keys(this.additionalParams) - .filter(item => !!this.getMetadata().get(['app', 'entityManagerParams', 'Global', item])); + /** @var {string[][]}*/ + const groups = []; - const paramList2 = Object.keys(this.additionalParams) - .filter(item => !paramList1.includes(item)); + for (const [param, it] of Object.entries(this.additionalParams)) { + const index = (it.groupIndex === undefined ? 9999 : it.groupIndex) + 100; - const add = function (rows, list) { - list.forEach((param, i) => { - if (i % 2 === 0) { - rows.push([]); - } - - const row = rows[rows.length - 1]; - - row.push({name: param}); - - if ( - i === list.length - 1 && - row.length === 1 - ) { - row.push(false); - } - }); - }; - - add(rows1, paramList1); - add(rows2, paramList2); - - if (rows1.length) { - this.detailLayout.push({rows: rows1}); + if (groups[index] === undefined) { + groups[index] = []; } - if (rows2.length) { - this.detailLayout.push({rows: rows2}); + groups[index] ??= []; + groups[index].push(param); + } + + const add = function (rows, list) { + list.forEach((param, i) => { + if (i % 2 === 0) { + rows.push([]); + } + + const row = rows[rows.length - 1]; + + row.push({name: param}); + + if ( + i === list.length - 1 && + row.length === 1 + ) { + row.push(false); + } + }); + }; + + groups.forEach(paramList => { + const rows = []; + + add(rows, paramList); + + if (rows.length) { + this.detailLayout.push({rows: rows}); } + }); + } + + /** + * @private + */ + setupModelValues() { + const scope = this.scope; + + this.model.set('name', scope); + this.model.set('labelSingular', this.translate(scope, 'scopeNames')); + this.model.set('labelPlural', this.translate(scope, 'scopeNamesPlural')); + this.model.set('type', this.getMetadata().get(`scopes.${scope}.type`) || ''); + this.model.set('stream', this.getMetadata().get(`scopes.${scope}.stream`) || false); + this.model.set('disabled', this.getMetadata().get(`scopes.${scope}.disabled`) || false); + + this.model.set('sortBy', this.getMetadata().get(`entityDefs.${scope}.collection.orderBy`)); + this.model.set('sortDirection', this.getMetadata().get(`entityDefs.${scope}.collection.order`)); + + this.model.set('textFilterFields', + this.getMetadata().get(['entityDefs', scope, 'collection', 'textFilterFields']) || ['name'] + ); + + this.model.set('fullTextSearch', + this.getMetadata().get(['entityDefs', scope, 'collection', 'fullTextSearch']) || false + ); + + this.model.set('countDisabled', + this.getMetadata().get(['entityDefs', scope, 'collection', 'countDisabled']) || false + ); + + this.model.set('statusField', this.getMetadata().get(`scopes.${scope}.statusField`) || null); + + if (this.hasColorField) { + this.model.set('color', this.getMetadata().get(['clientDefs', scope, 'color']) || null); + } + + this.model.set('iconClass', this.getMetadata().get(['clientDefs', scope, 'iconClass']) || null); + + this.model.set( + 'kanbanViewMode', + this.getMetadata().get(['clientDefs', scope, 'kanbanViewMode']) || false + ); + + this.model.set( + 'kanbanStatusIgnoreList', + this.getMetadata().get(['scopes', scope, 'kanbanStatusIgnoreList']) || [] + ); + + for (const param in this.additionalParams) { + /** @type {{fieldDefs: Object, location?: string, param?: string}} */ + const defs = this.additionalParams[param]; + const location = defs.location || this.defaultParamLocation; + const defaultValue = defs.fieldDefs.type === 'bool' ? false : null; + const actualParam = defs.param || param; + + const value = this.getMetadata().get([location, scope, actualParam]) || defaultValue; + + this.model.set(param, value); } } + /** + * @private + */ + setupAdditionalParams() { + const scope = this.scope; + const templateType = this.getMetadata().get(`scopes.${this.scope}.type`) ?? null; + + const tKey = '@' + (templateType ?? '_'); + + /** @var {Record.} */ + const globalParams = Espo.Utils.cloneDeep(this.getMetadata().get('app.entityManagerParams.Global', {})); + /** @var {Record.} */ + const templateParams = Espo.Utils.cloneDeep(this.getMetadata().get(`app.entityManagerParams.${tKey}`, {})); + /** @var {Record.} */ + const scopeParams = Espo.Utils.cloneDeep(this.getMetadata().get(`app.entityManagerParams.${scope}`, {})); + + for (const [, it] of Object.entries(globalParams)) { + it.groupIndex ??= -100; + } + + for (const [, it] of Object.entries(templateParams)) { + it.groupIndex ??= 50; + } + + for (const [, it] of Object.entries(scopeParams)) { + it.groupIndex ??= 100; + } + + this.additionalParams = {...globalParams, ...templateParams, ...scopeParams}; + } + setup() { - const scope = this.scope = this.options.scope || false; + const scope = this.scope = this.options.scope ?? null; this.isNew = !scope; this.model = new Model(); diff --git a/schema/metadata/app/entityManagerParams.json b/schema/metadata/app/entityManagerParams.json index 9ac2b08fdb..827debb4a1 100644 --- a/schema/metadata/app/entityManagerParams.json +++ b/schema/metadata/app/entityManagerParams.json @@ -34,6 +34,10 @@ "fieldDefs": { "description": "Field definitions. The defined field will be rendered on the entity manager edit view.", "$ref": "./../entityDefs.json#/definitions/fieldDefs" + }, + "groupIndex": { + "type": "integer", + "description": "An index to group related parameters into panels. As of v9.4." } } }