datatrails: feat: metadata for metric panels (#84872)
* feat: metadata for metric panels * fix: missing import? * fix: async await to get description first - also add description to metric-name-only panels * fix: change description, remove from main viz * fix: remove import
This commit is contained in:
@@ -10,9 +10,7 @@ import {
|
||||
} from '@grafana/scenes';
|
||||
import { Stack, Text, TextLink } from '@grafana/ui';
|
||||
|
||||
import PrometheusLanguageProvider from '../../../plugins/datasource/prometheus/language_provider';
|
||||
import { PromMetricsMetadataItem } from '../../../plugins/datasource/prometheus/types';
|
||||
import { getDatasourceSrv } from '../../plugins/datasource_srv';
|
||||
import { ALL_VARIABLE_VALUE } from '../../variables/constants';
|
||||
import { StatusWrapper } from '../StatusWrapper';
|
||||
import { TRAILS_ROUTE, VAR_DATASOURCE_EXPR, VAR_GROUP_BY } from '../shared';
|
||||
@@ -58,25 +56,12 @@ export class MetricOverviewScene extends SceneObjectBase<MetricOverviewSceneStat
|
||||
|
||||
private async updateMetadata() {
|
||||
this.setState({ metadataLoading: true, metadata: undefined });
|
||||
const ds = await getDatasourceSrv().get(VAR_DATASOURCE_EXPR, { __sceneObject: { value: this } });
|
||||
|
||||
const languageProvider: PrometheusLanguageProvider = ds.languageProvider;
|
||||
|
||||
if (!languageProvider) {
|
||||
return;
|
||||
}
|
||||
|
||||
const metricScene = getMetricSceneFor(this);
|
||||
const metric = metricScene.state.metric;
|
||||
|
||||
if (languageProvider.metricsMetadata) {
|
||||
this.setState({ metadata: languageProvider.metricsMetadata[metric], metadataLoading: false });
|
||||
return;
|
||||
}
|
||||
|
||||
await languageProvider.start();
|
||||
|
||||
this.setState({ metadata: languageProvider.metricsMetadata?.[metric], metadataLoading: false });
|
||||
const trail = getTrailFor(this);
|
||||
const metadata = await trail.getMetricMetadata(metric);
|
||||
this.setState({ metadata, metadataLoading: false });
|
||||
}
|
||||
|
||||
public static Component = ({ model }: SceneComponentProps<MetricOverviewScene>) => {
|
||||
|
||||
@@ -8,12 +8,13 @@ import { getColorByIndex } from '../utils';
|
||||
|
||||
import { getAutoQueriesForMetric } from './AutoQueryEngine';
|
||||
|
||||
export function getPreviewPanelFor(metric: string, index: number, currentFilterCount: number) {
|
||||
export function getPreviewPanelFor(metric: string, index: number, currentFilterCount: number, description?: string) {
|
||||
const autoQuery = getAutoQueriesForMetric(metric);
|
||||
|
||||
const vizPanel = autoQuery.preview
|
||||
.vizBuilder()
|
||||
.setColor({ mode: 'fixed', fixedColor: getColorByIndex(index) })
|
||||
.setDescription(description)
|
||||
.setHeaderActions(new SelectMetricAction({ metric, title: 'Select' }))
|
||||
.build();
|
||||
|
||||
|
||||
@@ -18,7 +18,9 @@ import {
|
||||
SceneRefreshPicker,
|
||||
SceneTimePicker,
|
||||
SceneTimeRange,
|
||||
SceneVariable,
|
||||
SceneVariableSet,
|
||||
VariableDependencyConfig,
|
||||
VariableValueSelectors,
|
||||
} from '@grafana/scenes';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
@@ -29,6 +31,7 @@ import { MetricScene } from './MetricScene';
|
||||
import { MetricSelectScene } from './MetricSelectScene';
|
||||
import { MetricsHeader } from './MetricsHeader';
|
||||
import { getTrailStore } from './TrailStore/TrailStore';
|
||||
import { MetricDatasourceHelper } from './helpers/MetricDatasourceHelper';
|
||||
import { MetricSelectedEvent, trailDS, VAR_DATASOURCE, VAR_FILTERS } from './shared';
|
||||
import { getUrlForTrail } from './utils';
|
||||
|
||||
@@ -111,6 +114,26 @@ export class DataTrail extends SceneObjectBase<DataTrailState> {
|
||||
};
|
||||
}
|
||||
|
||||
protected _variableDependency = new VariableDependencyConfig(this, {
|
||||
variableNames: [VAR_DATASOURCE],
|
||||
onReferencedVariableValueChanged: async (variable: SceneVariable) => {
|
||||
const { name } = variable.state;
|
||||
if (name === VAR_DATASOURCE) {
|
||||
this.datasourceHelper.reset();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
private datasourceHelper = new MetricDatasourceHelper(this);
|
||||
|
||||
public getMetricMetadata(metric?: string) {
|
||||
return this.datasourceHelper.getMetricMetadata(metric);
|
||||
}
|
||||
|
||||
public getCurrentMetricMetadata() {
|
||||
return this.getMetricMetadata(this.state.metric);
|
||||
}
|
||||
|
||||
private goBackToStep(step: DataTrailHistoryStep) {
|
||||
if (!this.state.embedded) {
|
||||
getUrlSyncManager().cleanUp(this);
|
||||
|
||||
@@ -26,6 +26,7 @@ import { getPreviewPanelFor } from './AutomaticMetricQueries/previewPanel';
|
||||
import { MetricScene } from './MetricScene';
|
||||
import { SelectMetricAction } from './SelectMetricAction';
|
||||
import { StatusWrapper } from './StatusWrapper';
|
||||
import { getMetricDescription } from './helpers/MetricDatasourceHelper';
|
||||
import { sortRelatedMetrics } from './relatedMetrics';
|
||||
import { getVariablesWithMetricConstant, trailDS, VAR_DATASOURCE, VAR_FILTERS_EXPR, VAR_METRIC_NAMES } from './shared';
|
||||
import { getFilters, getTrailFor } from './utils';
|
||||
@@ -202,7 +203,7 @@ export class MetricSelectScene extends SceneObjectBase<MetricSelectSceneState> {
|
||||
this.previewCache = metricsMap;
|
||||
}
|
||||
|
||||
private buildLayout() {
|
||||
private async buildLayout() {
|
||||
// Temp hack when going back to select metric scene and variable updates
|
||||
if (this.ignoreNextUpdate) {
|
||||
this.ignoreNextUpdate = false;
|
||||
@@ -225,6 +226,8 @@ export class MetricSelectScene extends SceneObjectBase<MetricSelectSceneState> {
|
||||
|
||||
const children: SceneFlexItem[] = [];
|
||||
|
||||
const trail = getTrailFor(this);
|
||||
|
||||
const metricsList = this.sortedPreviewMetrics();
|
||||
|
||||
// Get the current filters to determine the count of them
|
||||
@@ -234,13 +237,16 @@ export class MetricSelectScene extends SceneObjectBase<MetricSelectSceneState> {
|
||||
|
||||
for (let index = 0; index < metricsList.length; index++) {
|
||||
const metric = metricsList[index];
|
||||
const metadata = await trail.getMetricMetadata(metric.name);
|
||||
const description = getMetricDescription(metadata);
|
||||
|
||||
if (this.state.showPreviews) {
|
||||
if (metric.itemRef && metric.isPanel) {
|
||||
children.push(metric.itemRef.resolve());
|
||||
continue;
|
||||
}
|
||||
const panel = getPreviewPanelFor(metric.name, index, currentFilterCount);
|
||||
const panel = getPreviewPanelFor(metric.name, index, currentFilterCount, description);
|
||||
|
||||
metric.itemRef = panel.getRef();
|
||||
metric.isPanel = true;
|
||||
children.push(panel);
|
||||
@@ -249,7 +255,7 @@ export class MetricSelectScene extends SceneObjectBase<MetricSelectSceneState> {
|
||||
$variables: new SceneVariableSet({
|
||||
variables: getVariablesWithMetricConstant(metric.name),
|
||||
}),
|
||||
body: getCardPanelFor(metric.name),
|
||||
body: getCardPanelFor(metric.name, description),
|
||||
});
|
||||
metric.itemRef = panel.getRef();
|
||||
metric.isPanel = false;
|
||||
@@ -357,9 +363,10 @@ function getMetricNamesVariableSet() {
|
||||
});
|
||||
}
|
||||
|
||||
function getCardPanelFor(metric: string) {
|
||||
function getCardPanelFor(metric: string, description?: string) {
|
||||
return PanelBuilders.text()
|
||||
.setTitle(metric)
|
||||
.setDescription(description)
|
||||
.setHeaderActions(new SelectMetricAction({ metric, title: 'Select' }))
|
||||
.setOption('content', '')
|
||||
.build();
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import { DataSourceApi } from '@grafana/data';
|
||||
import { PromMetricsMetadata, PromMetricsMetadataItem } from '@grafana/prometheus';
|
||||
import { getDataSourceSrv } from '@grafana/runtime';
|
||||
|
||||
import PrometheusLanguageProvider from '../../../plugins/datasource/prometheus/language_provider';
|
||||
import { DataTrail } from '../DataTrail';
|
||||
import { VAR_DATASOURCE_EXPR } from '../shared';
|
||||
|
||||
export class MetricDatasourceHelper {
|
||||
constructor(trail: DataTrail) {
|
||||
this._trail = trail;
|
||||
}
|
||||
|
||||
public reset() {
|
||||
this._datasource = undefined;
|
||||
this._metricsMetadata = undefined;
|
||||
}
|
||||
|
||||
private _trail: DataTrail;
|
||||
|
||||
private _datasource?: Promise<DataSourceApi>;
|
||||
|
||||
private async getDatasource() {
|
||||
if (!this._datasource) {
|
||||
this._datasource = getDataSourceSrv().get(VAR_DATASOURCE_EXPR, { __sceneObject: { value: this._trail } });
|
||||
}
|
||||
|
||||
const ds = await this._datasource;
|
||||
return ds;
|
||||
}
|
||||
|
||||
private _metricsMetadata?: Promise<PromMetricsMetadata | undefined>;
|
||||
|
||||
private async _getMetricsMetadata() {
|
||||
const ds = await this.getDatasource();
|
||||
|
||||
if (ds.languageProvider instanceof PrometheusLanguageProvider) {
|
||||
if (!ds.languageProvider.metricsMetadata) {
|
||||
await ds.languageProvider.start();
|
||||
}
|
||||
|
||||
return ds.languageProvider.metricsMetadata!;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public async getMetricMetadata(metric?: string) {
|
||||
if (!metric) {
|
||||
return undefined;
|
||||
}
|
||||
if (!this._metricsMetadata) {
|
||||
this._metricsMetadata = this._getMetricsMetadata();
|
||||
}
|
||||
|
||||
const metadata = await this._metricsMetadata;
|
||||
return metadata?.[metric];
|
||||
}
|
||||
}
|
||||
|
||||
export function getMetricDescription(metadata?: PromMetricsMetadataItem) {
|
||||
if (!metadata) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const { type, help, unit } = metadata;
|
||||
|
||||
const lines = [
|
||||
help, //
|
||||
type && `**Type:** *${type}*`,
|
||||
unit && `**Unit:** ${unit}`,
|
||||
];
|
||||
|
||||
return lines.join('\n\n');
|
||||
}
|
||||
Reference in New Issue
Block a user