mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
5484e0a2d5
commit
401ec3c4b0
@ -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 {
|
||||||
|
@ -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} />;
|
||||||
|
};
|
||||||
|
}
|
@ -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 }));
|
||||||
|
@ -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 });
|
||||||
|
27
public/app/plugins/datasource/testdata/MetaDataInspector.tsx
vendored
Normal file
27
public/app/plugins/datasource/testdata/MetaDataInspector.tsx
vendored
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
@ -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',
|
||||||
|
@ -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}}",
|
||||||
|
@ -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}}",
|
||||||
|
Loading…
Reference in New Issue
Block a user