The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/features/scenes/dashboard/DashboardsLoader.ts

164 lines
4.6 KiB

import { StateManagerBase } from 'app/core/services/StateManagerBase';
import { dashboardLoaderSrv } from 'app/features/dashboard/services/DashboardLoaderSrv';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { DashboardDTO } from 'app/types';
import { VizPanel, SceneTimePicker, SceneGridLayout, SceneGridRow } from '../components';
import { SceneTimeRange } from '../core/SceneTimeRange';
import { SceneObject } from '../core/types';
import { SceneQueryRunner } from '../querying/SceneQueryRunner';
import { DashboardScene } from './DashboardScene';
export interface DashboardLoaderState {
dashboard?: DashboardScene;
isLoading?: boolean;
loadError?: string;
}
export class DashboardLoader extends StateManagerBase<DashboardLoaderState> {
private cache: Record<string, DashboardScene> = {};
public async load(uid: string) {
const fromCache = this.cache[uid];
if (fromCache) {
this.setState({ dashboard: fromCache });
return;
}
this.setState({ isLoading: true });
try {
const rsp = await dashboardLoaderSrv.loadDashboard('db', '', uid);
if (rsp.dashboard) {
this.initDashboard(rsp);
} else {
throw new Error('No dashboard returned');
}
} catch (err) {
this.setState({ isLoading: false, loadError: String(err) });
}
}
private initDashboard(rsp: DashboardDTO) {
// Just to have migrations run
const oldModel = new DashboardModel(rsp.dashboard, rsp.meta);
const dashboard = new DashboardScene({
title: oldModel.title,
uid: oldModel.uid,
layout: new SceneGridLayout({
children: this.buildSceneObjectsFromDashboard(oldModel),
}),
$timeRange: new SceneTimeRange(),
actions: [new SceneTimePicker({})],
});
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,
size: {
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,
size: {
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,
size: {
y: currentRow.gridPos.y,
},
children: currentRowPanels,
})
);
}
return panels;
}
}
function createVizPanelFromPanelModel(panel: PanelModel) {
return new VizPanel({
title: panel.title,
pluginId: panel.type,
size: {
x: panel.gridPos.x,
y: panel.gridPos.y,
width: panel.gridPos.w,
height: panel.gridPos.h,
},
options: panel.options,
fieldConfig: panel.fieldConfig,
pluginVersion: panel.pluginVersion,
$data: new SceneQueryRunner({
queries: panel.targets,
}),
});
}
let loader: DashboardLoader | null = null;
export function getDashboardLoader(): DashboardLoader {
if (!loader) {
loader = new DashboardLoader({});
}
return loader;
}