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() timeWalkerMs += query.Interval.Milliseconds()
} }
return data.NewFrame("", frame := data.NewFrame("",
data.NewField("time", nil, timeVec). data.NewField("time", nil, timeVec).
SetConfig(&data.FieldConfig{ SetConfig(&data.FieldConfig{
Interval: float64(query.Interval.Milliseconds()), Interval: float64(query.Interval.Milliseconds()),
}), }),
data.NewField(frameNameForQuery(query, model, index), parseLabels(model, index), floatVec), 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 { 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, SceneObjectRef,
} from '@grafana/scenes'; } from '@grafana/scenes';
import { Alert, Drawer, Tab, TabsBar } from '@grafana/ui'; 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 { supportsDataQuery } from 'app/features/dashboard/components/PanelEditor/utils';
import { InspectDataTab } from './InspectDataTab'; import { InspectDataTab } from './InspectDataTab';
import { InspectJsonTab } from './InspectJsonTab'; import { InspectJsonTab } from './InspectJsonTab';
import { InspectMetaDataTab } from './InspectMetaDataTab';
import { InspectQueryTab } from './InspectQueryTab'; import { InspectQueryTab } from './InspectQueryTab';
import { InspectStatsTab } from './InspectStatsTab'; import { InspectStatsTab } from './InspectStatsTab';
import { SceneInspectTab } from './types'; import { SceneInspectTab } from './types';
@ -32,7 +34,10 @@ export class PanelInspectDrawer extends SceneObjectBase<PanelInspectDrawerState>
constructor(state: PanelInspectDrawerState) { constructor(state: PanelInspectDrawerState) {
super(state); super(state);
this.addActivationHandler(() => this._activationHandler());
}
private _activationHandler() {
this.buildTabs(0); 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. * 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. * 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 panelRef = this.state.panelRef;
const panel = panelRef.resolve(); const panel = panelRef.resolve();
const plugin = panel.getPlugin(); const plugin = panel.getPlugin();
@ -55,9 +60,16 @@ export class PanelInspectDrawer extends SceneObjectBase<PanelInspectDrawerState>
} }
if (supportsDataQuery(plugin)) { if (supportsDataQuery(plugin)) {
const data = sceneGraph.getData(panel);
tabs.push(new InspectDataTab({ panelRef })); tabs.push(new InspectDataTab({ panelRef }));
tabs.push(new InspectStatsTab({ panelRef })); tabs.push(new InspectStatsTab({ panelRef }));
tabs.push(new InspectQueryTab({ 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 })); 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 * Given PanelData return first data source supporting metadata inspector
*/ */
export const useDatasourceMetadata = (data?: PanelData) => { export const useDatasourceMetadata = (data?: PanelData) => {
const state = useAsync(async () => { const state = useAsync(async () => getDataSourceWithInspector(data), [data]);
const targets = data?.request?.targets || []; return state.value;
};
if (data && data.series && targets.length) { export async function getDataSourceWithInspector(data?: PanelData): Promise<DataSourceApi | undefined> {
for (const frame of data.series) { const targets = data?.request?.targets || [];
if (frame.meta && frame.meta.custom) {
// get data source from first query if (data && data.series && targets.length) {
const dataSource = await getDataSourceSrv().get(targets[0].datasource); for (const frame of data.series) {
if (dataSource && dataSource.components?.MetadataInspector) { if (frame.meta && frame.meta.custom) {
return dataSource; // get data source from first query
} const dataSource = await getDataSourceSrv().get(targets[0].datasource);
if (dataSource && dataSource.components?.MetadataInspector) {
return dataSource;
} }
} }
} }
}
return undefined; return undefined;
}, [data]); }
return state.value;
};
/** /**
* Configures tabs for PanelInspector * Configures tabs for PanelInspector
@ -51,7 +53,7 @@ export const useInspectTabs = (
} }
if (metaDs) { 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 }); 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 { DataSourcePlugin } from '@grafana/data';
import { ConfigEditor } from './ConfigEditor'; import { ConfigEditor } from './ConfigEditor';
import { MetaDataInspector } from './MetaDataInspector';
import { QueryEditor } from './QueryEditor'; import { QueryEditor } from './QueryEditor';
import { TestInfoTab } from './TestInfoTab'; import { TestInfoTab } from './TestInfoTab';
import { TestDataDataSource } from './datasource'; import { TestDataDataSource } from './datasource';
@ -8,6 +9,7 @@ import { TestDataDataSource } from './datasource';
export const plugin = new DataSourcePlugin(TestDataDataSource) export const plugin = new DataSourcePlugin(TestDataDataSource)
.setConfigEditor(ConfigEditor) .setConfigEditor(ConfigEditor)
.setQueryEditor(QueryEditor) .setQueryEditor(QueryEditor)
.setMetadataInspector(MetaDataInspector)
.addConfigPage({ .addConfigPage({
title: 'Setup', title: 'Setup',
icon: 'list-ul', icon: 'list-ul',

View File

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

View File

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