From 20d201ca6a85a0f4d9d9143e6019778d03aada4b Mon Sep 17 00:00:00 2001 From: Victor Marin <36818606+mdvictor@users.noreply.github.com> Date: Thu, 7 Mar 2024 10:24:12 +0200 Subject: [PATCH] Scenes: Remove normal and library panels from layout or rows (#83969) * Remove normal/lib panels from layout or rows * refactor --- .../scene/DashboardScene.test.tsx | 70 ++++++++++++++++--- .../dashboard-scene/scene/DashboardScene.tsx | 43 ++++++++++++ .../scene/PanelMenuBehavior.tsx | 64 +++++------------ .../scene/keyboardShortcuts.ts | 4 +- 4 files changed, 126 insertions(+), 55 deletions(-) diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx index fd938520442..bfad9110786 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx @@ -261,7 +261,7 @@ describe('DashboardScene', () => { const gridItem = body.state.children[0] as SceneGridItem; expect(body.state.children.length).toBe(6); - expect(gridItem.state.body!.state.key).toBe('panel-5'); + expect(gridItem.state.body!.state.key).toBe('panel-7'); }); it('Should create and add a new row to the dashboard', () => { @@ -271,7 +271,7 @@ describe('DashboardScene', () => { const gridRow = body.state.children[0] as SceneGridRow; expect(body.state.children.length).toBe(4); - expect(gridRow.state.key).toBe('panel-5'); + expect(gridRow.state.key).toBe('panel-7'); expect(gridRow.state.children[0].state.key).toBe('griditem-1'); expect(gridRow.state.children[1].state.key).toBe('griditem-2'); }); @@ -405,7 +405,7 @@ describe('DashboardScene', () => { expect(buildGridItemForPanel).toHaveBeenCalledTimes(1); expect(body.state.children.length).toBe(6); - expect(gridItem.state.body!.state.key).toBe('panel-5'); + expect(gridItem.state.body!.state.key).toBe('panel-7'); expect(gridItem.state.y).toBe(0); expect(scene.state.hasCopiedPanel).toBe(false); }); @@ -433,8 +433,8 @@ describe('DashboardScene', () => { expect(buildGridItemForLibPanel).toHaveBeenCalledTimes(1); expect(body.state.children.length).toBe(6); - expect(libVizPanel.state.panelKey).toBe('panel-5'); - expect(libVizPanel.state.panel?.state.key).toBe('panel-5'); + expect(libVizPanel.state.panelKey).toBe('panel-7'); + expect(libVizPanel.state.panel?.state.key).toBe('panel-7'); expect(gridItem.state.y).toBe(0); expect(scene.state.hasCopiedPanel).toBe(false); }); @@ -446,9 +446,50 @@ describe('DashboardScene', () => { const gridItem = body.state.children[0] as SceneGridItem; expect(body.state.children.length).toBe(6); - expect(gridItem.state.body!.state.key).toBe('panel-5'); + expect(gridItem.state.body!.state.key).toBe('panel-7'); expect(gridItem.state.y).toBe(0); }); + + it('Should remove a panel', () => { + const vizPanel = ((scene.state.body as SceneGridLayout).state.children[0] as SceneGridItem).state.body; + scene.removePanel(vizPanel as VizPanel); + + const body = scene.state.body as SceneGridLayout; + expect(body.state.children.length).toBe(4); + }); + + it('Should remove a panel within a row', () => { + const vizPanel = ( + ((scene.state.body as SceneGridLayout).state.children[2] as SceneGridRow).state.children[0] as SceneGridItem + ).state.body; + scene.removePanel(vizPanel as VizPanel); + + const body = scene.state.body as SceneGridLayout; + const gridRow = body.state.children[2] as SceneGridRow; + expect(gridRow.state.children.length).toBe(1); + }); + + it('Should remove a library panel', () => { + const libraryPanel = ((scene.state.body as SceneGridLayout).state.children[4] as SceneGridItem).state.body; + const vizPanel = (libraryPanel as LibraryVizPanel).state.panel; + scene.removePanel(vizPanel as VizPanel); + + const body = scene.state.body as SceneGridLayout; + expect(body.state.children.length).toBe(4); + }); + + it('Should remove a library panel within a row', () => { + const libraryPanel = ( + ((scene.state.body as SceneGridLayout).state.children[2] as SceneGridRow).state.children[1] as SceneGridItem + ).state.body; + const vizPanel = (libraryPanel as LibraryVizPanel).state.panel; + + scene.removePanel(vizPanel as VizPanel); + + const body = scene.state.body as SceneGridLayout; + const gridRow = body.state.children[2] as SceneGridRow; + expect(gridRow.state.children.length).toBe(1); + }); }); }); @@ -639,6 +680,19 @@ function buildTestScene(overrides?: Partial) { pluginId: 'table', }), }), + new SceneGridItem({ + body: new LibraryVizPanel({ + uid: 'uid', + name: 'libraryPanel', + panelKey: 'panel-5', + title: 'Library Panel', + panel: new VizPanel({ + title: 'Library Panel', + key: 'panel-5', + pluginId: 'table', + }), + }), + }), ], }), new SceneGridItem({ @@ -653,11 +707,11 @@ function buildTestScene(overrides?: Partial) { body: new LibraryVizPanel({ uid: 'uid', name: 'libraryPanel', - panelKey: 'panel-4', + panelKey: 'panel-6', title: 'Library Panel', panel: new VizPanel({ title: 'Library Panel', - key: 'panel-4', + key: 'panel-6', pluginId: 'table', }), }), diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.tsx index c5ddb5ecfe5..a08933bac67 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.tsx @@ -560,6 +560,49 @@ export class DashboardScene extends SceneObjectBase { store.delete(LS_PANEL_COPY_KEY); } + public removePanel(panel: VizPanel) { + const panels: SceneObject[] = []; + const key = panel.parent instanceof LibraryVizPanel ? panel.parent.parent?.state.key : panel.parent?.state.key; + + if (!key) { + return; + } + + let row: SceneGridRow | undefined; + + try { + row = sceneGraph.getAncestor(panel, SceneGridRow); + } catch { + row = undefined; + } + + if (row) { + row.forEachChild((child: SceneObject) => { + if (child.state.key !== key) { + panels.push(child); + } + }); + + row.setState({ children: panels }); + + this.state.body.forceRender(); + + return; + } + + this.state.body.forEachChild((child: SceneObject) => { + if (child.state.key !== key) { + panels.push(child); + } + }); + + const layout = this.state.body; + + if (layout instanceof SceneGridLayout || layout instanceof SceneFlexLayout) { + layout.setState({ children: panels }); + } + } + public showModal(modal: SceneObject) { this.setState({ overlay: modal }); } diff --git a/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx b/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx index f5b823d5e9e..84d7870b5ef 100644 --- a/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx +++ b/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx @@ -8,16 +8,7 @@ import { urlUtil, } from '@grafana/data'; import { config, getPluginLinkExtensions, locationService } from '@grafana/runtime'; -import { - LocalValueVariable, - SceneFlexLayout, - SceneGridLayout, - SceneGridRow, - SceneObject, - VizPanel, - VizPanelMenu, - sceneGraph, -} from '@grafana/scenes'; +import { LocalValueVariable, SceneGridRow, VizPanel, VizPanelMenu, sceneGraph } from '@grafana/scenes'; import { DataQuery, OptionsWithLegend } from '@grafana/schema'; import appEvents from 'app/core/app_events'; import { t } from 'app/core/internationalization'; @@ -203,7 +194,7 @@ export function panelMenuBehavior(menu: VizPanelMenu) { iconClassName: 'trash-alt', onClick: () => { DashboardInteractions.panelMenuItemClicked('remove'); - removePanel(dashboard, panel, true); + onRemovePanel(dashboard, panel); }, shortcut: 'p r', }); @@ -377,7 +368,7 @@ function createExtensionContext(panel: VizPanel, dashboard: DashboardScene): Plu }; } -export function removePanel(dashboard: DashboardScene, panel: VizPanel, ask: boolean) { +export function onRemovePanel(dashboard: DashboardScene, panel: VizPanel) { const vizPanelData = sceneGraph.getData(panel); let panelHasAlert = false; @@ -385,40 +376,23 @@ export function removePanel(dashboard: DashboardScene, panel: VizPanel, ask: boo panelHasAlert = true; } - if (ask !== false) { - const text2 = - panelHasAlert && !config.unifiedAlertingEnabled - ? 'Panel includes an alert rule. removing the panel will also remove the alert rule' - : undefined; - const confirmText = panelHasAlert ? 'YES' : undefined; + const text2 = + panelHasAlert && !config.unifiedAlertingEnabled + ? 'Panel includes an alert rule. removing the panel will also remove the alert rule' + : undefined; + const confirmText = panelHasAlert ? 'YES' : undefined; - appEvents.publish( - new ShowConfirmModalEvent({ - title: 'Remove panel', - text: 'Are you sure you want to remove this panel?', - text2: text2, - icon: 'trash-alt', - confirmText: confirmText, - yesText: 'Remove', - onConfirm: () => removePanel(dashboard, panel, false), - }) - ); - - return; - } - - const panels: SceneObject[] = []; - dashboard.state.body.forEachChild((child: SceneObject) => { - if (child.state.key !== panel.parent?.state.key) { - panels.push(child); - } - }); - - const layout = dashboard.state.body; - - if (layout instanceof SceneGridLayout || SceneFlexLayout) { - layout.setState({ children: panels }); - } + appEvents.publish( + new ShowConfirmModalEvent({ + title: 'Remove panel', + text: 'Are you sure you want to remove this panel?', + text2: text2, + icon: 'trash-alt', + confirmText: confirmText, + yesText: 'Remove', + onConfirm: () => dashboard.removePanel(panel), + }) + ); } const onCreateAlert = async (panel: VizPanel) => { diff --git a/public/app/features/dashboard-scene/scene/keyboardShortcuts.ts b/public/app/features/dashboard-scene/scene/keyboardShortcuts.ts index 8462b640007..e1bb7aea75d 100644 --- a/public/app/features/dashboard-scene/scene/keyboardShortcuts.ts +++ b/public/app/features/dashboard-scene/scene/keyboardShortcuts.ts @@ -8,7 +8,7 @@ import { getEditPanelUrl, getInspectUrl, getViewPanelUrl, tryGetExploreUrlForPan import { getPanelIdForVizPanel } from '../utils/utils'; import { DashboardScene } from './DashboardScene'; -import { removePanel, toggleVizPanelLegend } from './PanelMenuBehavior'; +import { onRemovePanel, toggleVizPanelLegend } from './PanelMenuBehavior'; export function setupKeyboardShortcuts(scene: DashboardScene) { const keybindings = new KeybindingSet(); @@ -120,7 +120,7 @@ export function setupKeyboardShortcuts(scene: DashboardScene) { keybindings.addBinding({ key: 'p r', onTrigger: withFocusedPanel(scene, (vizPanel: VizPanel) => { - removePanel(scene, vizPanel, true); + onRemovePanel(scene, vizPanel); }), });