diff --git a/public/app/features/dashboard-scene/serialization/sceneVariablesSetToVariables.ts b/public/app/features/dashboard-scene/serialization/sceneVariablesSetToVariables.ts index 5063c6fd594..e8afa5b56b9 100644 --- a/public/app/features/dashboard-scene/serialization/sceneVariablesSetToVariables.ts +++ b/public/app/features/dashboard-scene/serialization/sceneVariablesSetToVariables.ts @@ -1,16 +1,16 @@ import { - SceneVariableSet, QueryVariable, CustomVariable, DataSourceVariable, ConstantVariable, IntervalVariable, + SceneVariables, } from '@grafana/scenes'; import { VariableModel, VariableHide, VariableRefresh, VariableSort } from '@grafana/schema'; import { getIntervalsQueryFromNewIntervalModel } from '../utils/utils'; -export function sceneVariablesSetToVariables(set: SceneVariableSet) { +export function sceneVariablesSetToVariables(set: SceneVariables) { const variables: VariableModel[] = []; for (const variable of set.state.variables) { const commonProperties = { diff --git a/public/app/features/dashboard-scene/utils/getVariablesCompatibility.ts b/public/app/features/dashboard-scene/utils/getVariablesCompatibility.ts new file mode 100644 index 00000000000..ed26220201f --- /dev/null +++ b/public/app/features/dashboard-scene/utils/getVariablesCompatibility.ts @@ -0,0 +1,16 @@ +import { TypedVariableModel } from '@grafana/data'; +import { sceneGraph, SceneObject } from '@grafana/scenes'; + +import { sceneVariablesSetToVariables } from '../serialization/sceneVariablesSetToVariables'; + +export function getVariablesCompatibility(sceneObject: SceneObject): TypedVariableModel[] { + const set = sceneGraph.getVariables(sceneObject); + const legacyModels = sceneVariablesSetToVariables(set); + + // Sadly templateSrv.getVariables returns TypedVariableModel but sceneVariablesSetToVariables return persisted schema model + // They look close to identical (differ in what is optional in some places). + // The way templateSrv.getVariables is used it should not matter. it is mostly used to get names of all variables (for query editors). + // So type and name are important. Maybe some external data sourcess also check current value so that is also important. + // @ts-expect-error + return legacyModels; +} diff --git a/public/app/features/templating/template_srv.test.ts b/public/app/features/templating/template_srv.test.ts index 3dfef81ed81..d6a13535532 100644 --- a/public/app/features/templating/template_srv.test.ts +++ b/public/app/features/templating/template_srv.test.ts @@ -1,6 +1,16 @@ -import { dateTime, TimeRange, TypedVariableModel } from '@grafana/data'; +import { dateTime, QueryVariableModel, TimeRange, TypedVariableModel } from '@grafana/data'; import { setDataSourceSrv, VariableInterpolation } from '@grafana/runtime'; -import { ConstantVariable, EmbeddedScene, SceneCanvasText, SceneVariableSet, TestVariable } from '@grafana/scenes'; +import { + ConstantVariable, + CustomVariable, + DataSourceVariable, + EmbeddedScene, + IntervalVariable, + QueryVariable, + SceneCanvasText, + SceneVariableSet, + TestVariable, +} from '@grafana/scenes'; import { VariableFormatID } from '@grafana/schema'; import { silenceConsoleOutput } from '../../../test/core/utils/silenceConsoleOutput'; @@ -24,6 +34,7 @@ const interpolateMock = jest.fn(); jest.mock('@grafana/scenes', () => ({ ...jest.requireActual('@grafana/scenes'), sceneGraph: { + ...jest.requireActual('@grafana/scenes').sceneGraph, interpolate: (...args: unknown[]) => interpolateMock(...args), }, })); @@ -844,5 +855,39 @@ describe('templateSrv', () => { expect(interpolateMock.mock.calls[0][0]).toEqual(window.__grafanaSceneContext); expect(interpolateMock.mock.calls[0][1]).toEqual('test ${sceneVar}'); }); + + it('Can use getVariables to access scene variables', () => { + window.__grafanaSceneContext = new EmbeddedScene({ + $variables: new SceneVariableSet({ + variables: [ + new QueryVariable({ name: 'server', value: 'serverA', text: 'Server A' }), + new QueryVariable({ name: 'pods', value: ['pA', 'pB'], text: ['podA', 'podB'] }), + new DataSourceVariable({ name: 'ds', value: 'dsA', text: 'dsA', pluginId: 'prometheus' }), + new CustomVariable({ name: 'custom', value: 'A', text: 'A', query: 'A, B, C' }), + new IntervalVariable({ name: 'interval', value: '1m', intervals: ['1m', '2m'] }), + ], + }), + body: new SceneCanvasText({ text: 'hello' }), + }); + + window.__grafanaSceneContext.activate(); + + const vars = _templateSrv.getVariables(); + expect(vars.length).toBe(5); + + const serverVar = vars[0] as QueryVariableModel; + + expect(serverVar.name).toBe('server'); + expect(serverVar.type).toBe('query'); + expect(serverVar.current.value).toBe('serverA'); + expect(serverVar.current.text).toBe('Server A'); + + const podVar = vars[1] as QueryVariableModel; + + expect(podVar.name).toBe('pods'); + expect(podVar.type).toBe('query'); + expect(podVar.current.value).toEqual(['pA', 'pB']); + expect(podVar.current.text).toEqual(['podA', 'podB']); + }); }); }); diff --git a/public/app/features/templating/template_srv.ts b/public/app/features/templating/template_srv.ts index ab4760f1c6a..4722938134d 100644 --- a/public/app/features/templating/template_srv.ts +++ b/public/app/features/templating/template_srv.ts @@ -18,6 +18,7 @@ import { import { sceneGraph, VariableCustomFormatterFn } from '@grafana/scenes'; import { VariableFormatID } from '@grafana/schema'; +import { getVariablesCompatibility } from '../dashboard-scene/utils/getVariablesCompatibility'; import { variableAdapters } from '../variables/adapters'; import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE } from '../variables/constants'; import { isAdHoc } from '../variables/guard'; @@ -74,6 +75,11 @@ export class TemplateSrv implements BaseTemplateSrv { } getVariables(): TypedVariableModel[] { + // For scenes we have this backward compatiblity translation + if (window.__grafanaSceneContext) { + return getVariablesCompatibility(window.__grafanaSceneContext); + } + return this.dependencies.getVariables(); }