diff --git a/package.json b/package.json index 6675780ae2d..9532abb2f01 100644 --- a/package.json +++ b/package.json @@ -251,7 +251,7 @@ "@grafana/lezer-traceql": "0.0.6", "@grafana/monaco-logql": "^0.0.7", "@grafana/runtime": "workspace:*", - "@grafana/scenes": "^1.3.3", + "@grafana/scenes": "^1.5.1", "@grafana/schema": "workspace:*", "@grafana/ui": "workspace:*", "@kusto/monaco-kusto": "^7.4.0", diff --git a/public/app/features/dashboard-scene/scene/DashboardAnnotationsDataLayer.test.ts b/public/app/features/dashboard-scene/scene/DashboardAnnotationsDataLayer.test.ts new file mode 100644 index 00000000000..e6faf39203e --- /dev/null +++ b/public/app/features/dashboard-scene/scene/DashboardAnnotationsDataLayer.test.ts @@ -0,0 +1,71 @@ +import { map, of } from 'rxjs'; + +import { DataSourceApi, DataQueryRequest, PanelData } from '@grafana/data'; +import { LoadingState } from '@grafana/schema'; +import { PublicAnnotationsDataSource } from 'app/features/query/state/DashboardQueryRunner/PublicAnnotationsDataSource'; + +import { DashboardAnnotationsDataLayer } from './DashboardAnnotationsDataLayer'; + +const getDataSourceSrvSpy = jest.fn(); +const runRequestMock = jest.fn().mockImplementation((ds: DataSourceApi, request: DataQueryRequest) => { + const result: PanelData = { + state: LoadingState.Loading, + series: [], + timeRange: request.range, + }; + + return of([]).pipe( + map(() => { + result.state = LoadingState.Done; + result.series = []; + + return result; + }) + ); +}); + +jest.mock('app/features/query/state/DashboardQueryRunner/PublicAnnotationsDataSource'); +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), + getDataSourceSrv: () => { + getDataSourceSrvSpy(); + }, + getRunRequest: () => (ds: DataSourceApi, request: DataQueryRequest) => { + return runRequestMock(ds, request); + }, + config: { + publicDashboardAccessToken: 'ac123', + }, +})); + +describe('DashboardAnnotationsDataLayer', () => { + it('should use PublicAnnotationsDataSource when config.publicDashboardAccessToken is set', () => { + const dataLayer = new DashboardAnnotationsDataLayer({ + name: 'Annotations & Alerts', + query: { + builtIn: 1, + datasource: { + type: 'grafana', + uid: '-- Grafana --', + }, + enable: true, + hide: true, + iconColor: 'rgba(0, 211, 255, 1)', + name: 'Annotations & Alerts', + target: { + // @ts-expect-error + limit: 100, + matchAny: false, + tags: [], + type: 'dashboard', + }, + type: 'dashboard', + }, + }); + + dataLayer.activate(); + + expect(PublicAnnotationsDataSource).toHaveBeenCalledTimes(1); + expect(getDataSourceSrvSpy).not.toHaveBeenCalled(); + }); +}); diff --git a/public/app/features/dashboard-scene/scene/DashboardAnnotationsDataLayer.ts b/public/app/features/dashboard-scene/scene/DashboardAnnotationsDataLayer.ts new file mode 100644 index 00000000000..52d2957ea29 --- /dev/null +++ b/public/app/features/dashboard-scene/scene/DashboardAnnotationsDataLayer.ts @@ -0,0 +1,45 @@ +import { AnnotationEvent, arrayToDataFrame, DataTopic, getDefaultTimeRange, PanelData } from '@grafana/data'; +import { config } from '@grafana/runtime'; +import { dataLayers } from '@grafana/scenes'; +import { AnnotationQuery, LoadingState } from '@grafana/schema'; +import { PublicAnnotationsDataSource } from 'app/features/query/state/DashboardQueryRunner/PublicAnnotationsDataSource'; + +/** + * This class is an extension to dataLayers.AnnotationsDataLayer to provide support for public dashboards. + */ +export class DashboardAnnotationsDataLayer extends dataLayers.AnnotationsDataLayer { + protected async resolveDataSource(query: AnnotationQuery) { + if (config.publicDashboardAccessToken) { + return new PublicAnnotationsDataSource(); + } + return super.resolveDataSource(query); + } + + protected processEvents( + query: AnnotationQuery, + events: { + state: LoadingState; + events: AnnotationEvent[]; + } + ) { + if (config.publicDashboardAccessToken) { + const stateUpdate: PanelData = { + series: [], + timeRange: getDefaultTimeRange(), + state: events.state, + }; + + const df = arrayToDataFrame(events.events); + df.meta = { + ...df.meta, + dataTopic: DataTopic.Annotations, + }; + + stateUpdate.annotations = [df]; + + return stateUpdate; + } else { + return super.processEvents(query, events); + } + } +} diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts index f494c0a8e50..4ec12db2dfe 100644 --- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts +++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts @@ -27,7 +27,6 @@ import { VizPanelState, SceneGridItemLike, SceneDataLayers, - dataLayers, SceneDataLayerProvider, SceneDataLayerControls, } from '@grafana/scenes'; @@ -35,6 +34,7 @@ import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import { DashboardDTO } from 'app/types'; +import { DashboardAnnotationsDataLayer } from '../scene/DashboardAnnotationsDataLayer'; import { DashboardScene } from '../scene/DashboardScene'; import { LibraryVizPanel } from '../scene/LibraryVizPanel'; import { panelMenuBehavior } from '../scene/PanelMenuBehavior'; @@ -180,7 +180,7 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel) if (oldModel.annotations?.list?.length) { layers = oldModel.annotations?.list.map((a) => { // Each annotation query is an individual data layer - return new dataLayers.AnnotationsDataLayer({ + return new DashboardAnnotationsDataLayer({ query: a, name: a.name, isEnabled: Boolean(a.enable), diff --git a/yarn.lock b/yarn.lock index 7972505979e..16780e7151f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4010,9 +4010,9 @@ __metadata: languageName: unknown linkType: soft -"@grafana/scenes@npm:^1.3.3": - version: 1.3.3 - resolution: "@grafana/scenes@npm:1.3.3" +"@grafana/scenes@npm:^1.5.1": + version: 1.5.1 + resolution: "@grafana/scenes@npm:1.5.1" dependencies: "@grafana/e2e-selectors": 10.0.2 react-grid-layout: 1.3.4 @@ -4024,7 +4024,7 @@ __metadata: "@grafana/runtime": 10.0.3 "@grafana/schema": 10.0.3 "@grafana/ui": 10.0.3 - checksum: 3c630aaeca7bc240b1db1a6cc7856808d940c354a558e6f1c5c0fac7268c5f57e0b6f8f55a1d9d1dbfbb02011f1beecc5fe1aae1209bc4430599e2660fd76f6d + checksum: 9f3adbe54078181e8770c79c6958b9cf6ad5d511a799d3f05aab64cbd06fffdcf7a4f7ae4b518db8b3562408a95221f1a8783499119fe96f2100f53a3b9ddb22 languageName: node linkType: hard @@ -19701,7 +19701,7 @@ __metadata: "@grafana/lezer-traceql": 0.0.6 "@grafana/monaco-logql": ^0.0.7 "@grafana/runtime": "workspace:*" - "@grafana/scenes": ^1.3.3 + "@grafana/scenes": ^1.5.1 "@grafana/schema": "workspace:*" "@grafana/tsconfig": ^1.3.0-rc1 "@grafana/ui": "workspace:*"