datatrails: interpolate adhoc variables and datasource variables when opening "explore metrics" from dashboard panels (#86252)

* fix: interpolate "explore metrics" from panels

---------

Co-authored-by: Darren Janeczek <darren.janeczek@grafana.com>

* fix: remove support for legacy dashboard

- simplify code
- take advantage of scenes dashboard async and datasource api object

---------

Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
pull/86885/head
Darren Janeczek 1 year ago committed by GitHub
parent 8028d1c3e1
commit 53ead9904d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx
  2. 5
      public/app/features/dashboard/utils/getPanelMenu.ts
  3. 93
      public/app/features/trails/Integrations/dashboardIntegration.ts
  4. 29
      public/app/features/trails/Integrations/utils.ts

@ -168,7 +168,7 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
}
if (config.featureToggles.exploreMetrics) {
addDataTrailPanelAction(dashboard, panel, items);
await addDataTrailPanelAction(dashboard, panel, items);
}
if (exploreMenuItem) {

@ -25,7 +25,6 @@ import { DashboardInteractions } from 'app/features/dashboard-scene/utils/intera
import { InspectTab } from 'app/features/inspector/types';
import { isPanelModelLibraryPanel } from 'app/features/library-panels/guard';
import { createExtensionSubMenu } from 'app/features/plugins/extensions/utils';
import { addDataTrailPanelAction } from 'app/features/trails/Integrations/dashboardIntegration';
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
import { dispatch, store } from 'app/store/store';
@ -164,10 +163,6 @@ export function getPanelMenu(
});
}
if (config.featureToggles.exploreMetrics) {
addDataTrailPanelAction(dashboard, panel, menu);
}
const inspectMenu: PanelMenuItem[] = [];
// Only show these inspect actions for data plugins

@ -1,55 +1,55 @@
import { isString } from 'lodash';
import { PanelMenuItem, PanelModel } from '@grafana/data';
import { PanelMenuItem } from '@grafana/data';
import { PromQuery } from '@grafana/prometheus';
import { getDataSourceSrv } from '@grafana/runtime';
import { SceneTimeRangeLike, VizPanel } from '@grafana/scenes';
import { DataSourceRef } from '@grafana/schema';
import { DataQuery, DataSourceRef } from '@grafana/schema';
import { getQueryRunnerFor } from 'app/features/dashboard-scene/utils/utils';
import { DashboardModel } from '../../dashboard/state';
import { DashboardScene } from '../../dashboard-scene/scene/DashboardScene';
import { MetricScene } from '../MetricScene';
import { reportExploreMetrics } from '../interactions';
import { DataTrailEmbedded, DataTrailEmbeddedState } from './DataTrailEmbedded';
import { SceneDrawerAsScene, launchSceneDrawerInGlobalModal } from './SceneDrawer';
import { SceneDrawerAsScene } from './SceneDrawer';
import { QueryMetric, getQueryMetrics } from './getQueryMetrics';
import {
createAdHocFilters,
getPanelType,
getQueryMetricLabel,
getQueryRunner,
getTimeRangeFromDashboard,
} from './utils';
export function addDataTrailPanelAction(
dashboard: DashboardScene | DashboardModel,
panel: VizPanel | PanelModel,
items: PanelMenuItem[]
) {
const panelType = getPanelType(panel);
if (panelType !== 'timeseries') {
import { createAdHocFilters, getQueryMetricLabel, getTimeRangeFromDashboard } from './utils';
export async function addDataTrailPanelAction(dashboard: DashboardScene, panel: VizPanel, items: PanelMenuItem[]) {
if (panel.state.pluginId !== 'timeseries') {
return;
}
const queryRunner = getQueryRunnerFor(panel);
if (queryRunner == null) {
return;
}
const { queries, datasource, data } = queryRunner.state;
if (datasource == null) {
return;
}
const queryRunner = getQueryRunner(panel);
if (!queryRunner) {
if (datasource.type !== 'prometheus') {
return;
}
const ds = getDataSourceSrv().getInstanceSettings(queryRunner.state.datasource);
const dataSourceApi = await getDataSourceSrv().get(datasource);
if (ds?.meta.id !== 'prometheus') {
if (dataSourceApi.interpolateVariablesInQueries == null) {
return;
}
const queries = queryRunner.state.queries.map((q) => q.expr).filter(isString);
const interpolated = dataSourceApi
.interpolateVariablesInQueries(queries, { __sceneObject: { value: panel } }, data?.request?.filters)
.filter(isPromQuery);
const queryMetrics = getQueryMetrics(queries);
const queryMetrics = getQueryMetrics(interpolated.map((q) => q.expr));
const subMenu: PanelMenuItem[] = queryMetrics.map((item) => {
return {
text: getQueryMetricLabel(item),
onClick: createClickHandler(item, dashboard, ds),
onClick: createClickHandler(item, dashboard, dataSourceApi),
};
});
@ -88,11 +88,7 @@ function getEmbeddedTrailsState(
return state;
}
function createCommonEmbeddedTrailStateProps(
item: QueryMetric,
dashboard: DashboardScene | DashboardModel,
ds: DataSourceRef
) {
function createCommonEmbeddedTrailStateProps(item: QueryMetric, dashboard: DashboardScene, ds: DataSourceRef) {
const timeRange = getTimeRangeFromDashboard(dashboard);
const trailState = getEmbeddedTrailsState(item, timeRange, ds.uid);
const embeddedTrail: DataTrailEmbedded = new DataTrailEmbedded(trailState);
@ -111,21 +107,18 @@ function createCommonEmbeddedTrailStateProps(
return commonProps;
}
function createClickHandler(item: QueryMetric, dashboard: DashboardScene | DashboardModel, ds: DataSourceRef) {
if (dashboard instanceof DashboardScene) {
return () => {
const commonProps = createCommonEmbeddedTrailStateProps(item, dashboard, ds);
const drawerScene = new SceneDrawerAsScene({
...commonProps,
onDismiss: () => dashboard.closeModal(),
});
reportExploreMetrics('exploration_started', { cause: 'dashboard_panel' });
dashboard.showModal(drawerScene);
};
} else {
return () => {
reportExploreMetrics('exploration_started', { cause: 'dashboard_panel' });
launchSceneDrawerInGlobalModal(createCommonEmbeddedTrailStateProps(item, dashboard, ds));
};
}
function createClickHandler(item: QueryMetric, dashboard: DashboardScene, ds: DataSourceRef) {
return () => {
const commonProps = createCommonEmbeddedTrailStateProps(item, dashboard, ds);
const drawerScene = new SceneDrawerAsScene({
...commonProps,
onDismiss: () => dashboard.closeModal(),
});
reportExploreMetrics('exploration_started', { cause: 'dashboard_panel' });
dashboard.showModal(drawerScene);
};
}
export function isPromQuery(model: DataQuery): model is PromQuery {
return 'expr' in model;
}

@ -1,9 +1,5 @@
import { PanelModel } from '@grafana/data';
import { QueryBuilderLabelFilter } from '@grafana/prometheus/src/querybuilder/shared/types';
import { SceneQueryRunner, SceneTimeRange, VizPanel } from '@grafana/scenes';
import { DashboardModel } from 'app/features/dashboard/state';
import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene';
import { getQueryRunnerFor } from 'app/features/dashboard-scene/utils/utils';
import { QueryMetric } from './getQueryMetrics';
@ -12,22 +8,8 @@ export function isEquals(labelFilter: QueryBuilderLabelFilter) {
return labelFilter.op === '=';
}
export function getQueryRunner(panel: VizPanel | PanelModel) {
if (panel instanceof VizPanel) {
return getQueryRunnerFor(panel);
}
return new SceneQueryRunner({ datasource: panel.datasource || undefined, queries: panel.targets || [] });
}
export function getTimeRangeFromDashboard(dashboard: DashboardScene | DashboardModel) {
if (dashboard instanceof DashboardScene) {
return dashboard.state.$timeRange!.clone();
}
if (dashboard instanceof DashboardModel) {
return new SceneTimeRange({ ...dashboard.time });
}
return new SceneTimeRange();
export function getTimeRangeFromDashboard(dashboard: DashboardScene) {
return dashboard.state.$timeRange!.clone();
}
export function getQueryMetricLabel({ metric, labelFilters }: QueryMetric) {
@ -43,10 +25,3 @@ export function getQueryMetricLabel({ metric, labelFilters }: QueryMetric) {
export function createAdHocFilters(labels: QueryBuilderLabelFilter[]) {
return labels?.map((label) => ({ key: label.label, value: label.value, operator: label.op }));
}
export function getPanelType(panel: VizPanel | PanelModel) {
if (panel instanceof VizPanel) {
return panel.state.pluginId;
}
return panel.type;
}

Loading…
Cancel
Save