From 5bba89fc86f9b988e55857eeb7c2e7113ac2b333 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 4 Oct 2023 13:21:01 +0200 Subject: [PATCH] Scenes: Backward compatability with new template variable system for functions that don't pass scopedVars (#75937) * Use __grafanaScene in templateSrv * Update * fix --- .betterer.results | 5 +++-- package.json | 2 +- .../dashboard-scene/scene/DashboardScene.tsx | 3 +++ .../dashboard/services/TimeSrv.test.ts | 11 +++++----- .../features/dashboard/services/TimeSrv.ts | 5 +++-- .../features/templating/template_srv.test.ts | 20 ++++++++++++++++++- .../app/features/templating/template_srv.ts | 11 ++++++++++ public/app/types/window.d.ts | 7 +------ yarn.lock | 10 +++++----- 9 files changed, 51 insertions(+), 23 deletions(-) diff --git a/.betterer.results b/.betterer.results index a0abaf55e10..3501bb129a1 100644 --- a/.betterer.results +++ b/.betterer.results @@ -5214,8 +5214,9 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "10"], [0, 0, 0, "Unexpected any. Specify a different type.", "11"], [0, 0, 0, "Do not use any type assertions.", "12"], - [0, 0, 0, "Unexpected any. Specify a different type.", "13"], - [0, 0, 0, "Do not use any type assertions.", "14"] + [0, 0, 0, "Do not use any type assertions.", "13"], + [0, 0, 0, "Unexpected any. Specify a different type.", "14"], + [0, 0, 0, "Do not use any type assertions.", "15"] ], "public/app/features/transformers/FilterByValueTransformer/FilterByValueTransformerEditor.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] diff --git a/package.json b/package.json index 77210b3cd29..6d540f84489 100644 --- a/package.json +++ b/package.json @@ -250,7 +250,7 @@ "@grafana/lezer-traceql": "0.0.6", "@grafana/monaco-logql": "^0.0.7", "@grafana/runtime": "workspace:*", - "@grafana/scenes": "^1.11.0", + "@grafana/scenes": "^1.13.0", "@grafana/schema": "workspace:*", "@grafana/ui": "workspace:*", "@kusto/monaco-kusto": "^7.4.0", diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.tsx index a25fe340ff1..a31f99b2423 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.tsx @@ -78,12 +78,15 @@ export class DashboardScene extends SceneObjectBase { } private _activationHandler() { + window.__grafanaSceneContext = this; + if (this.state.isEditing) { this.startTrackingChanges(); } // Deactivation logic return () => { + window.__grafanaSceneContext = undefined; this.stopTrackingChanges(); this.stopUrlSync(); }; diff --git a/public/app/features/dashboard/services/TimeSrv.test.ts b/public/app/features/dashboard/services/TimeSrv.test.ts index 5fb8640adf8..aa067ae98ba 100644 --- a/public/app/features/dashboard/services/TimeSrv.test.ts +++ b/public/app/features/dashboard/services/TimeSrv.test.ts @@ -3,7 +3,7 @@ import { ContextSrvStub } from 'test/specs/helpers'; import { dateTime, isDateTime } from '@grafana/data'; import { config, HistoryWrapper, locationService, setLocationService } from '@grafana/runtime'; -import { SceneTimeRange } from '@grafana/scenes'; +import { EmbeddedScene, SceneCanvasText, SceneTimeRange } from '@grafana/scenes'; import { TimeModel } from '../state/TimeModel'; @@ -348,17 +348,16 @@ describe('timeSrv', () => { it('should use scene provided range if active', () => { timeSrv.setTime({ from: 'now-6h', to: 'now' }); - const timeRange = new SceneTimeRange({ - from: 'now-1h', - to: 'now', + window.__grafanaSceneContext = new EmbeddedScene({ + $timeRange: new SceneTimeRange({ from: 'now-1h', to: 'now' }), + body: new SceneCanvasText({ text: 'hello' }), }); - window.__timeRangeSceneObject = timeRange; let time = timeSrv.timeRange(); expect(time.raw.from).toBe('now-6h'); expect(time.raw.to).toBe('now'); - timeRange.activate(); + window.__grafanaSceneContext.activate(); time = timeSrv.timeRange(); expect(time.raw.from).toBe('now-1h'); expect(time.raw.to).toBe('now'); diff --git a/public/app/features/dashboard/services/TimeSrv.ts b/public/app/features/dashboard/services/TimeSrv.ts index accd2c13824..e2e2dd40a96 100644 --- a/public/app/features/dashboard/services/TimeSrv.ts +++ b/public/app/features/dashboard/services/TimeSrv.ts @@ -12,6 +12,7 @@ import { IntervalValues, } from '@grafana/data'; import { locationService } from '@grafana/runtime'; +import { sceneGraph } from '@grafana/scenes'; import appEvents from 'app/core/app_events'; import { config } from 'app/core/config'; import { AutoRefreshInterval, contextSrv, ContextSrv } from 'app/core/services/context_srv'; @@ -340,8 +341,8 @@ export class TimeSrv { timeRange(): TimeRange { // Scenes can set this global object to the current time range. // This is a patch to support data sources that rely on TimeSrv.getTimeRange() - if (window.__timeRangeSceneObject && window.__timeRangeSceneObject.isActive) { - return window.__timeRangeSceneObject.state.value; + if (window.__grafanaSceneContext && window.__grafanaSceneContext.isActive) { + return sceneGraph.getTimeRange(window.__grafanaSceneContext).state.value; } return getTimeRange(this.time, this.timeModel); diff --git a/public/app/features/templating/template_srv.test.ts b/public/app/features/templating/template_srv.test.ts index 413c2c11063..190bff5cce2 100644 --- a/public/app/features/templating/template_srv.test.ts +++ b/public/app/features/templating/template_srv.test.ts @@ -1,6 +1,6 @@ import { dateTime, TimeRange } from '@grafana/data'; import { setDataSourceSrv, VariableInterpolation } from '@grafana/runtime'; -import { TestVariable } from '@grafana/scenes'; +import { ConstantVariable, EmbeddedScene, SceneCanvasText, SceneVariableSet, TestVariable } from '@grafana/scenes'; import { VariableFormatID } from '@grafana/schema'; import { silenceConsoleOutput } from '../../../test/core/utils/silenceConsoleOutput'; @@ -813,7 +813,9 @@ describe('templateSrv', () => { describe('scenes compatibility', () => { beforeEach(() => { _templateSrv = initTemplateSrv(key, []); + interpolateMock.mockClear(); }); + it('should use scene interpolator when scoped var provided', () => { const variable = new TestVariable({}); @@ -823,5 +825,21 @@ describe('templateSrv', () => { expect(interpolateMock.mock.calls[0][0]).toEqual(variable); expect(interpolateMock.mock.calls[0][1]).toEqual('test ${test}'); }); + + it('should use scene interpolator global __grafanaSceneContext is active', () => { + window.__grafanaSceneContext = new EmbeddedScene({ + $variables: new SceneVariableSet({ + variables: [new ConstantVariable({ name: 'sceneVar', value: 'hello' })], + }), + body: new SceneCanvasText({ text: 'hello' }), + }); + + window.__grafanaSceneContext.activate(); + + _templateSrv.replace('test ${sceneVar}'); + expect(interpolateMock).toHaveBeenCalledTimes(1); + expect(interpolateMock.mock.calls[0][0]).toEqual(window.__grafanaSceneContext); + expect(interpolateMock.mock.calls[0][1]).toEqual('test ${sceneVar}'); + }); }); }); diff --git a/public/app/features/templating/template_srv.ts b/public/app/features/templating/template_srv.ts index c4ea8ba5a6a..7365efae0f7 100644 --- a/public/app/features/templating/template_srv.ts +++ b/public/app/features/templating/template_srv.ts @@ -241,6 +241,7 @@ export class TemplateSrv implements BaseTemplateSrv { format?: string | Function | undefined, interpolations?: VariableInterpolation[] ): string { + // Scenes compatability (primary method) is via SceneObject inside scopedVars. This way we get a much more accurate "local" scope for the evaluation if (scopedVars && scopedVars.__sceneObject) { return sceneGraph.interpolate( scopedVars.__sceneObject.value, @@ -250,6 +251,16 @@ export class TemplateSrv implements BaseTemplateSrv { ); } + // Scenes compatability: (secondary method) is using the current active scene as the scope for evaluation. + if (window.__grafanaSceneContext && window.__grafanaSceneContext.isActive) { + return sceneGraph.interpolate( + window.__grafanaSceneContext, + target, + scopedVars, + format as string | VariableCustomFormatterFn | undefined + ); + } + if (!target) { return target ?? ''; } diff --git a/public/app/types/window.d.ts b/public/app/types/window.d.ts index 311937d2554..bf4e7c5f049 100644 --- a/public/app/types/window.d.ts +++ b/public/app/types/window.d.ts @@ -1,11 +1,6 @@ export declare global { interface Window { - __timeRangeSceneObject: { - isActive: boolean; - state: { - value: TimeRange; - }; - }; + __grafanaSceneContext: SceneObject; __grafana_app_bundle_loaded: boolean; __grafana_public_path__: string; __grafana_load_failed: () => void; diff --git a/yarn.lock b/yarn.lock index 70ca8482d11..13ceaafd6cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3343,9 +3343,9 @@ __metadata: languageName: unknown linkType: soft -"@grafana/scenes@npm:^1.11.0": - version: 1.11.0 - resolution: "@grafana/scenes@npm:1.11.0" +"@grafana/scenes@npm:^1.13.0": + version: 1.13.0 + resolution: "@grafana/scenes@npm:1.13.0" dependencies: "@grafana/e2e-selectors": 10.0.2 react-grid-layout: 1.3.4 @@ -3357,7 +3357,7 @@ __metadata: "@grafana/runtime": 10.0.3 "@grafana/schema": 10.0.3 "@grafana/ui": 10.0.3 - checksum: fb7e21e11af29d861de2a47db25fc87fa6ffa4bc2c80784afcbf24d273f4aad1e21e7aa4cb176838cf5d869ae03b14822da235c9a398a2c41f816a93ef48c7e5 + checksum: 3a6c4419ee324d49f41b9569dc86ca7ffa926438eedd762aa79c3327c39cd16b9671047ad02f5de3c52190a81b4139cdb75653a4b3741753f851ca0c9155b9bf languageName: node linkType: hard @@ -17645,7 +17645,7 @@ __metadata: "@grafana/lezer-traceql": 0.0.6 "@grafana/monaco-logql": ^0.0.7 "@grafana/runtime": "workspace:*" - "@grafana/scenes": ^1.11.0 + "@grafana/scenes": ^1.13.0 "@grafana/schema": "workspace:*" "@grafana/tsconfig": ^1.3.0-rc1 "@grafana/ui": "workspace:*"