DashboardScene: Meta data tab (#74810)

* DashboardScene: Inspect meta tab

* DashboardScene: Inspect meta tab

* fix casing

* Added meta data inspector to testdata data source
This commit is contained in:
Torkel Ödegaard 2023-09-18 09:00:59 +02:00 committed by GitHub
parent 5484e0a2d5
commit 401ec3c4b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 110 additions and 19 deletions

View File

@ -757,13 +757,21 @@ func RandomWalk(query backend.DataQuery, model JSONModel, index int) *data.Frame
timeWalkerMs += query.Interval.Milliseconds()
}
return data.NewFrame("",
frame := data.NewFrame("",
data.NewField("time", nil, timeVec).
SetConfig(&data.FieldConfig{
Interval: float64(query.Interval.Milliseconds()),
}),
data.NewField(frameNameForQuery(query, model, index), parseLabels(model, index), floatVec),
)
frame.SetMeta(&data.FrameMeta{
Custom: map[string]interface{}{
"customStat": 10,
},
})
return frame
}
func randomWalkTable(query backend.DataQuery, model JSONModel) *data.Frame {

View File

@ -0,0 +1,40 @@
import React from 'react';
import { DataSourceApi } from '@grafana/data';
import {
SceneComponentProps,
sceneGraph,
SceneObjectBase,
SceneObjectState,
SceneObjectRef,
VizPanel,
} from '@grafana/scenes';
import { t } from 'app/core/internationalization';
import { InspectTab } from 'app/features/inspector/types';
export interface InspectMetaDataTabState extends SceneObjectState {
panelRef: SceneObjectRef<VizPanel>;
dataSource: DataSourceApi;
}
export class InspectMetaDataTab extends SceneObjectBase<InspectMetaDataTabState> {
public getTabLabel() {
return t('dashboard.inspect.meta-tab', 'Meta data');
}
public getTabValue() {
return InspectTab.Meta;
}
static Component = ({ model }: SceneComponentProps<InspectMetaDataTab>) => {
const { panelRef, dataSource } = model.state;
const data = sceneGraph.getData(panelRef.resolve());
const Inspector = dataSource.components?.MetadataInspector;
if (!data.state.data || !Inspector) {
return null;
}
return <Inspector datasource={dataSource} data={data.state.data.series} />;
};
}

View File

@ -12,10 +12,12 @@ import {
SceneObjectRef,
} from '@grafana/scenes';
import { Alert, Drawer, Tab, TabsBar } from '@grafana/ui';
import { getDataSourceWithInspector } from 'app/features/dashboard/components/Inspector/hooks';
import { supportsDataQuery } from 'app/features/dashboard/components/PanelEditor/utils';
import { InspectDataTab } from './InspectDataTab';
import { InspectJsonTab } from './InspectJsonTab';
import { InspectMetaDataTab } from './InspectMetaDataTab';
import { InspectQueryTab } from './InspectQueryTab';
import { InspectStatsTab } from './InspectStatsTab';
import { SceneInspectTab } from './types';
@ -32,7 +34,10 @@ export class PanelInspectDrawer extends SceneObjectBase<PanelInspectDrawerState>
constructor(state: PanelInspectDrawerState) {
super(state);
this.addActivationHandler(() => this._activationHandler());
}
private _activationHandler() {
this.buildTabs(0);
}
@ -40,7 +45,7 @@ export class PanelInspectDrawer extends SceneObjectBase<PanelInspectDrawerState>
* We currently have no async await to get the panel plugin from the VizPanel.
* That is why there is a retry argument here and a setTimeout, to try again a bit later.
*/
buildTabs(retry: number) {
async buildTabs(retry: number) {
const panelRef = this.state.panelRef;
const panel = panelRef.resolve();
const plugin = panel.getPlugin();
@ -55,9 +60,16 @@ export class PanelInspectDrawer extends SceneObjectBase<PanelInspectDrawerState>
}
if (supportsDataQuery(plugin)) {
const data = sceneGraph.getData(panel);
tabs.push(new InspectDataTab({ panelRef }));
tabs.push(new InspectStatsTab({ panelRef }));
tabs.push(new InspectQueryTab({ panelRef }));
const dsWithInspector = await getDataSourceWithInspector(data.state.data);
if (dsWithInspector) {
tabs.push(new InspectMetaDataTab({ panelRef, dataSource: dsWithInspector }));
}
}
tabs.push(new InspectJsonTab({ panelRef, onClose: this.onClose }));

View File

@ -13,25 +13,27 @@ import { supportsDataQuery } from '../PanelEditor/utils';
* Given PanelData return first data source supporting metadata inspector
*/
export const useDatasourceMetadata = (data?: PanelData) => {
const state = useAsync(async () => {
const targets = data?.request?.targets || [];
const state = useAsync(async () => getDataSourceWithInspector(data), [data]);
return state.value;
};
if (data && data.series && targets.length) {
for (const frame of data.series) {
if (frame.meta && frame.meta.custom) {
// get data source from first query
const dataSource = await getDataSourceSrv().get(targets[0].datasource);
if (dataSource && dataSource.components?.MetadataInspector) {
return dataSource;
}
export async function getDataSourceWithInspector(data?: PanelData): Promise<DataSourceApi | undefined> {
const targets = data?.request?.targets || [];
if (data && data.series && targets.length) {
for (const frame of data.series) {
if (frame.meta && frame.meta.custom) {
// get data source from first query
const dataSource = await getDataSourceSrv().get(targets[0].datasource);
if (dataSource && dataSource.components?.MetadataInspector) {
return dataSource;
}
}
}
}
return undefined;
}, [data]);
return state.value;
};
return undefined;
}
/**
* Configures tabs for PanelInspector
@ -51,7 +53,7 @@ export const useInspectTabs = (
}
if (metaDs) {
tabs.push({ label: t('dashboard.inspect.meta-tab', 'Meta Data'), value: InspectTab.Meta });
tabs.push({ label: t('dashboard.inspect.meta-tab', 'Meta data'), value: InspectTab.Meta });
}
tabs.push({ label: t('dashboard.inspect.json-tab', 'JSON'), value: InspectTab.JSON });

View File

@ -0,0 +1,27 @@
import React from 'react';
import { MetadataInspectorProps } from '@grafana/data';
import { Stack } from '@grafana/experimental';
import { TestData } from './dataquery.gen';
import { TestDataDataSource } from './datasource';
export type Props = MetadataInspectorProps<TestDataDataSource, TestData>;
export function MetaDataInspector({ data }: Props) {
return (
<Stack direction="column">
<div>Meta data inspector for the TestData data source.</div>
{data.map((frame, index) => (
<>
<div>Frame: {index}</div>
<div>
Custom meta: <br />
{JSON.stringify(frame.meta?.custom, null, 2)}
</div>
</>
))}
</Stack>
);
}

View File

@ -1,6 +1,7 @@
import { DataSourcePlugin } from '@grafana/data';
import { ConfigEditor } from './ConfigEditor';
import { MetaDataInspector } from './MetaDataInspector';
import { QueryEditor } from './QueryEditor';
import { TestInfoTab } from './TestInfoTab';
import { TestDataDataSource } from './datasource';
@ -8,6 +9,7 @@ import { TestDataDataSource } from './datasource';
export const plugin = new DataSourcePlugin(TestDataDataSource)
.setConfigEditor(ConfigEditor)
.setQueryEditor(QueryEditor)
.setMetadataInspector(MetaDataInspector)
.addConfigPage({
title: 'Setup',
icon: 'list-ul',

View File

@ -152,7 +152,7 @@
"data-tab": "Data",
"error-tab": "Error",
"json-tab": "JSON",
"meta-tab": "Meta Data",
"meta-tab": "Meta data",
"query-tab": "Query",
"stats-tab": "Stats",
"subtitle": "{{queryCount}} queries with total query time of {{formatted}}",

View File

@ -152,7 +152,7 @@
"data-tab": "Đäŧä",
"error-tab": "Ēřřőř",
"json-tab": "ĴŜØŃ",
"meta-tab": "Męŧä Đäŧä",
"meta-tab": "Męŧä đäŧä",
"query-tab": "Qūęřy",
"stats-tab": "Ŝŧäŧş",
"subtitle": "{{queryCount}} qūęřįęş ŵįŧĥ ŧőŧäľ qūęřy ŧįmę őƒ {{formatted}}",