Snapshots: Use the grafana datasource to render snapshot (#54870)

This commit is contained in:
Ryan McKinley 2022-09-09 13:16:24 -07:00 committed by GitHub
parent dbb33eaba9
commit c49c238974
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 63 additions and 40 deletions

View File

@ -7,8 +7,6 @@ import {
DataQuery, DataQuery,
PanelData, PanelData,
DataTransformerConfig, DataTransformerConfig,
getValueFormat,
formattedValueToString,
DataFrameJSON, DataFrameJSON,
LoadingState, LoadingState,
dataFrameToJSON, dataFrameToJSON,
@ -16,6 +14,7 @@ import {
} from '@grafana/data'; } from '@grafana/data';
import { config } from '@grafana/runtime'; import { config } from '@grafana/runtime';
import { PanelModel } from 'app/features/dashboard/state'; import { PanelModel } from 'app/features/dashboard/state';
import { GrafanaQueryType } from 'app/plugins/datasource/grafana/types';
import { Randomize, randomizeData } from './randomizer'; import { Randomize, randomizeData } from './randomizer';
@ -74,8 +73,8 @@ export async function getDebugDashboard(panel: PanelModel, rand: Randomize, time
withTransforms: false, withTransforms: false,
}) })
); );
const dsref = panel.datasource;
const frames = randomizeData(getPanelDataFrames(data), rand); const frames = randomizeData(getPanelDataFrames(data), rand);
const rawFrameContent = JSON.stringify(frames);
const grafanaVersion = `${config.buildInfo.version} (${config.buildInfo.commit})`; const grafanaVersion = `${config.buildInfo.version} (${config.buildInfo.commit})`;
const queries = saveModel?.targets ?? []; const queries = saveModel?.targets ?? [];
const html = `<table width="100%"> const html = `<table width="100%">
@ -84,15 +83,16 @@ export async function getDebugDashboard(panel: PanelModel, rand: Randomize, time
<td >${info.panelType} @ ${saveModel.pluginVersion ?? grafanaVersion}</td> <td >${info.panelType} @ ${saveModel.pluginVersion ?? grafanaVersion}</td>
</tr> </tr>
<tr> <tr>
<th>Queries&nbsp;(${queries.length})</th> <th>Queries</th>
<td>${queries <td>${queries
.map((t: DataQuery) => { .map((t: DataQuery) => {
return `${t.refId}[${t.datasource?.type}]`; const ds = t.datasource ?? dsref;
return `${t.refId}[${ds?.type}]`;
}) })
.join(', ')}</td> .join(', ')}</td>
</tr> </tr>
${getTransformsRow(saveModel)} ${getTransformsRow(saveModel)}
${getDataRow(data, rawFrameContent)} ${getDataRow(data, frames)}
${getAnnotationsRow(data)} ${getAnnotationsRow(data)}
<tr> <tr>
<th>Grafana</th> <th>Grafana</th>
@ -108,11 +108,11 @@ export async function getDebugDashboard(panel: PanelModel, rand: Randomize, time
{ {
refId: 'A', refId: 'A',
datasource: { datasource: {
type: 'testdata', type: 'grafana',
uid: '${testdata}', uid: 'grafana',
}, },
rawFrameContent, queryType: GrafanaQueryType.Snapshot,
scenarioId: 'raw_frame', snapshot: frames,
}, },
], ],
}; };
@ -137,8 +137,8 @@ export async function getDebugDashboard(panel: PanelModel, rand: Randomize, time
type: 'table', type: 'table',
title: 'Annotations', title: 'Annotations',
datasource: { datasource: {
type: 'testdata', type: 'grafana',
uid: '${testdata}', uid: 'grafana',
}, },
targets: [ targets: [
{ {
@ -174,19 +174,22 @@ function getTransformsRow(saveModel: any): string {
</tr>`; </tr>`;
} }
function getDataRow(data: PanelData, raw: string): string { function getDataRow(data: PanelData, frames: DataFrameJSON[]): string {
let frameCount = data.series.length ?? 0; let frameCount = data.series.length ?? 0;
let fieldCount = 0; let fieldCount = 0;
let rowCount = 0;
for (const frame of data.series) { for (const frame of data.series) {
fieldCount += frame.fields.length; fieldCount += frame.fields.length;
rowCount += frame.length;
} }
return ( return (
'<tr>' + '<tr>' +
'<th>Data</th>' + '<th>Data</th>' +
'<td>' + '<td>' +
`${data.state !== LoadingState.Done ? data.state : ''} ` + `${data.state !== LoadingState.Done ? data.state : ''} ` +
`${frameCount} frames, ${fieldCount} fields` + `${frameCount} frames, ${fieldCount} fields, ` +
`(${formattedValueToString(getValueFormat('decbytes')(raw?.length))} JSON)` + `${rowCount} rows ` +
// `(${formattedValueToString(getValueFormat('decbytes')(raw?.length))} JSON)` +
'</td>' + '</td>' +
'</tr>' '</tr>'
); );
@ -211,8 +214,8 @@ const embeddedDataTemplate: any = {
id: 2, id: 2,
title: 'Reproduced with embedded data', title: 'Reproduced with embedded data',
datasource: { datasource: {
type: 'testdata', type: 'grafana',
uid: '${testdata}', uid: 'grafana',
}, },
gridPos: { gridPos: {
h: 13, h: 13,
@ -283,23 +286,4 @@ const embeddedDataTemplate: any = {
}, },
], ],
schemaVersion: 37, schemaVersion: 37,
templating: {
list: [
{
current: {
selected: true,
text: 'gdev-testdata',
value: 'gdev-testdata',
},
hide: 0,
includeAll: false,
multi: false,
name: 'testdata',
options: [],
query: 'testdata',
skipUrlSync: false,
type: 'datasource',
},
],
},
}; };

View File

@ -1,3 +1,4 @@
import pluralize from 'pluralize';
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { import {
@ -9,7 +10,7 @@ import {
DataFrame, DataFrame,
} from '@grafana/data'; } from '@grafana/data';
import { config, getBackendSrv, getDataSourceSrv } from '@grafana/runtime'; import { config, getBackendSrv, getDataSourceSrv } from '@grafana/runtime';
import { InlineField, Select, Alert, Input, InlineFieldRow } from '@grafana/ui'; import { InlineField, Select, Alert, Input, InlineFieldRow, InlineLabel } from '@grafana/ui';
import { hasAlphaPanels } from 'app/core/config'; import { hasAlphaPanels } from 'app/core/config';
import { SearchQuery } from 'app/features/search/service'; import { SearchQuery } from 'app/features/search/service';
@ -344,6 +345,18 @@ export class QueryEditor extends PureComponent<Props, State> {
); );
} }
renderSnapshotQuery() {
const { query } = this.props;
return (
<InlineFieldRow>
<InlineField label="Snapshot" grow={true} labelWidth={labelWidth}>
<InlineLabel>{pluralize('frame', query.snapshot?.length ?? 0, true)}</InlineLabel>
</InlineField>
</InlineFieldRow>
);
}
onSearchChange = (search: SearchQuery) => { onSearchChange = (search: SearchQuery) => {
const { query, onChange, onRunQuery } = this.props; const { query, onChange, onRunQuery } = this.props;
@ -362,6 +375,18 @@ export class QueryEditor extends PureComponent<Props, State> {
const { queryType } = query; const { queryType } = query;
// Only show "snapshot" when it already exists
let queryTypes = this.queryTypes;
if (queryType === GrafanaQueryType.Snapshot) {
queryTypes = [
...this.queryTypes,
{
label: 'Snapshot',
value: queryType,
},
];
}
return ( return (
<> <>
{queryType === GrafanaQueryType.Search && ( {queryType === GrafanaQueryType.Search && (
@ -373,14 +398,15 @@ export class QueryEditor extends PureComponent<Props, State> {
<InlineFieldRow> <InlineFieldRow>
<InlineField label="Query type" grow={true} labelWidth={labelWidth}> <InlineField label="Query type" grow={true} labelWidth={labelWidth}>
<Select <Select
options={this.queryTypes} options={queryTypes}
value={this.queryTypes.find((v) => v.value === queryType) || this.queryTypes[0]} value={queryTypes.find((v) => v.value === queryType) || queryTypes[0]}
onChange={this.onQueryTypeChange} onChange={this.onQueryTypeChange}
/> />
</InlineField> </InlineField>
</InlineFieldRow> </InlineFieldRow>
{queryType === GrafanaQueryType.LiveMeasurements && this.renderMeasurementsQuery()} {queryType === GrafanaQueryType.LiveMeasurements && this.renderMeasurementsQuery()}
{queryType === GrafanaQueryType.List && this.renderListPublicFiles()} {queryType === GrafanaQueryType.List && this.renderListPublicFiles()}
{queryType === GrafanaQueryType.Snapshot && this.renderSnapshotQuery()}
{queryType === GrafanaQueryType.Search && ( {queryType === GrafanaQueryType.Search && (
<SearchEditor value={query.search ?? {}} onChange={this.onSearchChange} /> <SearchEditor value={query.search ?? {}} onChange={this.onSearchChange} />
)} )}

View File

@ -14,6 +14,8 @@ import {
MutableDataFrame, MutableDataFrame,
parseLiveChannelAddress, parseLiveChannelAddress,
toDataFrame, toDataFrame,
dataFrameFromJSON,
LoadingState,
} from '@grafana/data'; } from '@grafana/data';
import { import {
DataSourceWithBackend, DataSourceWithBackend,
@ -82,6 +84,15 @@ export class GrafanaDatasource extends DataSourceWithBackend<GrafanaQuery> {
if (target.hide) { if (target.hide) {
continue; continue;
} }
if (target.queryType === GrafanaQueryType.Snapshot) {
results.push(
of({
data: (target.snapshot ?? []).map((v) => dataFrameFromJSON(v)),
state: LoadingState.Done,
})
);
continue;
}
if (target.queryType === GrafanaQueryType.LiveMeasurements) { if (target.queryType === GrafanaQueryType.LiveMeasurements) {
let channel = templateSrv.replace(target.channel, request.scopedVars); let channel = templateSrv.replace(target.channel, request.scopedVars);
const { filter } = target; const { filter } = target;

View File

@ -1,4 +1,4 @@
import { DataQuery } from '@grafana/data'; import { DataQuery, DataFrameJSON } from '@grafana/data';
import { LiveDataFilter } from '@grafana/runtime'; import { LiveDataFilter } from '@grafana/runtime';
import { SearchQuery } from 'app/features/search/service'; import { SearchQuery } from 'app/features/search/service';
@ -9,6 +9,7 @@ import { SearchQuery } from 'app/features/search/service';
export enum GrafanaQueryType { export enum GrafanaQueryType {
LiveMeasurements = 'measurements', LiveMeasurements = 'measurements',
Annotations = 'annotations', Annotations = 'annotations',
Snapshot = 'snapshot',
// backend // backend
RandomWalk = 'randomWalk', RandomWalk = 'randomWalk',
@ -24,6 +25,7 @@ export interface GrafanaQuery extends DataQuery {
buffer?: number; buffer?: number;
path?: string; // for list and read path?: string; // for list and read
search?: SearchQuery; search?: SearchQuery;
snapshot?: DataFrameJSON[];
} }
export const defaultQuery: GrafanaQuery = { export const defaultQuery: GrafanaQuery = {