From f7202460c76155ae4a2e07abfaeb26b39b5e5a92 Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:11:01 +0100 Subject: [PATCH 1/4] fix --- .../CustomDashboard/CanvasElement.react.js | 17 ++- .../CustomDashboard/CustomDashboard.react.js | 110 +++++++++++++++++- 2 files changed, 122 insertions(+), 5 deletions(-) diff --git a/src/dashboard/Data/CustomDashboard/CanvasElement.react.js b/src/dashboard/Data/CustomDashboard/CanvasElement.react.js index fab828eb8..7e563a5e0 100644 --- a/src/dashboard/Data/CustomDashboard/CanvasElement.react.js +++ b/src/dashboard/Data/CustomDashboard/CanvasElement.react.js @@ -15,12 +15,26 @@ const CanvasElement = ({ onSelect, onPositionChange, onSizeChange, + onDrag, + onResize, children, }) => { + const handleDrag = (e, d) => { + if (onDrag) { + onDrag(element.id, d.x, d.y, element.width, element.height); + } + }; + const handleDragStop = (e, d) => { onPositionChange(element.id, d.x, d.y); }; + const handleResize = (e, direction, ref, delta, position) => { + if (onResize) { + onResize(element.id, ref.offsetWidth, ref.offsetHeight, position.x, position.y); + } + }; + const handleResizeStop = (e, direction, ref, delta, position) => { onSizeChange( element.id, @@ -44,9 +58,10 @@ const CanvasElement = ({ resizeGrid={[16, 16]} minWidth={100} minHeight={50} - bounds="parent" dragHandleClassName={styles.dragHandle} + onDrag={handleDrag} onDragStop={handleDragStop} + onResize={handleResize} onResizeStop={handleResizeStop} className={`${styles.canvasElement} ${isSelected ? styles.selected : ''}`} enableResizing={{ diff --git a/src/dashboard/Data/CustomDashboard/CustomDashboard.react.js b/src/dashboard/Data/CustomDashboard/CustomDashboard.react.js index 39aa5379c..5ccfebdf2 100644 --- a/src/dashboard/Data/CustomDashboard/CustomDashboard.react.js +++ b/src/dashboard/Data/CustomDashboard/CustomDashboard.react.js @@ -76,6 +76,8 @@ class CustomDashboard extends DashboardView { currentCanvasFavorite: false, hasUnsavedChanges: false, isFullscreen: false, + // Track dragging element position for canvas auto-extend + dragPosition: null, }; this.autoReloadTimer = null; this.autoReloadProgressTimer = null; @@ -83,6 +85,7 @@ class CustomDashboard extends DashboardView { this.canvasPreferencesManager = null; this._isMounted = false; this._elementSeq = {}; + this.canvasRef = React.createRef(); } componentDidMount() { @@ -623,21 +626,95 @@ class CustomDashboard extends DashboardView { }; handlePositionChange = (id, x, y) => { + // Ensure position is not negative + const safeX = Math.max(0, x); + const safeY = Math.max(0, y); this.setState(state => ({ elements: state.elements.map(el => - el.id === id ? { ...el, x, y } : el + el.id === id ? { ...el, x: safeX, y: safeY } : el ), }), this.markUnsavedChanges); }; handleSizeChange = (id, width, height, x, y) => { + // Ensure position is not negative when resizing from left/top edges + const safeX = Math.max(0, x); + const safeY = Math.max(0, y); this.setState(state => ({ elements: state.elements.map(el => - el.id === id ? { ...el, width, height, x, y } : el + el.id === id ? { ...el, width, height, x: safeX, y: safeY } : el ), }), this.markUnsavedChanges); }; + handleDrag = (id, x, y, width, height) => { + // Update drag position to trigger canvas auto-extend during drag + this.setState({ + dragPosition: { id, x, y, width, height }, + }); + }; + + handleDragEnd = () => { + // Clear drag position when drag ends + this.setState({ dragPosition: null }); + }; + + handleResize = (id, width, height, x, y) => { + // Update drag position to trigger canvas auto-extend during resize + this.setState({ + dragPosition: { id, x, y, width, height }, + }); + }; + + handleResizeEnd = () => { + // Clear drag position when resize ends + this.setState({ dragPosition: null }); + }; + + // Calculate the required canvas size based on all elements and current drag position + // Returns dimensions only when content extends beyond the default CSS size + getCanvasSize() { + const { elements, dragPosition } = this.state; + const padding = 100; // Extra padding to allow easy placement at edges + + let maxRight = 0; + let maxBottom = 0; + + // Calculate bounds from all elements + elements.forEach(el => { + const right = el.x + el.width; + const bottom = el.y + el.height; + if (right > maxRight) { + maxRight = right; + } + if (bottom > maxBottom) { + maxBottom = bottom; + } + }); + + // Include current drag position if dragging + if (dragPosition) { + const dragRight = dragPosition.x + dragPosition.width; + const dragBottom = dragPosition.y + dragPosition.height; + if (dragRight > maxRight) { + maxRight = dragRight; + } + if (dragBottom > maxBottom) { + maxBottom = dragBottom; + } + } + + // Add padding to content bounds + const contentWidth = maxRight + padding; + const contentHeight = maxBottom + padding; + + // Return the content-based dimensions (CSS handles minimum via width:100% and min-height) + return { + minWidth: contentWidth, + minHeight: contentHeight, + }; + } + handleDeleteElement = (id) => { this.setState(state => ({ elements: state.elements.filter(el => el.id !== id), @@ -1065,13 +1142,30 @@ class CustomDashboard extends DashboardView { wrapperClasses.push(styles.fullscreen); } + // Calculate dynamic canvas size based on element positions + const canvasSize = this.getCanvasSize(); + return (
+ {/* Invisible sizing element that expands the canvas when elements extend beyond */} + {(canvasSize.minWidth > 0 || canvasSize.minHeight > 0) && ( +
+ )} {elements.length === 0 && !isFullscreen ? ( { + this.handleDragEnd(); + this.handlePositionChange(id, x, y); + }} + onSizeChange={(id, width, height, x, y) => { + this.handleResizeEnd(); + this.handleSizeChange(id, width, height, x, y); + }} + onDrag={this.handleDrag} + onResize={this.handleResize} > {this.renderElementContent(element)} From 61e3446a0f89f85afd01b7436ffd267d6092c486 Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:12:03 +0100 Subject: [PATCH 2/4] padding --- src/dashboard/Data/CustomDashboard/CustomDashboard.react.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dashboard/Data/CustomDashboard/CustomDashboard.react.js b/src/dashboard/Data/CustomDashboard/CustomDashboard.react.js index 5ccfebdf2..3e599a2e3 100644 --- a/src/dashboard/Data/CustomDashboard/CustomDashboard.react.js +++ b/src/dashboard/Data/CustomDashboard/CustomDashboard.react.js @@ -675,7 +675,7 @@ class CustomDashboard extends DashboardView { // Returns dimensions only when content extends beyond the default CSS size getCanvasSize() { const { elements, dragPosition } = this.state; - const padding = 100; // Extra padding to allow easy placement at edges + const padding = 50; // Extra padding to allow easy placement at edges let maxRight = 0; let maxBottom = 0; From 4c2308e0ec4d461f23fec5e8a9a1efb0326d677f Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:20:41 +0100 Subject: [PATCH 3/4] fix grid snap --- .../CustomDashboard/CanvasElement.react.js | 4 ++-- .../CustomDashboard/CustomDashboard.react.js | 21 ++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/dashboard/Data/CustomDashboard/CanvasElement.react.js b/src/dashboard/Data/CustomDashboard/CanvasElement.react.js index 7e563a5e0..f0b5ad441 100644 --- a/src/dashboard/Data/CustomDashboard/CanvasElement.react.js +++ b/src/dashboard/Data/CustomDashboard/CanvasElement.react.js @@ -54,8 +54,8 @@ const CanvasElement = ({ { - // Ensure position is not negative - const safeX = Math.max(0, x); - const safeY = Math.max(0, y); + // Snap to grid and ensure position is not negative + const safeX = Math.max(0, this.snapToGrid(x)); + const safeY = Math.max(0, this.snapToGrid(y)); this.setState(state => ({ elements: state.elements.map(el => el.id === id ? { ...el, x: safeX, y: safeY } : el @@ -637,12 +642,14 @@ class CustomDashboard extends DashboardView { }; handleSizeChange = (id, width, height, x, y) => { - // Ensure position is not negative when resizing from left/top edges - const safeX = Math.max(0, x); - const safeY = Math.max(0, y); + // Snap to grid and ensure position is not negative when resizing from left/top edges + const safeX = Math.max(0, this.snapToGrid(x)); + const safeY = Math.max(0, this.snapToGrid(y)); + const snappedWidth = this.snapToGrid(width); + const snappedHeight = this.snapToGrid(height); this.setState(state => ({ elements: state.elements.map(el => - el.id === id ? { ...el, width, height, x: safeX, y: safeY } : el + el.id === id ? { ...el, width: snappedWidth, height: snappedHeight, x: safeX, y: safeY } : el ), }), this.markUnsavedChanges); }; From e38b0c3038f798563a6d542c54a698bf9ae4435d Mon Sep 17 00:00:00 2001 From: Manuel Trezza <5673677+mtrezza@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:26:09 +0100 Subject: [PATCH 4/4] minor layout issues --- src/dashboard/Data/CustomDashboard/CanvasElement.scss | 4 ---- src/dashboard/Data/CustomDashboard/CustomDashboard.scss | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/dashboard/Data/CustomDashboard/CanvasElement.scss b/src/dashboard/Data/CustomDashboard/CanvasElement.scss index 359fea71e..09c2a91db 100644 --- a/src/dashboard/Data/CustomDashboard/CanvasElement.scss +++ b/src/dashboard/Data/CustomDashboard/CanvasElement.scss @@ -41,8 +41,4 @@ .resizeHandle { background: transparent !important; - - &:hover { - background: rgba(22, 156, 238, 0.3) !important; - } } diff --git a/src/dashboard/Data/CustomDashboard/CustomDashboard.scss b/src/dashboard/Data/CustomDashboard/CustomDashboard.scss index 6f743ce62..85be61607 100644 --- a/src/dashboard/Data/CustomDashboard/CustomDashboard.scss +++ b/src/dashboard/Data/CustomDashboard/CustomDashboard.scss @@ -11,7 +11,7 @@ position: relative; width: 100%; min-height: calc(100vh - 96px); - background-color: #f4f5f7; + background-color: #ffffff; overflow: auto; outline: none; }