Dashboard Schema V2: Introduce __legacyStringValue and deprecate string type for query prop in QueryVariableSpec (#99716)

* Introduce __legacyStringValue and deprecate string type for query

* Fix tests

* Fix tests

* remove default

* kind should default to default ds if variable doesn't have ds field

* lint

* getDefaultDataSourceRef should not return undefined
This commit is contained in:
Haris Rozajac 2025-02-06 07:33:06 -07:00 committed by GitHub
parent f1eac34b54
commit 4c52abb6b4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 66 additions and 29 deletions

View File

@ -651,7 +651,7 @@ QueryVariableSpec: {
skipUrlSync: bool | *false
description?: string
datasource?: DataSourceRef
query: string | DataQueryKind | *""
query: DataQueryKind
regex: string | *""
sort: VariableSort
definition?: string

View File

@ -344,7 +344,13 @@ export const handyTestingSchema: DashboardV2Spec = {
multi: true,
name: 'queryVar',
options: [],
query: 'query1',
query: {
kind: 'prometheus',
spec: {
expr: 'test-query',
refId: 'A',
},
},
refresh: 'onDashboardLoad',
regex: 'regex1',
skipUrlSync: false,

View File

@ -960,7 +960,7 @@ export interface QueryVariableSpec {
skipUrlSync: boolean;
description?: string;
datasource?: DataSourceRef;
query: string | DataQueryKind;
query: DataQueryKind;
regex: string;
sort: VariableSort;
definition?: string;
@ -977,7 +977,7 @@ export const defaultQueryVariableSpec = (): QueryVariableSpec => ({
hide: "dontHide",
refresh: "never",
skipUrlSync: false,
query: "",
query: defaultDataQueryKind(),
regex: "",
sort: "disabled",
options: [],

View File

@ -222,7 +222,13 @@ exports[`transformSceneToSaveModelSchemaV2 should transform scene to save model
"multi": true,
"name": "queryVar",
"options": [],
"query": "query1",
"query": {
"kind": "prometheus",
"spec": {
"expr": "label_values(node_boot_time_seconds)",
"refId": "A",
},
},
"refresh": "onDashboardLoad",
"regex": "regex1",
"skipUrlSync": false,

View File

@ -775,7 +775,12 @@ describe('sceneVariablesSetToVariables', () => {
"multi": true,
"name": "test",
"options": [],
"query": "query",
"query": {
"kind": "fake-std",
"spec": {
"__legacyStringValue": "query",
},
},
"refresh": "onDashboardLoad",
"regex": "",
"skipUrlSync": false,

View File

@ -27,6 +27,7 @@ import {
transformVariableRefreshToEnum,
transformVariableHideToEnum,
transformSortVariableToEnum,
LEGACY_STRING_VALUE_KEY,
} from './transformToV2TypesUtils';
/**
* Converts a SceneVariables object into an array of VariableModel objects.
@ -269,16 +270,20 @@ export function sceneVariablesSetToSchemaV2Variables(
if (transformVariableRefreshToEnum(variable.state.refresh) === 'never' || keepQueryOptions) {
options = variableValueOptionsToVariableOptions(variable.state);
}
//query: DataQueryKind | string;
const query = variable.state.query;
let dataQuery: DataQueryKind | string;
if (typeof query !== 'string') {
dataQuery = {
kind: getDataQueryKind(query),
kind: variable.state.datasource?.type ?? getDataQueryKind(query),
spec: getDataQuerySpec(query),
};
} else {
dataQuery = query;
dataQuery = {
kind: variable.state.datasource?.type ?? getDataQueryKind(query),
spec: {
[LEGACY_STRING_VALUE_KEY]: query,
},
};
}
const queryVariable: QueryVariableKind = {
kind: 'QueryVariable',

View File

@ -100,6 +100,7 @@ import {
transformVariableHideToEnumV1,
transformVariableRefreshToEnumV1,
} from './transformToV1TypesUtils';
import { LEGACY_STRING_VALUE_KEY } from './transformToV2TypesUtils';
const DEFAULT_DATASOURCE = 'default';
@ -635,12 +636,12 @@ function createSceneVariableFromVariableModel(variable: TypedVariableModelV2): S
}
function getDataQueryForVariable(variable: QueryVariableKind) {
return typeof variable.spec.query !== 'string'
? {
return LEGACY_STRING_VALUE_KEY in variable.spec.query.spec
? (variable.spec.query.spec[LEGACY_STRING_VALUE_KEY] ?? '')
: {
...variable.spec.query.spec,
refId: variable.spec.query.spec.refId ?? 'A',
}
: (variable.spec.query ?? '');
};
}
export function getCurrentValueForOldIntervalModel(variable: IntervalVariableKind, intervals: string[]): string {

View File

@ -225,7 +225,10 @@ describe('transformSceneToSaveModelSchemaV2', () => {
hide: VariableHideV1.hideLabel,
value: 'value1',
text: 'text1',
query: 'query1',
query: {
expr: 'label_values(node_boot_time_seconds)',
refId: 'A',
},
definition: 'definition1',
datasource: { uid: 'datasource1', type: 'prometheus' },
sort: VariableSortV1.alphabeticalDesc,

View File

@ -403,8 +403,11 @@ function getVizPanelQueries(vizPanel: VizPanel): PanelQueryKind[] {
return queries;
}
export function getDataQueryKind(query: SceneDataQuery): string {
// If the query has a datasource, use the datasource type, otherwise return empty kind
export function getDataQueryKind(query: SceneDataQuery | string): string {
if (typeof query === 'string') {
return getDefaultDataSourceRef()?.type ?? '';
}
return query.datasource?.type ?? getDefaultDataSourceRef()?.type ?? '';
}
@ -616,19 +619,15 @@ export function getAnnotationQueryKind(annotationQuery: AnnotationQuery): string
}
}
export function getDefaultDataSourceRef(): DataSourceRef | undefined {
export function getDefaultDataSourceRef(): DataSourceRef {
// we need to return the default datasource configured in the BootConfig
const defaultDatasource = config.bootData.settings.defaultDatasource;
// get default datasource type
const dsList = config.bootData.settings.datasources ?? {};
const dsList = config.bootData.settings.datasources;
const ds = dsList[defaultDatasource];
if (ds) {
return { type: ds.meta.id, uid: ds.name }; // in the datasource list from bootData "id" is the type
}
return undefined;
return { type: ds.meta.id, uid: ds.name }; // in the datasource list from bootData "id" is the type
}
// Function to know if the dashboard transformed is a valid DashboardV2Spec

View File

@ -19,6 +19,9 @@ import {
FieldColorModeId as FieldColorModeIdV2,
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0';
// used for QueryVariableKind's query prop - in schema V2 we've deprecated string type and support only DataQuery
export const LEGACY_STRING_VALUE_KEY = '__legacyStringValue';
export function transformCursorSynctoEnum(cursorSync?: DashboardCursorSyncV1): DashboardCursorSync {
switch (cursorSync) {
case 0:

View File

@ -53,7 +53,7 @@ export function validateVariable<
}
if (sceneVariable instanceof QueryVariable && variableKind.kind === 'QueryVariable') {
expect(sceneVariable?.state.datasource).toBe(variableKind.spec.datasource);
expect(sceneVariable?.state.query).toBe(variableKind.spec.query);
expect(sceneVariable?.state.query).toEqual(variableKind.spec.query.spec);
}
if (sceneVariable instanceof CustomVariable && variableKind.kind === 'CustomVariable') {
expect(sceneVariable?.state.query).toBe(variableKind.spec.query);

View File

@ -19,6 +19,7 @@ import {
} from 'app/features/apiserver/types';
import { getDefaultDataSourceRef } from 'app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2';
import {
LEGACY_STRING_VALUE_KEY,
transformVariableHideToEnum,
transformVariableRefreshToEnum,
} from 'app/features/dashboard-scene/serialization/transformToV2TypesUtils';
@ -915,7 +916,7 @@ describe('ResponseTransformers', () => {
expect(v2.spec.datasource).toEqual(v1.datasource);
if (typeof v1.query === 'string') {
expect(v2.spec.query).toEqual(v1.query);
expect(v2.spec.query.spec[LEGACY_STRING_VALUE_KEY]).toEqual(v1.query);
} else {
expect(v2.spec.query).toEqual({
kind: v1.datasource?.type,

View File

@ -62,6 +62,7 @@ import {
transformVariableRefreshToEnumV1,
} from 'app/features/dashboard-scene/serialization/transformToV1TypesUtils';
import {
LEGACY_STRING_VALUE_KEY,
transformCursorSynctoEnum,
transformDataTopic,
transformSortVariableToEnum,
@ -504,8 +505,12 @@ function getVariables(vars: TypedVariableModel[]): DashboardV2Spec['variables']
let query = v.query || {};
if (typeof query === 'string') {
console.error('Query variable query is a string. It needs to extend DataQuery.');
query = {};
console.warn(
'Query variable query is a string which is deprecated in the schema v2. It should extend DataQuery'
);
query = {
[LEGACY_STRING_VALUE_KEY]: query,
};
}
const qv: QueryVariableKind = {
@ -527,7 +532,7 @@ function getVariables(vars: TypedVariableModel[]): DashboardV2Spec['variables']
query: {
kind: v.datasource?.type || getDefaultDatasourceType(),
spec: {
...query,
...v.query,
},
},
},
@ -708,7 +713,10 @@ function getVariablesV1(vars: DashboardV2Spec['variables']): VariableModel[] {
...commonProperties,
current: v.spec.current,
options: v.spec.options,
query: typeof v.spec.query === 'string' ? v.spec.query : v.spec.query.spec,
query:
LEGACY_STRING_VALUE_KEY in v.spec.query.spec
? v.spec.query.spec[LEGACY_STRING_VALUE_KEY]
: v.spec.query.spec,
datasource: v.spec.datasource,
sort: transformSortVariableToEnumV1(v.spec.sort),
refresh: transformVariableRefreshToEnumV1(v.spec.refresh),