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 (