diff --git a/public/app/features/dashboard/components/DebugWizard/utils.ts b/public/app/features/dashboard/components/DebugWizard/utils.ts
index 401e00d2193..5eef71659f7 100644
--- a/public/app/features/dashboard/components/DebugWizard/utils.ts
+++ b/public/app/features/dashboard/components/DebugWizard/utils.ts
@@ -7,8 +7,6 @@ import {
DataQuery,
PanelData,
DataTransformerConfig,
- getValueFormat,
- formattedValueToString,
DataFrameJSON,
LoadingState,
dataFrameToJSON,
@@ -16,6 +14,7 @@ import {
} from '@grafana/data';
import { config } from '@grafana/runtime';
import { PanelModel } from 'app/features/dashboard/state';
+import { GrafanaQueryType } from 'app/plugins/datasource/grafana/types';
import { Randomize, randomizeData } from './randomizer';
@@ -74,8 +73,8 @@ export async function getDebugDashboard(panel: PanelModel, rand: Randomize, time
withTransforms: false,
})
);
+ const dsref = panel.datasource;
const frames = randomizeData(getPanelDataFrames(data), rand);
- const rawFrameContent = JSON.stringify(frames);
const grafanaVersion = `${config.buildInfo.version} (${config.buildInfo.commit})`;
const queries = saveModel?.targets ?? [];
const html = `
@@ -84,15 +83,16 @@ export async function getDebugDashboard(panel: PanelModel, rand: Randomize, time
${info.panelType} @ ${saveModel.pluginVersion ?? grafanaVersion} |
- Queries (${queries.length}) |
+ Queries |
${queries
.map((t: DataQuery) => {
- return `${t.refId}[${t.datasource?.type}]`;
+ const ds = t.datasource ?? dsref;
+ return `${t.refId}[${ds?.type}]`;
})
.join(', ')} |
${getTransformsRow(saveModel)}
- ${getDataRow(data, rawFrameContent)}
+ ${getDataRow(data, frames)}
${getAnnotationsRow(data)}
Grafana |
@@ -108,11 +108,11 @@ export async function getDebugDashboard(panel: PanelModel, rand: Randomize, time
{
refId: 'A',
datasource: {
- type: 'testdata',
- uid: '${testdata}',
+ type: 'grafana',
+ uid: 'grafana',
},
- rawFrameContent,
- scenarioId: 'raw_frame',
+ queryType: GrafanaQueryType.Snapshot,
+ snapshot: frames,
},
],
};
@@ -137,8 +137,8 @@ export async function getDebugDashboard(panel: PanelModel, rand: Randomize, time
type: 'table',
title: 'Annotations',
datasource: {
- type: 'testdata',
- uid: '${testdata}',
+ type: 'grafana',
+ uid: 'grafana',
},
targets: [
{
@@ -174,19 +174,22 @@ function getTransformsRow(saveModel: any): string {
`;
}
-function getDataRow(data: PanelData, raw: string): string {
+function getDataRow(data: PanelData, frames: DataFrameJSON[]): string {
let frameCount = data.series.length ?? 0;
let fieldCount = 0;
+ let rowCount = 0;
for (const frame of data.series) {
fieldCount += frame.fields.length;
+ rowCount += frame.length;
}
return (
'' +
'Data | ' +
'' +
`${data.state !== LoadingState.Done ? data.state : ''} ` +
- `${frameCount} frames, ${fieldCount} fields` +
- `(${formattedValueToString(getValueFormat('decbytes')(raw?.length))} JSON)` +
+ `${frameCount} frames, ${fieldCount} fields, ` +
+ `${rowCount} rows ` +
+ // `(${formattedValueToString(getValueFormat('decbytes')(raw?.length))} JSON)` +
' | ' +
'
'
);
@@ -211,8 +214,8 @@ const embeddedDataTemplate: any = {
id: 2,
title: 'Reproduced with embedded data',
datasource: {
- type: 'testdata',
- uid: '${testdata}',
+ type: 'grafana',
+ uid: 'grafana',
},
gridPos: {
h: 13,
@@ -283,23 +286,4 @@ const embeddedDataTemplate: any = {
},
],
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',
- },
- ],
- },
};
diff --git a/public/app/plugins/datasource/grafana/components/QueryEditor.tsx b/public/app/plugins/datasource/grafana/components/QueryEditor.tsx
index a72bd5bd881..aae44eac03b 100644
--- a/public/app/plugins/datasource/grafana/components/QueryEditor.tsx
+++ b/public/app/plugins/datasource/grafana/components/QueryEditor.tsx
@@ -1,3 +1,4 @@
+import pluralize from 'pluralize';
import React, { PureComponent } from 'react';
import {
@@ -9,7 +10,7 @@ import {
DataFrame,
} from '@grafana/data';
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 { SearchQuery } from 'app/features/search/service';
@@ -344,6 +345,18 @@ export class QueryEditor extends PureComponent {
);
}
+ renderSnapshotQuery() {
+ const { query } = this.props;
+
+ return (
+
+
+ {pluralize('frame', query.snapshot?.length ?? 0, true)}
+
+
+ );
+ }
+
onSearchChange = (search: SearchQuery) => {
const { query, onChange, onRunQuery } = this.props;
@@ -362,6 +375,18 @@ export class QueryEditor extends PureComponent {
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 (
<>
{queryType === GrafanaQueryType.Search && (
@@ -373,14 +398,15 @@ export class QueryEditor extends PureComponent {
{queryType === GrafanaQueryType.LiveMeasurements && this.renderMeasurementsQuery()}
{queryType === GrafanaQueryType.List && this.renderListPublicFiles()}
+ {queryType === GrafanaQueryType.Snapshot && this.renderSnapshotQuery()}
{queryType === GrafanaQueryType.Search && (
)}
diff --git a/public/app/plugins/datasource/grafana/datasource.ts b/public/app/plugins/datasource/grafana/datasource.ts
index 715d56d5f9a..b2e4c76470f 100644
--- a/public/app/plugins/datasource/grafana/datasource.ts
+++ b/public/app/plugins/datasource/grafana/datasource.ts
@@ -14,6 +14,8 @@ import {
MutableDataFrame,
parseLiveChannelAddress,
toDataFrame,
+ dataFrameFromJSON,
+ LoadingState,
} from '@grafana/data';
import {
DataSourceWithBackend,
@@ -82,6 +84,15 @@ export class GrafanaDatasource extends DataSourceWithBackend {
if (target.hide) {
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) {
let channel = templateSrv.replace(target.channel, request.scopedVars);
const { filter } = target;
diff --git a/public/app/plugins/datasource/grafana/types.ts b/public/app/plugins/datasource/grafana/types.ts
index 76d83798fe5..55988f8fd81 100644
--- a/public/app/plugins/datasource/grafana/types.ts
+++ b/public/app/plugins/datasource/grafana/types.ts
@@ -1,4 +1,4 @@
-import { DataQuery } from '@grafana/data';
+import { DataQuery, DataFrameJSON } from '@grafana/data';
import { LiveDataFilter } from '@grafana/runtime';
import { SearchQuery } from 'app/features/search/service';
@@ -9,6 +9,7 @@ import { SearchQuery } from 'app/features/search/service';
export enum GrafanaQueryType {
LiveMeasurements = 'measurements',
Annotations = 'annotations',
+ Snapshot = 'snapshot',
// backend
RandomWalk = 'randomWalk',
@@ -24,6 +25,7 @@ export interface GrafanaQuery extends DataQuery {
buffer?: number;
path?: string; // for list and read
search?: SearchQuery;
+ snapshot?: DataFrameJSON[];
}
export const defaultQuery: GrafanaQuery = {