mirror of
https://github.com/grafana/grafana.git
synced 2025-02-11 16:15:42 -06:00
Scene: Dashboard loader supports transformations & unit tests (#60855)
* Scene: use transformations for panel queries * refactor: Clean up DashboardLoader class * test: Add unit tests for creators * test: Ensure the row herarchy is properly replicated * test: Ensure the URLSync is initialized * refactor: Use fixture to create panels
This commit is contained in:
parent
6ab6d661e2
commit
d0f6a3a4ca
@ -5,6 +5,7 @@ import {
|
||||
defaultVariableModel,
|
||||
GraphPanel,
|
||||
Panel,
|
||||
RowPanel,
|
||||
VariableModel,
|
||||
} from '@grafana/schema';
|
||||
import { GetVariables } from 'app/features/variables/state/selectors';
|
||||
@ -29,7 +30,7 @@ export function createDashboardModelFixture(
|
||||
return new DashboardModel(dashboardJson, meta, getVariablesFromState);
|
||||
}
|
||||
|
||||
export function createPanelJSONFixture(panelInput: Partial<Panel | GraphPanel> = {}): Panel {
|
||||
export function createPanelJSONFixture(panelInput: Partial<Panel | GraphPanel | RowPanel> = {}): Panel {
|
||||
return {
|
||||
fieldConfig: {
|
||||
defaults: {},
|
||||
|
@ -1,13 +1,308 @@
|
||||
import { VariableType } from '@grafana/schema';
|
||||
import { defaultDashboard, LoadingState, Panel, RowPanel, VariableType } from '@grafana/schema';
|
||||
import { DashboardLoaderSrv, setDashboardLoaderSrv } from 'app/features/dashboard/services/DashboardLoaderSrv';
|
||||
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
||||
import { createPanelJSONFixture } from 'app/features/dashboard/state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { SceneGridLayout, SceneGridRow, VizPanel } from '../components';
|
||||
import { SceneQueryRunner } from '../querying/SceneQueryRunner';
|
||||
import { CustomVariable } from '../variables/variants/CustomVariable';
|
||||
import { DataSourceVariable } from '../variables/variants/DataSourceVariable';
|
||||
import { QueryVariable } from '../variables/variants/query/QueryVariable';
|
||||
|
||||
import { createVariableFromLegacyModel } from './DashboardsLoader';
|
||||
import { DashboardScene } from './DashboardScene';
|
||||
import {
|
||||
createDashboardSceneFromDashboardModel,
|
||||
createSceneVariableFromVariableModel,
|
||||
DashboardLoader,
|
||||
createVizPanelFromPanelModel,
|
||||
} from './DashboardsLoader';
|
||||
|
||||
describe('DashboardLoader', () => {
|
||||
describe('variables migration', () => {
|
||||
describe('when fetching/loading a dashboard', () => {
|
||||
beforeEach(() => {
|
||||
new DashboardLoader({});
|
||||
});
|
||||
|
||||
it('should load the dashboard from the cache if it exists', () => {
|
||||
const loader = new DashboardLoader({});
|
||||
const dashboard = new DashboardScene({
|
||||
title: 'cached',
|
||||
uid: 'fake-uid',
|
||||
body: new SceneGridLayout({ children: [] }),
|
||||
});
|
||||
// @ts-expect-error
|
||||
loader.cache['fake-uid'] = dashboard;
|
||||
loader.load('fake-uid');
|
||||
expect(loader.state.dashboard).toBe(dashboard);
|
||||
expect(loader.state.isLoading).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should call dashboard loader server if the dashboard is not cached', async () => {
|
||||
const loadDashboardMock = jest.fn().mockResolvedValue({ dashboard: { uid: 'fake-dash' }, meta: {} });
|
||||
setDashboardLoaderSrv({
|
||||
loadDashboard: loadDashboardMock,
|
||||
} as unknown as DashboardLoaderSrv);
|
||||
|
||||
const loader = new DashboardLoader({});
|
||||
await loader.load('fake-dash');
|
||||
|
||||
expect(loadDashboardMock).toHaveBeenCalledWith('db', '', 'fake-dash');
|
||||
});
|
||||
|
||||
it("should error when the dashboard doesn't exist", async () => {
|
||||
const loadDashboardMock = jest.fn().mockResolvedValue({ dashboard: undefined, meta: undefined });
|
||||
setDashboardLoaderSrv({
|
||||
loadDashboard: loadDashboardMock,
|
||||
} as unknown as DashboardLoaderSrv);
|
||||
|
||||
const loader = new DashboardLoader({});
|
||||
await loader.load('fake-dash');
|
||||
|
||||
expect(loader.state.dashboard).toBeUndefined();
|
||||
expect(loader.state.isLoading).toBe(false);
|
||||
// @ts-expect-error - private
|
||||
expect(loader.cache['fake-dash']).toBeUndefined();
|
||||
expect(loader.state.loadError).toBe('Error: Dashboard not found');
|
||||
});
|
||||
|
||||
it('should initialize the dashboard scene with the loaded dashboard', async () => {
|
||||
const loadDashboardMock = jest.fn().mockResolvedValue({ dashboard: { uid: 'fake-dash' }, meta: {} });
|
||||
setDashboardLoaderSrv({
|
||||
loadDashboard: loadDashboardMock,
|
||||
} as unknown as DashboardLoaderSrv);
|
||||
|
||||
const loader = new DashboardLoader({});
|
||||
await loader.load('fake-dash');
|
||||
|
||||
expect(loader.state.dashboard?.state.uid).toBe('fake-dash');
|
||||
expect(loader.state.loadError).toBe(undefined);
|
||||
expect(loader.state.isLoading).toBe(false);
|
||||
// It updates the cache
|
||||
// @ts-expect-error - private
|
||||
expect(loader.cache['fake-dash']).toBeDefined();
|
||||
});
|
||||
|
||||
it('should use DashboardScene creator to initialize the scene', async () => {
|
||||
const loadDashboardMock = jest.fn().mockResolvedValue({ dashboard: { uid: 'fake-dash' }, meta: {} });
|
||||
setDashboardLoaderSrv({
|
||||
loadDashboard: loadDashboardMock,
|
||||
} as unknown as DashboardLoaderSrv);
|
||||
|
||||
const loader = new DashboardLoader({});
|
||||
await loader.load('fake-dash');
|
||||
expect(loader.state.dashboard).toBeInstanceOf(DashboardScene);
|
||||
// @ts-expect-error - private
|
||||
expect(loader.state.dashboard?.urlSyncManager).toBeDefined();
|
||||
expect(loader.state.isLoading).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when creating dashboard scene', () => {
|
||||
it('should initialize the DashboardScene with the model state', () => {
|
||||
const dash = {
|
||||
...defaultDashboard,
|
||||
title: 'test',
|
||||
uid: 'test-uid',
|
||||
time: { from: 'now-10h', to: 'now' },
|
||||
templating: {
|
||||
list: [
|
||||
{
|
||||
hide: 2,
|
||||
name: 'constant',
|
||||
skipUrlSync: false,
|
||||
type: 'constant' as VariableType,
|
||||
rootStateKey: 'N4XLmH5Vz',
|
||||
query: 'test',
|
||||
id: 'constant',
|
||||
global: false,
|
||||
index: 3,
|
||||
state: LoadingState.Done,
|
||||
error: null,
|
||||
description: '',
|
||||
datasource: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
const oldModel = new DashboardModel(dash);
|
||||
|
||||
const scene = createDashboardSceneFromDashboardModel(oldModel);
|
||||
|
||||
expect(scene.state.title).toBe('test');
|
||||
expect(scene.state.uid).toBe('test-uid');
|
||||
expect(scene.state?.$timeRange?.state.value.raw).toEqual(dash.time);
|
||||
expect(scene.state?.$variables?.state.variables).toHaveLength(1);
|
||||
expect(scene.state.subMenu).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when organizing panels as scene children', () => {
|
||||
it('should create panels within collapsed rows', () => {
|
||||
const panel = createPanelJSONFixture({
|
||||
title: 'test',
|
||||
gridPos: { x: 1, y: 0, w: 12, h: 8 },
|
||||
}) as Panel;
|
||||
|
||||
const row = createPanelJSONFixture({
|
||||
title: 'test',
|
||||
type: 'row',
|
||||
gridPos: { x: 0, y: 0, w: 12, h: 1 },
|
||||
collapsed: true,
|
||||
panels: [panel],
|
||||
}) as unknown as RowPanel;
|
||||
|
||||
const dashboard = {
|
||||
...defaultDashboard,
|
||||
panels: [row],
|
||||
};
|
||||
|
||||
const oldModel = new DashboardModel(dashboard);
|
||||
|
||||
const scene = createDashboardSceneFromDashboardModel(oldModel);
|
||||
|
||||
expect(scene.state.body.state.children).toHaveLength(1);
|
||||
const rowScene = scene.state.body.state.children[0] as SceneGridRow;
|
||||
expect(rowScene).toBeInstanceOf(SceneGridRow);
|
||||
expect(rowScene.state.title).toEqual(row.title);
|
||||
expect(rowScene.state.placement?.y).toEqual(row.gridPos!.y);
|
||||
expect(rowScene.state.isCollapsed).toEqual(row.collapsed);
|
||||
expect(rowScene.state.children).toHaveLength(1);
|
||||
expect(rowScene.state.children[0]).toBeInstanceOf(VizPanel);
|
||||
});
|
||||
|
||||
it('should create panels within expanded row', () => {
|
||||
const panelOutOfRow = createPanelJSONFixture({
|
||||
title: 'Out of a row',
|
||||
gridPos: {
|
||||
h: 8,
|
||||
w: 12,
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
});
|
||||
const rowWithPanel = createPanelJSONFixture({
|
||||
title: 'Row with panel',
|
||||
type: 'row',
|
||||
collapsed: false,
|
||||
gridPos: {
|
||||
h: 1,
|
||||
w: 24,
|
||||
x: 0,
|
||||
y: 8,
|
||||
},
|
||||
// This panels array is not used if the row is not collapsed
|
||||
panels: [],
|
||||
});
|
||||
const panelInRow = createPanelJSONFixture({
|
||||
gridPos: {
|
||||
h: 8,
|
||||
w: 12,
|
||||
x: 0,
|
||||
y: 9,
|
||||
},
|
||||
title: 'In row 1',
|
||||
});
|
||||
const emptyRow = createPanelJSONFixture({
|
||||
collapsed: false,
|
||||
gridPos: {
|
||||
h: 1,
|
||||
w: 24,
|
||||
x: 0,
|
||||
y: 17,
|
||||
},
|
||||
// This panels array is not used if the row is not collapsed
|
||||
panels: [],
|
||||
title: 'Empty row',
|
||||
type: 'row',
|
||||
});
|
||||
const dashboard = {
|
||||
...defaultDashboard,
|
||||
panels: [panelOutOfRow, rowWithPanel, panelInRow, emptyRow],
|
||||
};
|
||||
|
||||
const oldModel = new DashboardModel(dashboard);
|
||||
|
||||
const scene = createDashboardSceneFromDashboardModel(oldModel);
|
||||
|
||||
expect(scene.state.body.state.children).toHaveLength(3);
|
||||
expect(scene.state.body).toBeInstanceOf(SceneGridLayout);
|
||||
// Panel out of row
|
||||
expect(scene.state.body.state.children[0]).toBeInstanceOf(VizPanel);
|
||||
const panelOutOfRowVizPanel = scene.state.body.state.children[0] as VizPanel;
|
||||
expect(panelOutOfRowVizPanel.state.title).toBe(panelOutOfRow.title);
|
||||
// Row with panel
|
||||
expect(scene.state.body.state.children[1]).toBeInstanceOf(SceneGridRow);
|
||||
const rowWithPanelsScene = scene.state.body.state.children[1] as SceneGridRow;
|
||||
expect(rowWithPanelsScene.state.title).toBe(rowWithPanel.title);
|
||||
expect(rowWithPanelsScene.state.children).toHaveLength(1);
|
||||
// Panel within row
|
||||
expect(rowWithPanelsScene.state.children[0]).toBeInstanceOf(VizPanel);
|
||||
const panelInRowVizPanel = rowWithPanelsScene.state.children[0] as VizPanel;
|
||||
expect(panelInRowVizPanel.state.title).toBe(panelInRow.title);
|
||||
// Empty row
|
||||
expect(scene.state.body.state.children[2]).toBeInstanceOf(SceneGridRow);
|
||||
const emptyRowScene = scene.state.body.state.children[2] as SceneGridRow;
|
||||
expect(emptyRowScene.state.title).toBe(emptyRow.title);
|
||||
expect(emptyRowScene.state.children).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when creating viz panel objects', () => {
|
||||
it('should initalize the VizPanel scene object state', () => {
|
||||
const panel = {
|
||||
title: 'test',
|
||||
type: 'test-plugin',
|
||||
gridPos: { x: 0, y: 0, w: 12, h: 8 },
|
||||
options: {
|
||||
fieldOptions: {
|
||||
defaults: {
|
||||
unit: 'none',
|
||||
decimals: 2,
|
||||
},
|
||||
overrides: [],
|
||||
},
|
||||
},
|
||||
fieldConfig: {
|
||||
defaults: {
|
||||
unit: 'none',
|
||||
},
|
||||
},
|
||||
pluginVersion: '1.0.0',
|
||||
transformations: [
|
||||
{
|
||||
id: 'reduce',
|
||||
options: {
|
||||
reducers: [
|
||||
{
|
||||
id: 'mean',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
targets: [
|
||||
{
|
||||
refId: 'A',
|
||||
queryType: 'randomWalk',
|
||||
},
|
||||
],
|
||||
};
|
||||
const vizPanelSceneObject = createVizPanelFromPanelModel(new PanelModel(panel));
|
||||
|
||||
expect(vizPanelSceneObject.state.title).toBe('test');
|
||||
expect(vizPanelSceneObject.state.pluginId).toBe('test-plugin');
|
||||
expect(vizPanelSceneObject.state.placement).toEqual({ x: 0, y: 0, width: 12, height: 8 });
|
||||
expect(vizPanelSceneObject.state.options).toEqual(panel.options);
|
||||
expect(vizPanelSceneObject.state.fieldConfig).toEqual(panel.fieldConfig);
|
||||
expect(vizPanelSceneObject.state.pluginVersion).toBe('1.0.0');
|
||||
expect((vizPanelSceneObject.state.$data as SceneQueryRunner)?.state.queries).toEqual(panel.targets);
|
||||
expect((vizPanelSceneObject.state.$data as SceneQueryRunner)?.state.transformations).toEqual(
|
||||
panel.transformations
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when creating variables objects', () => {
|
||||
it('should migrate custom variable', () => {
|
||||
const variable = {
|
||||
current: {
|
||||
@ -54,7 +349,7 @@ describe('DashboardLoader', () => {
|
||||
allValue: null,
|
||||
};
|
||||
|
||||
const migrated = createVariableFromLegacyModel(variable);
|
||||
const migrated = createSceneVariableFromVariableModel(variable);
|
||||
const { key, ...rest } = migrated.state;
|
||||
|
||||
expect(migrated).toBeInstanceOf(CustomVariable);
|
||||
@ -133,7 +428,7 @@ describe('DashboardLoader', () => {
|
||||
description: null,
|
||||
};
|
||||
|
||||
const migrated = createVariableFromLegacyModel(variable);
|
||||
const migrated = createSceneVariableFromVariableModel(variable);
|
||||
const { key, ...rest } = migrated.state;
|
||||
|
||||
expect(migrated).toBeInstanceOf(QueryVariable);
|
||||
@ -205,7 +500,7 @@ describe('DashboardLoader', () => {
|
||||
allValue: 'Custom all',
|
||||
};
|
||||
|
||||
const migrated = createVariableFromLegacyModel(variable);
|
||||
const migrated = createSceneVariableFromVariableModel(variable);
|
||||
const { key, ...rest } = migrated.state;
|
||||
|
||||
expect(migrated).toBeInstanceOf(DataSourceVariable);
|
||||
@ -257,7 +552,7 @@ describe('DashboardLoader', () => {
|
||||
description: null,
|
||||
};
|
||||
|
||||
const migrated = createVariableFromLegacyModel(variable);
|
||||
const migrated = createSceneVariableFromVariableModel(variable);
|
||||
const { key, ...rest } = migrated.state;
|
||||
|
||||
expect(rest).toEqual({
|
||||
@ -277,7 +572,7 @@ describe('DashboardLoader', () => {
|
||||
type: type as VariableType,
|
||||
};
|
||||
|
||||
expect(() => createVariableFromLegacyModel(variable)).toThrow();
|
||||
expect(() => createSceneVariableFromVariableModel(variable)).toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -48,7 +48,7 @@ export class DashboardLoader extends StateManagerBase<DashboardLoaderState> {
|
||||
if (rsp.dashboard) {
|
||||
this.initDashboard(rsp);
|
||||
} else {
|
||||
throw new Error('No dashboard returned');
|
||||
throw new Error('Dashboard not found');
|
||||
}
|
||||
} catch (err) {
|
||||
this.setState({ isLoading: false, loadError: String(err) });
|
||||
@ -59,30 +59,7 @@ export class DashboardLoader extends StateManagerBase<DashboardLoaderState> {
|
||||
// Just to have migrations run
|
||||
const oldModel = new DashboardModel(rsp.dashboard, rsp.meta);
|
||||
|
||||
let subMenu: SceneSubMenu | undefined = undefined;
|
||||
let variables: SceneVariableSet | undefined = undefined;
|
||||
|
||||
if (oldModel.templating.list.length) {
|
||||
const variableObjects = this.migrateVariables(oldModel);
|
||||
subMenu = new SceneSubMenu({
|
||||
children: [new VariableValueSelectors({})],
|
||||
});
|
||||
variables = new SceneVariableSet({
|
||||
variables: variableObjects,
|
||||
});
|
||||
}
|
||||
|
||||
const dashboard = new DashboardScene({
|
||||
title: oldModel.title,
|
||||
uid: oldModel.uid,
|
||||
body: new SceneGridLayout({
|
||||
children: this.buildSceneObjectsFromDashboard(oldModel),
|
||||
}),
|
||||
$timeRange: new SceneTimeRange(),
|
||||
actions: [new SceneTimePicker({})],
|
||||
$variables: variables,
|
||||
subMenu,
|
||||
});
|
||||
const dashboard = createDashboardSceneFromDashboardModel(oldModel);
|
||||
|
||||
// We initialize URL sync here as it better to do that before mounting and doing any rendering.
|
||||
// But would be nice to have a conditional around this so you can pre-load dashboards without url sync.
|
||||
@ -91,100 +68,121 @@ export class DashboardLoader extends StateManagerBase<DashboardLoaderState> {
|
||||
this.cache[rsp.dashboard.uid] = dashboard;
|
||||
this.setState({ dashboard, isLoading: false });
|
||||
}
|
||||
|
||||
private buildSceneObjectsFromDashboard(dashboard: DashboardModel) {
|
||||
// collects all panels and rows
|
||||
const panels: SceneObject[] = [];
|
||||
|
||||
// indicates expanded row that's currently processed
|
||||
let currentRow: PanelModel | null = null;
|
||||
// collects panels in the currently processed, expanded row
|
||||
let currentRowPanels: SceneObject[] = [];
|
||||
|
||||
for (const panel of dashboard.panels) {
|
||||
if (panel.type === 'row') {
|
||||
if (!currentRow) {
|
||||
if (Boolean(panel.collapsed)) {
|
||||
// collapsed rows contain their panels within the row model
|
||||
panels.push(
|
||||
new SceneGridRow({
|
||||
title: panel.title,
|
||||
isCollapsed: true,
|
||||
placement: {
|
||||
y: panel.gridPos.y,
|
||||
},
|
||||
children: panel.panels ? panel.panels.map(createVizPanelFromPanelModel) : [],
|
||||
})
|
||||
);
|
||||
} else {
|
||||
// indicate new row to be processed
|
||||
currentRow = panel;
|
||||
}
|
||||
} else {
|
||||
// when a row has been processed, and we hit a next one for processing
|
||||
if (currentRow.id !== panel.id) {
|
||||
// commit previous row panels
|
||||
panels.push(
|
||||
new SceneGridRow({
|
||||
title: currentRow!.title,
|
||||
placement: {
|
||||
y: currentRow.gridPos.y,
|
||||
},
|
||||
children: currentRowPanels,
|
||||
})
|
||||
);
|
||||
|
||||
currentRow = panel;
|
||||
currentRowPanels = [];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const panelObject = createVizPanelFromPanelModel(panel);
|
||||
|
||||
// when processing an expanded row, collect its panels
|
||||
if (currentRow) {
|
||||
currentRowPanels.push(panelObject);
|
||||
} else {
|
||||
panels.push(panelObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// commit a row if it's the last one
|
||||
if (currentRow) {
|
||||
panels.push(
|
||||
new SceneGridRow({
|
||||
title: currentRow!.title,
|
||||
placement: {
|
||||
y: currentRow.gridPos.y,
|
||||
},
|
||||
children: currentRowPanels,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return panels;
|
||||
}
|
||||
|
||||
private migrateVariables(dashboard: DashboardModel) {
|
||||
return (
|
||||
dashboard.templating.list
|
||||
.map((v) => {
|
||||
try {
|
||||
return createVariableFromLegacyModel(v);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
// TODO: Remove filter
|
||||
// Added temporarily to allow skipping non-compatible variables
|
||||
.filter((v): v is SceneVariable => Boolean(v))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function createVariableFromLegacyModel(variable: VariableModel): SceneVariable {
|
||||
export function createSceneObjectsForPanels(oldPanels: PanelModel[]): SceneObject[] {
|
||||
// collects all panels and rows
|
||||
const panels: SceneObject[] = [];
|
||||
|
||||
// indicates expanded row that's currently processed
|
||||
let currentRow: PanelModel | null = null;
|
||||
// collects panels in the currently processed, expanded row
|
||||
let currentRowPanels: SceneObject[] = [];
|
||||
|
||||
for (const panel of oldPanels) {
|
||||
if (panel.type === 'row') {
|
||||
if (!currentRow) {
|
||||
if (Boolean(panel.collapsed)) {
|
||||
// collapsed rows contain their panels within the row model
|
||||
panels.push(
|
||||
new SceneGridRow({
|
||||
title: panel.title,
|
||||
isCollapsed: true,
|
||||
placement: {
|
||||
y: panel.gridPos.y,
|
||||
},
|
||||
children: panel.panels ? panel.panels.map(createVizPanelFromPanelModel) : [],
|
||||
})
|
||||
);
|
||||
} else {
|
||||
// indicate new row to be processed
|
||||
currentRow = panel;
|
||||
}
|
||||
} else {
|
||||
// when a row has been processed, and we hit a next one for processing
|
||||
if (currentRow.id !== panel.id) {
|
||||
// commit previous row panels
|
||||
panels.push(
|
||||
new SceneGridRow({
|
||||
title: currentRow!.title,
|
||||
placement: {
|
||||
y: currentRow.gridPos.y,
|
||||
},
|
||||
children: currentRowPanels,
|
||||
})
|
||||
);
|
||||
|
||||
currentRow = panel;
|
||||
currentRowPanels = [];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const panelObject = createVizPanelFromPanelModel(panel);
|
||||
|
||||
// when processing an expanded row, collect its panels
|
||||
if (currentRow) {
|
||||
currentRowPanels.push(panelObject);
|
||||
} else {
|
||||
panels.push(panelObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// commit a row if it's the last one
|
||||
if (currentRow) {
|
||||
panels.push(
|
||||
new SceneGridRow({
|
||||
title: currentRow!.title,
|
||||
placement: {
|
||||
y: currentRow.gridPos.y,
|
||||
},
|
||||
children: currentRowPanels,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return panels;
|
||||
}
|
||||
|
||||
export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel) {
|
||||
let subMenu: SceneSubMenu | undefined = undefined;
|
||||
let variables: SceneVariableSet | undefined = undefined;
|
||||
|
||||
if (oldModel.templating.list.length) {
|
||||
const variableObjects = oldModel.templating.list
|
||||
.map((v) => {
|
||||
try {
|
||||
return createSceneVariableFromVariableModel(v);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
// TODO: Remove filter
|
||||
// Added temporarily to allow skipping non-compatible variables
|
||||
.filter((v): v is SceneVariable => Boolean(v));
|
||||
subMenu = new SceneSubMenu({
|
||||
children: [new VariableValueSelectors({})],
|
||||
});
|
||||
variables = new SceneVariableSet({
|
||||
variables: variableObjects,
|
||||
});
|
||||
}
|
||||
|
||||
return new DashboardScene({
|
||||
title: oldModel.title,
|
||||
uid: oldModel.uid,
|
||||
body: new SceneGridLayout({
|
||||
children: createSceneObjectsForPanels(oldModel.panels),
|
||||
}),
|
||||
$timeRange: new SceneTimeRange(oldModel.time),
|
||||
actions: [new SceneTimePicker({})],
|
||||
$variables: variables,
|
||||
subMenu,
|
||||
});
|
||||
}
|
||||
|
||||
export function createSceneVariableFromVariableModel(variable: VariableModel): SceneVariable {
|
||||
const commonProperties = {
|
||||
name: variable.name,
|
||||
label: variable.label,
|
||||
@ -249,7 +247,7 @@ export function createVariableFromLegacyModel(variable: VariableModel): SceneVar
|
||||
}
|
||||
}
|
||||
|
||||
function createVizPanelFromPanelModel(panel: PanelModel) {
|
||||
export function createVizPanelFromPanelModel(panel: PanelModel) {
|
||||
return new VizPanel({
|
||||
title: panel.title,
|
||||
pluginId: panel.type,
|
||||
@ -263,6 +261,7 @@ function createVizPanelFromPanelModel(panel: PanelModel) {
|
||||
fieldConfig: panel.fieldConfig,
|
||||
pluginVersion: panel.pluginVersion,
|
||||
$data: new SceneQueryRunner({
|
||||
transformations: panel.transformations,
|
||||
queries: panel.targets,
|
||||
}),
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user