From f88bf474bd5cb716322a72774b3f2a64503eff3f Mon Sep 17 00:00:00 2001 From: Victor Marin <36818606+mdvictor@users.noreply.github.com> Date: Fri, 5 Jul 2024 17:58:55 +0300 Subject: [PATCH] Fix panel paste button in nav toolbar (#90143) fix panel paste button in nav toolbar --- .../scene/DashboardScene.test.tsx | 19 ++++++++++--------- .../dashboard-scene/scene/DashboardScene.tsx | 5 ----- .../scene/NavToolbarActions.tsx | 17 ++++------------- 3 files changed, 14 insertions(+), 27 deletions(-) diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx index 91e50fba9e1..9e2ca410700 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx @@ -1,4 +1,4 @@ -import { CoreApp, LoadingState, getDefaultTimeRange } from '@grafana/data'; +import { CoreApp, LoadingState, getDefaultTimeRange, store } from '@grafana/data'; import { locationService } from '@grafana/runtime'; import { sceneGraph, @@ -14,6 +14,7 @@ import { } from '@grafana/scenes'; import { Dashboard, DashboardCursorSync, LibraryPanel } from '@grafana/schema'; import appEvents from 'app/core/app_events'; +import { LS_PANEL_COPY_KEY } from 'app/core/constants'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; import { VariablesChanged } from 'app/features/variables/types'; @@ -620,7 +621,7 @@ describe('DashboardScene', () => { scene.copyPanel(vizPanel); - expect(scene.state.hasCopiedPanel).toBe(false); + expect(store.exists(LS_PANEL_COPY_KEY)).toBe(false); }); it('Should fail to copy a library panel if it does not have a grid item parent', () => { @@ -638,14 +639,14 @@ describe('DashboardScene', () => { scene.copyPanel(libVizPanel.state.panel as VizPanel); - expect(scene.state.hasCopiedPanel).toBe(false); + expect(store.exists(LS_PANEL_COPY_KEY)).toBe(false); }); it('Should copy a panel', () => { const vizPanel = ((scene.state.body as SceneGridLayout).state.children[0] as DashboardGridItem).state.body; scene.copyPanel(vizPanel as VizPanel); - expect(scene.state.hasCopiedPanel).toBe(true); + expect(store.exists(LS_PANEL_COPY_KEY)).toBe(true); }); it('Should copy a library viz panel', () => { @@ -654,11 +655,11 @@ describe('DashboardScene', () => { scene.copyPanel(libVizPanel.state.panel as VizPanel); - expect(scene.state.hasCopiedPanel).toBe(true); + expect(store.exists(LS_PANEL_COPY_KEY)).toBe(true); }); it('Should paste a panel', () => { - scene.setState({ hasCopiedPanel: true }); + store.set(LS_PANEL_COPY_KEY, JSON.stringify({ key: 'panel-7' })); jest.spyOn(JSON, 'parse').mockReturnThis(); jest.mocked(buildGridItemForPanel).mockReturnValue( new DashboardGridItem({ @@ -680,11 +681,11 @@ describe('DashboardScene', () => { expect(body.state.children.length).toBe(6); expect(gridItem.state.body!.state.key).toBe('panel-7'); expect(gridItem.state.y).toBe(0); - expect(scene.state.hasCopiedPanel).toBe(false); + expect(store.exists(LS_PANEL_COPY_KEY)).toBe(false); }); it('Should paste a library viz panel', () => { - scene.setState({ hasCopiedPanel: true }); + store.set(LS_PANEL_COPY_KEY, JSON.stringify({ key: 'panel-7' })); jest.spyOn(JSON, 'parse').mockReturnValue({ libraryPanel: { uid: 'uid', name: 'libraryPanel' } }); jest.mocked(buildGridItemForLibPanel).mockReturnValue( new DashboardGridItem({ @@ -709,7 +710,7 @@ describe('DashboardScene', () => { 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); + expect(store.exists(LS_PANEL_COPY_KEY)).toBe(false); }); it('Should remove a panel', () => { diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.tsx index 8c84394c5eb..8c66b347edd 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.tsx @@ -121,8 +121,6 @@ export interface DashboardSceneState extends SceneObjectState { editPanel?: PanelEditor; /** Scene object that handles the current drawer or modal */ overlay?: SceneObject; - /** True when a user copies a panel in the dashboard */ - hasCopiedPanel?: boolean; /** The dashboard doesn't have panels */ isEmpty?: boolean; /** Scene object that handles the scopes selector */ @@ -172,7 +170,6 @@ export class DashboardScene extends SceneObjectBase { editable: true, body: state.body ?? new SceneFlexLayout({ children: [] }), links: state.links ?? [], - hasCopiedPanel: store.exists(LS_PANEL_COPY_KEY), scopes: state.uid && config.featureToggles.scopeFilters ? new ScopesScene() : undefined, ...state, }); @@ -648,7 +645,6 @@ export class DashboardScene extends SceneObjectBase { store.set(LS_PANEL_COPY_KEY, JSON.stringify(jsonData)); appEvents.emit(AppEvents.alertSuccess, ['Panel copied. Use **Paste panel** toolbar action to paste.']); - this.setState({ hasCopiedPanel: true }); } public pastePanel() { @@ -703,7 +699,6 @@ export class DashboardScene extends SceneObjectBase { children: [gridItem, ...sceneGridLayout.state.children], }); - this.setState({ hasCopiedPanel: false }); store.delete(LS_PANEL_COPY_KEY); } diff --git a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx index e851c1ea4cc..c40f3e08697 100644 --- a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx +++ b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx @@ -2,7 +2,7 @@ import { css } from '@emotion/css'; import { useEffect, useId, useState } from 'react'; import * as React from 'react'; -import { GrafanaTheme2 } from '@grafana/data'; +import { GrafanaTheme2, store } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; import { config, locationService } from '@grafana/runtime'; import { @@ -18,6 +18,7 @@ import { } from '@grafana/ui'; import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate'; import { NavToolbarSeparator } from 'app/core/components/AppChrome/NavToolbar/NavToolbarSeparator'; +import { LS_PANEL_COPY_KEY } from 'app/core/constants'; import { contextSrv } from 'app/core/core'; import { Trans, t } from 'app/core/internationalization'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; @@ -51,17 +52,7 @@ NavToolbarActions.displayName = 'NavToolbarActions'; * This part is split into a separate component to help test this */ export function ToolbarActions({ dashboard }: Props) { - const { - isEditing, - viewPanelScene, - isDirty, - uid, - meta, - editview, - editPanel, - editable, - hasCopiedPanel: copiedPanel, - } = dashboard.useState(); + const { isEditing, viewPanelScene, isDirty, uid, meta, editview, editPanel, editable } = dashboard.useState(); const { isPlaying } = playlistSrv.useState(); const [isAddPanelMenuOpen, setIsAddPanelMenuOpen] = useState(false); @@ -72,7 +63,7 @@ export function ToolbarActions({ dashboard }: Props) { const isViewingPanel = Boolean(viewPanelScene); const isEditedPanelDirty = useVizManagerDirty(editPanel); const isEditingLibraryPanel = useEditingLibraryPanel(editPanel); - const hasCopiedPanel = Boolean(copiedPanel); + const hasCopiedPanel = store.exists(LS_PANEL_COPY_KEY); // Means we are not in settings view, fullscreen panel or edit panel const isShowingDashboard = !editview && !isViewingPanel && !isEditingPanel; const isEditingAndShowingDashboard = isEditing && isShowingDashboard;