mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
DashboardSchema: Add library panel to v2 (#98484)
Co-authored-by: Haris Rozajac <haris.rozajac12@gmail.com>
This commit is contained in:
@@ -22,7 +22,7 @@ import { transformSceneToSaveModel } from '../serialization/transformSceneToSave
|
||||
import { findVizPanelByKey } from '../utils/utils';
|
||||
|
||||
import { V1DashboardSerializer, V2DashboardSerializer } from './DashboardSceneSerializer';
|
||||
import { transformSaveModelSchemaV2ToScene } from './transformSaveModelSchemaV2ToScene';
|
||||
import { getPanelElement, transformSaveModelSchemaV2ToScene } from './transformSaveModelSchemaV2ToScene';
|
||||
import { transformSceneToSaveModelSchemaV2 } from './transformSceneToSaveModelSchemaV2';
|
||||
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
@@ -559,8 +559,9 @@ describe('DashboardSceneSerializer', () => {
|
||||
editScene.state.panelRef.resolve().setState({ title: 'changed title' });
|
||||
|
||||
const result = dashboard.getDashboardChanges(false, true);
|
||||
const panelSaveModel = (result.changedSaveModel as DashboardV2Spec).elements['panel-1'].spec;
|
||||
expect(panelSaveModel.title).toBe('changed title');
|
||||
const panelSaveModel = getPanelElement(result.changedSaveModel as DashboardV2Spec, 'panel-1')!;
|
||||
|
||||
expect(panelSaveModel.spec.title).toBe('changed title');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -38,7 +38,11 @@ import { getQueryRunnerFor } from '../utils/utils';
|
||||
import { validateVariable, validateVizPanel } from '../v2schema/test-helpers';
|
||||
|
||||
import { SnapshotVariable } from './custom-variables/SnapshotVariable';
|
||||
import { transformSaveModelSchemaV2ToScene } from './transformSaveModelSchemaV2ToScene';
|
||||
import {
|
||||
getLibraryPanelElement,
|
||||
getPanelElement,
|
||||
transformSaveModelSchemaV2ToScene,
|
||||
} from './transformSaveModelSchemaV2ToScene';
|
||||
import { transformCursorSynctoEnum } from './transformToV2TypesUtils';
|
||||
|
||||
const defaultDashboard: DashboardWithAccessInfo<DashboardV2Spec> = {
|
||||
@@ -217,29 +221,44 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
||||
|
||||
// VizPanel
|
||||
const vizPanels = (scene.state.body as DashboardLayoutManager).getVizPanels();
|
||||
expect(vizPanels).toHaveLength(1);
|
||||
const vizPanel = vizPanels[0];
|
||||
validateVizPanel(vizPanel, dash);
|
||||
expect(vizPanels).toHaveLength(2);
|
||||
|
||||
// Layout
|
||||
const layout = scene.state.body as DefaultGridLayoutManager;
|
||||
expect(layout.state.grid.state.children.length).toBe(1);
|
||||
expect(layout.state.grid.state.children[0].state.key).toBe(`grid-item-${dash.elements['panel-1'].spec.id}`);
|
||||
|
||||
// Panel
|
||||
const panel = getPanelElement(dash, 'panel-1')!;
|
||||
expect(layout.state.grid.state.children.length).toBe(2);
|
||||
expect(layout.state.grid.state.children[0].state.key).toBe(`grid-item-${panel.spec.id}`);
|
||||
const gridLayoutItemSpec = dash.layout.spec.items[0].spec;
|
||||
expect(layout.state.grid.state.children[0].state.width).toBe(gridLayoutItemSpec.width);
|
||||
expect(layout.state.grid.state.children[0].state.height).toBe(gridLayoutItemSpec.height);
|
||||
expect(layout.state.grid.state.children[0].state.x).toBe(gridLayoutItemSpec.x);
|
||||
expect(layout.state.grid.state.children[0].state.y).toBe(gridLayoutItemSpec.y);
|
||||
const vizPanel = vizPanels.find((p) => p.state.key === 'panel-1')!;
|
||||
validateVizPanel(vizPanel, dash);
|
||||
|
||||
// Library Panel
|
||||
const libraryPanel = getLibraryPanelElement(dash, 'library-panel-1')!;
|
||||
expect(layout.state.grid.state.children[1].state.key).toBe(`grid-item-${libraryPanel.spec.uid}`);
|
||||
const libraryGridLayoutItemSpec = dash.layout.spec.items[1].spec;
|
||||
expect(layout.state.grid.state.children[1].state.width).toBe(libraryGridLayoutItemSpec.width);
|
||||
expect(layout.state.grid.state.children[1].state.height).toBe(libraryGridLayoutItemSpec.height);
|
||||
expect(layout.state.grid.state.children[1].state.x).toBe(libraryGridLayoutItemSpec.x);
|
||||
expect(layout.state.grid.state.children[1].state.y).toBe(libraryGridLayoutItemSpec.y);
|
||||
const vizLibraryPanel = vizPanels.find((p) => p.state.key === 'library-panel-1')!;
|
||||
validateVizPanel(vizLibraryPanel, dash);
|
||||
|
||||
// Transformations
|
||||
expect((vizPanel.state.$data as SceneDataTransformer)?.state.transformations[0]).toEqual(
|
||||
dash.elements['panel-1'].spec.data.spec.transformations[0].spec
|
||||
const panelWithTransformations = vizPanels.find((p) => p.state.key === 'panel-1')!;
|
||||
expect((panelWithTransformations.state.$data as SceneDataTransformer)?.state.transformations[0]).toEqual(
|
||||
getPanelElement(dash, 'panel-1')!.spec.data.spec.transformations[0].spec
|
||||
);
|
||||
});
|
||||
|
||||
it('should set panel ds if it is mixed DS', () => {
|
||||
const dashboard = cloneDeep(defaultDashboard);
|
||||
dashboard.spec.elements['panel-1'].spec.data.spec.queries.push({
|
||||
getPanelElement(dashboard.spec, 'panel-1')?.spec.data.spec.queries.push({
|
||||
kind: 'PanelQuery',
|
||||
spec: {
|
||||
refId: 'A',
|
||||
@@ -260,14 +279,14 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
||||
const scene = transformSaveModelSchemaV2ToScene(dashboard);
|
||||
|
||||
const vizPanels = (scene.state.body as DashboardLayoutManager).getVizPanels();
|
||||
expect(vizPanels.length).toBe(1);
|
||||
expect(vizPanels.length).toBe(2);
|
||||
expect(getQueryRunnerFor(vizPanels[0])?.state.datasource?.type).toBe('mixed');
|
||||
expect(getQueryRunnerFor(vizPanels[0])?.state.datasource?.uid).toBe(MIXED_DATASOURCE_NAME);
|
||||
});
|
||||
|
||||
it('should set panel ds as undefined if it is not mixed DS', () => {
|
||||
const dashboard = cloneDeep(defaultDashboard);
|
||||
dashboard.spec.elements['panel-1'].spec.data.spec.queries.push({
|
||||
getPanelElement(dashboard.spec, 'panel-1')?.spec.data.spec.queries.push({
|
||||
kind: 'PanelQuery',
|
||||
spec: {
|
||||
refId: 'A',
|
||||
@@ -288,14 +307,14 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
||||
const scene = transformSaveModelSchemaV2ToScene(dashboard);
|
||||
|
||||
const vizPanels = (scene.state.body as DashboardLayoutManager).getVizPanels();
|
||||
expect(vizPanels.length).toBe(1);
|
||||
expect(vizPanels.length).toBe(2);
|
||||
expect(getQueryRunnerFor(vizPanels[0])?.state.datasource).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should set panel ds as mixed if one ds is undefined', () => {
|
||||
const dashboard = cloneDeep(defaultDashboard);
|
||||
|
||||
dashboard.spec.elements['panel-1'].spec.data.spec.queries.push({
|
||||
getPanelElement(dashboard.spec, 'panel-1')?.spec.data.spec.queries.push({
|
||||
kind: 'PanelQuery',
|
||||
spec: {
|
||||
refId: 'A',
|
||||
@@ -312,7 +331,7 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
||||
const scene = transformSaveModelSchemaV2ToScene(dashboard);
|
||||
|
||||
const vizPanels = (scene.state.body as DashboardLayoutManager).getVizPanels();
|
||||
expect(vizPanels.length).toBe(1);
|
||||
expect(vizPanels.length).toBe(2);
|
||||
expect(getQueryRunnerFor(vizPanels[0])?.state.datasource?.type).toBe('mixed');
|
||||
expect(getQueryRunnerFor(vizPanels[0])?.state.datasource?.uid).toBe(MIXED_DATASOURCE_NAME);
|
||||
});
|
||||
|
||||
@@ -46,6 +46,7 @@ import {
|
||||
defaultTextVariableKind,
|
||||
GroupByVariableKind,
|
||||
IntervalVariableKind,
|
||||
LibraryPanelKind,
|
||||
PanelKind,
|
||||
PanelQueryKind,
|
||||
QueryVariableKind,
|
||||
@@ -74,6 +75,7 @@ import { registerDashboardMacro } from '../scene/DashboardMacro';
|
||||
import { DashboardReloadBehavior } from '../scene/DashboardReloadBehavior';
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { DashboardScopesFacade } from '../scene/DashboardScopesFacade';
|
||||
import { LibraryPanelBehavior } from '../scene/LibraryPanelBehavior';
|
||||
import { VizPanelLinks, VizPanelLinksMenu } from '../scene/PanelLinks';
|
||||
import { panelLinksBehavior, panelMenuBehavior } from '../scene/PanelMenuBehavior';
|
||||
import { PanelNotices } from '../scene/PanelNotices';
|
||||
@@ -253,6 +255,18 @@ function createSceneGridLayoutForItems(dashboard: DashboardV2Spec): SceneGridIte
|
||||
repeatDirection: element.spec.repeat?.direction,
|
||||
maxPerRow: element.spec.repeat?.maxPerRow,
|
||||
});
|
||||
} else if (panel.kind === 'LibraryPanel') {
|
||||
const libraryPanel = buildLibraryPanel(panel);
|
||||
|
||||
return new DashboardGridItem({
|
||||
key: `grid-item-${panel.spec.uid}`,
|
||||
x: element.spec.x,
|
||||
y: element.spec.y,
|
||||
width: element.spec.width,
|
||||
height: element.spec.height,
|
||||
itemHeight: element.spec.height,
|
||||
body: libraryPanel,
|
||||
});
|
||||
} else {
|
||||
throw new Error(`Unknown element kind: ${element.kind}`);
|
||||
}
|
||||
@@ -262,6 +276,45 @@ function createSceneGridLayoutForItems(dashboard: DashboardV2Spec): SceneGridIte
|
||||
});
|
||||
}
|
||||
|
||||
function buildLibraryPanel(panel: LibraryPanelKind): VizPanel {
|
||||
const titleItems: SceneObject[] = [];
|
||||
|
||||
if (config.featureToggles.angularDeprecationUI) {
|
||||
titleItems.push(new AngularDeprecation());
|
||||
}
|
||||
|
||||
titleItems.push(
|
||||
new VizPanelLinks({
|
||||
rawLinks: [],
|
||||
menu: new VizPanelLinksMenu({ $behaviors: [panelLinksBehavior] }),
|
||||
})
|
||||
);
|
||||
|
||||
titleItems.push(new PanelNotices());
|
||||
|
||||
const vizPanelState: VizPanelState = {
|
||||
key: panel.spec.uid,
|
||||
titleItems,
|
||||
$behaviors: [new LibraryPanelBehavior({ uid: panel.spec.uid, name: panel.spec.name })],
|
||||
extendPanelContext: setDashboardPanelContext,
|
||||
pluginId: LibraryPanelBehavior.LOADING_VIZ_PANEL_PLUGIN_ID,
|
||||
title: '',
|
||||
options: {},
|
||||
fieldConfig: {
|
||||
defaults: {},
|
||||
overrides: [],
|
||||
},
|
||||
};
|
||||
|
||||
if (!config.publicDashboardAccessToken) {
|
||||
vizPanelState.menu = new VizPanelMenu({
|
||||
$behaviors: [panelMenuBehavior],
|
||||
});
|
||||
}
|
||||
|
||||
return new VizPanel(vizPanelState);
|
||||
}
|
||||
|
||||
function buildVizPanel(panel: PanelKind): VizPanel {
|
||||
const titleItems: SceneObject[] = [];
|
||||
|
||||
@@ -299,15 +352,6 @@ function buildVizPanel(panel: PanelKind): VizPanel {
|
||||
// _UNSAFE_customMigrationHandler: getAngularPanelMigrationHandler(panel), //FIXME: Angular Migration
|
||||
};
|
||||
|
||||
// FIXME: Library Panel
|
||||
// if (panel.spec.libraryPanel) {
|
||||
// vizPanelState.$behaviors!.push(
|
||||
// new LibraryPanelBehavior({ uid: panel.spec.libraryPanel.uid, name: panel.spec.libraryPanel.name })
|
||||
// );
|
||||
// vizPanelState.pluginId = LibraryPanelBehavior.LOADING_VIZ_PANEL_PLUGIN_ID;
|
||||
// vizPanelState.$data = undefined;
|
||||
// }
|
||||
|
||||
if (!config.publicDashboardAccessToken) {
|
||||
vizPanelState.menu = new VizPanelMenu({
|
||||
$behaviors: [panelMenuBehavior],
|
||||
@@ -679,3 +723,11 @@ export function createSnapshotVariable(variable: TypedVariableModelV2): SceneVar
|
||||
});
|
||||
return snapshotVariable;
|
||||
}
|
||||
|
||||
export function getPanelElement(dashboard: DashboardV2Spec, elementName: string): PanelKind | undefined {
|
||||
return dashboard.elements[elementName].kind === 'Panel' ? dashboard.elements[elementName] : undefined;
|
||||
}
|
||||
|
||||
export function getLibraryPanelElement(dashboard: DashboardV2Spec, elementName: string): LibraryPanelKind | undefined {
|
||||
return dashboard.elements[elementName].kind === 'LibraryPanel' ? dashboard.elements[elementName] : undefined;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ import {
|
||||
AdhocVariableKind,
|
||||
AnnotationQueryKind,
|
||||
DataLink,
|
||||
LibraryPanelKind,
|
||||
Element,
|
||||
RepeatOptions,
|
||||
} from '../../../../../packages/grafana-schema/src/schema/dashboard/v2alpha0';
|
||||
import { DashboardDataLayerSet } from '../scene/DashboardDataLayerSet';
|
||||
@@ -45,6 +47,7 @@ import { DashboardGridItem } from '../scene/layout-default/DashboardGridItem';
|
||||
import { DefaultGridLayoutManager } from '../scene/layout-default/DefaultGridLayoutManager';
|
||||
import { dashboardSceneGraph } from '../utils/dashboardSceneGraph';
|
||||
import {
|
||||
getLibraryPanelBehavior,
|
||||
getPanelIdForVizPanel,
|
||||
getQueryRunnerFor,
|
||||
getVizPanelKeyForPanelId,
|
||||
@@ -237,33 +240,46 @@ export function gridItemToGridLayoutItemKind(gridItem: DashboardGridItem, isSnap
|
||||
|
||||
function getElements(state: DashboardSceneState) {
|
||||
const panels = state.body.getVizPanels() ?? [];
|
||||
const panelsArray = panels.reduce((acc: PanelKind[], vizPanel: VizPanel) => {
|
||||
const elementSpec: PanelKind = {
|
||||
kind: 'Panel',
|
||||
spec: {
|
||||
id: getPanelIdForVizPanel(vizPanel),
|
||||
title: vizPanel.state.title,
|
||||
description: vizPanel.state.description ?? '',
|
||||
links: getPanelLinks(vizPanel),
|
||||
data: {
|
||||
kind: 'QueryGroup',
|
||||
spec: {
|
||||
queries: getVizPanelQueries(vizPanel),
|
||||
transformations: getVizPanelTransformations(vizPanel),
|
||||
queryOptions: getVizPanelQueryOptions(vizPanel),
|
||||
const panelsArray = panels.reduce((acc: Element[], vizPanel: VizPanel) => {
|
||||
if (isLibraryPanel(vizPanel)) {
|
||||
const behavior = getLibraryPanelBehavior(vizPanel)!;
|
||||
const elementSpec: LibraryPanelKind = {
|
||||
kind: 'LibraryPanel',
|
||||
spec: {
|
||||
name: behavior.state.name,
|
||||
uid: behavior.state.uid,
|
||||
},
|
||||
};
|
||||
acc.push(elementSpec);
|
||||
} else {
|
||||
const elementSpec: PanelKind = {
|
||||
kind: 'Panel',
|
||||
spec: {
|
||||
id: getPanelIdForVizPanel(vizPanel),
|
||||
title: vizPanel.state.title,
|
||||
description: vizPanel.state.description ?? '',
|
||||
links: getPanelLinks(vizPanel),
|
||||
data: {
|
||||
kind: 'QueryGroup',
|
||||
spec: {
|
||||
queries: getVizPanelQueries(vizPanel),
|
||||
transformations: getVizPanelTransformations(vizPanel),
|
||||
queryOptions: getVizPanelQueryOptions(vizPanel),
|
||||
},
|
||||
},
|
||||
vizConfig: {
|
||||
kind: vizPanel.state.pluginId,
|
||||
spec: {
|
||||
pluginVersion: vizPanel.state.pluginVersion ?? '',
|
||||
options: vizPanel.state.options,
|
||||
fieldConfig: (vizPanel.state.fieldConfig as FieldConfigSource) ?? defaultFieldConfigSource(),
|
||||
},
|
||||
},
|
||||
},
|
||||
vizConfig: {
|
||||
kind: vizPanel.state.pluginId,
|
||||
spec: {
|
||||
pluginVersion: vizPanel.state.pluginVersion ?? '',
|
||||
options: vizPanel.state.options,
|
||||
fieldConfig: (vizPanel.state.fieldConfig as FieldConfigSource) ?? defaultFieldConfigSource(),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
acc.push(elementSpec);
|
||||
};
|
||||
acc.push(elementSpec);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
// create elements
|
||||
@@ -382,14 +398,14 @@ function getVizPanelQueryOptions(vizPanel: VizPanel): QueryOptionsSpec {
|
||||
return queryOptions;
|
||||
}
|
||||
|
||||
function createElements(panels: PanelKind[]): Record<string, PanelKind> {
|
||||
function createElements(panels: Element[]): Record<string, Element> {
|
||||
return panels.reduce(
|
||||
(acc, panel) => {
|
||||
const key = getVizPanelKeyForPanelId(panel.spec.id);
|
||||
const key = panel.kind === 'Panel' ? getVizPanelKeyForPanelId(panel.spec.id) : panel.spec.uid;
|
||||
acc[key] = panel;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, PanelKind>
|
||||
{} as Record<string, Element>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,10 @@ import {
|
||||
import { DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0';
|
||||
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { LibraryPanelBehavior } from '../scene/LibraryPanelBehavior';
|
||||
import { VizPanelLinks } from '../scene/PanelLinks';
|
||||
import { TypedVariableModelV2 } from '../serialization/transformSaveModelSchemaV2ToScene';
|
||||
import { getPanelIdForVizPanel, getQueryRunnerFor } from '../utils/utils';
|
||||
import { getLibraryPanelBehavior, getPanelIdForVizPanel, getQueryRunnerFor } from '../utils/utils';
|
||||
|
||||
type SceneVariableConstructor<T extends SceneVariableState, V extends SceneVariable<T>> = new (
|
||||
initialState: Partial<T>
|
||||
@@ -60,34 +61,44 @@ export function validateVariable<
|
||||
}
|
||||
|
||||
export function validateVizPanel(vizPanel: VizPanel, dash: DashboardV2Spec) {
|
||||
expect(vizPanel.state.title).toBe(dash.elements['panel-1'].spec.title);
|
||||
expect(vizPanel.state.description).toBe(dash.elements['panel-1'].spec.description);
|
||||
expect(vizPanel.state.pluginId).toBe(dash.elements['panel-1'].spec.vizConfig.kind);
|
||||
expect(vizPanel.state.pluginVersion).toBe(dash.elements['panel-1'].spec.vizConfig.spec.pluginVersion);
|
||||
expect(vizPanel.state.options).toEqual(dash.elements['panel-1'].spec.vizConfig.spec.options);
|
||||
expect(vizPanel.state.fieldConfig).toEqual(dash.elements['panel-1'].spec.vizConfig.spec.fieldConfig);
|
||||
expect(getPanelIdForVizPanel(vizPanel)).toBe(dash.elements['panel-1'].spec.id);
|
||||
expect(vizPanel.state.displayMode).toBe(dash.elements['panel-1'].spec.transparent ? 'transparent' : 'default');
|
||||
const panel = dash.elements[vizPanel.state.key!];
|
||||
|
||||
expect(vizPanel.state.$data).toBeInstanceOf(SceneDataTransformer);
|
||||
const dataTransformer = vizPanel.state.$data as SceneDataTransformer;
|
||||
expect(dataTransformer.state.transformations[0]).toEqual(
|
||||
dash.elements['panel-1'].spec.data.spec.transformations[0].spec
|
||||
);
|
||||
if (panel.kind === 'Panel') {
|
||||
expect(vizPanel.state.title).toBe(panel.spec.title);
|
||||
expect(vizPanel.state.description).toBe(panel.spec.description);
|
||||
expect(vizPanel.state.pluginId).toBe(panel.spec.vizConfig.kind);
|
||||
expect(vizPanel.state.pluginVersion).toBe(panel.spec.vizConfig.spec.pluginVersion);
|
||||
expect(vizPanel.state.options).toEqual(panel.spec.vizConfig.spec.options);
|
||||
expect(vizPanel.state.fieldConfig).toEqual(panel.spec.vizConfig.spec.fieldConfig);
|
||||
expect(getPanelIdForVizPanel(vizPanel)).toBe(panel.spec.id);
|
||||
expect(vizPanel.state.displayMode).toBe(panel.spec.transparent ? 'transparent' : 'default');
|
||||
|
||||
expect(dataTransformer.state.$data).toBeInstanceOf(SceneQueryRunner);
|
||||
const queryRunner = getQueryRunnerFor(vizPanel)!;
|
||||
expect(queryRunner).toBeInstanceOf(SceneQueryRunner);
|
||||
expect(queryRunner.state.queries).toEqual([
|
||||
{ datasource: { type: 'prometheus', uid: 'datasource1' }, expr: 'test-query', hide: false, refId: 'A' },
|
||||
]);
|
||||
expect(queryRunner.state.maxDataPoints).toBe(100);
|
||||
expect(queryRunner.state.cacheTimeout).toBe('1m');
|
||||
expect(queryRunner.state.queryCachingTTL).toBe(60);
|
||||
expect(queryRunner.state.minInterval).toBe('1m');
|
||||
const titleItems = vizPanel.state.titleItems as SceneObject[];
|
||||
const vizPanelLinks = titleItems[0] as VizPanelLinks;
|
||||
expect(vizPanelLinks.state.rawLinks).toHaveLength(dash.elements['panel-1'].spec.links.length);
|
||||
expect(vizPanelLinks.state.rawLinks).toEqual(dash.elements['panel-1'].spec.links);
|
||||
expect(queryRunner.state.dataLayerFilter?.panelId).toBe(dash.elements['panel-1'].spec.id);
|
||||
expect(vizPanel.state.$data).toBeInstanceOf(SceneDataTransformer);
|
||||
const dataTransformer = vizPanel.state.$data as SceneDataTransformer;
|
||||
expect(dataTransformer.state.transformations[0]).toEqual(panel.spec.data.spec.transformations[0].spec);
|
||||
|
||||
expect(dataTransformer.state.$data).toBeInstanceOf(SceneQueryRunner);
|
||||
const queryRunner = getQueryRunnerFor(vizPanel)!;
|
||||
expect(queryRunner).toBeInstanceOf(SceneQueryRunner);
|
||||
expect(queryRunner.state.queries).toEqual([
|
||||
{ datasource: { type: 'prometheus', uid: 'datasource1' }, expr: 'test-query', hide: false, refId: 'A' },
|
||||
]);
|
||||
expect(queryRunner.state.maxDataPoints).toBe(100);
|
||||
expect(queryRunner.state.cacheTimeout).toBe('1m');
|
||||
expect(queryRunner.state.queryCachingTTL).toBe(60);
|
||||
expect(queryRunner.state.minInterval).toBe('1m');
|
||||
const titleItems = vizPanel.state.titleItems as SceneObject[];
|
||||
const vizPanelLinks = titleItems[0] as VizPanelLinks;
|
||||
|
||||
expect(vizPanelLinks.state.rawLinks).toHaveLength(panel.spec.links.length);
|
||||
expect(vizPanelLinks.state.rawLinks).toEqual(panel.spec.links);
|
||||
expect(queryRunner.state.dataLayerFilter?.panelId).toBe(panel.spec.id);
|
||||
} else if (panel.kind === 'LibraryPanel') {
|
||||
expect(getLibraryPanelBehavior(vizPanel)?.state.name).toBe(panel.spec.name);
|
||||
expect(getLibraryPanelBehavior(vizPanel)?.state.uid).toBe(panel.spec.uid);
|
||||
|
||||
expect(vizPanel.state.pluginId).toBe(LibraryPanelBehavior.LOADING_VIZ_PANEL_PLUGIN_ID);
|
||||
} else {
|
||||
throw new Error('vizPanel is not a valid element kind');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { config } from '@grafana/runtime';
|
||||
import { CustomVariable, GroupByVariable } from '@grafana/scenes';
|
||||
import { LibraryPanel } from '@grafana/schema';
|
||||
import { DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0';
|
||||
import { handyTestingSchema } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0/examples';
|
||||
import { DashboardWithAccessInfo } from 'app/features/dashboard/api/types';
|
||||
import * as libpanels from 'app/features/library-panels/state/api';
|
||||
|
||||
import { transformSaveModelSchemaV2ToScene } from '../serialization/transformSaveModelSchemaV2ToScene';
|
||||
import { transformSceneToSaveModelSchemaV2 } from '../serialization/transformSceneToSaveModelSchemaV2';
|
||||
@@ -43,6 +45,23 @@ jest.mock('@grafana/runtime', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
const libraryPanel: LibraryPanel = {
|
||||
name: 'LibraryPanel A',
|
||||
uid: '111',
|
||||
type: 'table',
|
||||
model: {
|
||||
title: 'LibraryPanel A title',
|
||||
type: 'table',
|
||||
options: { showHeader: true },
|
||||
fieldConfig: { defaults: {}, overrides: [] },
|
||||
datasource: { uid: 'abcdef' },
|
||||
targets: [{ refId: 'A' }],
|
||||
},
|
||||
version: 1,
|
||||
};
|
||||
|
||||
jest.spyOn(libpanels, 'getLibraryPanel').mockResolvedValue(libraryPanel);
|
||||
|
||||
describe('V2 Transformers', () => {
|
||||
beforeAll(() => {
|
||||
config.featureToggles.groupByVariable = true;
|
||||
|
||||
@@ -281,6 +281,40 @@ describe('ResponseTransformers', () => {
|
||||
},
|
||||
],
|
||||
},
|
||||
panels: [
|
||||
{
|
||||
id: 1,
|
||||
type: 'timeseries',
|
||||
title: 'Panel Title',
|
||||
gridPos: { x: 0, y: 0, w: 12, h: 8 },
|
||||
targets: [
|
||||
{
|
||||
refId: 'A',
|
||||
datasource: 'datasource1',
|
||||
expr: 'test-query',
|
||||
hide: false,
|
||||
},
|
||||
],
|
||||
datasource: {
|
||||
type: 'prometheus',
|
||||
uid: 'datasource1',
|
||||
},
|
||||
fieldConfig: { defaults: {}, overrides: [] },
|
||||
options: {},
|
||||
transparent: false,
|
||||
links: [],
|
||||
transformations: [],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
type: 'table',
|
||||
libraryPanel: {
|
||||
uid: 'library-panel-table',
|
||||
name: 'Table Panel as Library Panel',
|
||||
},
|
||||
gridPos: { x: 0, y: 8, w: 12, h: 8 },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const dto: DashboardWithAccessInfo<DashboardDataDTO> = {
|
||||
@@ -317,6 +351,7 @@ describe('ResponseTransformers', () => {
|
||||
|
||||
const transformed = ResponseTransformers.ensureV2Response(dto);
|
||||
|
||||
// Metadata
|
||||
expect(transformed.apiVersion).toBe('v2alpha1');
|
||||
expect(transformed.kind).toBe('DashboardWithAccessInfo');
|
||||
expect(transformed.metadata.annotations?.[AnnoKeyCreatedBy]).toEqual('user1');
|
||||
@@ -327,6 +362,7 @@ describe('ResponseTransformers', () => {
|
||||
expect(transformed.metadata.annotations?.[AnnoKeyDashboardId]).toBe(123);
|
||||
expect(transformed.metadata.annotations?.[AnnoKeyDashboardGnetId]).toBe('something-like-a-uid');
|
||||
|
||||
// Spec
|
||||
const spec = transformed.spec;
|
||||
expect(spec.title).toBe(dashboardV1.title);
|
||||
expect(spec.description).toBe(dashboardV1.description);
|
||||
@@ -349,6 +385,90 @@ describe('ResponseTransformers', () => {
|
||||
expect(spec.timeSettings.weekStart).toBe(dashboardV1.weekStart);
|
||||
expect(spec.links).toEqual(dashboardV1.links);
|
||||
expect(spec.annotations).toEqual([]);
|
||||
|
||||
// Panel
|
||||
expect(spec.layout.spec.items).toHaveLength(2);
|
||||
expect(spec.layout.spec.items[0].spec).toEqual({
|
||||
element: {
|
||||
kind: 'ElementReference',
|
||||
name: '1',
|
||||
},
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 12,
|
||||
height: 8,
|
||||
});
|
||||
expect(spec.elements['1']).toEqual({
|
||||
kind: 'Panel',
|
||||
spec: {
|
||||
title: 'Panel Title',
|
||||
description: '',
|
||||
id: 1,
|
||||
links: [],
|
||||
vizConfig: {
|
||||
kind: 'timeseries',
|
||||
spec: {
|
||||
fieldConfig: {
|
||||
defaults: {},
|
||||
overrides: [],
|
||||
},
|
||||
options: {},
|
||||
pluginVersion: undefined,
|
||||
},
|
||||
},
|
||||
data: {
|
||||
kind: 'QueryGroup',
|
||||
spec: {
|
||||
queries: [
|
||||
{
|
||||
kind: 'PanelQuery',
|
||||
spec: {
|
||||
datasource: 'datasource1',
|
||||
hidden: false,
|
||||
query: {
|
||||
kind: 'prometheus',
|
||||
spec: {
|
||||
expr: 'test-query',
|
||||
},
|
||||
},
|
||||
refId: 'A',
|
||||
},
|
||||
},
|
||||
],
|
||||
queryOptions: {
|
||||
cacheTimeout: undefined,
|
||||
hideTimeOverride: undefined,
|
||||
interval: undefined,
|
||||
maxDataPoints: undefined,
|
||||
queryCachingTTL: undefined,
|
||||
timeFrom: undefined,
|
||||
timeShift: undefined,
|
||||
},
|
||||
transformations: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
// Library Panel
|
||||
expect(spec.layout.spec.items[1].spec).toEqual({
|
||||
element: {
|
||||
kind: 'ElementReference',
|
||||
name: 'library-panel-table',
|
||||
},
|
||||
x: 0,
|
||||
y: 8,
|
||||
width: 12,
|
||||
height: 8,
|
||||
});
|
||||
expect(spec.elements['library-panel-table']).toEqual({
|
||||
kind: 'LibraryPanel',
|
||||
spec: {
|
||||
uid: 'library-panel-table',
|
||||
name: 'Table Panel as Library Panel',
|
||||
},
|
||||
});
|
||||
|
||||
// Variables
|
||||
validateVariablesV1ToV2(spec.variables[0], dashboardV1.templating?.list?.[0]);
|
||||
validateVariablesV1ToV2(spec.variables[1], dashboardV1.templating?.list?.[1]);
|
||||
validateVariablesV1ToV2(spec.variables[2], dashboardV1.templating?.list?.[2]);
|
||||
|
||||
@@ -254,56 +254,73 @@ function getElementsFromPanels(panels: Panel[]): [DashboardV2Spec['elements'], D
|
||||
|
||||
// iterate over panels
|
||||
for (const p of panels) {
|
||||
// FIXME: for now we should skip row panels
|
||||
if (p.type === 'row') {
|
||||
continue;
|
||||
}
|
||||
let elementName;
|
||||
|
||||
const queries = getPanelQueries(
|
||||
(p.targets as unknown as DataQuery[]) || [],
|
||||
p.datasource || getDefaultDatasource()
|
||||
);
|
||||
// LibraryPanelKind
|
||||
if (p.libraryPanel) {
|
||||
elementName = p.libraryPanel.uid;
|
||||
|
||||
const transformations = getPanelTransformations(p.transformations || []);
|
||||
|
||||
elements[p.id!] = {
|
||||
kind: 'Panel',
|
||||
spec: {
|
||||
title: p.title || '',
|
||||
description: p.description || '',
|
||||
vizConfig: {
|
||||
kind: p.type,
|
||||
spec: {
|
||||
fieldConfig: (p.fieldConfig as any) || defaultFieldConfigSource(),
|
||||
options: p.options as any,
|
||||
pluginVersion: p.pluginVersion!,
|
||||
},
|
||||
elements[elementName] = {
|
||||
kind: 'LibraryPanel',
|
||||
spec: {
|
||||
uid: p.libraryPanel.uid,
|
||||
name: p.libraryPanel.name,
|
||||
},
|
||||
links:
|
||||
p.links?.map<DataLink>((l) => ({
|
||||
title: l.title,
|
||||
url: l.url || '',
|
||||
targetBlank: l.targetBlank,
|
||||
})) || [],
|
||||
id: p.id!,
|
||||
data: {
|
||||
kind: 'QueryGroup',
|
||||
spec: {
|
||||
queries,
|
||||
transformations, // TODO[schema v2]: handle transformations
|
||||
queryOptions: {
|
||||
cacheTimeout: p.cacheTimeout,
|
||||
maxDataPoints: p.maxDataPoints,
|
||||
interval: p.interval,
|
||||
hideTimeOverride: p.hideTimeOverride,
|
||||
queryCachingTTL: p.queryCachingTTL,
|
||||
timeFrom: p.timeFrom,
|
||||
timeShift: p.timeShift,
|
||||
};
|
||||
// PanelKind
|
||||
} else {
|
||||
elementName = p.id!.toString();
|
||||
|
||||
// FIXME: for now we should skip row panels
|
||||
if (p.type === 'row') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const queries = getPanelQueries(
|
||||
(p.targets as unknown as DataQuery[]) || [],
|
||||
p.datasource || getDefaultDatasource()
|
||||
);
|
||||
const transformations = getPanelTransformations(p.transformations || []);
|
||||
|
||||
elements[elementName] = {
|
||||
kind: 'Panel',
|
||||
spec: {
|
||||
title: p.title || '',
|
||||
description: p.description || '',
|
||||
vizConfig: {
|
||||
kind: p.type,
|
||||
spec: {
|
||||
fieldConfig: (p.fieldConfig as any) || defaultFieldConfigSource(),
|
||||
options: p.options as any,
|
||||
pluginVersion: p.pluginVersion!,
|
||||
},
|
||||
},
|
||||
links:
|
||||
p.links?.map<DataLink>((l) => ({
|
||||
title: l.title,
|
||||
url: l.url || '',
|
||||
targetBlank: l.targetBlank,
|
||||
})) || [],
|
||||
id: p.id!,
|
||||
data: {
|
||||
kind: 'QueryGroup',
|
||||
spec: {
|
||||
queries,
|
||||
transformations, // TODO[schema v2]: handle transformations
|
||||
queryOptions: {
|
||||
cacheTimeout: p.cacheTimeout,
|
||||
maxDataPoints: p.maxDataPoints,
|
||||
interval: p.interval,
|
||||
hideTimeOverride: p.hideTimeOverride,
|
||||
queryCachingTTL: p.queryCachingTTL,
|
||||
timeFrom: p.timeFrom,
|
||||
timeShift: p.timeShift,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
layout.spec.items.push({
|
||||
kind: 'GridLayoutItem',
|
||||
@@ -314,7 +331,7 @@ function getElementsFromPanels(panels: Panel[]): [DashboardV2Spec['elements'], D
|
||||
height: p.gridPos!.h,
|
||||
element: {
|
||||
kind: 'ElementReference',
|
||||
name: p.id!.toString(),
|
||||
name: elementName,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user