mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Dashboard SchemaV2: V2 -> Scene -> V2 integration test (#98146)
* Tests for layout, transformations; displayMode * wip * fix annotations * fix panel query and transformation topic * fix dash id, default options, fieldConfig * Complete integration test * fix annotation query * Fix test * Clarify * Have default value of builtIn * update import path
This commit is contained in:
parent
e43e86376e
commit
a110917577
@ -3198,6 +3198,9 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Do not use any type assertions.", "4"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"]
|
||||
],
|
||||
"public/app/features/dashboard-scene/serialization/transformToV1TypesUtils.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
"public/app/features/dashboard-scene/settings/DeleteDashboardButton.tsx:5381": [
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
|
||||
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"],
|
||||
|
@ -476,7 +476,7 @@ export const defaultVizConfigKind = (): VizConfigKind => ({
|
||||
|
||||
export interface AnnotationQuerySpec {
|
||||
datasource?: DataSourceRef;
|
||||
query: DataQueryKind;
|
||||
query?: DataQueryKind;
|
||||
builtIn?: boolean;
|
||||
enable: boolean;
|
||||
filter: AnnotationPanelFilter;
|
||||
@ -486,7 +486,7 @@ export interface AnnotationQuerySpec {
|
||||
}
|
||||
|
||||
export const defaultAnnotationQuerySpec = (): AnnotationQuerySpec => ({
|
||||
query: defaultDataQueryKind(),
|
||||
builtIn: false,
|
||||
enable: false,
|
||||
filter: defaultAnnotationPanelFilter(),
|
||||
hide: false,
|
||||
@ -976,7 +976,6 @@ export interface DatasourceVariableSpec {
|
||||
refresh: VariableRefresh;
|
||||
regex: string;
|
||||
current: VariableOption;
|
||||
defaultOptionEnabled: boolean;
|
||||
options: VariableOption[];
|
||||
multi: boolean;
|
||||
includeAll: boolean;
|
||||
@ -993,7 +992,6 @@ export const defaultDatasourceVariableSpec = (): DatasourceVariableSpec => ({
|
||||
refresh: "never",
|
||||
regex: "",
|
||||
current: { text: "", value: "", },
|
||||
defaultOptionEnabled: false,
|
||||
options: [],
|
||||
multi: false,
|
||||
includeAll: false,
|
||||
|
@ -369,8 +369,8 @@ VizConfigKind: {
|
||||
|
||||
AnnotationQuerySpec: {
|
||||
datasource?: DataSourceRef
|
||||
query: DataQueryKind
|
||||
builtIn?: bool
|
||||
query?: DataQueryKind
|
||||
builtIn?: bool | *false
|
||||
enable: bool
|
||||
filter: AnnotationPanelFilter
|
||||
hide: bool
|
||||
@ -672,7 +672,6 @@ DatasourceVariableSpec: {
|
||||
text: ""
|
||||
value: ""
|
||||
}
|
||||
defaultOptionEnabled: bool | *false
|
||||
options: [...VariableOption] | *[]
|
||||
multi: bool | *false
|
||||
includeAll: bool | *false
|
||||
|
@ -26,7 +26,7 @@ export const handyTestingSchema: DashboardV2Spec = {
|
||||
{
|
||||
kind: 'AnnotationQuery',
|
||||
spec: {
|
||||
builtIn: true,
|
||||
builtIn: false,
|
||||
query: {
|
||||
kind: 'prometheus',
|
||||
spec: {
|
||||
@ -47,6 +47,7 @@ export const handyTestingSchema: DashboardV2Spec = {
|
||||
{
|
||||
kind: 'AnnotationQuery',
|
||||
spec: {
|
||||
builtIn: false,
|
||||
datasource: {
|
||||
type: 'grafana-testdata-datasource',
|
||||
uid: 'uid',
|
||||
@ -69,6 +70,7 @@ export const handyTestingSchema: DashboardV2Spec = {
|
||||
{
|
||||
kind: 'AnnotationQuery',
|
||||
spec: {
|
||||
builtIn: false,
|
||||
datasource: {
|
||||
type: 'grafana-testdata-datasource',
|
||||
uid: 'uid',
|
||||
@ -87,6 +89,7 @@ export const handyTestingSchema: DashboardV2Spec = {
|
||||
{
|
||||
kind: 'AnnotationQuery',
|
||||
spec: {
|
||||
builtIn: false,
|
||||
datasource: {
|
||||
type: 'grafana-testdata-datasource',
|
||||
uid: 'uid',
|
||||
@ -284,7 +287,6 @@ export const handyTestingSchema: DashboardV2Spec = {
|
||||
text: 'text1',
|
||||
value: 'value1',
|
||||
},
|
||||
defaultOptionEnabled: true,
|
||||
description: 'A datasource variable',
|
||||
hide: 'dontHide',
|
||||
includeAll: false,
|
||||
@ -345,7 +347,7 @@ export const handyTestingSchema: DashboardV2Spec = {
|
||||
},
|
||||
],
|
||||
query: '1m,5m,10m',
|
||||
refresh: 'onDashboardLoad',
|
||||
refresh: 'onTimeRangeChanged',
|
||||
skipUrlSync: false,
|
||||
},
|
||||
},
|
||||
|
@ -19,14 +19,6 @@ exports[`transformSceneToSaveModelSchemaV2 should transform scene to save model
|
||||
"hide": false,
|
||||
"iconColor": "red",
|
||||
"name": "query1",
|
||||
"query": {
|
||||
"kind": "grafana",
|
||||
"spec": {
|
||||
"enable": true,
|
||||
"iconColor": "red",
|
||||
"name": "query1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -45,14 +37,6 @@ exports[`transformSceneToSaveModelSchemaV2 should transform scene to save model
|
||||
"hide": true,
|
||||
"iconColor": "blue",
|
||||
"name": "query2",
|
||||
"query": {
|
||||
"kind": "prometheus",
|
||||
"spec": {
|
||||
"enable": true,
|
||||
"iconColor": "blue",
|
||||
"name": "query2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -71,14 +55,6 @@ exports[`transformSceneToSaveModelSchemaV2 should transform scene to save model
|
||||
"hide": true,
|
||||
"iconColor": "green",
|
||||
"name": "query3",
|
||||
"query": {
|
||||
"kind": "loki",
|
||||
"spec": {
|
||||
"enable": true,
|
||||
"iconColor": "green",
|
||||
"name": "query3",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
@ -125,6 +101,7 @@ exports[`transformSceneToSaveModelSchemaV2 should transform scene to save model
|
||||
},
|
||||
},
|
||||
},
|
||||
"id": 1,
|
||||
"layout": {
|
||||
"kind": "GridLayout",
|
||||
"spec": {
|
||||
@ -249,7 +226,6 @@ exports[`transformSceneToSaveModelSchemaV2 should transform scene to save model
|
||||
"text": "text1",
|
||||
"value": "value1",
|
||||
},
|
||||
"defaultOptionEnabled": true,
|
||||
"description": "A datasource variable",
|
||||
"hide": "dontHide",
|
||||
"includeAll": false,
|
||||
|
@ -888,7 +888,6 @@ describe('sceneVariablesSetToVariables', () => {
|
||||
"selected-ds-2",
|
||||
],
|
||||
},
|
||||
"defaultOptionEnabled": false,
|
||||
"description": "test-desc",
|
||||
"hide": "dontHide",
|
||||
"includeAll": true,
|
||||
|
@ -326,7 +326,6 @@ export function sceneVariablesSetToSchemaV2Variables(
|
||||
regex: variable.state.regex,
|
||||
refresh: 'onDashboardLoad',
|
||||
pluginId: variable.state.pluginId,
|
||||
defaultOptionEnabled: !!variable.state.defaultOptionEnabled,
|
||||
multi: variable.state.isMulti || false,
|
||||
allValue: variable.state.allValue,
|
||||
includeAll: variable.state.includeAll || false,
|
||||
|
@ -516,6 +516,7 @@ function createSceneVariableFromVariableModel(variable: TypedVariableModelV2): S
|
||||
value: variable.spec.current?.value || [],
|
||||
text: variable.spec.current?.text || [],
|
||||
skipUrlSync: variable.spec.skipUrlSync,
|
||||
isMulti: variable.spec.multi,
|
||||
hide: transformVariableHideToEnumV1(variable.spec.hide),
|
||||
// @ts-expect-error
|
||||
defaultOptions: variable.options,
|
||||
|
@ -85,6 +85,7 @@ describe('transformSceneToSaveModelSchemaV2', () => {
|
||||
// with all the possible properties set
|
||||
dashboardScene = setupDashboardScene({
|
||||
$data: new DashboardDataLayerSet({ annotationLayers }),
|
||||
id: 1,
|
||||
title: 'Test Dashboard',
|
||||
description: 'Test Description',
|
||||
preload: true,
|
||||
@ -328,7 +329,7 @@ describe('transformSceneToSaveModelSchemaV2', () => {
|
||||
// Check that the annotation layers are correctly transformed
|
||||
expect(result.annotations).toHaveLength(3);
|
||||
// check annotation layer 3 with no datasource has the default datasource defined as type
|
||||
expect(result.annotations?.[2].spec.query.kind).toBe('loki');
|
||||
expect(result.annotations?.[2].spec.datasource?.type).toBe('loki');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -36,7 +36,6 @@ import {
|
||||
AdhocVariableKind,
|
||||
AnnotationQueryKind,
|
||||
defaultAnnotationPanelFilter,
|
||||
defaultAnnotationQuerySpec,
|
||||
DataLink,
|
||||
} from '../../../../../packages/grafana-schema/src/schema/dashboard/v2alpha0/dashboard.gen';
|
||||
import { DashboardDataLayerSet } from '../scene/DashboardDataLayerSet';
|
||||
@ -66,6 +65,7 @@ export function transformSceneToSaveModelSchemaV2(scene: DashboardScene, isSnaps
|
||||
|
||||
const dashboardSchemaV2: DeepPartial<DashboardV2Spec> = {
|
||||
//dashboard settings
|
||||
id: oldDash.id ? oldDash.id : undefined,
|
||||
title: oldDash.title,
|
||||
description: oldDash.description ?? '',
|
||||
cursorSync: getCursorSync(oldDash),
|
||||
@ -265,13 +265,13 @@ function getVizPanelQueries(vizPanel: VizPanel): PanelQueryKind[] {
|
||||
vizPanelQueries.forEach((query) => {
|
||||
const dataQuery: DataQueryKind = {
|
||||
kind: getDataQueryKind(query),
|
||||
spec: query,
|
||||
spec: omit(query, 'datasource', 'refId', 'hide'),
|
||||
};
|
||||
const querySpec: PanelQuerySpec = {
|
||||
datasource: datasource ?? getDefaultDataSourceRef(),
|
||||
query: dataQuery,
|
||||
refId: query.refId,
|
||||
hidden: query.hidden,
|
||||
hidden: Boolean(query.hide),
|
||||
};
|
||||
queries.push({
|
||||
kind: 'PanelQuery',
|
||||
@ -312,10 +312,13 @@ function getVizPanelTransformations(vizPanel: VizPanel): TransformationKind[] {
|
||||
id: transformation.filter?.id ?? '',
|
||||
options: transformation.filter?.options ?? {},
|
||||
},
|
||||
topic: transformation.topic,
|
||||
options: transformation.options,
|
||||
};
|
||||
|
||||
if (transformation.topic !== undefined) {
|
||||
transformationSpec.topic = transformation.topic;
|
||||
}
|
||||
|
||||
transformations.push({
|
||||
kind: transformation.id,
|
||||
spec: transformationSpec,
|
||||
@ -349,6 +352,7 @@ function getVizPanelQueryOptions(vizPanel: VizPanel): QueryOptionsSpec {
|
||||
if (panelTime instanceof PanelTimeRange) {
|
||||
queryOptions.timeFrom = panelTime.state.timeFrom;
|
||||
queryOptions.timeShift = panelTime.state.timeShift;
|
||||
queryOptions.hideTimeOverride = panelTime.state.hideTimeOverride;
|
||||
}
|
||||
return queryOptions;
|
||||
}
|
||||
@ -399,22 +403,25 @@ function getAnnotations(state: DashboardSceneState): AnnotationQueryKind[] {
|
||||
const result: AnnotationQueryKind = {
|
||||
kind: 'AnnotationQuery',
|
||||
spec: {
|
||||
builtIn: Boolean(layer.state.query.builtIn),
|
||||
name: layer.state.query.name,
|
||||
datasource: layer.state.query.datasource || getDefaultDataSourceRef(),
|
||||
query: {
|
||||
kind: getAnnotationQueryKind(layer.state.query),
|
||||
spec: omit(layer.state.query, 'datasource'),
|
||||
},
|
||||
enable: Boolean(layer.state.isEnabled),
|
||||
hide: Boolean(layer.state.isHidden),
|
||||
filter: layer.state.query.filter ?? defaultAnnotationPanelFilter(),
|
||||
iconColor: layer.state.query.iconColor,
|
||||
builtIn:
|
||||
layer.state.query.builtIn === undefined
|
||||
? Boolean(layer.state.query.builtIn)
|
||||
: defaultAnnotationQuerySpec().builtIn,
|
||||
},
|
||||
};
|
||||
|
||||
// Check if DataQueryKind exists
|
||||
const queryKind = getAnnotationQueryKind(layer.state.query);
|
||||
if (layer.state.query.query?.kind === queryKind) {
|
||||
result.spec.query = {
|
||||
kind: queryKind,
|
||||
spec: layer.state.query.query.spec,
|
||||
};
|
||||
}
|
||||
|
||||
annotations.push(result);
|
||||
}
|
||||
return annotations;
|
||||
|
@ -113,44 +113,52 @@ export function transformMappingsToV1(fieldConfig: FieldConfigSource): FieldConf
|
||||
}
|
||||
};
|
||||
|
||||
const transformedDefaults: any = {
|
||||
...fieldConfig.defaults,
|
||||
};
|
||||
|
||||
if (fieldConfig.defaults.mappings) {
|
||||
transformedDefaults.mappings = fieldConfig.defaults.mappings.map((mapping) => {
|
||||
switch (mapping.type) {
|
||||
case 'value':
|
||||
return {
|
||||
...mapping,
|
||||
type: MappingTypeV1.ValueToText,
|
||||
};
|
||||
case 'range':
|
||||
return {
|
||||
...mapping,
|
||||
type: MappingTypeV1.RangeToText,
|
||||
};
|
||||
case 'regex':
|
||||
return {
|
||||
...mapping,
|
||||
type: MappingTypeV1.RegexToText,
|
||||
};
|
||||
case 'special':
|
||||
return {
|
||||
...mapping,
|
||||
options: {
|
||||
...mapping.options,
|
||||
match: transformSpecialValueMatchToV1(mapping.options.match),
|
||||
},
|
||||
type: MappingTypeV1.SpecialValue,
|
||||
};
|
||||
default:
|
||||
return mapping;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (fieldConfig.defaults.thresholds) {
|
||||
transformedDefaults.thresholds = {
|
||||
...fieldConfig.defaults.thresholds,
|
||||
mode: getThresholdsMode(fieldConfig.defaults.thresholds.mode),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...fieldConfig,
|
||||
defaults: {
|
||||
...fieldConfig.defaults,
|
||||
mappings: fieldConfig.defaults.mappings?.map((mapping) => {
|
||||
switch (mapping.type) {
|
||||
case 'value':
|
||||
return {
|
||||
...mapping,
|
||||
type: MappingTypeV1.ValueToText,
|
||||
};
|
||||
case 'range':
|
||||
return {
|
||||
...mapping,
|
||||
type: MappingTypeV1.RangeToText,
|
||||
};
|
||||
case 'regex':
|
||||
return {
|
||||
...mapping,
|
||||
type: MappingTypeV1.RegexToText,
|
||||
};
|
||||
case 'special':
|
||||
return {
|
||||
...mapping,
|
||||
options: {
|
||||
...mapping.options,
|
||||
match: transformSpecialValueMatchToV1(mapping.options.match),
|
||||
},
|
||||
type: MappingTypeV1.SpecialValue,
|
||||
};
|
||||
default:
|
||||
return mapping;
|
||||
}
|
||||
}),
|
||||
thresholds: fieldConfig.defaults.thresholds && {
|
||||
...fieldConfig.defaults.thresholds,
|
||||
mode: getThresholdsMode(fieldConfig.defaults.thresholds.mode),
|
||||
},
|
||||
},
|
||||
defaults: transformedDefaults,
|
||||
};
|
||||
}
|
||||
|
@ -0,0 +1,91 @@
|
||||
import { config } from '@grafana/runtime';
|
||||
import { CustomVariable, GroupByVariable } from '@grafana/scenes';
|
||||
import { DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0/dashboard.gen';
|
||||
import { handyTestingSchema } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0/examples';
|
||||
import { DashboardWithAccessInfo } from 'app/features/dashboard/api/types';
|
||||
|
||||
import { transformSaveModelSchemaV2ToScene } from '../serialization/transformSaveModelSchemaV2ToScene';
|
||||
import { transformSceneToSaveModelSchemaV2 } from '../serialization/transformSceneToSaveModelSchemaV2';
|
||||
|
||||
const defaultDashboard: DashboardWithAccessInfo<DashboardV2Spec> = {
|
||||
kind: 'DashboardWithAccessInfo',
|
||||
metadata: {
|
||||
name: 'dashboard-uid',
|
||||
namespace: 'default',
|
||||
labels: {},
|
||||
resourceVersion: '',
|
||||
creationTimestamp: '',
|
||||
},
|
||||
spec: handyTestingSchema,
|
||||
access: {},
|
||||
apiVersion: 'v2',
|
||||
};
|
||||
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
...jest.requireActual('@grafana/runtime'),
|
||||
getDataSourceSrv: () => ({
|
||||
getInstanceSettings: jest.fn(),
|
||||
}),
|
||||
config: {
|
||||
...jest.requireActual('@grafana/runtime').config,
|
||||
bootData: {
|
||||
settings: {
|
||||
defaultDatasource: 'prometheus',
|
||||
datasources: {
|
||||
prometheus: {
|
||||
name: 'datasource1',
|
||||
meta: { id: 'prometheus' },
|
||||
type: 'prometheus',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
describe('V2 Transformers', () => {
|
||||
beforeAll(() => {
|
||||
config.featureToggles.groupByVariable = true;
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
config.featureToggles.groupByVariable = false;
|
||||
});
|
||||
it('should match original V2 Schema when transforming to scene and back to V2 Schema', async () => {
|
||||
const dashV2Scene = transformSaveModelSchemaV2ToScene(defaultDashboard);
|
||||
// Find and manually set options for CustomVariable
|
||||
// Options are set based on query field using getValueOptions
|
||||
const customVariable = dashV2Scene.state.$variables?.state.variables.find(
|
||||
(v) => v instanceof CustomVariable
|
||||
) as CustomVariable;
|
||||
expect(customVariable).toBeDefined();
|
||||
|
||||
const customOptions$ = customVariable.getValueOptions({});
|
||||
const customOptions = await customOptions$.toPromise();
|
||||
customVariable.setState({ options: customOptions });
|
||||
|
||||
// Find and manually set defaultOptions for GroupByVariable
|
||||
// If defaultOptions are provided, getValueOptions will set options to defaultOptions
|
||||
const groupByVariable = dashV2Scene.state.$variables?.state.variables.find(
|
||||
(v) => v instanceof GroupByVariable
|
||||
) as GroupByVariable;
|
||||
expect(groupByVariable).toBeDefined();
|
||||
|
||||
// Set default options directly in state
|
||||
groupByVariable.setState({
|
||||
defaultOptions: [
|
||||
{ text: 'option1', value: 'option1' },
|
||||
{ text: 'option2', value: 'option2' },
|
||||
],
|
||||
});
|
||||
|
||||
const groupOptions$ = groupByVariable.getValueOptions({});
|
||||
const groupOptions = await groupOptions$.toPromise();
|
||||
groupByVariable.setState({ options: groupOptions });
|
||||
|
||||
// Transform back to dashboard V2 spec
|
||||
const dashV2 = transformSceneToSaveModelSchemaV2(dashV2Scene);
|
||||
|
||||
expect(dashV2).toEqual(defaultDashboard.spec);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user