From 47f00855e5fedb61c93928ce1d4feb721b3b34d9 Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Fri, 23 Jan 2026 18:48:54 +0100 Subject: [PATCH] feat --- .../CustomDashboard/CustomDashboard.react.js | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/dashboard/Data/CustomDashboard/CustomDashboard.react.js b/src/dashboard/Data/CustomDashboard/CustomDashboard.react.js index 31004f748..0d8366667 100644 --- a/src/dashboard/Data/CustomDashboard/CustomDashboard.react.js +++ b/src/dashboard/Data/CustomDashboard/CustomDashboard.react.js @@ -734,6 +734,33 @@ class CustomDashboard extends DashboardView { }), this.markUnsavedChanges); }; + handleDuplicateElement = (id) => { + const { elements } = this.state; + const element = elements.find(el => el.id === id); + + if (!element) { + return; + } + + const duplicatedElement = { + ...element, + id: generateId(), + x: element.x + 50, + y: element.y + 50, + config: { ...element.config }, + }; + + this.setState(state => ({ + elements: [...state.elements, duplicatedElement], + selectedElement: duplicatedElement.id, + }), () => { + if (element.type === 'graph' || element.type === 'dataTable' || element.type === 'view') { + this.fetchElementData(duplicatedElement.id); + } + this.markUnsavedChanges(); + }); + }; + handleEditElement = () => { const { selectedElement, elements } = this.state; if (!selectedElement) { @@ -1049,6 +1076,12 @@ class CustomDashboard extends DashboardView { if (!this.state.isFullscreen) { this.setState({ selectedElement: null }); } + } else if (e.key === 'd' && (e.metaKey || e.ctrlKey)) { + // Duplicate selected element with Cmd/Ctrl+D + if (this.state.selectedElement && !this.isEditableElement(document.activeElement)) { + e.preventDefault(); + this.handleDuplicateElement(this.state.selectedElement); + } } }; @@ -1288,6 +1321,14 @@ class CustomDashboard extends DashboardView { Edit
+ this.handleDuplicateElement(selectedElement)} + > + + Duplicate + +
this.handleDeleteElement(selectedElement)}