From 962fcf1fa872c1aa0509b6a52f3f1d4dfb9f53d2 Mon Sep 17 00:00:00 2001 From: Victor Marin <36818606+mdvictor@users.noreply.github.com> Date: Fri, 30 Aug 2024 16:50:22 +0300 Subject: [PATCH] DashboardScenes: Row repeater panels cannot be dragged outside and adding new panels to a cloned row updates all rows (#91062) * Disallow dragging panels in repeated rows + dropping panels into cloned rows will update all repeated rows * test --- .../scene/RowRepeaterBehavior.test.tsx | 36 +++++++++++++ .../scene/RowRepeaterBehavior.ts | 51 ++++++++++++++++++- 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/public/app/features/dashboard-scene/scene/RowRepeaterBehavior.test.tsx b/public/app/features/dashboard-scene/scene/RowRepeaterBehavior.test.tsx index 19878903d7d..bddb841cc14 100644 --- a/public/app/features/dashboard-scene/scene/RowRepeaterBehavior.test.tsx +++ b/public/app/features/dashboard-scene/scene/RowRepeaterBehavior.test.tsx @@ -67,6 +67,42 @@ describe('RowRepeaterBehavior', () => { expect(gridItem.state.body?.state.key).toBe('canvas-1-clone-B1'); }); + it('Should update all rows when a panel is added to a clone', async () => { + const originalRow = grid.state.children[1] as SceneGridRow; + const clone1 = grid.state.children[2] as SceneGridRow; + const clone2 = grid.state.children[3] as SceneGridRow; + + expect(originalRow.state.children.length).toBe(1); + expect(clone1.state.children.length).toBe(1); + expect(clone2.state.children.length).toBe(1); + + clone1.setState({ + children: [ + ...clone1.state.children, + new SceneGridItem({ + x: 0, + y: 16, + width: 24, + height: 5, + key: 'griditem-4', + body: new SceneCanvasText({ + text: 'new panel', + }), + }), + ], + }); + + grid.forceRender(); + + // repeater has run so there are new clone row objects + const newClone1 = grid.state.children[2] as SceneGridRow; + const newClone2 = grid.state.children[3] as SceneGridRow; + + expect(originalRow.state.children.length).toBe(2); + expect(newClone1.state.children.length).toBe(2); + expect(newClone2.state.children.length).toBe(2); + }); + it('Should push row at the bottom down', () => { // Should push row at the bottom down const rowAtTheBottom = grid.state.children[6] as SceneGridRow; diff --git a/public/app/features/dashboard-scene/scene/RowRepeaterBehavior.ts b/public/app/features/dashboard-scene/scene/RowRepeaterBehavior.ts index 12d11116678..663315e5d04 100644 --- a/public/app/features/dashboard-scene/scene/RowRepeaterBehavior.ts +++ b/public/app/features/dashboard-scene/scene/RowRepeaterBehavior.ts @@ -46,6 +46,48 @@ export class RowRepeaterBehavior extends SceneObjectBase { + const repeatedRows = layout.state.children.filter( + (child) => child instanceof SceneGridRow && child.state.key?.includes(filterKey) + ); + + // go through cloned rows, search for panels that are not clones + for (const row of repeatedRows) { + if (!(row instanceof SceneGridRow)) { + continue; + } + + // if no differences in row children compared to original, then no new panel added to clone + if (row.state.children.length === originalRow.state.children.length) { + continue; + } + + //if there are differences, find the new panel, move it to the original and perform re peat + const gridItem = row.state.children.find((gridItem) => !gridItem.state.key?.includes('clone')); + if (gridItem) { + const newGridItem = gridItem.clone(); + row.setState({ children: row.state.children.filter((item) => item !== gridItem) }); + + // if we are moving a panel from the origin row to a clone row, we just return + // this means we are modifying the origin row, retriggering the repeat and losing that panel + if (originalRow.state.children.find((item) => item.state.key === newGridItem.state.key)) { + return; + } + + originalRow.setState({ children: [...originalRow.state.children, newGridItem] }); + this.performRepeat(true); + } + } + }); + + return () => { + sub.unsubscribe(); + }; } private _getRow(): SceneGridRow { @@ -66,7 +108,7 @@ export class RowRepeaterBehavior extends SceneObjectBase 0) { ensureUniqueKeys(itemClone, localValue); + //disallow clones to be dragged around or out of the row if (itemClone instanceof DashboardGridItem) { + itemClone.setState({ + isDraggable: false, + }); + itemClone.state.body.setState({ menu: new VizPanelMenu({ $behaviors: [repeatPanelMenuBehavior],