2025-04-01 10:38:02 +09:00

155 lines
5.5 KiB
TypeScript

import { config } from '@grafana/runtime';
import {
SceneDataProvider,
SceneDataQuery,
SceneDataTransformer,
SceneObject,
SceneQueryRunner,
VizPanel,
VizPanelMenu,
VizPanelState,
} from '@grafana/scenes';
import { DataSourceRef } from '@grafana/schema/dist/esm/index.gen';
import { DashboardV2Spec, PanelKind, PanelQueryKind } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0';
import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
import { DashboardDatasourceBehaviour } from '../../scene/DashboardDatasourceBehaviour';
import { VizPanelLinks, VizPanelLinksMenu } from '../../scene/PanelLinks';
import { panelLinksBehavior, panelMenuBehavior } from '../../scene/PanelMenuBehavior';
import { PanelNotices } from '../../scene/PanelNotices';
import { PanelTimeRange } from '../../scene/PanelTimeRange';
import { AngularDeprecation } from '../../scene/angular/AngularDeprecation';
import { setDashboardPanelContext } from '../../scene/setDashboardPanelContext';
import { DashboardLayoutManager } from '../../scene/types/DashboardLayoutManager';
import { getVizPanelKeyForPanelId } from '../../utils/utils';
import { transformMappingsToV1 } from '../transformToV1TypesUtils';
import { layoutSerializerRegistry } from './layoutSerializerRegistry';
export function buildVizPanel(panel: PanelKind): VizPanel {
const titleItems: SceneObject[] = [];
if (config.featureToggles.angularDeprecationUI) {
titleItems.push(new AngularDeprecation());
}
titleItems.push(
new VizPanelLinks({
rawLinks: panel.spec.links,
menu: new VizPanelLinksMenu({ $behaviors: [panelLinksBehavior] }),
})
);
titleItems.push(new PanelNotices());
const queryOptions = panel.spec.data.spec.queryOptions;
const timeOverrideShown = (queryOptions.timeFrom || queryOptions.timeShift) && !queryOptions.hideTimeOverride;
const vizPanelState: VizPanelState = {
key: getVizPanelKeyForPanelId(panel.spec.id),
title: panel.spec.title,
description: panel.spec.description,
pluginId: panel.spec.vizConfig.kind,
options: panel.spec.vizConfig.spec.options,
fieldConfig: transformMappingsToV1(panel.spec.vizConfig.spec.fieldConfig),
pluginVersion: panel.spec.vizConfig.spec.pluginVersion,
displayMode: panel.spec.transparent ? 'transparent' : 'default',
hoverHeader: !panel.spec.title && !timeOverrideShown,
hoverHeaderOffset: 0,
$data: createPanelDataProvider(panel),
titleItems,
$behaviors: [],
extendPanelContext: setDashboardPanelContext,
// _UNSAFE_customMigrationHandler: getAngularPanelMigrationHandler(panel), //FIXME: Angular Migration
};
if (!config.publicDashboardAccessToken) {
vizPanelState.menu = new VizPanelMenu({
$behaviors: [panelMenuBehavior],
});
}
if (queryOptions.timeFrom || queryOptions.timeShift) {
vizPanelState.$timeRange = new PanelTimeRange({
timeFrom: queryOptions.timeFrom,
timeShift: queryOptions.timeShift,
hideTimeOverride: queryOptions.hideTimeOverride,
});
}
return new VizPanel(vizPanelState);
}
export function createPanelDataProvider(panelKind: PanelKind): SceneDataProvider | undefined {
const panel = panelKind.spec;
const targets = panel.data?.spec.queries ?? [];
// Skip setting query runner for panels without queries
if (!targets?.length) {
return undefined;
}
// Skip setting query runner for panel plugins with skipDataQuery
if (config.panels[panel.vizConfig.kind]?.skipDataQuery) {
return undefined;
}
let dataProvider: SceneDataProvider | undefined = undefined;
const datasource = getPanelDataSource(panelKind);
dataProvider = new SceneQueryRunner({
datasource,
queries: targets.map(panelQueryKindToSceneQuery),
maxDataPoints: panel.data.spec.queryOptions.maxDataPoints ?? undefined,
maxDataPointsFromWidth: true,
cacheTimeout: panel.data.spec.queryOptions.cacheTimeout,
queryCachingTTL: panel.data.spec.queryOptions.queryCachingTTL,
minInterval: panel.data.spec.queryOptions.interval ?? undefined,
dataLayerFilter: {
panelId: panel.id,
},
$behaviors: [new DashboardDatasourceBehaviour({})],
});
// Wrap inner data provider in a data transformer
return new SceneDataTransformer({
$data: dataProvider,
transformations: panel.data.spec.transformations.map((transformation) => transformation.spec),
});
}
function getPanelDataSource(panel: PanelKind): DataSourceRef | undefined {
if (!panel.spec.data?.spec.queries?.length) {
return undefined;
}
let datasource: DataSourceRef | undefined = undefined;
let isMixedDatasource = false;
panel.spec.data.spec.queries.forEach((query) => {
if (!datasource) {
datasource = query.spec.datasource;
} else if (datasource.uid !== query.spec.datasource?.uid || datasource.type !== query.spec.datasource?.type) {
isMixedDatasource = true;
}
});
return isMixedDatasource ? { type: 'mixed', uid: MIXED_DATASOURCE_NAME } : undefined;
}
function panelQueryKindToSceneQuery(query: PanelQueryKind): SceneDataQuery {
return {
refId: query.spec.refId,
datasource: query.spec.datasource,
hide: query.spec.hidden,
...query.spec.query.spec,
};
}
export function getLayout(sceneState: DashboardLayoutManager): DashboardV2Spec['layout'] {
const registryItem = layoutSerializerRegistry.get(sceneState.descriptor.kind ?? '');
if (!registryItem) {
throw new Error(`Layout serializer not found for kind: ${sceneState.descriptor.kind}`);
}
return registryItem.serializer.serialize(sceneState);
}