diff --git a/.betterer.results b/.betterer.results index d89b65b7bbf..48f308f57b5 100644 --- a/.betterer.results +++ b/.betterer.results @@ -2573,8 +2573,7 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "3"], [0, 0, 0, "Do not use any type assertions.", "4"], [0, 0, 0, "Do not use any type assertions.", "5"], - [0, 0, 0, "Do not use any type assertions.", "6"], - [0, 0, 0, "Do not use any type assertions.", "7"] + [0, 0, 0, "Do not use any type assertions.", "6"] ], "public/app/features/dashboard-scene/settings/variables/components/VariableSelectField.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] diff --git a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.test.ts b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.test.ts index f088fc622c6..7c3dadd80c9 100644 --- a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.test.ts +++ b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.test.ts @@ -1,3 +1,4 @@ +import 'whatwg-fetch'; import { advanceTo } from 'jest-date-mock'; import { map, of } from 'rxjs'; @@ -18,6 +19,7 @@ import { getPluginLinkExtensions, setPluginImportUtils } from '@grafana/runtime' import { MultiValueVariable, SceneDataLayers, + SceneGridItem, SceneGridItemLike, SceneGridLayout, SceneGridRow, @@ -29,6 +31,7 @@ import { getTimeRange } from 'app/features/dashboard/utils/timeRange'; import { reduceTransformRegistryItem } from 'app/features/transformers/editors/ReduceTransformerEditor'; import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard'; +import { LibraryVizPanel } from '../scene/LibraryVizPanel'; import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior'; import { NEW_LINK } from '../settings/links/utils'; import { activateFullSceneTree, buildPanelRepeaterScene } from '../utils/test-utils'; @@ -315,24 +318,41 @@ describe('transformSceneToSaveModel', () => { describe('Library panels', () => { it('given a library panel', () => { - const panel = buildGridItemFromPanelSchema({ - id: 4, - gridPos: { - h: 8, - w: 12, - x: 0, - y: 0, - }, - libraryPanel: { - name: 'Some lib panel panel', - uid: 'lib-panel-uid', - }, + // Not using buildGridItemFromPanelSchema since it strips options/fieldConfig + const libVizPanel = new LibraryVizPanel({ + name: 'Some lib panel panel', title: 'A panel', - transformations: [], - fieldConfig: { - defaults: {}, - overrides: [], - }, + uid: 'lib-panel-uid', + panelKey: 'lib-panel', + panel: new VizPanel({ + key: 'panel-4', + title: 'Panel blahh blah', + fieldConfig: { + defaults: {}, + overrides: [], + }, + options: { + legend: { + calcs: [], + displayMode: 'list', + placement: 'bottom', + showLegend: true, + }, + tooltip: { + maxHeight: 600, + mode: 'single', + sort: 'none', + }, + }, + }), + }); + + const panel = new SceneGridItem({ + body: libVizPanel, + y: 0, + x: 0, + width: 12, + height: 8, }); const result = gridItemToPanel(panel); @@ -351,6 +371,7 @@ describe('transformSceneToSaveModel', () => { expect(result.title).toBe('A panel'); expect(result.transformations).toBeUndefined(); expect(result.fieldConfig).toBeUndefined(); + expect(result.options).toBeUndefined(); }); it('given a library panel widget', () => { @@ -769,6 +790,53 @@ describe('transformSceneToSaveModel', () => { expect(result[1].title).toEqual('Panel $server'); }); + it('handles repeated library panels', () => { + const { scene, repeater } = buildPanelRepeaterScene( + { variableQueryTime: 0, numberOfOptions: 2 }, + new LibraryVizPanel({ + name: 'Some lib panel panel', + title: 'A panel', + uid: 'lib-panel-uid', + panelKey: 'lib-panel', + panel: new VizPanel({ + key: 'panel-4', + title: 'Panel blahh blah', + fieldConfig: { + defaults: {}, + overrides: [], + }, + options: { + legend: { + calcs: [], + displayMode: 'list', + placement: 'bottom', + showLegend: true, + }, + tooltip: { + maxHeight: 600, + mode: 'single', + sort: 'none', + }, + }, + }), + }) + ); + + activateFullSceneTree(scene); + const result = panelRepeaterToPanels(repeater, true); + + expect(result).toHaveLength(1); + + expect(result[0]).toMatchObject({ + id: 4, + title: 'A panel', + libraryPanel: { + name: 'Some lib panel panel', + uid: 'lib-panel-uid', + }, + }); + }); + it('handles row repeats ', () => { const { scene, row } = buildPanelRepeaterScene({ variableQueryTime: 0, diff --git a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts index 7e4a63dcaa8..b1329a4828c 100644 --- a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts +++ b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts @@ -139,6 +139,22 @@ export function transformSceneToSaveModel(scene: DashboardScene, isSnapshot = fa return sortedDeepCloneWithoutNulls(dashboard); } +export function libraryVizPanelToPanel(libPanel: LibraryVizPanel, gridPos: GridPos): Panel { + if (!libPanel.state.panel) { + throw new Error('Library panel has no panel'); + } + + return { + id: getPanelIdForVizPanel(libPanel.state.panel), + title: libPanel.state.title, + gridPos: gridPos, + libraryPanel: { + name: libPanel.state.name, + uid: libPanel.state.uid, + }, + } as Panel; +} + export function gridItemToPanel(gridItem: SceneGridItemLike, isSnapshot = false): Panel { let vizPanel: VizPanel | undefined; let x = 0, @@ -154,18 +170,7 @@ export function gridItemToPanel(gridItem: SceneGridItemLike, isSnapshot = false) w = gridItem.state.width ?? 0; h = gridItem.state.height ?? 0; - if (!gridItem.state.body.state.panel) { - throw new Error('Library panel has no panel'); - } - return { - id: getPanelIdForVizPanel(gridItem.state.body.state.panel), - title: gridItem.state.body.state.title, - gridPos: { x, y, w, h }, - libraryPanel: { - name: gridItem.state.body.state.name, - uid: gridItem.state.body.state.uid, - }, - } as Panel; + return libraryVizPanelToPanel(gridItem.state.body, { x, y, w, h }); } // Handle library panel widget as well and exit early @@ -194,16 +199,16 @@ export function gridItemToPanel(gridItem: SceneGridItemLike, isSnapshot = false) } if (gridItem instanceof PanelRepeaterGridItem) { - if (gridItem.state.source instanceof LibraryVizPanel) { - vizPanel = gridItem.state.source.state.panel; - } else { - vizPanel = gridItem.state.source; - } - x = gridItem.state.x ?? 0; y = gridItem.state.y ?? 0; w = gridItem.state.width ?? 0; h = gridItem.state.height ?? 0; + + if (gridItem.state.source instanceof LibraryVizPanel) { + return libraryVizPanelToPanel(gridItem.state.source, { x, y, w, h }); + } else { + vizPanel = gridItem.state.source; + } } if (!vizPanel) { @@ -323,18 +328,7 @@ export function panelRepeaterToPanels(repeater: PanelRepeaterGridItem, isSnapsho } else { if (repeater.state.source instanceof LibraryVizPanel) { const { x = 0, y = 0, width: w = 0, height: h = 0 } = repeater.state; - - return [ - { - id: getPanelIdForVizPanel(repeater.state.source), - title: repeater.state.source.state.title, - gridPos: { x, y, w, h }, - libraryPanel: { - name: repeater.state.source.state.name, - uid: repeater.state.source.state.uid, - }, - } as Panel, - ]; + return [libraryVizPanelToPanel(repeater.state.source, { x, y, w, h })]; } if (repeater.state.repeatedPanels) { diff --git a/public/app/features/dashboard-scene/utils/test-utils.ts b/public/app/features/dashboard-scene/utils/test-utils.ts index 9e6b18d0f97..b807efcdc69 100644 --- a/public/app/features/dashboard-scene/utils/test-utils.ts +++ b/public/app/features/dashboard-scene/utils/test-utils.ts @@ -15,6 +15,7 @@ import { DashboardLoaderSrv, setDashboardLoaderSrv } from 'app/features/dashboar import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE } from 'app/features/variables/constants'; import { DashboardDTO } from 'app/types'; +import { LibraryVizPanel } from '../scene/LibraryVizPanel'; import { VizPanelLinks, VizPanelLinksMenu } from '../scene/PanelLinks'; import { PanelRepeaterGridItem, RepeatDirection } from '../scene/PanelRepeaterGridItem'; import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior'; @@ -99,7 +100,7 @@ interface SceneOptions { useRowRepeater?: boolean; } -export function buildPanelRepeaterScene(options: SceneOptions) { +export function buildPanelRepeaterScene(options: SceneOptions, source?: VizPanel | LibraryVizPanel) { const defaults = { usePanelRepeater: true, ...options }; const repeater = new PanelRepeaterGridItem({ @@ -108,10 +109,12 @@ export function buildPanelRepeaterScene(options: SceneOptions) { repeatDirection: options.repeatDirection, maxPerRow: options.maxPerRow, itemHeight: options.itemHeight, - source: new VizPanel({ - title: 'Panel $server', - pluginId: 'timeseries', - }), + source: + source ?? + new VizPanel({ + title: 'Panel $server', + pluginId: 'timeseries', + }), x: options.x || 0, y: options.y || 0, });