Expressions: Create json schema for query types (#84032)

This commit is contained in:
Ryan McKinley 2024-03-26 07:58:56 +03:00 committed by GitHub
parent 2e06677240
commit 4cda34ff7d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 4649 additions and 654 deletions

View File

@ -1,143 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
//
// Generated by:
// public/app/plugins/gen.go
// Using jennies:
// TSTypesJenny
// PluginTsTypesJenny
//
// Run 'make gen-cue' from repository root to regenerate.
import * as common from '@grafana/schema';
export const pluginVersion = "%VERSION%";
export enum TestDataQueryType {
Annotations = 'annotations',
Arrow = 'arrow',
CSVContent = 'csv_content',
CSVFile = 'csv_file',
CSVMetricValues = 'csv_metric_values',
DataPointsOutsideRange = 'datapoints_outside_range',
ExponentialHeatmapBucketData = 'exponential_heatmap_bucket_data',
FlameGraph = 'flame_graph',
GrafanaAPI = 'grafana_api',
LinearHeatmapBucketData = 'linear_heatmap_bucket_data',
Live = 'live',
Logs = 'logs',
ManualEntry = 'manual_entry',
NoDataPoints = 'no_data_points',
NodeGraph = 'node_graph',
PredictableCSVWave = 'predictable_csv_wave',
PredictablePulse = 'predictable_pulse',
RandomWalk = 'random_walk',
RandomWalkTable = 'random_walk_table',
RandomWalkWithError = 'random_walk_with_error',
RawFrame = 'raw_frame',
ServerError500 = 'server_error_500',
Simulation = 'simulation',
SlowQuery = 'slow_query',
StreamingClient = 'streaming_client',
TableStatic = 'table_static',
Trace = 'trace',
USA = 'usa',
VariablesQuery = 'variables-query',
}
export interface StreamingQuery {
bands?: number;
noise: number;
speed: number;
spread: number;
type: ('signal' | 'logs' | 'fetch' | 'traces');
url?: string;
}
export interface PulseWaveQuery {
offCount?: number;
offValue?: number;
onCount?: number;
onValue?: number;
timeStep?: number;
}
export interface SimulationQuery {
config?: Record<string, unknown>;
key: {
type: string;
tick: number;
uid?: string;
};
last?: boolean;
stream?: boolean;
}
export interface NodesQuery {
count?: number;
seed?: number;
type?: ('random' | 'response_small' | 'response_medium' | 'random edges' | 'feature_showcase');
}
export interface USAQuery {
fields?: Array<string>;
mode?: string;
period?: string;
states?: Array<string>;
}
export const defaultUSAQuery: Partial<USAQuery> = {
fields: [],
states: [],
};
export interface CSVWave {
labels?: string;
name?: string;
timeStep?: number;
valuesCSV?: string;
}
/**
* TODO: Should this live here given it's not used in the dataquery?
*/
export interface Scenario {
description?: string;
hideAliasField?: boolean;
id: string;
name: string;
stringInput: string;
}
export interface TestDataDataQuery extends common.DataQuery {
alias?: string;
channel?: string;
csvContent?: string;
csvFileName?: string;
csvWave?: Array<CSVWave>; // TODO can we prevent partial from being generated
/**
* Drop percentage (the chance we will lose a point 0-100)
*/
dropPercent?: number;
errorType?: ('server_panic' | 'frontend_exception' | 'frontend_observable');
flamegraphDiff?: boolean;
labels?: string;
levelColumn?: boolean;
lines?: number;
nodes?: NodesQuery;
points?: Array<Array<(string | number)>>;
pulseWave?: PulseWaveQuery;
rawFrameContent?: string;
scenarioId?: TestDataQueryType;
seriesCount?: number;
sim?: SimulationQuery;
spanCount?: number;
stream?: StreamingQuery;
stringInput?: string;
usa?: USAQuery;
}
export const defaultTestDataDataQuery: Partial<TestDataDataQuery> = {
csvWave: [],
points: [],
scenarioId: TestDataQueryType.RandomWalk,
};

View File

@ -0,0 +1,162 @@
{
"type": "table",
"targets": [
{
"refId": "A",
"datasource": {
"type": "__expr__",
"uid": "TheUID"
},
"expression": "$A + 10",
"type": "math"
},
{
"refId": "B",
"datasource": {
"type": "__expr__",
"uid": "TheUID"
},
"type": "math",
"expression": "$A - $B"
},
{
"refId": "C",
"datasource": {
"type": "__expr__",
"uid": "TheUID"
},
"type": "reduce",
"expression": "$A",
"reducer": "max",
"settings": {
"mode": "dropNN"
}
},
{
"refId": "D",
"datasource": {
"type": "__expr__",
"uid": "TheUID"
},
"expression": "$A",
"window": "1d",
"downsampler": "last",
"upsampler": "pad",
"type": "resample"
},
{
"refId": "E",
"datasource": {
"type": "__expr__",
"uid": "TheUID"
},
"conditions": [
{
"evaluator": {
"params": [
5
],
"type": "gt"
},
"operator": {
"type": "and"
},
"query": {
"params": [
"A"
]
},
"reducer": {
"type": "max"
}
}
],
"type": "classic_conditions"
},
{
"refId": "F",
"datasource": {
"type": "__expr__",
"uid": "TheUID"
},
"expression": "A",
"conditions": [
{
"evaluator": {
"params": [
5
],
"type": "gt"
}
}
],
"type": "threshold"
},
{
"refId": "G",
"datasource": {
"type": "__expr__",
"uid": "TheUID"
},
"expression": "B",
"conditions": [
{
"evaluator": {
"params": [
100
],
"type": "gt"
},
"loadedDimensions": {
"data": {
"values": [
[
18446744073709552000,
2,
3,
4,
5
]
]
},
"schema": {
"fields": [
{
"name": "fingerprints",
"type": "number",
"typeInfo": {
"frame": "uint64"
}
}
],
"meta": {
"type": "fingerprints",
"typeVersion": [
1,
0
]
},
"name": "test"
}
},
"unloadEvaluator": {
"params": [
31
],
"type": "lt"
}
}
],
"type": "threshold"
},
{
"refId": "H",
"datasource": {
"type": "__expr__",
"uid": "TheUID"
},
"expression": "SELECT * FROM A limit 1",
"type": "sql"
}
]
}

View File

@ -0,0 +1,989 @@
{
"type": "object",
"required": [
"targets",
"type"
],
"properties": {
"targets": {
"type": "array",
"items": {
"type": "object",
"oneOf": [
{
"type": "object",
"required": [
"expression",
"type",
"refId"
],
"properties": {
"datasource": {
"description": "The datasource",
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"description": "The datasource plugin type",
"type": "string",
"pattern": "^__expr__$"
},
"uid": {
"description": "Datasource UID",
"type": "string"
}
},
"additionalProperties": false
},
"expression": {
"description": "General math expression",
"type": "string",
"minLength": 1,
"examples": [
"$A + 1",
"$A/$B"
]
},
"hide": {
"description": "true if query is disabled (ie should not be returned to the dashboard)\nNOTE: this does not always imply that the query should not be executed since\nthe results from a hidden query may be used as the input to other queries (SSE etc)",
"type": "boolean"
},
"queryType": {
"description": "QueryType is an optional identifier for the type of query.\nIt can be used to distinguish different types of queries.",
"type": "string"
},
"refId": {
"description": "RefID is the unique identifier of the query, set by the frontend call.",
"type": "string"
},
"resultAssertions": {
"description": "Optionally define expected query result behavior",
"type": "object",
"required": [
"typeVersion"
],
"properties": {
"maxFrames": {
"description": "Maximum frame count",
"type": "integer"
},
"type": {
"description": "Type asserts that the frame matches a known type structure.\n\n\nPossible enum values:\n - `\"\"` \n - `\"timeseries-wide\"` \n - `\"timeseries-long\"` \n - `\"timeseries-many\"` \n - `\"timeseries-multi\"` \n - `\"directory-listing\"` \n - `\"table\"` \n - `\"numeric-wide\"` \n - `\"numeric-multi\"` \n - `\"numeric-long\"` \n - `\"log-lines\"` ",
"type": "string",
"enum": [
"",
"timeseries-wide",
"timeseries-long",
"timeseries-many",
"timeseries-multi",
"directory-listing",
"table",
"numeric-wide",
"numeric-multi",
"numeric-long",
"log-lines"
],
"x-enum-description": {}
},
"typeVersion": {
"description": "TypeVersion is the version of the Type property. Versions greater than 0.0 correspond to the dataplane\ncontract documentation https://grafana.github.io/dataplane/contract/.",
"type": "array",
"maxItems": 2,
"minItems": 2,
"items": {
"type": "integer"
}
}
},
"additionalProperties": false
},
"timeRange": {
"description": "TimeRange represents the query range\nNOTE: unlike generic /ds/query, we can now send explicit time values in each query\nNOTE: the values for timeRange are not saved in a dashboard, they are constructed on the fly",
"type": "object",
"required": [
"from",
"to"
],
"properties": {
"from": {
"description": "From is the start time of the query.",
"type": "string",
"default": "now-6h",
"examples": [
"now-1h"
]
},
"to": {
"description": "To is the end time of the query.",
"type": "string",
"default": "now",
"examples": [
"now"
]
}
},
"additionalProperties": false
},
"type": {
"type": "string",
"pattern": "^math$"
}
},
"additionalProperties": false,
"$schema": "https://json-schema.org/draft-04/schema"
},
{
"type": "object",
"required": [
"expression",
"reducer",
"type",
"refId"
],
"properties": {
"datasource": {
"description": "The datasource",
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"description": "The datasource plugin type",
"type": "string",
"pattern": "^__expr__$"
},
"uid": {
"description": "Datasource UID",
"type": "string"
}
},
"additionalProperties": false
},
"expression": {
"description": "Reference to single query result",
"type": "string",
"minLength": 1,
"examples": [
"$A"
]
},
"hide": {
"description": "true if query is disabled (ie should not be returned to the dashboard)\nNOTE: this does not always imply that the query should not be executed since\nthe results from a hidden query may be used as the input to other queries (SSE etc)",
"type": "boolean"
},
"queryType": {
"description": "QueryType is an optional identifier for the type of query.\nIt can be used to distinguish different types of queries.",
"type": "string"
},
"reducer": {
"description": "The reducer\n\n\nPossible enum values:\n - `\"sum\"` \n - `\"mean\"` \n - `\"min\"` \n - `\"max\"` \n - `\"count\"` \n - `\"last\"` ",
"type": "string",
"enum": [
"sum",
"mean",
"min",
"max",
"count",
"last"
],
"x-enum-description": {}
},
"refId": {
"description": "RefID is the unique identifier of the query, set by the frontend call.",
"type": "string"
},
"resultAssertions": {
"description": "Optionally define expected query result behavior",
"type": "object",
"required": [
"typeVersion"
],
"properties": {
"maxFrames": {
"description": "Maximum frame count",
"type": "integer"
},
"type": {
"description": "Type asserts that the frame matches a known type structure.\n\n\nPossible enum values:\n - `\"\"` \n - `\"timeseries-wide\"` \n - `\"timeseries-long\"` \n - `\"timeseries-many\"` \n - `\"timeseries-multi\"` \n - `\"directory-listing\"` \n - `\"table\"` \n - `\"numeric-wide\"` \n - `\"numeric-multi\"` \n - `\"numeric-long\"` \n - `\"log-lines\"` ",
"type": "string",
"enum": [
"",
"timeseries-wide",
"timeseries-long",
"timeseries-many",
"timeseries-multi",
"directory-listing",
"table",
"numeric-wide",
"numeric-multi",
"numeric-long",
"log-lines"
],
"x-enum-description": {}
},
"typeVersion": {
"description": "TypeVersion is the version of the Type property. Versions greater than 0.0 correspond to the dataplane\ncontract documentation https://grafana.github.io/dataplane/contract/.",
"type": "array",
"maxItems": 2,
"minItems": 2,
"items": {
"type": "integer"
}
}
},
"additionalProperties": false
},
"settings": {
"description": "Reducer Options",
"type": "object",
"required": [
"mode"
],
"properties": {
"mode": {
"description": "Non-number reduce behavior\n\n\nPossible enum values:\n - `\"dropNN\"` Drop non-numbers\n - `\"replaceNN\"` Replace non-numbers",
"type": "string",
"enum": [
"dropNN",
"replaceNN"
],
"x-enum-description": {
"dropNN": "Drop non-numbers",
"replaceNN": "Replace non-numbers"
}
},
"replaceWithValue": {
"description": "Only valid when mode is replace",
"type": "number"
}
},
"additionalProperties": false
},
"timeRange": {
"description": "TimeRange represents the query range\nNOTE: unlike generic /ds/query, we can now send explicit time values in each query\nNOTE: the values for timeRange are not saved in a dashboard, they are constructed on the fly",
"type": "object",
"required": [
"from",
"to"
],
"properties": {
"from": {
"description": "From is the start time of the query.",
"type": "string",
"default": "now-6h",
"examples": [
"now-1h"
]
},
"to": {
"description": "To is the end time of the query.",
"type": "string",
"default": "now",
"examples": [
"now"
]
}
},
"additionalProperties": false
},
"type": {
"type": "string",
"pattern": "^reduce$"
}
},
"additionalProperties": false,
"$schema": "https://json-schema.org/draft-04/schema"
},
{
"description": "QueryType = resample",
"type": "object",
"required": [
"expression",
"window",
"downsampler",
"upsampler",
"type",
"refId"
],
"properties": {
"datasource": {
"description": "The datasource",
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"description": "The datasource plugin type",
"type": "string",
"pattern": "^__expr__$"
},
"uid": {
"description": "Datasource UID",
"type": "string"
}
},
"additionalProperties": false
},
"downsampler": {
"description": "The downsample function\n\n\nPossible enum values:\n - `\"sum\"` \n - `\"mean\"` \n - `\"min\"` \n - `\"max\"` \n - `\"count\"` \n - `\"last\"` ",
"type": "string",
"enum": [
"sum",
"mean",
"min",
"max",
"count",
"last"
],
"x-enum-description": {}
},
"expression": {
"description": "The math expression",
"type": "string",
"minLength": 1,
"examples": [
"$A + 1",
"$A"
]
},
"hide": {
"description": "true if query is disabled (ie should not be returned to the dashboard)\nNOTE: this does not always imply that the query should not be executed since\nthe results from a hidden query may be used as the input to other queries (SSE etc)",
"type": "boolean"
},
"queryType": {
"description": "QueryType is an optional identifier for the type of query.\nIt can be used to distinguish different types of queries.",
"type": "string"
},
"refId": {
"description": "RefID is the unique identifier of the query, set by the frontend call.",
"type": "string"
},
"resultAssertions": {
"description": "Optionally define expected query result behavior",
"type": "object",
"required": [
"typeVersion"
],
"properties": {
"maxFrames": {
"description": "Maximum frame count",
"type": "integer"
},
"type": {
"description": "Type asserts that the frame matches a known type structure.\n\n\nPossible enum values:\n - `\"\"` \n - `\"timeseries-wide\"` \n - `\"timeseries-long\"` \n - `\"timeseries-many\"` \n - `\"timeseries-multi\"` \n - `\"directory-listing\"` \n - `\"table\"` \n - `\"numeric-wide\"` \n - `\"numeric-multi\"` \n - `\"numeric-long\"` \n - `\"log-lines\"` ",
"type": "string",
"enum": [
"",
"timeseries-wide",
"timeseries-long",
"timeseries-many",
"timeseries-multi",
"directory-listing",
"table",
"numeric-wide",
"numeric-multi",
"numeric-long",
"log-lines"
],
"x-enum-description": {}
},
"typeVersion": {
"description": "TypeVersion is the version of the Type property. Versions greater than 0.0 correspond to the dataplane\ncontract documentation https://grafana.github.io/dataplane/contract/.",
"type": "array",
"maxItems": 2,
"minItems": 2,
"items": {
"type": "integer"
}
}
},
"additionalProperties": false
},
"timeRange": {
"description": "TimeRange represents the query range\nNOTE: unlike generic /ds/query, we can now send explicit time values in each query\nNOTE: the values for timeRange are not saved in a dashboard, they are constructed on the fly",
"type": "object",
"required": [
"from",
"to"
],
"properties": {
"from": {
"description": "From is the start time of the query.",
"type": "string",
"default": "now-6h",
"examples": [
"now-1h"
]
},
"to": {
"description": "To is the end time of the query.",
"type": "string",
"default": "now",
"examples": [
"now"
]
}
},
"additionalProperties": false
},
"type": {
"type": "string",
"pattern": "^resample$"
},
"upsampler": {
"description": "The upsample function\n\n\nPossible enum values:\n - `\"pad\"` Use the last seen value\n - `\"backfilling\"` backfill\n - `\"fillna\"` Do not fill values (nill)",
"type": "string",
"enum": [
"pad",
"backfilling",
"fillna"
],
"x-enum-description": {
"backfilling": "backfill",
"fillna": "Do not fill values (nill)",
"pad": "Use the last seen value"
}
},
"window": {
"description": "The time duration",
"type": "string",
"minLength": 1,
"examples": [
"1d",
"10m"
]
}
},
"additionalProperties": false,
"$schema": "https://json-schema.org/draft-04/schema"
},
{
"type": "object",
"required": [
"conditions",
"type",
"refId"
],
"properties": {
"conditions": {
"type": "array",
"items": {
"description": "ConditionJSON is the JSON model for a single condition in ConditionsCmd.",
"type": "object",
"required": [
"evaluator",
"operator",
"query",
"reducer"
],
"properties": {
"evaluator": {
"type": "object",
"required": [
"params",
"type"
],
"properties": {
"params": {
"type": "array",
"items": {
"type": "number"
}
},
"type": {
"description": "e.g. \"gt\"",
"type": "string"
}
},
"additionalProperties": false
},
"operator": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"and",
"or"
],
"x-enum-description": {}
}
},
"additionalProperties": false
},
"query": {
"type": "object",
"required": [
"params"
],
"properties": {
"params": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false
},
"reducer": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
},
"datasource": {
"description": "The datasource",
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"description": "The datasource plugin type",
"type": "string",
"pattern": "^__expr__$"
},
"uid": {
"description": "Datasource UID",
"type": "string"
}
},
"additionalProperties": false
},
"hide": {
"description": "true if query is disabled (ie should not be returned to the dashboard)\nNOTE: this does not always imply that the query should not be executed since\nthe results from a hidden query may be used as the input to other queries (SSE etc)",
"type": "boolean"
},
"queryType": {
"description": "QueryType is an optional identifier for the type of query.\nIt can be used to distinguish different types of queries.",
"type": "string"
},
"refId": {
"description": "RefID is the unique identifier of the query, set by the frontend call.",
"type": "string"
},
"resultAssertions": {
"description": "Optionally define expected query result behavior",
"type": "object",
"required": [
"typeVersion"
],
"properties": {
"maxFrames": {
"description": "Maximum frame count",
"type": "integer"
},
"type": {
"description": "Type asserts that the frame matches a known type structure.\n\n\nPossible enum values:\n - `\"\"` \n - `\"timeseries-wide\"` \n - `\"timeseries-long\"` \n - `\"timeseries-many\"` \n - `\"timeseries-multi\"` \n - `\"directory-listing\"` \n - `\"table\"` \n - `\"numeric-wide\"` \n - `\"numeric-multi\"` \n - `\"numeric-long\"` \n - `\"log-lines\"` ",
"type": "string",
"enum": [
"",
"timeseries-wide",
"timeseries-long",
"timeseries-many",
"timeseries-multi",
"directory-listing",
"table",
"numeric-wide",
"numeric-multi",
"numeric-long",
"log-lines"
],
"x-enum-description": {}
},
"typeVersion": {
"description": "TypeVersion is the version of the Type property. Versions greater than 0.0 correspond to the dataplane\ncontract documentation https://grafana.github.io/dataplane/contract/.",
"type": "array",
"maxItems": 2,
"minItems": 2,
"items": {
"type": "integer"
}
}
},
"additionalProperties": false
},
"timeRange": {
"description": "TimeRange represents the query range\nNOTE: unlike generic /ds/query, we can now send explicit time values in each query\nNOTE: the values for timeRange are not saved in a dashboard, they are constructed on the fly",
"type": "object",
"required": [
"from",
"to"
],
"properties": {
"from": {
"description": "From is the start time of the query.",
"type": "string",
"default": "now-6h",
"examples": [
"now-1h"
]
},
"to": {
"description": "To is the end time of the query.",
"type": "string",
"default": "now",
"examples": [
"now"
]
}
},
"additionalProperties": false
},
"type": {
"type": "string",
"pattern": "^classic_conditions$"
}
},
"additionalProperties": false,
"$schema": "https://json-schema.org/draft-04/schema"
},
{
"type": "object",
"required": [
"expression",
"conditions",
"type",
"refId"
],
"properties": {
"conditions": {
"description": "Threshold Conditions",
"type": "array",
"items": {
"type": "object",
"required": [
"evaluator"
],
"properties": {
"evaluator": {
"type": "object",
"required": [
"params",
"type"
],
"properties": {
"params": {
"type": "array",
"items": {
"type": "number"
}
},
"type": {
"description": "e.g. \"gt\"",
"type": "string",
"enum": [
"gt",
"lt",
"within_range",
"outside_range"
],
"x-enum-description": {}
}
},
"additionalProperties": false
},
"loadedDimensions": {
"type": "object",
"additionalProperties": true,
"x-grafana-type": "data.DataFrame"
},
"unloadEvaluator": {
"type": "object",
"required": [
"params",
"type"
],
"properties": {
"params": {
"type": "array",
"items": {
"type": "number"
}
},
"type": {
"description": "e.g. \"gt\"",
"type": "string",
"enum": [
"gt",
"lt",
"within_range",
"outside_range"
],
"x-enum-description": {}
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
},
"datasource": {
"description": "The datasource",
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"description": "The datasource plugin type",
"type": "string",
"pattern": "^__expr__$"
},
"uid": {
"description": "Datasource UID",
"type": "string"
}
},
"additionalProperties": false
},
"expression": {
"description": "Reference to single query result",
"type": "string",
"minLength": 1,
"examples": [
"$A"
]
},
"hide": {
"description": "true if query is disabled (ie should not be returned to the dashboard)\nNOTE: this does not always imply that the query should not be executed since\nthe results from a hidden query may be used as the input to other queries (SSE etc)",
"type": "boolean"
},
"queryType": {
"description": "QueryType is an optional identifier for the type of query.\nIt can be used to distinguish different types of queries.",
"type": "string"
},
"refId": {
"description": "RefID is the unique identifier of the query, set by the frontend call.",
"type": "string"
},
"resultAssertions": {
"description": "Optionally define expected query result behavior",
"type": "object",
"required": [
"typeVersion"
],
"properties": {
"maxFrames": {
"description": "Maximum frame count",
"type": "integer"
},
"type": {
"description": "Type asserts that the frame matches a known type structure.\n\n\nPossible enum values:\n - `\"\"` \n - `\"timeseries-wide\"` \n - `\"timeseries-long\"` \n - `\"timeseries-many\"` \n - `\"timeseries-multi\"` \n - `\"directory-listing\"` \n - `\"table\"` \n - `\"numeric-wide\"` \n - `\"numeric-multi\"` \n - `\"numeric-long\"` \n - `\"log-lines\"` ",
"type": "string",
"enum": [
"",
"timeseries-wide",
"timeseries-long",
"timeseries-many",
"timeseries-multi",
"directory-listing",
"table",
"numeric-wide",
"numeric-multi",
"numeric-long",
"log-lines"
],
"x-enum-description": {}
},
"typeVersion": {
"description": "TypeVersion is the version of the Type property. Versions greater than 0.0 correspond to the dataplane\ncontract documentation https://grafana.github.io/dataplane/contract/.",
"type": "array",
"maxItems": 2,
"minItems": 2,
"items": {
"type": "integer"
}
}
},
"additionalProperties": false
},
"timeRange": {
"description": "TimeRange represents the query range\nNOTE: unlike generic /ds/query, we can now send explicit time values in each query\nNOTE: the values for timeRange are not saved in a dashboard, they are constructed on the fly",
"type": "object",
"required": [
"from",
"to"
],
"properties": {
"from": {
"description": "From is the start time of the query.",
"type": "string",
"default": "now-6h",
"examples": [
"now-1h"
]
},
"to": {
"description": "To is the end time of the query.",
"type": "string",
"default": "now",
"examples": [
"now"
]
}
},
"additionalProperties": false
},
"type": {
"type": "string",
"pattern": "^threshold$"
}
},
"additionalProperties": false,
"$schema": "https://json-schema.org/draft-04/schema"
},
{
"description": "SQLQuery requires the sqlExpression feature flag",
"type": "object",
"required": [
"expression",
"type",
"refId"
],
"properties": {
"datasource": {
"description": "The datasource",
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"description": "The datasource plugin type",
"type": "string",
"pattern": "^__expr__$"
},
"uid": {
"description": "Datasource UID",
"type": "string"
}
},
"additionalProperties": false
},
"expression": {
"type": "string",
"minLength": 1,
"examples": [
"SELECT * FROM A LIMIT 1"
]
},
"hide": {
"description": "true if query is disabled (ie should not be returned to the dashboard)\nNOTE: this does not always imply that the query should not be executed since\nthe results from a hidden query may be used as the input to other queries (SSE etc)",
"type": "boolean"
},
"queryType": {
"description": "QueryType is an optional identifier for the type of query.\nIt can be used to distinguish different types of queries.",
"type": "string"
},
"refId": {
"description": "RefID is the unique identifier of the query, set by the frontend call.",
"type": "string"
},
"resultAssertions": {
"description": "Optionally define expected query result behavior",
"type": "object",
"required": [
"typeVersion"
],
"properties": {
"maxFrames": {
"description": "Maximum frame count",
"type": "integer"
},
"type": {
"description": "Type asserts that the frame matches a known type structure.\n\n\nPossible enum values:\n - `\"\"` \n - `\"timeseries-wide\"` \n - `\"timeseries-long\"` \n - `\"timeseries-many\"` \n - `\"timeseries-multi\"` \n - `\"directory-listing\"` \n - `\"table\"` \n - `\"numeric-wide\"` \n - `\"numeric-multi\"` \n - `\"numeric-long\"` \n - `\"log-lines\"` ",
"type": "string",
"enum": [
"",
"timeseries-wide",
"timeseries-long",
"timeseries-many",
"timeseries-multi",
"directory-listing",
"table",
"numeric-wide",
"numeric-multi",
"numeric-long",
"log-lines"
],
"x-enum-description": {}
},
"typeVersion": {
"description": "TypeVersion is the version of the Type property. Versions greater than 0.0 correspond to the dataplane\ncontract documentation https://grafana.github.io/dataplane/contract/.",
"type": "array",
"maxItems": 2,
"minItems": 2,
"items": {
"type": "integer"
}
}
},
"additionalProperties": false
},
"timeRange": {
"description": "TimeRange represents the query range\nNOTE: unlike generic /ds/query, we can now send explicit time values in each query\nNOTE: the values for timeRange are not saved in a dashboard, they are constructed on the fly",
"type": "object",
"required": [
"from",
"to"
],
"properties": {
"from": {
"description": "From is the start time of the query.",
"type": "string",
"default": "now-6h",
"examples": [
"now-1h"
]
},
"to": {
"description": "To is the end time of the query.",
"type": "string",
"default": "now",
"examples": [
"now"
]
}
},
"additionalProperties": false
},
"type": {
"type": "string",
"pattern": "^sql$"
}
},
"additionalProperties": false,
"$schema": "https://json-schema.org/draft-04/schema"
}
],
"$schema": "https://json-schema.org/draft-04/schema#"
}
},
"type": {
"description": "the panel type",
"type": "string"
}
},
"additionalProperties": true,
"$schema": "https://json-schema.org/draft-04/schema#"
}

View File

@ -0,0 +1,147 @@
{
"from": "now-1h",
"to": "now",
"queries": [
{
"refId": "A",
"maxDataPoints": 1000,
"intervalMs": 5,
"expression": "$A + 10",
"type": "math"
},
{
"refId": "B",
"maxDataPoints": 1000,
"intervalMs": 5,
"type": "math",
"expression": "$A - $B"
},
{
"refId": "C",
"maxDataPoints": 1000,
"intervalMs": 5,
"expression": "$A",
"reducer": "max",
"settings": {
"mode": "dropNN"
},
"type": "reduce"
},
{
"refId": "D",
"maxDataPoints": 1000,
"intervalMs": 5,
"upsampler": "pad",
"type": "resample",
"expression": "$A",
"window": "1d",
"downsampler": "last"
},
{
"refId": "E",
"maxDataPoints": 1000,
"intervalMs": 5,
"conditions": [
{
"evaluator": {
"params": [
5
],
"type": "gt"
},
"operator": {
"type": "and"
},
"query": {
"params": [
"A"
]
},
"reducer": {
"type": "max"
}
}
],
"type": "classic_conditions"
},
{
"refId": "F",
"maxDataPoints": 1000,
"intervalMs": 5,
"expression": "A",
"conditions": [
{
"evaluator": {
"params": [
5
],
"type": "gt"
}
}
],
"type": "threshold"
},
{
"refId": "G",
"maxDataPoints": 1000,
"intervalMs": 5,
"expression": "B",
"conditions": [
{
"evaluator": {
"params": [
100
],
"type": "gt"
},
"loadedDimensions": {
"data": {
"values": [
[
18446744073709552000,
2,
3,
4,
5
]
]
},
"schema": {
"fields": [
{
"name": "fingerprints",
"type": "number",
"typeInfo": {
"frame": "uint64"
}
}
],
"meta": {
"type": "fingerprints",
"typeVersion": [
1,
0
]
},
"name": "test"
}
},
"unloadEvaluator": {
"params": [
31
],
"type": "lt"
}
}
],
"type": "threshold"
},
{
"refId": "H",
"maxDataPoints": 1000,
"intervalMs": 5,
"expression": "SELECT * FROM A limit 1",
"type": "sql"
}
]
}

File diff suppressed because it is too large Load Diff

579
pkg/expr/query.types.json Normal file
View File

@ -0,0 +1,579 @@
{
"kind": "QueryTypeDefinitionList",
"apiVersion": "query.grafana.app/v0alpha1",
"metadata": {
"resourceVersion": "1709168280033"
},
"items": [
{
"metadata": {
"name": "math",
"resourceVersion": "1709915973363",
"creationTimestamp": "2024-02-21T22:09:26Z"
},
"spec": {
"discriminators": [
{
"field": "type",
"value": "math"
}
],
"schema": {
"$schema": "https://json-schema.org/draft-04/schema",
"additionalProperties": false,
"properties": {
"expression": {
"description": "General math expression",
"examples": [
"$A + 1",
"$A/$B"
],
"minLength": 1,
"type": "string"
}
},
"required": [
"expression"
],
"type": "object"
},
"examples": [
{
"name": "constant addition",
"saveModel": {
"expression": "$A + 10"
}
},
{
"name": "math with two queries",
"saveModel": {
"expression": "$A - $B"
}
}
]
}
},
{
"metadata": {
"name": "reduce",
"resourceVersion": "1709915979242",
"creationTimestamp": "2024-02-21T22:09:26Z"
},
"spec": {
"discriminators": [
{
"field": "type",
"value": "reduce"
}
],
"schema": {
"$schema": "https://json-schema.org/draft-04/schema",
"additionalProperties": false,
"properties": {
"expression": {
"description": "Reference to single query result",
"examples": [
"$A"
],
"minLength": 1,
"type": "string"
},
"reducer": {
"description": "The reducer\n\n\nPossible enum values:\n - `\"sum\"` \n - `\"mean\"` \n - `\"min\"` \n - `\"max\"` \n - `\"count\"` \n - `\"last\"` ",
"enum": [
"sum",
"mean",
"min",
"max",
"count",
"last"
],
"type": "string",
"x-enum-description": {}
},
"settings": {
"additionalProperties": false,
"description": "Reducer Options",
"properties": {
"mode": {
"description": "Non-number reduce behavior\n\n\nPossible enum values:\n - `\"dropNN\"` Drop non-numbers\n - `\"replaceNN\"` Replace non-numbers",
"enum": [
"dropNN",
"replaceNN"
],
"type": "string",
"x-enum-description": {
"dropNN": "Drop non-numbers",
"replaceNN": "Replace non-numbers"
}
},
"replaceWithValue": {
"description": "Only valid when mode is replace",
"type": "number"
}
},
"required": [
"mode"
],
"type": "object"
}
},
"required": [
"expression",
"reducer"
],
"type": "object"
},
"examples": [
{
"name": "get max value",
"saveModel": {
"expression": "$A",
"reducer": "max",
"settings": {
"mode": "dropNN"
}
}
}
]
}
},
{
"metadata": {
"name": "resample",
"resourceVersion": "1709915973363",
"creationTimestamp": "2024-02-21T22:09:26Z"
},
"spec": {
"discriminators": [
{
"field": "type",
"value": "resample"
}
],
"schema": {
"$schema": "https://json-schema.org/draft-04/schema",
"additionalProperties": false,
"description": "QueryType = resample",
"properties": {
"downsampler": {
"description": "The downsample function\n\n\nPossible enum values:\n - `\"sum\"` \n - `\"mean\"` \n - `\"min\"` \n - `\"max\"` \n - `\"count\"` \n - `\"last\"` ",
"enum": [
"sum",
"mean",
"min",
"max",
"count",
"last"
],
"type": "string",
"x-enum-description": {}
},
"expression": {
"description": "The math expression",
"examples": [
"$A + 1",
"$A"
],
"minLength": 1,
"type": "string"
},
"upsampler": {
"description": "The upsample function\n\n\nPossible enum values:\n - `\"pad\"` Use the last seen value\n - `\"backfilling\"` backfill\n - `\"fillna\"` Do not fill values (nill)",
"enum": [
"pad",
"backfilling",
"fillna"
],
"type": "string",
"x-enum-description": {
"backfilling": "backfill",
"fillna": "Do not fill values (nill)",
"pad": "Use the last seen value"
}
},
"window": {
"description": "The time duration",
"examples": [
"1d",
"10m"
],
"minLength": 1,
"type": "string"
}
},
"required": [
"expression",
"window",
"downsampler",
"upsampler"
],
"type": "object"
},
"examples": [
{
"name": "resample at a every day",
"saveModel": {
"downsampler": "last",
"expression": "$A",
"upsampler": "pad",
"window": "1d"
}
}
]
}
},
{
"metadata": {
"name": "classic_conditions",
"resourceVersion": "1709915973363",
"creationTimestamp": "2024-02-21T22:09:26Z"
},
"spec": {
"discriminators": [
{
"field": "type",
"value": "classic_conditions"
}
],
"schema": {
"$schema": "https://json-schema.org/draft-04/schema",
"additionalProperties": false,
"properties": {
"conditions": {
"items": {
"additionalProperties": false,
"description": "ConditionJSON is the JSON model for a single condition in ConditionsCmd.",
"properties": {
"evaluator": {
"additionalProperties": false,
"properties": {
"params": {
"items": {
"type": "number"
},
"type": "array"
},
"type": {
"description": "e.g. \"gt\"",
"type": "string"
}
},
"required": [
"params",
"type"
],
"type": "object"
},
"operator": {
"additionalProperties": false,
"properties": {
"type": {
"enum": [
"and",
"or"
],
"type": "string",
"x-enum-description": {}
}
},
"required": [
"type"
],
"type": "object"
},
"query": {
"additionalProperties": false,
"properties": {
"params": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"params"
],
"type": "object"
},
"reducer": {
"additionalProperties": false,
"properties": {
"type": {
"type": "string"
}
},
"required": [
"type"
],
"type": "object"
}
},
"required": [
"evaluator",
"operator",
"query",
"reducer"
],
"type": "object"
},
"type": "array"
}
},
"required": [
"conditions"
],
"type": "object"
},
"examples": [
{
"name": "Where query A \u003e 5",
"saveModel": {
"conditions": [
{
"evaluator": {
"params": [
5
],
"type": "gt"
},
"operator": {
"type": "and"
},
"query": {
"params": [
"A"
]
},
"reducer": {
"type": "max"
}
}
]
}
}
]
}
},
{
"metadata": {
"name": "threshold",
"resourceVersion": "1709915973363",
"creationTimestamp": "2024-02-21T22:09:26Z"
},
"spec": {
"discriminators": [
{
"field": "type",
"value": "threshold"
}
],
"schema": {
"$schema": "https://json-schema.org/draft-04/schema",
"additionalProperties": false,
"properties": {
"conditions": {
"description": "Threshold Conditions",
"items": {
"additionalProperties": false,
"properties": {
"evaluator": {
"additionalProperties": false,
"properties": {
"params": {
"items": {
"type": "number"
},
"type": "array"
},
"type": {
"description": "e.g. \"gt\"",
"enum": [
"gt",
"lt",
"within_range",
"outside_range"
],
"type": "string",
"x-enum-description": {}
}
},
"required": [
"params",
"type"
],
"type": "object"
},
"loadedDimensions": {
"additionalProperties": true,
"type": "object",
"x-grafana-type": "data.DataFrame"
},
"unloadEvaluator": {
"additionalProperties": false,
"properties": {
"params": {
"items": {
"type": "number"
},
"type": "array"
},
"type": {
"description": "e.g. \"gt\"",
"enum": [
"gt",
"lt",
"within_range",
"outside_range"
],
"type": "string",
"x-enum-description": {}
}
},
"required": [
"params",
"type"
],
"type": "object"
}
},
"required": [
"evaluator"
],
"type": "object"
},
"type": "array"
},
"expression": {
"description": "Reference to single query result",
"examples": [
"$A"
],
"minLength": 1,
"type": "string"
}
},
"required": [
"expression",
"conditions"
],
"type": "object"
},
"examples": [
{
"name": "Where query A \u003e 5",
"saveModel": {
"conditions": [
{
"evaluator": {
"params": [
5
],
"type": "gt"
}
}
],
"expression": "A"
}
},
{
"name": "With loaded+unloaded evaluators",
"saveModel": {
"conditions": [
{
"evaluator": {
"params": [
100
],
"type": "gt"
},
"loadedDimensions": {
"data": {
"values": [
[
18446744073709552000,
2,
3,
4,
5
]
]
},
"schema": {
"fields": [
{
"name": "fingerprints",
"type": "number",
"typeInfo": {
"frame": "uint64"
}
}
],
"meta": {
"type": "fingerprints",
"typeVersion": [
1,
0
]
},
"name": "test"
}
},
"unloadEvaluator": {
"params": [
31
],
"type": "lt"
}
}
],
"expression": "B"
}
}
]
}
},
{
"metadata": {
"name": "sql",
"resourceVersion": "1709915973363",
"creationTimestamp": "2024-02-29T00:58:00Z"
},
"spec": {
"discriminators": [
{
"field": "type",
"value": "sql"
}
],
"schema": {
"$schema": "https://json-schema.org/draft-04/schema",
"additionalProperties": false,
"description": "SQLQuery requires the sqlExpression feature flag",
"properties": {
"expression": {
"examples": [
"SELECT * FROM A LIMIT 1"
],
"minLength": 1,
"type": "string"
}
},
"required": [
"expression"
],
"type": "object"
},
"examples": [
{
"name": "Select the first row from A",
"saveModel": {
"expression": "SELECT * FROM A limit 1"
}
}
]
}
}
]
}

174
pkg/expr/query_test.go Normal file
View File

@ -0,0 +1,174 @@
package expr
import (
"encoding/json"
"reflect"
"testing"
data "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1"
"github.com/grafana/grafana-plugin-sdk-go/experimental/schemabuilder"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/expr/classic"
"github.com/grafana/grafana/pkg/expr/mathexp"
)
func TestQueryTypeDefinitions(t *testing.T) {
builder, err := schemabuilder.NewSchemaBuilder(
schemabuilder.BuilderOptions{
PluginID: []string{DatasourceType},
ScanCode: []schemabuilder.CodePaths{{
BasePackage: "github.com/grafana/grafana/pkg/expr",
CodePath: "./",
}},
Enums: []reflect.Type{
reflect.TypeOf(mathexp.ReducerSum), // pick an example value (not the root)
reflect.TypeOf(mathexp.UpsamplerPad), // pick an example value (not the root)
reflect.TypeOf(ReduceModeDrop), // pick an example value (not the root)
reflect.TypeOf(ThresholdIsAbove),
reflect.TypeOf(classic.ConditionOperatorAnd),
},
})
require.NoError(t, err)
err = builder.AddQueries(
schemabuilder.QueryTypeInfo{
Discriminators: data.NewDiscriminators("type", QueryTypeMath),
GoType: reflect.TypeOf(&MathQuery{}),
Examples: []data.QueryExample{
{
Name: "constant addition",
SaveModel: data.AsUnstructured(MathQuery{
Expression: "$A + 10",
}),
},
{
Name: "math with two queries",
SaveModel: data.AsUnstructured(MathQuery{
Expression: "$A - $B",
}),
},
},
},
schemabuilder.QueryTypeInfo{
Discriminators: data.NewDiscriminators("type", QueryTypeReduce),
GoType: reflect.TypeOf(&ReduceQuery{}),
Examples: []data.QueryExample{
{
Name: "get max value",
SaveModel: data.AsUnstructured(ReduceQuery{
Expression: "$A",
Reducer: mathexp.ReducerMax,
Settings: &ReduceSettings{
Mode: ReduceModeDrop,
},
}),
},
},
},
schemabuilder.QueryTypeInfo{
Discriminators: data.NewDiscriminators("type", QueryTypeResample),
GoType: reflect.TypeOf(&ResampleQuery{}),
Examples: []data.QueryExample{
{
Name: "resample at a every day",
SaveModel: data.AsUnstructured(ResampleQuery{
Expression: "$A",
Window: "1d",
Downsampler: mathexp.ReducerLast,
Upsampler: mathexp.UpsamplerPad,
}),
},
},
},
schemabuilder.QueryTypeInfo{
Discriminators: data.NewDiscriminators("type", QueryTypeSQL),
GoType: reflect.TypeOf(&SQLExpression{}),
Examples: []data.QueryExample{
{
Name: "Select the first row from A",
SaveModel: data.AsUnstructured(SQLExpression{
Expression: "SELECT * FROM A limit 1",
}),
},
},
},
schemabuilder.QueryTypeInfo{
Discriminators: data.NewDiscriminators("type", QueryTypeClassic),
GoType: reflect.TypeOf(&ClassicQuery{}),
Examples: []data.QueryExample{
{
Name: "Where query A > 5",
SaveModel: data.AsUnstructured(ClassicQuery{
Conditions: []classic.ConditionJSON{
{
Query: classic.ConditionQueryJSON{
Params: []string{"A"},
},
Reducer: classic.ConditionReducerJSON{
Type: "max",
},
Operator: classic.ConditionOperatorJSON{
Type: "and",
},
Evaluator: classic.ConditionEvalJSON{
Type: "gt",
Params: []float64{5},
},
},
},
}),
},
},
},
schemabuilder.QueryTypeInfo{
Discriminators: data.NewDiscriminators("type", QueryTypeThreshold),
GoType: reflect.TypeOf(&ThresholdQuery{}),
Examples: []data.QueryExample{
{
Name: "Where query A > 5",
SaveModel: data.AsUnstructured(ThresholdQuery{
Expression: "A",
Conditions: []ThresholdConditionJSON{{
Evaluator: ConditionEvalJSON{
Type: ThresholdIsAbove,
Params: []float64{5},
},
}},
}),
},
{
Name: "With loaded+unloaded evaluators",
SaveModel: toUnstructured(`{
"expression": "B",
"conditions": [
{
"evaluator": {
"params": [
100
],
"type": "gt"
},
"unloadEvaluator": {
"params": [
31
],
"type": "lt"
},
"loadedDimensions": {"schema":{"name":"test","meta":{"type":"fingerprints","typeVersion":[1,0]},"fields":[{"name":"fingerprints","type":"number","typeInfo":{"frame":"uint64"}}]},"data":{"values":[[18446744073709551615,2,3,4,5]]}}
}
]
}`),
},
},
},
)
require.NoError(t, err)
_ = builder.UpdateQueryDefinition(t, "./")
}
func toUnstructured(ex string) data.Unstructured {
v := data.Unstructured{}
_ = json.Unmarshal([]byte(ex), &v.Object)
return v
}

View File

@ -1,6 +1,7 @@
package expr
import (
"embed"
"fmt"
"strings"
@ -177,6 +178,13 @@ func (h *ExpressionQueryReader) ReadQuery(
return eq, err
}
//go:embed query.types.json
var f embed.FS
func (h *ExpressionQueryReader) QueryTypeDefinitionListJSON() ([]byte, error) {
return f.ReadFile("query.types.json")
}
func getReferenceVar(exp string, refId string) (string, error) {
exp = strings.TrimPrefix(exp, "$")
if exp == "" {

View File

@ -173,8 +173,8 @@ type ThresholdCommandConfig struct {
type ThresholdConditionJSON struct {
Evaluator ConditionEvalJSON `json:"evaluator"`
UnloadEvaluator *ConditionEvalJSON `json:"unloadEvaluator"`
LoadedDimensions *data.Frame `json:"loadedDimensions"`
UnloadEvaluator *ConditionEvalJSON `json:"unloadEvaluator,omitempty"`
LoadedDimensions *data.Frame `json:"loadedDimensions,omitempty"`
}
// IsHysteresisExpression returns true if the raw model describes a hysteresis command:

View File

@ -88,16 +88,6 @@ func GetComposableKinds() ([]ComposableKind, error) {
CueFile: grafanapyroscopeCue,
})
grafanatestdatadatasourceCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/datasource/grafana-testdata-datasource/dataquery.cue"))
if err != nil {
return nil, err
}
kinds = append(kinds, ComposableKind{
Name: "grafanatestdatadatasource",
Filename: "dataquery.cue",
CueFile: grafanatestdatadatasourceCue,
})
lokiCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/datasource/loki/dataquery.cue"))
if err != nil {
return nil, err

View File

@ -26,7 +26,7 @@ func (s *Service) handleCsvContentScenario(ctx context.Context, req *backend.Que
return nil, fmt.Errorf("failed to parse query json: %v", err)
}
csvContent := model.CSVContent
csvContent := model.CsvContent
if len(csvContent) == 0 {
return backend.NewQueryDataResponse(), nil
}
@ -63,7 +63,7 @@ func (s *Service) handleCsvFileScenario(ctx context.Context, req *backend.QueryD
return nil, fmt.Errorf("failed to parse query json %v", err)
}
fileName := model.CSVFileName
fileName := model.CsvFileName
if len(fileName) == 0 {
continue

View File

@ -1,211 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
//
// Generated by:
// public/app/plugins/gen.go
// Using jennies:
// PluginGoTypesJenny
//
// Run 'make gen-cue' from repository root to regenerate.
package dataquery
// Defines values for NodesQueryType.
const (
NodesQueryTypeFeatureShowcase NodesQueryType = "feature_showcase"
NodesQueryTypeRandom NodesQueryType = "random"
NodesQueryTypeRandomEdges NodesQueryType = "random edges"
NodesQueryTypeResponseMedium NodesQueryType = "response_medium"
NodesQueryTypeResponseSmall NodesQueryType = "response_small"
)
// Defines values for StreamingQueryType.
const (
StreamingQueryTypeFetch StreamingQueryType = "fetch"
StreamingQueryTypeLogs StreamingQueryType = "logs"
StreamingQueryTypeSignal StreamingQueryType = "signal"
StreamingQueryTypeTraces StreamingQueryType = "traces"
)
// Defines values for TestDataDataQueryErrorType.
const (
TestDataDataQueryErrorTypeFrontendException TestDataDataQueryErrorType = "frontend_exception"
TestDataDataQueryErrorTypeFrontendObservable TestDataDataQueryErrorType = "frontend_observable"
TestDataDataQueryErrorTypeServerPanic TestDataDataQueryErrorType = "server_panic"
)
// Defines values for TestDataQueryType.
const (
TestDataQueryTypeAnnotations TestDataQueryType = "annotations"
TestDataQueryTypeArrow TestDataQueryType = "arrow"
TestDataQueryTypeCsvContent TestDataQueryType = "csv_content"
TestDataQueryTypeCsvFile TestDataQueryType = "csv_file"
TestDataQueryTypeCsvMetricValues TestDataQueryType = "csv_metric_values"
TestDataQueryTypeDatapointsOutsideRange TestDataQueryType = "datapoints_outside_range"
TestDataQueryTypeExponentialHeatmapBucketData TestDataQueryType = "exponential_heatmap_bucket_data"
TestDataQueryTypeFlameGraph TestDataQueryType = "flame_graph"
TestDataQueryTypeGrafanaApi TestDataQueryType = "grafana_api"
TestDataQueryTypeLinearHeatmapBucketData TestDataQueryType = "linear_heatmap_bucket_data"
TestDataQueryTypeLive TestDataQueryType = "live"
TestDataQueryTypeLogs TestDataQueryType = "logs"
TestDataQueryTypeManualEntry TestDataQueryType = "manual_entry"
TestDataQueryTypeNoDataPoints TestDataQueryType = "no_data_points"
TestDataQueryTypeNodeGraph TestDataQueryType = "node_graph"
TestDataQueryTypePredictableCsvWave TestDataQueryType = "predictable_csv_wave"
TestDataQueryTypePredictablePulse TestDataQueryType = "predictable_pulse"
TestDataQueryTypeRandomWalk TestDataQueryType = "random_walk"
TestDataQueryTypeRandomWalkTable TestDataQueryType = "random_walk_table"
TestDataQueryTypeRandomWalkWithError TestDataQueryType = "random_walk_with_error"
TestDataQueryTypeRawFrame TestDataQueryType = "raw_frame"
TestDataQueryTypeServerError500 TestDataQueryType = "server_error_500"
TestDataQueryTypeSimulation TestDataQueryType = "simulation"
TestDataQueryTypeSlowQuery TestDataQueryType = "slow_query"
TestDataQueryTypeStreamingClient TestDataQueryType = "streaming_client"
TestDataQueryTypeTableStatic TestDataQueryType = "table_static"
TestDataQueryTypeTrace TestDataQueryType = "trace"
TestDataQueryTypeUsa TestDataQueryType = "usa"
TestDataQueryTypeVariablesQuery TestDataQueryType = "variables-query"
)
// CSVWave defines model for CSVWave.
type CSVWave struct {
Labels *string `json:"labels,omitempty"`
Name *string `json:"name,omitempty"`
TimeStep *int64 `json:"timeStep,omitempty"`
ValuesCSV *string `json:"valuesCSV,omitempty"`
}
// These are the common properties available to all queries in all datasources.
// Specific implementations will *extend* this interface, adding the required
// properties for the given context.
type DataQuery struct {
// For mixed data sources the selected datasource is on the query level.
// For non mixed scenarios this is undefined.
// TODO find a better way to do this ^ that's friendly to schema
// TODO this shouldn't be unknown but DataSourceRef | null
Datasource *any `json:"datasource,omitempty"`
// If hide is set to true, Grafana will filter out the response(s) associated with this query before returning it to the panel.
Hide *bool `json:"hide,omitempty"`
// Specify the query flavor
// TODO make this required and give it a default
QueryType *string `json:"queryType,omitempty"`
// A unique identifier for the query within the list of targets.
// In server side expressions, the refId is used as a variable name to identify results.
// By default, the UI will assign A->Z; however setting meaningful names may be useful.
RefId string `json:"refId"`
}
// NodesQuery defines model for NodesQuery.
type NodesQuery struct {
Count *int64 `json:"count,omitempty"`
Seed *int64 `json:"seed,omitempty"`
Type *NodesQueryType `json:"type,omitempty"`
}
// NodesQueryType defines model for NodesQuery.Type.
type NodesQueryType string
// PulseWaveQuery defines model for PulseWaveQuery.
type PulseWaveQuery struct {
OffCount *int64 `json:"offCount,omitempty"`
OffValue *float64 `json:"offValue,omitempty"`
OnCount *int64 `json:"onCount,omitempty"`
OnValue *float64 `json:"onValue,omitempty"`
TimeStep *int64 `json:"timeStep,omitempty"`
}
// TODO: Should this live here given it's not used in the dataquery?
type Scenario struct {
Description *string `json:"description,omitempty"`
HideAliasField *bool `json:"hideAliasField,omitempty"`
Id string `json:"id"`
Name string `json:"name"`
StringInput string `json:"stringInput"`
}
// SimulationQuery defines model for SimulationQuery.
type SimulationQuery struct {
Config map[string]any `json:"config,omitempty"`
Key struct {
Tick float64 `json:"tick"`
Type string `json:"type"`
Uid *string `json:"uid,omitempty"`
} `json:"key"`
Last *bool `json:"last,omitempty"`
Stream *bool `json:"stream,omitempty"`
}
// StreamingQuery defines model for StreamingQuery.
type StreamingQuery struct {
Bands *int32 `json:"bands,omitempty"`
Noise int32 `json:"noise"`
Speed int32 `json:"speed"`
Spread int32 `json:"spread"`
Type StreamingQueryType `json:"type"`
Url *string `json:"url,omitempty"`
}
// StreamingQueryType defines model for StreamingQuery.Type.
type StreamingQueryType string
// TestDataDataQuery defines model for TestDataDataQuery.
type TestDataDataQuery struct {
Alias *string `json:"alias,omitempty"`
Channel *string `json:"channel,omitempty"`
CsvContent *string `json:"csvContent,omitempty"`
CsvFileName *string `json:"csvFileName,omitempty"`
CsvWave []CSVWave `json:"csvWave,omitempty"`
// For mixed data sources the selected datasource is on the query level.
// For non mixed scenarios this is undefined.
// TODO find a better way to do this ^ that's friendly to schema
// TODO this shouldn't be unknown but DataSourceRef | null
Datasource *any `json:"datasource,omitempty"`
// Drop percentage (the chance we will lose a point 0-100)
DropPercent *float64 `json:"dropPercent,omitempty"`
ErrorType *TestDataDataQueryErrorType `json:"errorType,omitempty"`
FlamegraphDiff *bool `json:"flamegraphDiff,omitempty"`
// If hide is set to true, Grafana will filter out the response(s) associated with this query before returning it to the panel.
Hide *bool `json:"hide,omitempty"`
Labels *string `json:"labels,omitempty"`
LevelColumn *bool `json:"levelColumn,omitempty"`
Lines *int64 `json:"lines,omitempty"`
Nodes *NodesQuery `json:"nodes,omitempty"`
Points [][]any `json:"points,omitempty"`
PulseWave *PulseWaveQuery `json:"pulseWave,omitempty"`
// Specify the query flavor
// TODO make this required and give it a default
QueryType *string `json:"queryType,omitempty"`
RawFrameContent *string `json:"rawFrameContent,omitempty"`
// A unique identifier for the query within the list of targets.
// In server side expressions, the refId is used as a variable name to identify results.
// By default, the UI will assign A->Z; however setting meaningful names may be useful.
RefId *string `json:"refId,omitempty"`
ScenarioId *TestDataQueryType `json:"scenarioId,omitempty"`
SeriesCount *int32 `json:"seriesCount,omitempty"`
Sim *SimulationQuery `json:"sim,omitempty"`
SpanCount *int32 `json:"spanCount,omitempty"`
Stream *StreamingQuery `json:"stream,omitempty"`
StringInput *string `json:"stringInput,omitempty"`
Usa *USAQuery `json:"usa,omitempty"`
}
// TestDataDataQueryErrorType defines model for TestDataDataQuery.ErrorType.
type TestDataDataQueryErrorType string
// TestDataQueryType defines model for TestDataQueryType.
type TestDataQueryType string
// USAQuery defines model for USAQuery.
type USAQuery struct {
Fields []string `json:"fields,omitempty"`
Mode *string `json:"mode,omitempty"`
Period *string `json:"period,omitempty"`
States []string `json:"states,omitempty"`
}

View File

@ -0,0 +1,178 @@
package kinds
import (
"embed"
"encoding/json"
)
// NodesQueryType defines model for NodesQuery.Type.
// +enum
type NodesQueryType string
const (
NodesQueryTypeRandom NodesQueryType = "random"
NodesQueryTypeRandomEdges NodesQueryType = "random edges"
NodesQueryTypeResponseMedium NodesQueryType = "response_medium"
NodesQueryTypeResponseSmall NodesQueryType = "response_small"
NodesQueryTypeFeatureShowcase NodesQueryType = "feature_showcase"
)
// StreamingQueryType defines model for StreamingQuery.Type.
// +enum
type StreamingQueryType string
const (
StreamingQueryTypeFetch StreamingQueryType = "fetch"
StreamingQueryTypeLogs StreamingQueryType = "logs"
StreamingQueryTypeSignal StreamingQueryType = "signal"
StreamingQueryTypeTraces StreamingQueryType = "traces"
)
// ErrorType defines model for TestDataQuery.ErrorType.
// +enum
type ErrorType string
const (
ErrorTypeFrontendException ErrorType = "frontend_exception"
ErrorTypeFrontendObservable ErrorType = "frontend_observable"
ErrorTypeServerPanic ErrorType = "server_panic"
)
// TestDataQueryType defines model for TestDataQueryType.
// +enum
type TestDataQueryType string
// Defines values for TestDataQueryType.
const (
TestDataQueryTypeAnnotations TestDataQueryType = "annotations"
TestDataQueryTypeArrow TestDataQueryType = "arrow"
TestDataQueryTypeCsvContent TestDataQueryType = "csv_content"
TestDataQueryTypeCsvFile TestDataQueryType = "csv_file"
TestDataQueryTypeCsvMetricValues TestDataQueryType = "csv_metric_values"
TestDataQueryTypeDatapointsOutsideRange TestDataQueryType = "datapoints_outside_range"
TestDataQueryTypeExponentialHeatmapBucketData TestDataQueryType = "exponential_heatmap_bucket_data"
TestDataQueryTypeFlameGraph TestDataQueryType = "flame_graph"
TestDataQueryTypeGrafanaApi TestDataQueryType = "grafana_api"
TestDataQueryTypeLinearHeatmapBucketData TestDataQueryType = "linear_heatmap_bucket_data"
TestDataQueryTypeLive TestDataQueryType = "live"
TestDataQueryTypeLogs TestDataQueryType = "logs"
TestDataQueryTypeManualEntry TestDataQueryType = "manual_entry"
TestDataQueryTypeNoDataPoints TestDataQueryType = "no_data_points"
TestDataQueryTypeNodeGraph TestDataQueryType = "node_graph"
TestDataQueryTypePredictableCsvWave TestDataQueryType = "predictable_csv_wave"
TestDataQueryTypePredictablePulse TestDataQueryType = "predictable_pulse"
TestDataQueryTypeRandomWalk TestDataQueryType = "random_walk"
TestDataQueryTypeRandomWalkTable TestDataQueryType = "random_walk_table"
TestDataQueryTypeRandomWalkWithError TestDataQueryType = "random_walk_with_error"
TestDataQueryTypeRawFrame TestDataQueryType = "raw_frame"
TestDataQueryTypeServerError500 TestDataQueryType = "server_error_500"
TestDataQueryTypeSimulation TestDataQueryType = "simulation"
TestDataQueryTypeSlowQuery TestDataQueryType = "slow_query"
TestDataQueryTypeStreamingClient TestDataQueryType = "streaming_client"
TestDataQueryTypeTableStatic TestDataQueryType = "table_static"
TestDataQueryTypeTrace TestDataQueryType = "trace"
TestDataQueryTypeUsa TestDataQueryType = "usa"
TestDataQueryTypeVariablesQuery TestDataQueryType = "variables-query"
)
// TestDataQuery defines model for TestDataQuery.
type TestDataQuery struct {
ScenarioId TestDataQueryType `json:"scenarioId,omitempty"`
Alias string `json:"alias,omitempty"`
Labels string `json:"labels,omitempty"`
// common parameter used by many query types
StringInput string `json:"stringInput,omitempty"`
CsvContent string `json:"csvContent,omitempty"`
CsvFileName string `json:"csvFileName,omitempty"`
CsvWave []CSVWave `json:"csvWave,omitempty"`
// Used for live query
Channel string `json:"channel,omitempty"`
// Drop percentage (the chance we will lose a point 0-100)
DropPercent float64 `json:"dropPercent,omitempty"`
ErrorType ErrorType `json:"errorType,omitempty"`
FlamegraphDiff bool `json:"flamegraphDiff,omitempty"`
LevelColumn bool `json:"levelColumn,omitempty"`
StartValue float64 `json:"startValue,omitempty"`
Spread float64 `json:"spread,omitempty"`
Noise float64 `json:"noise,omitempty"`
Min *float64 `json:"min,omitempty"`
Max *float64 `json:"max,omitempty"`
WithNil bool `json:"withNil,omitempty"`
Lines int64 `json:"lines,omitempty"`
Points [][]any `json:"points,omitempty"`
RawFrameContent string `json:"rawFrameContent,omitempty"`
SeriesCount int `json:"seriesCount,omitempty"`
SpanCount int `json:"spanCount,omitempty"`
Nodes *NodesQuery `json:"nodes,omitempty"`
PulseWave *PulseWaveQuery `json:"pulseWave,omitempty"`
Sim *SimulationQuery `json:"sim,omitempty"`
Stream *StreamingQuery `json:"stream,omitempty"`
Usa *USAQuery `json:"usa,omitempty"`
}
// CSVWave defines model for CSVWave.
type CSVWave struct {
TimeStep int64 `json:"timeStep,omitempty"`
ValuesCSV string `json:"valuesCSV,omitempty"`
Labels string `json:"labels,omitempty"`
Name string `json:"name,omitempty"`
}
// NodesQuery defines model for NodesQuery.
type NodesQuery struct {
Count int64 `json:"count,omitempty"`
Seed int64 `json:"seed,omitempty"`
Type NodesQueryType `json:"type,omitempty"`
}
// PulseWaveQuery defines model for PulseWaveQuery.
type PulseWaveQuery struct {
OffCount int64 `json:"offCount,omitempty"`
OffValue float64 `json:"offValue,omitempty"`
OnCount int64 `json:"onCount,omitempty"`
OnValue float64 `json:"onValue,omitempty"`
TimeStep int64 `json:"timeStep,omitempty"`
}
// SimulationQuery defines model for SimulationQuery.
type SimulationQuery struct {
Config map[string]any `json:"config,omitempty"`
Key struct {
Tick float64 `json:"tick"`
Type string `json:"type"`
Uid *string `json:"uid,omitempty"`
} `json:"key"`
Last bool `json:"last,omitempty"`
Stream bool `json:"stream,omitempty"`
}
// StreamingQuery defines model for StreamingQuery.
type StreamingQuery struct {
Bands int32 `json:"bands,omitempty"`
Noise float64 `json:"noise"`
Speed float64 `json:"speed"`
Spread float64 `json:"spread"`
Type StreamingQueryType `json:"type"`
Url string `json:"url,omitempty"`
}
// USAQuery defines model for USAQuery.
type USAQuery struct {
Fields []string `json:"fields,omitempty"`
Mode string `json:"mode,omitempty"`
Period string `json:"period,omitempty"`
States []string `json:"states,omitempty"`
}
//go:embed query.types.json
var f embed.FS
// QueryTypeDefinitionsJSON returns the query type definitions
func QueryTypeDefinitionsJSON() (json.RawMessage, error) {
return f.ReadFile("query.types.json")
}

View File

@ -0,0 +1,28 @@
{
"type": "table",
"targets": [
{
"refId": "A",
"datasource": {
"type": "grafana-testdata-datasource",
"uid": "TheUID"
},
"scenarioId": "random_walk"
},
{
"refId": "B",
"datasource": {
"type": "grafana-testdata-datasource",
"uid": "TheUID"
},
"pulseWave": {
"offCount": 20,
"offValue": 1.23,
"onCount": 10,
"onValue": 4.56,
"timeStep": 1000
},
"scenarioId": "predictable_pulse"
}
]
}

View File

@ -0,0 +1,411 @@
{
"type": "object",
"required": [
"targets",
"type"
],
"properties": {
"targets": {
"type": "array",
"items": {
"description": "TestDataQuery defines model for TestDataQuery.",
"type": "object",
"properties": {
"alias": {
"type": "string"
},
"channel": {
"description": "Used for live query",
"type": "string"
},
"csvContent": {
"type": "string"
},
"csvFileName": {
"type": "string"
},
"csvWave": {
"type": "array",
"items": {
"description": "CSVWave defines model for CSVWave.",
"type": "object",
"properties": {
"labels": {
"type": "string"
},
"name": {
"type": "string"
},
"timeStep": {
"type": "integer"
},
"valuesCSV": {
"type": "string"
}
},
"additionalProperties": false
}
},
"datasource": {
"description": "The datasource",
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"description": "The datasource plugin type",
"type": "string",
"pattern": "^grafana-testdata-datasource$|^testdata$"
},
"uid": {
"description": "Datasource UID",
"type": "string"
}
},
"additionalProperties": false
},
"dropPercent": {
"description": "Drop percentage (the chance we will lose a point 0-100)",
"type": "number"
},
"errorType": {
"description": "Possible enum values:\n - `\"frontend_exception\"` \n - `\"frontend_observable\"` \n - `\"server_panic\"` ",
"type": "string",
"enum": [
"frontend_exception",
"frontend_observable",
"server_panic"
],
"x-enum-description": {}
},
"flamegraphDiff": {
"type": "boolean"
},
"hide": {
"description": "true if query is disabled (ie should not be returned to the dashboard)\nNOTE: this does not always imply that the query should not be executed since\nthe results from a hidden query may be used as the input to other queries (SSE etc)",
"type": "boolean"
},
"intervalMs": {
"description": "Interval is the suggested duration between time points in a time series query.\nNOTE: the values for intervalMs is not saved in the query model. It is typically calculated\nfrom the interval required to fill a pixels in the visualization",
"type": "number"
},
"labels": {
"type": "string"
},
"levelColumn": {
"type": "boolean"
},
"lines": {
"type": "integer"
},
"max": {
"type": "number"
},
"maxDataPoints": {
"description": "MaxDataPoints is the maximum number of data points that should be returned from a time series query.\nNOTE: the values for maxDataPoints is not saved in the query model. It is typically calculated\nfrom the number of pixels visible in a visualization",
"type": "integer"
},
"min": {
"type": "number"
},
"nodes": {
"type": "object",
"properties": {
"count": {
"type": "integer"
},
"seed": {
"type": "integer"
},
"type": {
"description": "Possible enum values:\n - `\"random\"` \n - `\"random edges\"` \n - `\"response_medium\"` \n - `\"response_small\"` \n - `\"feature_showcase\"` ",
"type": "string",
"enum": [
"random",
"random edges",
"response_medium",
"response_small",
"feature_showcase"
],
"x-enum-description": {}
}
},
"additionalProperties": false
},
"noise": {
"type": "number"
},
"points": {
"type": "array",
"items": {
"type": "array"
}
},
"pulseWave": {
"type": "object",
"properties": {
"offCount": {
"type": "integer"
},
"offValue": {
"type": "number"
},
"onCount": {
"type": "integer"
},
"onValue": {
"type": "number"
},
"timeStep": {
"type": "integer"
}
},
"additionalProperties": false
},
"queryType": {
"description": "QueryType is an optional identifier for the type of query.\nIt can be used to distinguish different types of queries.",
"type": "string"
},
"rawFrameContent": {
"type": "string"
},
"refId": {
"description": "RefID is the unique identifier of the query, set by the frontend call.",
"type": "string"
},
"resultAssertions": {
"description": "Optionally define expected query result behavior",
"type": "object",
"required": [
"typeVersion"
],
"properties": {
"maxFrames": {
"description": "Maximum frame count",
"type": "integer"
},
"type": {
"description": "Type asserts that the frame matches a known type structure.\n\n\nPossible enum values:\n - `\"\"` \n - `\"timeseries-wide\"` \n - `\"timeseries-long\"` \n - `\"timeseries-many\"` \n - `\"timeseries-multi\"` \n - `\"directory-listing\"` \n - `\"table\"` \n - `\"numeric-wide\"` \n - `\"numeric-multi\"` \n - `\"numeric-long\"` \n - `\"log-lines\"` ",
"type": "string",
"enum": [
"",
"timeseries-wide",
"timeseries-long",
"timeseries-many",
"timeseries-multi",
"directory-listing",
"table",
"numeric-wide",
"numeric-multi",
"numeric-long",
"log-lines"
],
"x-enum-description": {}
},
"typeVersion": {
"description": "TypeVersion is the version of the Type property. Versions greater than 0.0 correspond to the dataplane\ncontract documentation https://grafana.github.io/dataplane/contract/.",
"type": "array",
"maxItems": 2,
"minItems": 2,
"items": {
"type": "integer"
}
}
},
"additionalProperties": false
},
"scenarioId": {
"description": "Possible enum values:\n - `\"annotations\"` \n - `\"arrow\"` \n - `\"csv_content\"` \n - `\"csv_file\"` \n - `\"csv_metric_values\"` \n - `\"datapoints_outside_range\"` \n - `\"exponential_heatmap_bucket_data\"` \n - `\"flame_graph\"` \n - `\"grafana_api\"` \n - `\"linear_heatmap_bucket_data\"` \n - `\"live\"` \n - `\"logs\"` \n - `\"manual_entry\"` \n - `\"no_data_points\"` \n - `\"node_graph\"` \n - `\"predictable_csv_wave\"` \n - `\"predictable_pulse\"` \n - `\"random_walk\"` \n - `\"random_walk_table\"` \n - `\"random_walk_with_error\"` \n - `\"raw_frame\"` \n - `\"server_error_500\"` \n - `\"simulation\"` \n - `\"slow_query\"` \n - `\"streaming_client\"` \n - `\"table_static\"` \n - `\"trace\"` \n - `\"usa\"` \n - `\"variables-query\"` ",
"type": "string",
"enum": [
"annotations",
"arrow",
"csv_content",
"csv_file",
"csv_metric_values",
"datapoints_outside_range",
"exponential_heatmap_bucket_data",
"flame_graph",
"grafana_api",
"linear_heatmap_bucket_data",
"live",
"logs",
"manual_entry",
"no_data_points",
"node_graph",
"predictable_csv_wave",
"predictable_pulse",
"random_walk",
"random_walk_table",
"random_walk_with_error",
"raw_frame",
"server_error_500",
"simulation",
"slow_query",
"streaming_client",
"table_static",
"trace",
"usa",
"variables-query"
],
"x-enum-description": {}
},
"seriesCount": {
"type": "integer"
},
"sim": {
"type": "object",
"required": [
"key"
],
"properties": {
"config": {
"type": "object"
},
"key": {
"type": "object",
"required": [
"tick",
"type"
],
"properties": {
"tick": {
"type": "number"
},
"type": {
"type": "string"
},
"uid": {
"type": "string"
}
},
"additionalProperties": false
},
"last": {
"type": "boolean"
},
"stream": {
"type": "boolean"
}
},
"additionalProperties": false
},
"spanCount": {
"type": "integer"
},
"spread": {
"type": "number"
},
"startValue": {
"type": "number"
},
"stream": {
"type": "object",
"required": [
"noise",
"speed",
"spread",
"type"
],
"properties": {
"bands": {
"type": "integer"
},
"noise": {
"type": "number"
},
"speed": {
"type": "number"
},
"spread": {
"type": "number"
},
"type": {
"description": "Possible enum values:\n - `\"fetch\"` \n - `\"logs\"` \n - `\"signal\"` \n - `\"traces\"` ",
"type": "string",
"enum": [
"fetch",
"logs",
"signal",
"traces"
],
"x-enum-description": {}
},
"url": {
"type": "string"
}
},
"additionalProperties": false
},
"stringInput": {
"description": "common parameter used by many query types",
"type": "string"
},
"timeRange": {
"description": "TimeRange represents the query range\nNOTE: unlike generic /ds/query, we can now send explicit time values in each query\nNOTE: the values for timeRange are not saved in a dashboard, they are constructed on the fly",
"type": "object",
"required": [
"from",
"to"
],
"properties": {
"from": {
"description": "From is the start time of the query.",
"type": "string",
"default": "now-6h",
"examples": [
"now-1h"
]
},
"to": {
"description": "To is the end time of the query.",
"type": "string",
"default": "now",
"examples": [
"now"
]
}
},
"additionalProperties": false
},
"usa": {
"type": "object",
"properties": {
"fields": {
"type": "array",
"items": {
"type": "string"
}
},
"mode": {
"type": "string"
},
"period": {
"type": "string"
},
"states": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false
},
"withNil": {
"type": "boolean"
}
},
"additionalProperties": false,
"$schema": "https://json-schema.org/draft-04/schema#"
}
},
"type": {
"description": "the panel type",
"type": "string"
}
},
"additionalProperties": true,
"$schema": "https://json-schema.org/draft-04/schema#"
}

View File

@ -0,0 +1,25 @@
{
"from": "now-1h",
"to": "now",
"queries": [
{
"refId": "A",
"maxDataPoints": 1000,
"intervalMs": 5,
"scenarioId": "random_walk"
},
{
"refId": "B",
"maxDataPoints": 1000,
"intervalMs": 5,
"pulseWave": {
"offCount": 20,
"offValue": 1.23,
"onCount": 10,
"onValue": 4.56,
"timeStep": 1000
},
"scenarioId": "predictable_pulse"
}
]
}

View File

@ -0,0 +1,421 @@
{
"type": "object",
"required": [
"queries"
],
"properties": {
"$schema": {
"description": "helper",
"type": "string"
},
"debug": {
"type": "boolean"
},
"from": {
"description": "From Start time in epoch timestamps in milliseconds or relative using Grafana time units.",
"type": "string"
},
"queries": {
"type": "array",
"items": {
"description": "TestDataQuery defines model for TestDataQuery.",
"type": "object",
"properties": {
"alias": {
"type": "string"
},
"channel": {
"description": "Used for live query",
"type": "string"
},
"csvContent": {
"type": "string"
},
"csvFileName": {
"type": "string"
},
"csvWave": {
"type": "array",
"items": {
"description": "CSVWave defines model for CSVWave.",
"type": "object",
"properties": {
"labels": {
"type": "string"
},
"name": {
"type": "string"
},
"timeStep": {
"type": "integer"
},
"valuesCSV": {
"type": "string"
}
},
"additionalProperties": false
}
},
"datasource": {
"description": "The datasource",
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"description": "The datasource plugin type",
"type": "string",
"pattern": "^grafana-testdata-datasource$|^testdata$"
},
"uid": {
"description": "Datasource UID",
"type": "string"
}
},
"additionalProperties": false
},
"dropPercent": {
"description": "Drop percentage (the chance we will lose a point 0-100)",
"type": "number"
},
"errorType": {
"description": "Possible enum values:\n - `\"frontend_exception\"` \n - `\"frontend_observable\"` \n - `\"server_panic\"` ",
"type": "string",
"enum": [
"frontend_exception",
"frontend_observable",
"server_panic"
],
"x-enum-description": {}
},
"flamegraphDiff": {
"type": "boolean"
},
"hide": {
"description": "true if query is disabled (ie should not be returned to the dashboard)\nNOTE: this does not always imply that the query should not be executed since\nthe results from a hidden query may be used as the input to other queries (SSE etc)",
"type": "boolean"
},
"intervalMs": {
"description": "Interval is the suggested duration between time points in a time series query.\nNOTE: the values for intervalMs is not saved in the query model. It is typically calculated\nfrom the interval required to fill a pixels in the visualization",
"type": "number"
},
"labels": {
"type": "string"
},
"levelColumn": {
"type": "boolean"
},
"lines": {
"type": "integer"
},
"max": {
"type": "number"
},
"maxDataPoints": {
"description": "MaxDataPoints is the maximum number of data points that should be returned from a time series query.\nNOTE: the values for maxDataPoints is not saved in the query model. It is typically calculated\nfrom the number of pixels visible in a visualization",
"type": "integer"
},
"min": {
"type": "number"
},
"nodes": {
"type": "object",
"properties": {
"count": {
"type": "integer"
},
"seed": {
"type": "integer"
},
"type": {
"description": "Possible enum values:\n - `\"random\"` \n - `\"random edges\"` \n - `\"response_medium\"` \n - `\"response_small\"` \n - `\"feature_showcase\"` ",
"type": "string",
"enum": [
"random",
"random edges",
"response_medium",
"response_small",
"feature_showcase"
],
"x-enum-description": {}
}
},
"additionalProperties": false
},
"noise": {
"type": "number"
},
"points": {
"type": "array",
"items": {
"type": "array"
}
},
"pulseWave": {
"type": "object",
"properties": {
"offCount": {
"type": "integer"
},
"offValue": {
"type": "number"
},
"onCount": {
"type": "integer"
},
"onValue": {
"type": "number"
},
"timeStep": {
"type": "integer"
}
},
"additionalProperties": false
},
"queryType": {
"description": "QueryType is an optional identifier for the type of query.\nIt can be used to distinguish different types of queries.",
"type": "string"
},
"rawFrameContent": {
"type": "string"
},
"refId": {
"description": "RefID is the unique identifier of the query, set by the frontend call.",
"type": "string"
},
"resultAssertions": {
"description": "Optionally define expected query result behavior",
"type": "object",
"required": [
"typeVersion"
],
"properties": {
"maxFrames": {
"description": "Maximum frame count",
"type": "integer"
},
"type": {
"description": "Type asserts that the frame matches a known type structure.\n\n\nPossible enum values:\n - `\"\"` \n - `\"timeseries-wide\"` \n - `\"timeseries-long\"` \n - `\"timeseries-many\"` \n - `\"timeseries-multi\"` \n - `\"directory-listing\"` \n - `\"table\"` \n - `\"numeric-wide\"` \n - `\"numeric-multi\"` \n - `\"numeric-long\"` \n - `\"log-lines\"` ",
"type": "string",
"enum": [
"",
"timeseries-wide",
"timeseries-long",
"timeseries-many",
"timeseries-multi",
"directory-listing",
"table",
"numeric-wide",
"numeric-multi",
"numeric-long",
"log-lines"
],
"x-enum-description": {}
},
"typeVersion": {
"description": "TypeVersion is the version of the Type property. Versions greater than 0.0 correspond to the dataplane\ncontract documentation https://grafana.github.io/dataplane/contract/.",
"type": "array",
"maxItems": 2,
"minItems": 2,
"items": {
"type": "integer"
}
}
},
"additionalProperties": false
},
"scenarioId": {
"description": "Possible enum values:\n - `\"annotations\"` \n - `\"arrow\"` \n - `\"csv_content\"` \n - `\"csv_file\"` \n - `\"csv_metric_values\"` \n - `\"datapoints_outside_range\"` \n - `\"exponential_heatmap_bucket_data\"` \n - `\"flame_graph\"` \n - `\"grafana_api\"` \n - `\"linear_heatmap_bucket_data\"` \n - `\"live\"` \n - `\"logs\"` \n - `\"manual_entry\"` \n - `\"no_data_points\"` \n - `\"node_graph\"` \n - `\"predictable_csv_wave\"` \n - `\"predictable_pulse\"` \n - `\"random_walk\"` \n - `\"random_walk_table\"` \n - `\"random_walk_with_error\"` \n - `\"raw_frame\"` \n - `\"server_error_500\"` \n - `\"simulation\"` \n - `\"slow_query\"` \n - `\"streaming_client\"` \n - `\"table_static\"` \n - `\"trace\"` \n - `\"usa\"` \n - `\"variables-query\"` ",
"type": "string",
"enum": [
"annotations",
"arrow",
"csv_content",
"csv_file",
"csv_metric_values",
"datapoints_outside_range",
"exponential_heatmap_bucket_data",
"flame_graph",
"grafana_api",
"linear_heatmap_bucket_data",
"live",
"logs",
"manual_entry",
"no_data_points",
"node_graph",
"predictable_csv_wave",
"predictable_pulse",
"random_walk",
"random_walk_table",
"random_walk_with_error",
"raw_frame",
"server_error_500",
"simulation",
"slow_query",
"streaming_client",
"table_static",
"trace",
"usa",
"variables-query"
],
"x-enum-description": {}
},
"seriesCount": {
"type": "integer"
},
"sim": {
"type": "object",
"required": [
"key"
],
"properties": {
"config": {
"type": "object"
},
"key": {
"type": "object",
"required": [
"tick",
"type"
],
"properties": {
"tick": {
"type": "number"
},
"type": {
"type": "string"
},
"uid": {
"type": "string"
}
},
"additionalProperties": false
},
"last": {
"type": "boolean"
},
"stream": {
"type": "boolean"
}
},
"additionalProperties": false
},
"spanCount": {
"type": "integer"
},
"spread": {
"type": "number"
},
"startValue": {
"type": "number"
},
"stream": {
"type": "object",
"required": [
"noise",
"speed",
"spread",
"type"
],
"properties": {
"bands": {
"type": "integer"
},
"noise": {
"type": "number"
},
"speed": {
"type": "number"
},
"spread": {
"type": "number"
},
"type": {
"description": "Possible enum values:\n - `\"fetch\"` \n - `\"logs\"` \n - `\"signal\"` \n - `\"traces\"` ",
"type": "string",
"enum": [
"fetch",
"logs",
"signal",
"traces"
],
"x-enum-description": {}
},
"url": {
"type": "string"
}
},
"additionalProperties": false
},
"stringInput": {
"description": "common parameter used by many query types",
"type": "string"
},
"timeRange": {
"description": "TimeRange represents the query range\nNOTE: unlike generic /ds/query, we can now send explicit time values in each query\nNOTE: the values for timeRange are not saved in a dashboard, they are constructed on the fly",
"type": "object",
"required": [
"from",
"to"
],
"properties": {
"from": {
"description": "From is the start time of the query.",
"type": "string",
"default": "now-6h",
"examples": [
"now-1h"
]
},
"to": {
"description": "To is the end time of the query.",
"type": "string",
"default": "now",
"examples": [
"now"
]
}
},
"additionalProperties": false
},
"usa": {
"type": "object",
"properties": {
"fields": {
"type": "array",
"items": {
"type": "string"
}
},
"mode": {
"type": "string"
},
"period": {
"type": "string"
},
"states": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false
},
"withNil": {
"type": "boolean"
}
},
"additionalProperties": false,
"$schema": "https://json-schema.org/draft-04/schema#"
}
},
"to": {
"description": "To end time in epoch timestamps in milliseconds or relative using Grafana time units.",
"type": "string"
}
},
"additionalProperties": false,
"$schema": "https://json-schema.org/draft-04/schema#"
}

View File

@ -0,0 +1,325 @@
{
"kind": "QueryTypeDefinitionList",
"apiVersion": "query.grafana.app/v0alpha1",
"metadata": {
"resourceVersion": "1709261615323"
},
"items": [
{
"metadata": {
"name": "default",
"resourceVersion": "1711119846950",
"creationTimestamp": "2024-03-01T02:53:35Z"
},
"spec": {
"schema": {
"$schema": "https://json-schema.org/draft-04/schema",
"additionalProperties": false,
"description": "TestDataQuery defines model for TestDataQuery.",
"properties": {
"alias": {
"type": "string"
},
"channel": {
"description": "Used for live query",
"type": "string"
},
"csvContent": {
"type": "string"
},
"csvFileName": {
"type": "string"
},
"csvWave": {
"items": {
"additionalProperties": false,
"description": "CSVWave defines model for CSVWave.",
"properties": {
"labels": {
"type": "string"
},
"name": {
"type": "string"
},
"timeStep": {
"type": "integer"
},
"valuesCSV": {
"type": "string"
}
},
"type": "object"
},
"type": "array"
},
"dropPercent": {
"description": "Drop percentage (the chance we will lose a point 0-100)",
"type": "number"
},
"errorType": {
"description": "Possible enum values:\n - `\"frontend_exception\"` \n - `\"frontend_observable\"` \n - `\"server_panic\"` ",
"enum": [
"frontend_exception",
"frontend_observable",
"server_panic"
],
"type": "string",
"x-enum-description": {}
},
"flamegraphDiff": {
"type": "boolean"
},
"labels": {
"type": "string"
},
"levelColumn": {
"type": "boolean"
},
"lines": {
"type": "integer"
},
"max": {
"type": "number"
},
"min": {
"type": "number"
},
"nodes": {
"additionalProperties": false,
"properties": {
"count": {
"type": "integer"
},
"seed": {
"type": "integer"
},
"type": {
"description": "Possible enum values:\n - `\"random\"` \n - `\"random edges\"` \n - `\"response_medium\"` \n - `\"response_small\"` \n - `\"feature_showcase\"` ",
"enum": [
"random",
"random edges",
"response_medium",
"response_small",
"feature_showcase"
],
"type": "string",
"x-enum-description": {}
}
},
"type": "object"
},
"noise": {
"type": "number"
},
"points": {
"items": {
"type": "array"
},
"type": "array"
},
"pulseWave": {
"additionalProperties": false,
"properties": {
"offCount": {
"type": "integer"
},
"offValue": {
"type": "number"
},
"onCount": {
"type": "integer"
},
"onValue": {
"type": "number"
},
"timeStep": {
"type": "integer"
}
},
"type": "object"
},
"rawFrameContent": {
"type": "string"
},
"scenarioId": {
"description": "Possible enum values:\n - `\"annotations\"` \n - `\"arrow\"` \n - `\"csv_content\"` \n - `\"csv_file\"` \n - `\"csv_metric_values\"` \n - `\"datapoints_outside_range\"` \n - `\"exponential_heatmap_bucket_data\"` \n - `\"flame_graph\"` \n - `\"grafana_api\"` \n - `\"linear_heatmap_bucket_data\"` \n - `\"live\"` \n - `\"logs\"` \n - `\"manual_entry\"` \n - `\"no_data_points\"` \n - `\"node_graph\"` \n - `\"predictable_csv_wave\"` \n - `\"predictable_pulse\"` \n - `\"random_walk\"` \n - `\"random_walk_table\"` \n - `\"random_walk_with_error\"` \n - `\"raw_frame\"` \n - `\"server_error_500\"` \n - `\"simulation\"` \n - `\"slow_query\"` \n - `\"streaming_client\"` \n - `\"table_static\"` \n - `\"trace\"` \n - `\"usa\"` \n - `\"variables-query\"` ",
"enum": [
"annotations",
"arrow",
"csv_content",
"csv_file",
"csv_metric_values",
"datapoints_outside_range",
"exponential_heatmap_bucket_data",
"flame_graph",
"grafana_api",
"linear_heatmap_bucket_data",
"live",
"logs",
"manual_entry",
"no_data_points",
"node_graph",
"predictable_csv_wave",
"predictable_pulse",
"random_walk",
"random_walk_table",
"random_walk_with_error",
"raw_frame",
"server_error_500",
"simulation",
"slow_query",
"streaming_client",
"table_static",
"trace",
"usa",
"variables-query"
],
"type": "string",
"x-enum-description": {}
},
"seriesCount": {
"type": "integer"
},
"sim": {
"additionalProperties": false,
"properties": {
"config": {
"type": "object"
},
"key": {
"additionalProperties": false,
"properties": {
"tick": {
"type": "number"
},
"type": {
"type": "string"
},
"uid": {
"type": "string"
}
},
"required": [
"tick",
"type"
],
"type": "object"
},
"last": {
"type": "boolean"
},
"stream": {
"type": "boolean"
}
},
"required": [
"key"
],
"type": "object"
},
"spanCount": {
"type": "integer"
},
"spread": {
"type": "number"
},
"startValue": {
"type": "number"
},
"stream": {
"additionalProperties": false,
"properties": {
"bands": {
"type": "integer"
},
"noise": {
"type": "number"
},
"speed": {
"type": "number"
},
"spread": {
"type": "number"
},
"type": {
"description": "Possible enum values:\n - `\"fetch\"` \n - `\"logs\"` \n - `\"signal\"` \n - `\"traces\"` ",
"enum": [
"fetch",
"logs",
"signal",
"traces"
],
"type": "string",
"x-enum-description": {}
},
"url": {
"type": "string"
}
},
"required": [
"noise",
"speed",
"spread",
"type"
],
"type": "object"
},
"stringInput": {
"description": "common parameter used by many query types",
"type": "string"
},
"usa": {
"additionalProperties": false,
"properties": {
"fields": {
"items": {
"type": "string"
},
"type": "array"
},
"mode": {
"type": "string"
},
"period": {
"type": "string"
},
"states": {
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"withNil": {
"type": "boolean"
}
},
"type": "object"
},
"examples": [
{
"name": "simple random walk",
"saveModel": {
"scenarioId": "random_walk"
}
},
{
"name": "pulse wave example",
"saveModel": {
"pulseWave": {
"offCount": 20,
"offValue": 1.23,
"onCount": 10,
"onValue": 4.56,
"timeStep": 1000
},
"scenarioId": "predictable_pulse"
}
}
]
}
}
]
}

View File

@ -0,0 +1,62 @@
package kinds
import (
"reflect"
"testing"
data "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1"
"github.com/grafana/grafana-plugin-sdk-go/experimental/schemabuilder"
"github.com/stretchr/testify/require"
)
func TestQueryTypeDefinitions(t *testing.T) {
builder, err := schemabuilder.NewSchemaBuilder(
schemabuilder.BuilderOptions{
PluginID: []string{"grafana-testdata-datasource", "testdata"},
ScanCode: []schemabuilder.CodePaths{{
BasePackage: "github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource/kinds",
CodePath: "./",
}},
Enums: []reflect.Type{
reflect.TypeOf(NodesQueryTypeRandom), // pick an example value (not the root)
reflect.TypeOf(StreamingQueryTypeFetch), // pick an example value (not the root)
reflect.TypeOf(ErrorTypeServerPanic), // pick an example value (not the root)
reflect.TypeOf(TestDataQueryTypeAnnotations), // pick an example value (not the root)
},
})
require.NoError(t, err)
err = builder.AddQueries(
schemabuilder.QueryTypeInfo{
Name: "default",
GoType: reflect.TypeOf(&TestDataQuery{}),
Examples: []data.QueryExample{
{
Name: "simple random walk",
SaveModel: data.AsUnstructured(
TestDataQuery{
ScenarioId: TestDataQueryTypeRandomWalk,
},
),
},
{
Name: "pulse wave example",
SaveModel: data.AsUnstructured(
TestDataQuery{
ScenarioId: TestDataQueryTypePredictablePulse,
PulseWave: &PulseWaveQuery{
TimeStep: int64(1000),
OnCount: 10,
OffCount: 20,
OffValue: 1.23, // should be any (rather json any)
OnValue: 4.56, // should be any
},
},
),
},
},
},
)
require.NoError(t, err)
builder.UpdateQueryDefinition(t, "./")
}

View File

@ -10,6 +10,8 @@ import (
"time"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource/kinds"
)
func (s *Service) registerRoutes() *http.ServeMux {
@ -46,12 +48,12 @@ func (s *Service) getScenariosHandler(rw http.ResponseWriter, req *http.Request)
scenarioIds := make([]string, 0)
for id := range s.scenarios {
scenarioIds = append(scenarioIds, id)
scenarioIds = append(scenarioIds, string(id))
}
sort.Strings(scenarioIds)
for _, scenarioID := range scenarioIds {
scenario := s.scenarios[scenarioID]
scenario := s.scenarios[kinds.TestDataQueryType(scenarioID)]
result = append(result, map[string]any{
"id": scenario.ID,
"name": scenario.Name,

View File

@ -17,42 +17,13 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/data"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
)
const (
randomWalkQuery queryType = "random_walk"
randomWalkSlowQuery queryType = "slow_query"
randomWalkWithErrorQuery queryType = "random_walk_with_error"
randomWalkTableQuery queryType = "random_walk_table"
exponentialHeatmapBucketDataQuery queryType = "exponential_heatmap_bucket_data"
linearHeatmapBucketDataQuery queryType = "linear_heatmap_bucket_data"
noDataPointsQuery queryType = "no_data_points"
datapointsOutsideRangeQuery queryType = "datapoints_outside_range"
csvMetricValuesQuery queryType = "csv_metric_values"
predictablePulseQuery queryType = "predictable_pulse"
predictableCSVWaveQuery queryType = "predictable_csv_wave"
streamingClientQuery queryType = "streaming_client"
simulation queryType = "simulation"
usaQueryKey queryType = "usa"
liveQuery queryType = "live"
grafanaAPIQuery queryType = "grafana_api"
arrowQuery queryType = "arrow"
annotationsQuery queryType = "annotations"
tableStaticQuery queryType = "table_static"
serverError500Query queryType = "server_error_500"
logsQuery queryType = "logs"
nodeGraphQuery queryType = "node_graph"
flameGraphQuery queryType = "flame_graph"
rawFrameQuery queryType = "raw_frame"
csvFileQueryType queryType = "csv_file"
csvContentQueryType queryType = "csv_content"
traceType queryType = "trace"
"github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource/kinds"
)
type queryType string
type Scenario struct {
ID string `json:"id"`
ID kinds.TestDataQueryType `json:"id"`
Name string `json:"name"`
StringInput string `json:"stringInput"`
Description string `json:"description"`
@ -61,25 +32,25 @@ type Scenario struct {
func (s *Service) registerScenarios() {
s.registerScenario(&Scenario{
ID: string(exponentialHeatmapBucketDataQuery),
ID: kinds.TestDataQueryTypeExponentialHeatmapBucketData,
Name: "Exponential heatmap bucket data",
handler: s.handleExponentialHeatmapBucketDataScenario,
})
s.registerScenario(&Scenario{
ID: string(linearHeatmapBucketDataQuery),
ID: kinds.TestDataQueryTypeLinearHeatmapBucketData,
Name: "Linear heatmap bucket data",
handler: s.handleLinearHeatmapBucketDataScenario,
})
s.registerScenario(&Scenario{
ID: string(randomWalkQuery),
ID: kinds.TestDataQueryTypeRandomWalk,
Name: "Random Walk",
handler: s.handleRandomWalkScenario,
})
s.registerScenario(&Scenario{
ID: string(predictablePulseQuery),
ID: kinds.TestDataQueryTypePredictablePulse,
Name: "Predictable Pulse",
handler: s.handlePredictablePulseScenario,
Description: `Predictable Pulse returns a pulse wave where there is a datapoint every timeStepSeconds.
@ -89,100 +60,100 @@ Timestamps will line up evenly on timeStepSeconds (For example, 60 seconds means
})
s.registerScenario(&Scenario{
ID: string(predictableCSVWaveQuery),
ID: kinds.TestDataQueryTypePredictableCsvWave,
Name: "Predictable CSV Wave",
handler: s.handlePredictableCSVWaveScenario,
})
s.registerScenario(&Scenario{
ID: string(randomWalkTableQuery),
ID: kinds.TestDataQueryTypeRandomWalkTable,
Name: "Random Walk Table",
handler: s.handleRandomWalkTableScenario,
})
s.registerScenario(&Scenario{
ID: string(randomWalkSlowQuery),
ID: kinds.TestDataQueryTypeSlowQuery,
Name: "Slow Query",
StringInput: "5s",
handler: s.handleRandomWalkSlowScenario,
})
s.registerScenario(&Scenario{
ID: string(noDataPointsQuery),
ID: kinds.TestDataQueryTypeNoDataPoints,
Name: "No Data Points",
handler: s.handleClientSideScenario,
})
s.registerScenario(&Scenario{
ID: string(datapointsOutsideRangeQuery),
ID: kinds.TestDataQueryTypeDatapointsOutsideRange,
Name: "Datapoints Outside Range",
handler: s.handleDatapointsOutsideRangeScenario,
})
s.registerScenario(&Scenario{
ID: string(csvMetricValuesQuery),
ID: kinds.TestDataQueryTypeCsvMetricValues,
Name: "CSV Metric Values",
StringInput: "1,20,90,30,5,0",
handler: s.handleCSVMetricValuesScenario,
})
s.registerScenario(&Scenario{
ID: string(streamingClientQuery),
ID: kinds.TestDataQueryTypeStreamingClient,
Name: "Streaming Client",
handler: s.handleClientSideScenario,
})
s.registerScenario(&Scenario{
ID: string(liveQuery),
ID: kinds.TestDataQueryTypeLive,
Name: "Grafana Live",
handler: s.handleClientSideScenario,
})
s.registerScenario(&Scenario{
ID: string(simulation),
ID: kinds.TestDataQueryTypeSimulation,
Name: "Simulation",
handler: s.sims.QueryData,
})
s.registerScenario(&Scenario{
ID: string(usaQueryKey),
ID: kinds.TestDataQueryTypeUsa,
Name: "USA generated data",
handler: s.handleUSAScenario,
})
s.registerScenario(&Scenario{
ID: string(grafanaAPIQuery),
ID: kinds.TestDataQueryTypeGrafanaApi,
Name: "Grafana API",
handler: s.handleClientSideScenario,
})
s.registerScenario(&Scenario{
ID: string(arrowQuery),
ID: kinds.TestDataQueryTypeArrow,
Name: "Load Apache Arrow Data",
handler: s.handleArrowScenario,
})
s.registerScenario(&Scenario{
ID: string(annotationsQuery),
ID: kinds.TestDataQueryTypeAnnotations,
Name: "Annotations",
handler: s.handleClientSideScenario,
})
s.registerScenario(&Scenario{
ID: string(tableStaticQuery),
ID: kinds.TestDataQueryTypeTableStatic,
Name: "Table Static",
handler: s.handleTableStaticScenario,
})
s.registerScenario(&Scenario{
ID: string(randomWalkWithErrorQuery),
ID: kinds.TestDataQueryTypeRandomWalkWithError,
Name: "Random Walk (with error)",
handler: s.handleRandomWalkWithErrorScenario,
})
s.registerScenario(&Scenario{
// Is no longer strictly a _server_ error scenario, but ID is kept for legacy :)
ID: string(serverError500Query),
ID: kinds.TestDataQueryTypeServerError500,
Name: "Conditional Error",
handler: s.handleServerError500Scenario,
StringInput: "1,20,90,30,5,0",
@ -190,40 +161,40 @@ Timestamps will line up evenly on timeStepSeconds (For example, 60 seconds means
})
s.registerScenario(&Scenario{
ID: string(logsQuery),
ID: kinds.TestDataQueryTypeLogs,
Name: "Logs",
handler: s.handleLogsScenario,
})
s.registerScenario(&Scenario{
ID: string(nodeGraphQuery),
ID: kinds.TestDataQueryTypeNodeGraph,
Name: "Node Graph",
})
s.registerScenario(&Scenario{
ID: string(flameGraphQuery),
ID: kinds.TestDataQueryTypeFlameGraph,
Name: "Flame Graph",
})
s.registerScenario(&Scenario{
ID: string(rawFrameQuery),
ID: kinds.TestDataQueryTypeRawFrame,
Name: "Raw Frames",
})
s.registerScenario(&Scenario{
ID: string(csvFileQueryType),
ID: kinds.TestDataQueryTypeCsvFile,
Name: "CSV File",
handler: s.handleCsvFileScenario,
})
s.registerScenario(&Scenario{
ID: string(csvContentQueryType),
ID: kinds.TestDataQueryTypeCsvContent,
Name: "CSV Content",
handler: s.handleCsvContentScenario,
})
s.registerScenario(&Scenario{
ID: string(traceType),
ID: kinds.TestDataQueryTypeTrace,
Name: "Trace",
})
@ -232,14 +203,14 @@ Timestamps will line up evenly on timeStepSeconds (For example, 60 seconds means
func (s *Service) registerScenario(scenario *Scenario) {
s.scenarios[scenario.ID] = scenario
s.queryMux.HandleFunc(scenario.ID, instrumentScenarioHandler(s.logger, scenario.ID, scenario.handler))
s.queryMux.HandleFunc(string(scenario.ID), instrumentScenarioHandler(s.logger, scenario.ID, scenario.handler))
}
func instrumentScenarioHandler(logger log.Logger, scenario string, fn backend.QueryDataHandlerFunc) backend.QueryDataHandlerFunc {
func instrumentScenarioHandler(logger log.Logger, scenario kinds.TestDataQueryType, fn backend.QueryDataHandlerFunc) backend.QueryDataHandlerFunc {
return backend.QueryDataHandlerFunc(func(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
ctx, span := tracing.DefaultTracer().Start(ctx, "testdatasource.queryData",
trace.WithAttributes(
attribute.String("scenario", scenario),
attribute.String("scenario", string(scenario)),
))
defer span.End()
@ -250,52 +221,18 @@ func instrumentScenarioHandler(logger log.Logger, scenario string, fn backend.Qu
})
}
type JSONModel struct {
ScenarioID string `json:"scenarioId"`
SeriesCount int `json:"seriesCount"`
StringInput string `json:"stringInput"`
Lines int64 `json:"lines"`
IncludeLevelColumn bool `json:"includeLevelColumn"`
StartValue float64 `json:"startValue"`
Spread float64 `json:"spread"`
Noise float64 `json:"noise"`
Drop float64 `json:"drop"`
Min *float64 `json:"min,omitempty"`
Max *float64 `json:"max,omitempty"`
Labels string `json:"labels"`
WithNil bool `json:"withNil"`
PulseWave pulseWave `json:"pulseWave"`
Alias string `json:"alias"`
// Cannot specify a type for csvWave since legacy queries
// does not follow the same format as the new ones (and there is no migration).
CSVWave any `json:"csvWave"`
CSVContent string `json:"csvContent"`
CSVFileName string `json:"csvFileName"`
DropPercent float64 `json:"dropPercent"`
}
type pulseWave struct {
TimeStep int64 `json:"timeStep"`
OnCount int64 `json:"onCount"`
OffCount int64 `json:"offCount"`
OnValue any `json:"onValue"`
OffValue any `json:"offValue"`
}
func GetJSONModel(j json.RawMessage) (JSONModel, error) {
model := JSONModel{
func GetJSONModel(j json.RawMessage) (kinds.TestDataQuery, error) {
model := kinds.TestDataQuery{
// Default values
ScenarioID: string(randomWalkQuery),
ScenarioId: kinds.TestDataQueryTypeRandomWalk,
SeriesCount: 1,
Lines: 10,
StartValue: rand.Float64() * 100,
Spread: 1,
}
if len(j) > 0 {
err := json.Unmarshal(j, &model)
if err != nil {
return JSONModel{}, err
}
// csvWave has saved values that are single values, not arrays
_ = json.Unmarshal(j, &model)
}
return model, nil
}
@ -303,7 +240,7 @@ func GetJSONModel(j json.RawMessage) (JSONModel, error) {
// handleFallbackScenario handles the scenario where queryType is not set and fallbacks to scenarioId.
func (s *Service) handleFallbackScenario(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
ctxLogger := s.logger.FromContext(ctx)
scenarioQueries := map[string][]backend.DataQuery{}
scenarioQueries := map[kinds.TestDataQueryType][]backend.DataQuery{}
for _, q := range req.Queries {
model, err := GetJSONModel(q.JSON)
@ -312,7 +249,7 @@ func (s *Service) handleFallbackScenario(ctx context.Context, req *backend.Query
continue
}
scenarioID := model.ScenarioID
scenarioID := model.ScenarioId
if _, exist := s.scenarios[scenarioID]; exist {
if _, ok := scenarioQueries[scenarioID]; !ok {
scenarioQueries[scenarioID] = []backend.DataQuery{}
@ -654,7 +591,7 @@ func (s *Service) handleLogsScenario(ctx context.Context, req *backend.QueryData
}
lines := model.Lines
includeLevelColumn := model.IncludeLevelColumn
includeLevelColumn := model.LevelColumn
logLevelGenerator := newRandomStringProvider([]string{
"emerg",
@ -726,14 +663,14 @@ func (s *Service) handleLogsScenario(ctx context.Context, req *backend.QueryData
return resp, nil
}
func RandomWalk(query backend.DataQuery, model JSONModel, index int) *data.Frame {
func RandomWalk(query backend.DataQuery, model kinds.TestDataQuery, index int) *data.Frame {
rand := rand.New(rand.NewSource(time.Now().UnixNano() + int64(index)))
timeWalkerMs := query.TimeRange.From.UnixNano() / int64(time.Millisecond)
to := query.TimeRange.To.UnixNano() / int64(time.Millisecond)
startValue := model.StartValue
spread := model.Spread
noise := model.Noise
drop := model.Drop / 100.0 // value is 0-100
drop := model.DropPercent / 100.0 // value is 0-100
min := float64(0)
hasMin := false
@ -795,7 +732,7 @@ func RandomWalk(query backend.DataQuery, model JSONModel, index int) *data.Frame
return frame
}
func randomWalkTable(query backend.DataQuery, model JSONModel) *data.Frame {
func randomWalkTable(query backend.DataQuery, model kinds.TestDataQuery) *data.Frame {
rand := rand.New(rand.NewSource(time.Now().UnixNano()))
timeWalkerMs := query.TimeRange.From.UnixNano() / int64(time.Millisecond)
to := query.TimeRange.To.UnixNano() / int64(time.Millisecond)
@ -868,23 +805,8 @@ func randomWalkTable(query backend.DataQuery, model JSONModel) *data.Frame {
return frame
}
type pCSVOptions struct {
TimeStep int64 `json:"timeStep"`
ValuesCSV string `json:"valuesCSV"`
Labels string `json:"labels"`
Name string `json:"name"`
}
func predictableCSVWave(query backend.DataQuery, model JSONModel) ([]*data.Frame, error) {
queries := []pCSVOptions{}
input, err := json.Marshal(model.CSVWave)
if err != nil {
return nil, err
}
err = json.Unmarshal(input, &queries)
if err != nil {
return nil, err
}
func predictableCSVWave(query backend.DataQuery, model kinds.TestDataQuery) ([]*data.Frame, error) {
queries := model.CsvWave
frames := make([]*data.Frame, 0, len(queries))
@ -972,7 +894,7 @@ func predictableSeries(timeRange backend.TimeRange, timeStep, length int64, getV
}, nil
}
func predictablePulse(query backend.DataQuery, model JSONModel) (*data.Frame, error) {
func predictablePulse(query backend.DataQuery, model kinds.TestDataQuery) (*data.Frame, error) {
// Process Input
var timeStep int64
var onCount int64
@ -1042,7 +964,7 @@ func randomHeatmapData(query backend.DataQuery, fnBucketGen func(index int) floa
return frame
}
func doArrowQuery(query backend.DataQuery, model JSONModel) (*data.Frame, error) {
func doArrowQuery(query backend.DataQuery, model kinds.TestDataQuery) (*data.Frame, error) {
encoded := model.StringInput
if encoded == "" {
return nil, nil
@ -1054,7 +976,7 @@ func doArrowQuery(query backend.DataQuery, model JSONModel) (*data.Frame, error)
return data.UnmarshalArrowFrame(arrow)
}
func newSeriesForQuery(query backend.DataQuery, model JSONModel, index int) *data.Frame {
func newSeriesForQuery(query backend.DataQuery, model kinds.TestDataQuery, index int) *data.Frame {
alias := model.Alias
suffix := ""
@ -1082,7 +1004,7 @@ func newSeriesForQuery(query backend.DataQuery, model JSONModel, index int) *dat
*
* '{job="foo", instance="bar"} => {job: "foo", instance: "bar"}`
*/
func parseLabels(model JSONModel, seriesIndex int) data.Labels {
func parseLabels(model kinds.TestDataQuery, seriesIndex int) data.Labels {
return parseLabelsString(model.Labels, seriesIndex)
}
@ -1110,7 +1032,7 @@ func parseLabelsString(labelText string, seriesIndex int) data.Labels {
return tags
}
func frameNameForQuery(query backend.DataQuery, model JSONModel, index int) string {
func frameNameForQuery(query backend.DataQuery, model kinds.TestDataQuery, index int) string {
name := model.Alias
suffix := ""

View File

@ -11,6 +11,8 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource/kinds"
)
func TestTestdataScenarios(t *testing.T) {
@ -184,32 +186,32 @@ func TestParseLabels(t *testing.T) {
tests := []struct {
name string
model JSONModel
model kinds.TestDataQuery
expected data.Labels
}{
{
name: "wrapped in {} and quoted value ",
model: JSONModel{Labels: `{job="foo", instance="bar"}`},
model: kinds.TestDataQuery{Labels: `{job="foo", instance="bar"}`},
expected: expectedTags,
},
{
name: "comma-separated non-quoted",
model: JSONModel{Labels: `job=foo, instance=bar`},
model: kinds.TestDataQuery{Labels: `job=foo, instance=bar`},
expected: expectedTags,
},
{
name: "comma-separated quoted",
model: JSONModel{Labels: `job="foo"", instance="bar"`},
model: kinds.TestDataQuery{Labels: `job="foo"", instance="bar"`},
expected: expectedTags,
},
{
name: "comma-separated with spaces, non quoted",
model: JSONModel{Labels: `job = foo,instance = bar`},
model: kinds.TestDataQuery{Labels: `job = foo,instance = bar`},
expected: expectedTags,
},
{
name: "expands $seriesIndex",
model: JSONModel{Labels: `job=series-$seriesIndex,instance=bar`},
model: kinds.TestDataQuery{Labels: `job=series-$seriesIndex,instance=bar`},
expected: data.Labels{
"job": fmt.Sprintf("series-%d", seriesIndex),
"instance": "bar",

View File

@ -10,6 +10,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource/kinds"
"github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource/sims"
)
@ -19,7 +20,7 @@ import (
func ProvideService() *Service {
s := &Service{
queryMux: datasource.NewQueryTypeMux(),
scenarios: map[string]*Scenario{},
scenarios: map[kinds.TestDataQueryType]*Scenario{},
frame: data.NewFrame("testdata",
data.NewField("Time", nil, make([]time.Time, 1)),
data.NewField("Value", nil, make([]float64, 1)),
@ -48,7 +49,7 @@ func ProvideService() *Service {
type Service struct {
logger log.Logger
scenarios map[string]*Scenario
scenarios map[kinds.TestDataQueryType]*Scenario
frame *data.Frame
labelFrame *data.Frame
queryMux *datasource.QueryTypeMux

View File

@ -3,7 +3,7 @@ import React from 'react';
import { MetadataInspectorProps } from '@grafana/data';
import { Stack } from '@grafana/ui';
import { TestDataDataQuery } from './dataquery.gen';
import { TestDataDataQuery } from './dataquery';
import { TestDataDataSource } from './datasource';
export type Props = MetadataInspectorProps<TestDataDataSource, TestDataDataQuery>;

View File

@ -5,7 +5,7 @@ import React from 'react';
import { QueryEditor, Props } from './QueryEditor';
import { scenarios } from './__mocks__/scenarios';
import { defaultQuery } from './constants';
import { TestDataQueryType } from './dataquery.gen';
import { TestDataQueryType } from './dataquery';
import { TestDataDataSource } from './datasource';
import { defaultStreamQuery } from './runStreams';

View File

@ -17,7 +17,7 @@ import { RawFrameEditor } from './components/RawFrameEditor';
import { SimulationQueryEditor } from './components/SimulationQueryEditor';
import { USAQueryEditor, usaQueryModes } from './components/USAQueryEditor';
import { defaultCSVWaveQuery, defaultPulseQuery, defaultQuery } from './constants';
import { CSVWave, NodesQuery, TestDataDataQuery, TestDataQueryType, USAQuery } from './dataquery.gen';
import { CSVWave, NodesQuery, TestDataDataQuery, TestDataQueryType, USAQuery } from './dataquery';
import { TestDataDataSource } from './datasource';
import { defaultStreamQuery } from './runStreams';

View File

@ -1,4 +1,4 @@
import { TestDataQueryType } from '../dataquery.gen';
import { TestDataQueryType } from '../dataquery';
export const scenarios = [
{

View File

@ -3,7 +3,7 @@ import React, { PureComponent, useState } from 'react';
import { Button, InlineField, InlineFieldRow, Input } from '@grafana/ui';
import { defaultCSVWaveQuery } from '../constants';
import type { CSVWave } from '../dataquery.gen';
import type { CSVWave } from '../dataquery';
interface WavesProps {
waves?: CSVWave[];

View File

@ -2,7 +2,7 @@ import React from 'react';
import { Input, InlineFieldRow, InlineField, Select } from '@grafana/ui';
import { NodesQuery, TestDataDataQuery } from '../dataquery.gen';
import { NodesQuery, TestDataDataQuery } from '../dataquery';
export interface Props {
onChange: (value: NodesQuery) => void;

View File

@ -3,7 +3,7 @@ import React, { ChangeEvent } from 'react';
import { InlineField, InlineFieldRow, Input } from '@grafana/ui';
import { EditorProps } from '../QueryEditor';
import { PulseWaveQuery } from '../dataquery.gen';
import { PulseWaveQuery } from '../dataquery';
const fields: Array<{
label: string;

View File

@ -4,7 +4,7 @@ import { selectors } from '@grafana/e2e-selectors';
import { InlineField, InlineFieldRow, Input } from '@grafana/ui';
import { EditorProps } from '../QueryEditor';
import { TestDataDataQuery } from '../dataquery.gen';
import { TestDataDataQuery } from '../dataquery';
const randomWalkFields: Array<{
label: string;

View File

@ -5,7 +5,7 @@ import { DataFrameJSON, SelectableValue } from '@grafana/data';
import { InlineField, InlineFieldRow, InlineSwitch, Input, Label, Select } from '@grafana/ui';
import { EditorProps } from '../QueryEditor';
import { SimulationQuery } from '../dataquery.gen';
import { SimulationQuery } from '../dataquery';
import { SimulationSchemaForm } from './SimulationSchemaForm';

View File

@ -3,7 +3,7 @@ import React from 'react';
import { SelectableValue } from '@grafana/data';
import { InlineFieldRow, InlineField, Select, MultiSelect, Input } from '@grafana/ui';
import { USAQuery } from '../dataquery.gen';
import { USAQuery } from '../dataquery';
export interface Props {
onChange: (value: USAQuery) => void;

View File

@ -1,4 +1,4 @@
import { CSVWave, PulseWaveQuery, TestDataDataQuery, TestDataQueryType } from './dataquery.gen';
import { CSVWave, PulseWaveQuery, TestDataDataQuery, TestDataQueryType } from './dataquery';
export const defaultPulseQuery: PulseWaveQuery = {
timeStep: 60,

View File

@ -1,117 +0,0 @@
// Copyright 2023 Grafana Labs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package grafanaplugin
import (
"github.com/grafana/grafana/packages/grafana-schema/src/common"
)
composableKinds: DataQuery: {
maturity: "experimental"
lineage: {
schemas: [{
version: [0, 0]
schema: {
common.DataQuery
alias?: string
scenarioId?: #TestDataQueryType & (*"random_walk" | _)
stringInput?: string
stream?: #StreamingQuery
pulseWave?: #PulseWaveQuery
sim?: #SimulationQuery
csvWave?: [...#CSVWave] //TODO can we prevent partial from being generated
labels?: string
lines?: int64
levelColumn?: bool
channel?: string
nodes?: #NodesQuery
csvFileName?: string
csvContent?: string
rawFrameContent?: string
seriesCount?: int32
usa?: #USAQuery
errorType?: "server_panic" | "frontend_exception" | "frontend_observable"
spanCount?: int32
points?: [...[...string | int64]]
// Drop percentage (the chance we will lose a point 0-100)
dropPercent?: float64
flamegraphDiff?: bool
#TestDataQueryType: "random_walk" | "slow_query" | "random_walk_with_error" | "random_walk_table" | "exponential_heatmap_bucket_data" | "linear_heatmap_bucket_data" | "no_data_points" | "datapoints_outside_range" | "csv_metric_values" | "predictable_pulse" | "predictable_csv_wave" | "streaming_client" | "simulation" | "usa" | "live" | "grafana_api" | "arrow" | "annotations" | "table_static" | "server_error_500" | "logs" | "node_graph" | "flame_graph" | "raw_frame" | "csv_file" | "csv_content" | "trace" | "manual_entry" | "variables-query" @cuetsy(kind="enum", memberNames="RandomWalk|SlowQuery|RandomWalkWithError|RandomWalkTable|ExponentialHeatmapBucketData|LinearHeatmapBucketData|NoDataPoints|DataPointsOutsideRange|CSVMetricValues|PredictablePulse|PredictableCSVWave|StreamingClient|Simulation|USA|Live|GrafanaAPI|Arrow|Annotations|TableStatic|ServerError500|Logs|NodeGraph|FlameGraph|RawFrame|CSVFile|CSVContent|Trace|ManualEntry|VariablesQuery")
#StreamingQuery: {
type: "signal" | "logs" | "fetch" | "traces"
speed: int32
spread: int32
noise: int32
bands?: int32
url?: string
} @cuetsy(kind="interface")
#PulseWaveQuery: {
timeStep?: int64
onCount?: int64
offCount?: int64
onValue?: float64
offValue?: float64
} @cuetsy(kind="interface")
#SimulationQuery: {
key: {
type: string
tick: float64
uid?: string
}
config?: {...}
stream?: bool
last?: bool
} @cuetsy(kind="interface")
#NodesQuery: {
type?: "random" | "response_small" | "response_medium" | "random edges" | "feature_showcase"
count?: int64
seed?: int64
} @cuetsy(kind="interface")
#USAQuery: {
mode?: string
period?: string
fields?: [...string]
states?: [...string]
} @cuetsy(kind="interface")
#CSVWave: {
timeStep?: int64
name?: string
valuesCSV?: string
labels?: string
} @cuetsy(kind="interface")
// TODO: Should this live here given it's not used in the dataquery?
#Scenario: {
id: string
name: string
stringInput: string
description?: string
hideAliasField?: bool
} @cuetsy(kind="interface")
}
}]
lenses: []
}
}

View File

@ -1,12 +1,5 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
//
// Generated by:
// public/app/plugins/gen.go
// Using jennies:
// TSTypesJenny
// PluginTsTypesJenny
//
// Run 'make gen-cue' from repository root to regenerate.
// Code was originally generated from cue
// It must now be updated manually
import * as common from '@grafana/schema';
@ -47,7 +40,7 @@ export interface StreamingQuery {
noise: number;
speed: number;
spread: number;
type: ('signal' | 'logs' | 'fetch' | 'traces');
type: 'signal' | 'logs' | 'fetch' | 'traces';
url?: string;
}
@ -73,14 +66,14 @@ export interface SimulationQuery {
export interface NodesQuery {
count?: number;
seed?: number;
type?: ('random' | 'response_small' | 'response_medium' | 'random edges' | 'feature_showcase');
type?: 'random' | 'response_small' | 'response_medium' | 'random edges' | 'feature_showcase';
}
export interface USAQuery {
fields?: Array<string>;
fields?: string[];
mode?: string;
period?: string;
states?: Array<string>;
states?: string[];
}
export const defaultUSAQuery: Partial<USAQuery> = {
@ -111,18 +104,18 @@ export interface TestDataDataQuery extends common.DataQuery {
channel?: string;
csvContent?: string;
csvFileName?: string;
csvWave?: Array<CSVWave>; // TODO can we prevent partial from being generated
csvWave?: CSVWave[]; // TODO can we prevent partial from being generated
/**
* Drop percentage (the chance we will lose a point 0-100)
*/
dropPercent?: number;
errorType?: ('server_panic' | 'frontend_exception' | 'frontend_observable');
errorType?: 'server_panic' | 'frontend_exception' | 'frontend_observable';
flamegraphDiff?: boolean;
labels?: string;
levelColumn?: boolean;
lines?: number;
nodes?: NodesQuery;
points?: Array<Array<(string | number)>>;
points?: Array<Array<string | number>>;
pulseWave?: PulseWaveQuery;
rawFrameContent?: string;
scenarioId?: TestDataQueryType;

View File

@ -20,7 +20,7 @@ import {
} from '@grafana/data';
import { DataSourceWithBackend, getBackendSrv, getGrafanaLiveSrv, getTemplateSrv, TemplateSrv } from '@grafana/runtime';
import { Scenario, TestDataDataQuery, TestDataQueryType } from './dataquery.gen';
import { Scenario, TestDataDataQuery, TestDataQueryType } from './dataquery';
import { queryMetricTree } from './metricTree';
import { generateRandomEdges, generateRandomNodes, generateShowcaseData, savedNodesResponse } from './nodeGraphUtils';
import { runStream } from './runStreams';

View File

@ -20,7 +20,7 @@ import {
} from '@grafana/data';
import { getRandomLine } from './LogIpsum';
import { TestDataDataQuery, StreamingQuery } from './dataquery.gen';
import { TestDataDataQuery, StreamingQuery } from './dataquery';
export const defaultStreamQuery: StreamingQuery = {
type: 'signal',

View File

@ -1,6 +1,6 @@
import { StandardVariableQuery, StandardVariableSupport } from '@grafana/data';
import { TestDataDataQuery, TestDataQueryType } from './dataquery.gen';
import { TestDataDataQuery, TestDataQueryType } from './dataquery';
import { TestDataDataSource } from './datasource';
export class TestDataVariableSupport extends StandardVariableSupport<TestDataDataSource> {