diff --git a/package.json b/package.json index 286a3f46878..c5f6e4338c6 100644 --- a/package.json +++ b/package.json @@ -252,7 +252,7 @@ "@grafana/prometheus": "workspace:*", "@grafana/runtime": "workspace:*", "@grafana/saga-icons": "workspace:*", - "@grafana/scenes": "3.13.3", + "@grafana/scenes": "4.0.1", "@grafana/schema": "workspace:*", "@grafana/sql": "workspace:*", "@grafana/ui": "workspace:*", diff --git a/public/app/features/dashboard-scene/panel-edit/VizPanelManager.test.tsx b/public/app/features/dashboard-scene/panel-edit/VizPanelManager.test.tsx index 8fa98555ea8..bd656881769 100644 --- a/public/app/features/dashboard-scene/panel-edit/VizPanelManager.test.tsx +++ b/public/app/features/dashboard-scene/panel-edit/VizPanelManager.test.tsx @@ -95,6 +95,17 @@ const instance2SettingsMock = { }, }; +// Mocking the build in Grafana data source to avoid annotations data layer errors. +const grafanaDs = { + id: 1, + uid: '-- Grafana --', + name: 'grafana', + type: 'grafana', + meta: { + id: 'grafana', + }, +}; + // Mock the store module jest.mock('app/core/store', () => ({ exists: jest.fn(), @@ -112,6 +123,11 @@ jest.mock('@grafana/runtime', () => ({ }, getDataSourceSrv: () => ({ get: async (ref: DataSourceRef) => { + // Mocking the build in Grafana data source to avoid annotations data layer errors. + if (ref.uid === '-- Grafana --') { + return grafanaDs; + } + if (ref.uid === 'gdev-testdata') { return ds1Mock; } @@ -707,6 +723,7 @@ describe('VizPanelManager', () => { const setupTest = (panelId: string) => { const scene = transformSaveModelToScene({ dashboard: testDashboard, meta: {} }); + const panel = findVizPanelByKey(scene, panelId)!; const vizPanelManager = VizPanelManager.createFor(panel); diff --git a/public/app/features/dashboard-scene/saving/DashboardSceneChangeTracker.ts b/public/app/features/dashboard-scene/saving/DashboardSceneChangeTracker.ts index be1bcd00218..09640d8b300 100644 --- a/public/app/features/dashboard-scene/saving/DashboardSceneChangeTracker.ts +++ b/public/app/features/dashboard-scene/saving/DashboardSceneChangeTracker.ts @@ -1,7 +1,7 @@ import { Unsubscribable } from 'rxjs'; import { - SceneDataLayers, + SceneDataLayerSet, SceneGridLayout, SceneObjectStateChangedEvent, SceneRefreshPicker, @@ -38,7 +38,7 @@ export class DashboardSceneChangeTracker { if (payload.changedObject instanceof behaviors.CursorSync) { this.detectChanges(); } - if (payload.changedObject instanceof SceneDataLayers) { + if (payload.changedObject instanceof SceneDataLayerSet) { this.detectChanges(); } if (payload.changedObject instanceof DashboardGridItem) { diff --git a/public/app/features/dashboard-scene/scene/AlertStatesDataLayer.ts b/public/app/features/dashboard-scene/scene/AlertStatesDataLayer.ts index ec64e60a499..5bea2d7b023 100644 --- a/public/app/features/dashboard-scene/scene/AlertStatesDataLayer.ts +++ b/public/app/features/dashboard-scene/scene/AlertStatesDataLayer.ts @@ -122,30 +122,33 @@ export class AlertStatesDataLayer this.querySub = alerStatesExecution.subscribe({ next: (stateUpdate) => { - this.publishResults( - { - state: LoadingState.Done, - series: [toDataFrame(stateUpdate)], - timeRange: timeRange.state.value, - }, - DataTopic.AlertStates - ); + const frame = toDataFrame(stateUpdate); + this.publishResults({ + state: LoadingState.Done, + series: [ + { + ...frame, + meta: { + ...frame.meta, + dataTopic: DataTopic.AlertStates, + }, + }, + ], + timeRange: timeRange.state.value, + }); }, error: (err) => { this.handleError(err); - this.publishResults( - { - state: LoadingState.Error, - series: [], - errors: [ - { - message: getMessageFromError(err), - }, - ], - timeRange: timeRange.state.value, - }, - DataTopic.AlertStates - ); + this.publishResults({ + state: LoadingState.Error, + series: [], + errors: [ + { + message: getMessageFromError(err), + }, + ], + timeRange: timeRange.state.value, + }); }, }); } diff --git a/public/app/features/dashboard-scene/scene/setDashboardPanelContext.ts b/public/app/features/dashboard-scene/scene/setDashboardPanelContext.ts index bb10455fd72..516ff3080b2 100644 --- a/public/app/features/dashboard-scene/scene/setDashboardPanelContext.ts +++ b/public/app/features/dashboard-scene/scene/setDashboardPanelContext.ts @@ -1,5 +1,5 @@ import { AnnotationChangeEvent, AnnotationEventUIModel, CoreApp, DataFrame } from '@grafana/data'; -import { AdHocFiltersVariable, dataLayers, SceneDataLayers, sceneGraph, sceneUtils, VizPanel } from '@grafana/scenes'; +import { AdHocFiltersVariable, dataLayers, SceneDataLayerSet, sceneGraph, sceneUtils, VizPanel } from '@grafana/scenes'; import { DataSourceRef } from '@grafana/schema'; import { AdHocFilterItem, PanelContext } from '@grafana/ui'; import { deleteAnnotation, saveAnnotation, updateAnnotation } from 'app/features/annotations/api'; @@ -129,7 +129,7 @@ export function setDashboardPanelContext(vizPanel: VizPanel, context: PanelConte function getBuiltInAnnotationsLayer(scene: DashboardScene): dataLayers.AnnotationsDataLayer | undefined { // When there is no builtin annotations query we disable the ability to add annotations - if (scene.state.$data instanceof SceneDataLayers) { + if (scene.state.$data instanceof SceneDataLayerSet) { for (const layer of scene.state.$data.state.layers) { if (layer instanceof dataLayers.AnnotationsDataLayer) { if (layer.state.isEnabled && layer.state.query.builtIn) { diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts index 7fc18f19aeb..3bc76a2d975 100644 --- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts +++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts @@ -20,7 +20,7 @@ import { GroupByVariable, QueryVariable, SceneDataLayerControls, - SceneDataLayers, + SceneDataLayerSet, SceneDataTransformer, SceneGridLayout, SceneGridRow, @@ -1230,10 +1230,10 @@ describe('transformSaveModelToScene', () => { it('Should build correct scene model', () => { const scene = transformSaveModelToScene({ dashboard: dashboard_to_load1 as any, meta: {} }); - expect(scene.state.$data).toBeInstanceOf(SceneDataLayers); + expect(scene.state.$data).toBeInstanceOf(SceneDataLayerSet); expect(scene.state.controls!.state.variableControls[1]).toBeInstanceOf(SceneDataLayerControls); - const dataLayers = scene.state.$data as SceneDataLayers; + const dataLayers = scene.state.$data as SceneDataLayerSet; expect(dataLayers.state.layers).toHaveLength(4); expect(dataLayers.state.layers[0].state.name).toBe('Annotations & Alerts'); expect(dataLayers.state.layers[0].state.isEnabled).toBe(true); @@ -1258,10 +1258,10 @@ describe('transformSaveModelToScene', () => { config.unifiedAlertingEnabled = true; const scene = transformSaveModelToScene({ dashboard: dashboard_to_load1 as any, meta: {} }); - expect(scene.state.$data).toBeInstanceOf(SceneDataLayers); + expect(scene.state.$data).toBeInstanceOf(SceneDataLayerSet); expect(scene.state.controls!.state.variableControls[1]).toBeInstanceOf(SceneDataLayerControls); - const dataLayers = scene.state.$data as SceneDataLayers; + const dataLayers = scene.state.$data as SceneDataLayerSet; expect(dataLayers.state.layers).toHaveLength(5); expect(dataLayers.state.layers[4].state.name).toBe('Alert States'); }); @@ -1272,10 +1272,10 @@ describe('transformSaveModelToScene', () => { dashboard.panels![0].alert = {}; const scene = transformSaveModelToScene({ dashboard: dashboard_to_load1 as any, meta: {} }); - expect(scene.state.$data).toBeInstanceOf(SceneDataLayers); + expect(scene.state.$data).toBeInstanceOf(SceneDataLayerSet); expect(scene.state.controls!.state.variableControls[1]).toBeInstanceOf(SceneDataLayerControls); - const dataLayers = scene.state.$data as SceneDataLayers; + const dataLayers = scene.state.$data as SceneDataLayerSet; expect(dataLayers.state.layers).toHaveLength(5); expect(dataLayers.state.layers[4].state.name).toBe('Alert States'); }); diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts index 1827e5f2b83..ae68c88821f 100644 --- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts +++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts @@ -20,7 +20,7 @@ import { behaviors, VizPanelState, SceneGridItemLike, - SceneDataLayers, + SceneDataLayerSet, SceneDataLayerProvider, SceneDataLayerControls, TextBoxVariable, @@ -309,7 +309,7 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel) ], $data: layers.length > 0 - ? new SceneDataLayers({ + ? new SceneDataLayerSet({ layers, }) : undefined, diff --git a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.test.ts b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.test.ts index 741d23b3c9a..a70db28790a 100644 --- a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.test.ts +++ b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.test.ts @@ -16,7 +16,7 @@ import { } from '@grafana/data'; import { getPanelPlugin } from '@grafana/data/test/__mocks__/pluginMocks'; import { getPluginLinkExtensions, setPluginImportUtils } from '@grafana/runtime'; -import { MultiValueVariable, SceneDataLayers, SceneGridLayout, SceneGridRow, VizPanel } from '@grafana/scenes'; +import { MultiValueVariable, SceneDataLayerSet, SceneGridLayout, SceneGridRow, VizPanel } from '@grafana/scenes'; import { Dashboard, LoadingState, Panel, RowPanel, VariableRefresh } from '@grafana/schema'; import { PanelModel } from 'app/features/dashboard/state'; import { getTimeRange } from 'app/features/dashboard/utils/timeRange'; @@ -405,7 +405,7 @@ describe('transformSceneToSaveModel', () => { it('should transform annotations to save model after state changes', () => { const scene = transformSaveModelToScene({ dashboard: dashboard_to_load1 as any, meta: {} }); - const layers = (scene.state.$data as SceneDataLayers)?.state.layers; + const layers = (scene.state.$data as SceneDataLayerSet)?.state.layers; const enabledLayer = layers[1]; const hiddenLayer = layers[3]; diff --git a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts index 492a70ff804..d590c168b6f 100644 --- a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts +++ b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts @@ -3,7 +3,6 @@ import { isEqual } from 'lodash'; import { isEmptyObject, ScopedVars, TimeRange } from '@grafana/data'; import { behaviors, - SceneDataLayers, SceneGridItemLike, SceneGridLayout, SceneGridRow, @@ -11,6 +10,7 @@ import { SceneDataTransformer, SceneVariableSet, LocalValueVariable, + SceneDataLayerSet, } from '@grafana/scenes'; import { AnnotationQuery, @@ -77,7 +77,7 @@ export function transformSceneToSaveModel(scene: DashboardScene, isSnapshot = fa } let annotations: AnnotationQuery[] = []; - if (data instanceof SceneDataLayers) { + if (data instanceof SceneDataLayerSet) { const layers = data.state.layers; annotations = dataLayersToAnnotations(layers); diff --git a/public/app/features/dashboard-scene/settings/AnnotationsEditView.test.tsx b/public/app/features/dashboard-scene/settings/AnnotationsEditView.test.tsx index d422842e14f..5d2e3a78187 100644 --- a/public/app/features/dashboard-scene/settings/AnnotationsEditView.test.tsx +++ b/public/app/features/dashboard-scene/settings/AnnotationsEditView.test.tsx @@ -1,7 +1,7 @@ import { map, of } from 'rxjs'; import { AnnotationQuery, DataQueryRequest, DataSourceApi, LoadingState, PanelData } from '@grafana/data'; -import { SceneDataLayers, SceneGridLayout, SceneTimeRange, dataLayers } from '@grafana/scenes'; +import { SceneDataLayerSet, SceneGridLayout, SceneTimeRange, dataLayers } from '@grafana/scenes'; import { AlertStatesDataLayer } from '../scene/AlertStatesDataLayer'; import { DashboardAnnotationsDataLayer } from '../scene/DashboardAnnotationsDataLayer'; @@ -66,7 +66,7 @@ describe('AnnotationsEditView', () => { it('should return 0 if no annotations', () => { dashboardScene.setState({ - $data: new SceneDataLayers({ layers: [] }), + $data: new SceneDataLayerSet({ layers: [] }), }); expect(annotationsView.getAnnotationsLength()).toBe(0); @@ -158,7 +158,7 @@ async function buildTestScene() { meta: { canEdit: true, }, - $data: new SceneDataLayers({ + $data: new SceneDataLayerSet({ layers: [ new DashboardAnnotationsDataLayer({ key: `annotations-test`, diff --git a/public/app/features/dashboard-scene/settings/AnnotationsEditView.tsx b/public/app/features/dashboard-scene/settings/AnnotationsEditView.tsx index 131b72c98bb..e93d1bd3e74 100644 --- a/public/app/features/dashboard-scene/settings/AnnotationsEditView.tsx +++ b/public/app/features/dashboard-scene/settings/AnnotationsEditView.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { AnnotationQuery, DataTopic, NavModel, NavModelItem, PageLayoutType, getDataSourceRef } from '@grafana/data'; +import { AnnotationQuery, NavModel, NavModelItem, PageLayoutType, getDataSourceRef } from '@grafana/data'; import { getDataSourceSrv } from '@grafana/runtime'; import { SceneComponentProps, SceneObjectBase, VizPanel, dataLayers } from '@grafana/scenes'; import { Page } from 'app/core/components/Page/Page'; @@ -52,7 +52,7 @@ export class AnnotationsEditView extends SceneObjectBase layer.topic === DataTopic.Annotations).length; + .state.layers.filter((layer) => layer instanceof DashboardAnnotationsDataLayer).length; } public getDashboard(): DashboardScene { @@ -68,7 +68,6 @@ export class AnnotationsEditView extends SceneObjectBase { it('should return the scene data layers', () => { const dataLayers = dashboardSceneGraph.getDataLayers(scene); - expect(dataLayers).toBeInstanceOf(SceneDataLayers); + expect(dataLayers).toBeInstanceOf(SceneDataLayerSet); expect(dataLayers?.state.layers.length).toBe(2); }); @@ -84,7 +84,7 @@ describe('dashboardSceneGraph', () => { $data: undefined, }); - expect(() => dashboardSceneGraph.getDataLayers(scene)).toThrow('SceneDataLayers not found'); + expect(() => dashboardSceneGraph.getDataLayers(scene)).toThrow('SceneDataLayerSet not found'); }); }); @@ -241,7 +241,7 @@ function buildTestScene(overrides?: Partial) { sync: DashboardCursorSync.Crosshair, }), ], - $data: new SceneDataLayers({ + $data: new SceneDataLayerSet({ layers: [ new DashboardAnnotationsDataLayer({ key: `annotation`, diff --git a/public/app/features/dashboard-scene/utils/dashboardSceneGraph.ts b/public/app/features/dashboard-scene/utils/dashboardSceneGraph.ts index ff6abf43b8a..119e2d522a6 100644 --- a/public/app/features/dashboard-scene/utils/dashboardSceneGraph.ts +++ b/public/app/features/dashboard-scene/utils/dashboardSceneGraph.ts @@ -1,4 +1,4 @@ -import { VizPanel, SceneGridRow, SceneDataLayers, sceneGraph, SceneGridLayout, behaviors } from '@grafana/scenes'; +import { VizPanel, SceneGridRow, SceneDataLayerSet, sceneGraph, SceneGridLayout, behaviors } from '@grafana/scenes'; import { DashboardGridItem } from '../scene/DashboardGridItem'; import { DashboardScene } from '../scene/DashboardScene'; @@ -53,11 +53,11 @@ function getVizPanels(scene: DashboardScene): VizPanel[] { return panels; } -function getDataLayers(scene: DashboardScene): SceneDataLayers { +function getDataLayers(scene: DashboardScene): SceneDataLayerSet { const data = sceneGraph.getData(scene); - if (!(data instanceof SceneDataLayers)) { - throw new Error('SceneDataLayers not found'); + if (!(data instanceof SceneDataLayerSet)) { + throw new Error('SceneDataLayerSet not found'); } return data; diff --git a/yarn.lock b/yarn.lock index dfe0862c982..ff648ab5ce8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4126,9 +4126,9 @@ __metadata: languageName: unknown linkType: soft -"@grafana/scenes@npm:3.13.3": - version: 3.13.3 - resolution: "@grafana/scenes@npm:3.13.3" +"@grafana/scenes@npm:4.0.1": + version: 4.0.1 + resolution: "@grafana/scenes@npm:4.0.1" dependencies: "@grafana/e2e-selectors": "npm:10.3.3" react-grid-layout: "npm:1.3.4" @@ -4142,7 +4142,7 @@ __metadata: "@grafana/ui": ^10.0.3 react: ^18.0.0 react-dom: ^18.0.0 - checksum: 10/5b7f2e2714dcdbc3ad58352ec0cc7f513f7a240dc11a3e309733a662760a598e9333ec377f2899b6b668e018c2e885e8a044af7d42d1be4487d692cda3b9359a + checksum: 10/e12737e1a73155ef48bc507b20a2e47d1d7784730c625d799ea74b8719f0bfa2babc193ecdbcb85727ac81dbba0bfad27d4090696b34a7ed1a97caa9813540de languageName: node linkType: hard @@ -5240,7 +5240,7 @@ __metadata: languageName: node linkType: hard -"@msagl/core@npm:^1.1.16, @msagl/core@npm:^1.1.18": +"@msagl/core@npm:^1.1.16": version: 1.1.18 resolution: "@msagl/core@npm:1.1.18" dependencies: @@ -5254,25 +5254,39 @@ __metadata: languageName: node linkType: hard -"@msagl/drawing@npm:^1.1.18": - version: 1.1.18 - resolution: "@msagl/drawing@npm:1.1.18" +"@msagl/core@npm:^1.1.17": + version: 1.1.17 + resolution: "@msagl/core@npm:1.1.17" dependencies: - "@msagl/core": "npm:^1.1.18" - checksum: 10/4cba6bd172dc39e09da9487c87b9caf511fb12eff433715ba3efeac95650315c5a5fb8cc6dfffd6f76de304a8cab0ecb839fc933268f0a0a004ee130594e4773 + "@esfx/collections": "npm:^1.0.0" + "@esfx/collections-sortedmap": "npm:^1.0.0" + queue-typescript: "npm:^1.0.1" + reliable-random: "npm:^0.0.1" + stack-typescript: "npm:^1.0.4" + typescript-string-operations: "npm:^1.4.1" + checksum: 10/6a0c83911d0802cf4372a9d976017117d9ecbec8e8bda8850fb58dec76558c0453290a51ad1c55b451ae70deeb3a57b1623bcbf7d054b3bfdacb9ea2a8190d5a + languageName: node + linkType: hard + +"@msagl/drawing@npm:^1.1.17": + version: 1.1.17 + resolution: "@msagl/drawing@npm:1.1.17" + dependencies: + "@msagl/core": "npm:^1.1.17" + checksum: 10/7a3f38cf2cafeda292cbd7c3f78d55f39f11a5923c3675ecd5a51d362660461fca50b42e5c9aa58431ad34f650fff0443be99670947c6fcd6f07701057a08c52 languageName: node linkType: hard "@msagl/parser@npm:^1.1.16": - version: 1.1.18 - resolution: "@msagl/parser@npm:1.1.18" + version: 1.1.17 + resolution: "@msagl/parser@npm:1.1.17" dependencies: - "@msagl/core": "npm:^1.1.18" - "@msagl/drawing": "npm:^1.1.18" + "@msagl/core": "npm:^1.1.17" + "@msagl/drawing": "npm:^1.1.17" "@types/parse-color": "npm:^1.0.1" dotparser: "npm:^1.1.1" parse-color: "npm:^1.0.0" - checksum: 10/f2b2d01d08e82341251cc8907a19881b2b203480342a49d14432922d68edf03a26bf3b4959d6673f45347afce7655f7cb95ace2218e06617cde5f4ed5a669f80 + checksum: 10/eae9c0a02410177b9c8f73edcad3c9e4610a31a972b3c58a870fe1db7c75b857304a87b82e8b7f9d6afedf91be73969856626ebb0f3fdae0d47c4e62da805ca1 languageName: node linkType: hard @@ -18540,7 +18554,7 @@ __metadata: "@grafana/prometheus": "workspace:*" "@grafana/runtime": "workspace:*" "@grafana/saga-icons": "workspace:*" - "@grafana/scenes": "npm:3.13.3" + "@grafana/scenes": "npm:4.0.1" "@grafana/schema": "workspace:*" "@grafana/sql": "workspace:*" "@grafana/tsconfig": "npm:^1.3.0-rc1"