From eb5d667109b49127b79420645c3bb9c4842eaf05 Mon Sep 17 00:00:00 2001 From: Yurii Date: Thu, 11 Jun 2026 20:00:39 +0300 Subject: [PATCH] Record edit view dropdown actions --- .../Espo/Core/Utils/Metadata/Builder.php | 4 +++ client/src/views/modals/edit.js | 20 ++++++++++++ client/src/views/record/detail.ts | 32 +++++++++++++++++-- schema/metadata/clientDefs.json | 24 ++++++++++++++ 4 files changed, 77 insertions(+), 3 deletions(-) diff --git a/application/Espo/Core/Utils/Metadata/Builder.php b/application/Espo/Core/Utils/Metadata/Builder.php index 41c8b53b49..2bb489c31f 100644 --- a/application/Espo/Core/Utils/Metadata/Builder.php +++ b/application/Espo/Core/Utils/Metadata/Builder.php @@ -97,6 +97,10 @@ class Builder ['recordDefs', self::ANY_KEY, 'beforeUnlinkHookClassNameList'], ['recordDefs', self::ANY_KEY, 'afterLinkHookClassNameList'], ['recordDefs', self::ANY_KEY, 'afterUnlinkHookClassNameList'], + + ['clientDefs', self::ANY_KEY, 'detailActionList'], + ['clientDefs', self::ANY_KEY, 'editActionList'], + ['clientDefs', self::ANY_KEY, 'modalDetailActionList'], ]; private const ANY_KEY = '__ANY__'; diff --git a/client/src/views/modals/edit.js b/client/src/views/modals/edit.js index 2f2801d1b1..8b3ff2d079 100644 --- a/client/src/views/modals/edit.js +++ b/client/src/views/modals/edit.js @@ -31,6 +31,7 @@ import ModalView from 'views/modal'; import Backbone from 'backbone'; import DefaultsPopulator from 'helpers/model/defaults-populator'; +import ActionItemSetup from 'helpers/action-item-setup'; /** * A quick edit modal. @@ -234,6 +235,7 @@ class EditModalView extends ModalView { this.headerHtml = this.composeHeaderHtml(); } + this.setupActionItems(); this.createRecordView(model); return; @@ -257,6 +259,7 @@ class EditModalView extends ModalView { this.headerHtml = this.composeHeaderHtml(); } + this.setupActionItems(); this.createRecordView(model); }); @@ -539,6 +542,23 @@ class EditModalView extends ModalView { this.getRouter().removeWindowLeaveOutObject(this); } + + /** + * @private + */ + setupActionItems() { + const actionItemSetup = new ActionItemSetup(); + + actionItemSetup.setup( + this, + 'modalEdit', + promise => this.wait(promise), + item => this.addDropdownItem(item), + name => this.showActionItem(name), + name => this.hideActionItem(name), + {listenToViewModelSync: true} + ); + } } export default EditModalView; diff --git a/client/src/views/record/detail.ts b/client/src/views/record/detail.ts index 31dc006015..c299aea5cb 100644 --- a/client/src/views/record/detail.ts +++ b/client/src/views/record/detail.ts @@ -1023,6 +1023,10 @@ class DetailRecordView this.wait(promise), + item => { + if (this.type === this.TYPE_EDIT) { + this.addDropdownItem(item); + } else { + this.dropdownEditItemList.push(item); + } + }, + name => this.showActionItem(name), + name => this.hideActionItem(name) + ); + } } /** @@ -1808,10 +1831,13 @@ class DetailRecordView { + const list = type === 'edit' ? + this.dropdownEditItemList : this.dropdownItemList; + + list.forEach(item => { // For bc. if ((item as any) === false) { return; @@ -3816,7 +3842,7 @@ class DetailRecordView { return { buttonList: this.buttonEditList, - dropdownItemList: this.dropdownEditItemList, + dropdownItemList: this.getDropdownItemDataList('edit'), allDisabled: this.allActionItemsDisabled, }; }, diff --git a/schema/metadata/clientDefs.json b/schema/metadata/clientDefs.json index d48f739e15..f8f7933b76 100644 --- a/schema/metadata/clientDefs.json +++ b/schema/metadata/clientDefs.json @@ -726,6 +726,18 @@ ] } }, + "editActionList": { + "description": "Edit view actions (available from the dropdown next to the Save button). As of v10.0.", + "type": "array", + "items": { + "anyOf": [ + {"const": "__APPEND__"}, + { + "$ref": "#/definitions/actionDefs" + } + ] + } + }, "modalDetailActionList": { "description": "Modal detail view actions.", "type": "array", @@ -738,6 +750,18 @@ ] } }, + "modalEditActionList": { + "description": "Modal edit view actions. As of v10.0.", + "type": "array", + "items": { + "anyOf": [ + {"const": "__APPEND__"}, + { + "$ref": "#/definitions/actionDefs" + } + ] + } + }, "iconClass": { "description": "A scope icon CSS class.", "type": "string"