From 51fab9adf48355de74bc2bd9c8ef660d1ae4d62b Mon Sep 17 00:00:00 2001 From: Ivan Ortega Alba Date: Mon, 15 Jul 2024 10:29:26 +0200 Subject: [PATCH] SoloPanel: Avoid fatal error when panelId correspond to a row (#90271) --- .../solo/useSoloPanel.test.tsx | 133 ++++++++++++++++++ .../dashboard-scene/solo/useSoloPanel.ts | 10 +- 2 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 public/app/features/dashboard-scene/solo/useSoloPanel.test.tsx diff --git a/public/app/features/dashboard-scene/solo/useSoloPanel.test.tsx b/public/app/features/dashboard-scene/solo/useSoloPanel.test.tsx new file mode 100644 index 00000000000..174374aaa25 --- /dev/null +++ b/public/app/features/dashboard-scene/solo/useSoloPanel.test.tsx @@ -0,0 +1,133 @@ +import { renderHook } from '@testing-library/react'; + +import { DataSourceRef } from '@grafana/schema'; + +import { transformSaveModelToScene } from '../serialization/transformSaveModelToScene'; +import { findVizPanelByKey } from '../utils/utils'; + +import { useSoloPanel } from './useSoloPanel'; + +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), + getDataSourceSrv: () => ({ + get: async (ref: DataSourceRef) => { + // Mocking the build in Grafana data source to avoid annotations data layer errors. + return { + id: 1, + uid: '-- Grafana --', + name: 'grafana', + type: 'grafana', + meta: { + id: 'grafana', + }, + }; + }, + }), +})); + +describe('useSoloPanel', () => { + it('should return undefined panel and error when panel is not found', () => { + const { dashboard } = setup(); + const { result } = renderHook(() => useSoloPanel(dashboard, 'foo-key')); + + expect(result.current[0]).toBeUndefined(); + expect(result.current[1]).toBe('Panel not found'); + }); + + it('should return the panel when panel is found', () => { + const { dashboard } = setup(); + + const { result } = renderHook(() => useSoloPanel(dashboard, 'panel-1')); + const panel = findVizPanelByKey(dashboard, 'panel-1'); + + expect(result.current[0]).toEqual(panel); + expect(result.current[1]).toBeUndefined(); + }); + + it('should return the cloned panel when panel is found', () => { + const { dashboard } = setup(); + const { result } = renderHook(() => useSoloPanel(dashboard, 'panel-1_clone')); + const panel = findVizPanelByKey(dashboard, 'panel-1'); + + expect(result.current[0]).not.toBe(panel); + expect(result.current[1]).toBeUndefined(); + }); + + it('should return error when panelId correspond to a non VizPanel', () => { + const { dashboard } = setup(); + const { result } = renderHook(() => useSoloPanel(dashboard, 'panel-2')); + + expect(result.current[0]).toBeUndefined(); + expect(result.current[1]).toBe('Panel not found'); + }); +}); + +const setup = () => { + const dashboard = transformSaveModelToScene({ dashboard: TEST_DASHBOARD, meta: {} }); + + return { dashboard }; +}; + +const TEST_DASHBOARD = { + title: 'Scenes/PanelEdit/Queries: Edit', + annotations: { + list: [], + }, + editable: true, + fiscalYearStartMonth: 0, + graphTooltip: 0, + id: 2378, + links: [], + liveNow: false, + panels: [ + { + type: 'timeseries', + datasource: 'prometheus', + fieldConfig: { + defaults: { + custom: {}, + }, + overrides: [], + }, + gridPos: { + h: 9, + w: 24, + x: 0, + y: 0, + }, + id: 1, + options: { + colorMode: 'background', + graphMode: 'area', + justifyMode: 'auto', + orientation: 'auto', + reduceOptions: { + calcs: ['lastNotNull', 'last', 'first', 'min', 'max', 'mean', 'sum', 'count'], + fields: '', + values: false, + }, + text: {}, + }, + pluginVersion: '8.0.3', + }, + { + id: 2, + type: 'row', + }, + ], + refresh: '', + schemaVersion: 39, + tags: [], + templating: { + list: [], + }, + time: { + from: 'now-6h', + to: 'now', + }, + timepicker: {}, + timezone: '', + uid: 'ffbe00e2-803c-4d49-adb7-41aad336234f', + version: 6, + weekStart: '', +}; diff --git a/public/app/features/dashboard-scene/solo/useSoloPanel.ts b/public/app/features/dashboard-scene/solo/useSoloPanel.ts index 27acec7d414..1ae44ef76de 100644 --- a/public/app/features/dashboard-scene/solo/useSoloPanel.ts +++ b/public/app/features/dashboard-scene/solo/useSoloPanel.ts @@ -17,7 +17,13 @@ export function useSoloPanel(dashboard: DashboardScene, panelId: string): [VizPa const cleanUp = dashboard.activate(); - const panel = findVizPanelByKey(dashboard, panelId); + let panel: VizPanel | null = null; + try { + panel = findVizPanelByKey(dashboard, panelId); + } catch (e) { + // do nothing, just the panel is not found or not a VizPanel + } + if (panel) { activateParents(panel); setPanel(panel); @@ -29,6 +35,8 @@ export function useSoloPanel(dashboard: DashboardScene, panelId: string): [VizPa setError('Panel not found'); } }); + } else { + setError('Panel not found'); } return cleanUp;