From f8cd448441b8761944c04239166e171f7607b455 Mon Sep 17 00:00:00 2001 From: Alexa V <239999+axelavargas@users.noreply.github.com> Date: Mon, 2 Sep 2024 16:46:20 +0200 Subject: [PATCH] Dashboard: Fix Annotation runtime error when a data source does not support annotations (#92504) When data source does not support annotations, shows an inline Error in Annotation Settings page --- .../settings/AnnotationsEditView.test.tsx | 61 ++++++++++++++++++- .../settings/AnnotationsEditView.tsx | 19 ++++-- .../annotations/AnnotationSettingsEdit.tsx | 10 ++- .../AnnotationSettingsEdit.tsx | 9 +++ public/locales/en-US/grafana.json | 7 +++ public/locales/pseudo-LOCALE/grafana.json | 7 +++ 6 files changed, 105 insertions(+), 8 deletions(-) diff --git a/public/app/features/dashboard-scene/settings/AnnotationsEditView.test.tsx b/public/app/features/dashboard-scene/settings/AnnotationsEditView.test.tsx index 105f747a867..d464023a07a 100644 --- a/public/app/features/dashboard-scene/settings/AnnotationsEditView.test.tsx +++ b/public/app/features/dashboard-scene/settings/AnnotationsEditView.test.tsx @@ -1,7 +1,18 @@ import { map, of } from 'rxjs'; +import { MockDataSourceApi } from 'test/mocks/datasource_srv'; -import { AnnotationQuery, DataQueryRequest, DataSourceApi, LoadingState, PanelData } from '@grafana/data'; +import { + AnnotationQuery, + DataQueryRequest, + DataSourceApi, + DataSourceInstanceSettings, + DataSourcePluginMeta, + getDataSourceUID, + LoadingState, + PanelData, +} from '@grafana/data'; import { SceneGridLayout, SceneTimeRange, dataLayers } from '@grafana/scenes'; +import { DataSourceRef } from '@grafana/schema'; import { DashboardAnnotationsDataLayer } from '../scene/DashboardAnnotationsDataLayer'; import { DashboardDataLayerSet } from '../scene/DashboardDataLayerSet'; @@ -29,11 +40,49 @@ const runRequestMock = jest.fn().mockImplementation((ds: DataSourceApi, request: ); }); +const noAnnotationsDsInstanceSettings = { + name: 'noAnnotationsDs', + uid: 'noAnnotationsDs', + meta: { + annotations: false, + } as DataSourcePluginMeta, + readOnly: false, + type: 'noAnnotations', +} as DataSourceInstanceSettings; + +const grafanaDsInstanceSettings = { + name: 'Grafana', + uid: '-- Grafana --', + meta: { + annotations: true, + } as DataSourcePluginMeta, + readOnly: false, + type: 'grafana', +} as DataSourceInstanceSettings; + jest.mock('@grafana/runtime', () => ({ ...jest.requireActual('@grafana/runtime'), getDataSourceSrv: () => { return { - getInstanceSettings: jest.fn().mockResolvedValue({ uid: 'ds1' }), + //return default datasource when no ref is provided + getInstanceSettings: (ref: DataSourceRef | string | null) => { + if (!ref) { + return new MockDataSourceApi(noAnnotationsDsInstanceSettings); + } + if (getDataSourceUID(ref) === '-- Grafana --') { + return new MockDataSourceApi(grafanaDsInstanceSettings); + } + return jest.fn().mockResolvedValue({ uid: 'ds1' }); + }, + get: (ref: DataSourceRef) => { + if (getDataSourceUID(ref) === 'noAnnotationsDs') { + return Promise.resolve(new MockDataSourceApi(noAnnotationsDsInstanceSettings)); + } + if (getDataSourceUID(ref) === '-- Grafana --') { + return Promise.resolve(new MockDataSourceApi(grafanaDsInstanceSettings)); + } + return Promise.resolve(new MockDataSourceApi('ds1')); + }, }; }, getRunRequest: () => (ds: DataSourceApi, request: DataQueryRequest) => { @@ -52,17 +101,23 @@ describe('AnnotationsEditView', () => { beforeEach(async () => { const result = await buildTestScene(); annotationsView = result.annotationsView; + jest.spyOn(console, 'error').mockImplementation(); }); it('should return the correct urlKey', () => { expect(annotationsView.getUrlKey()).toBe('annotations'); }); + it('should return undefined when datasource does not support annotations', () => { + const ds = annotationsView.getDataSourceRefForAnnotation(); + expect(ds).toBe(undefined); + expect(console.error).toHaveBeenCalledWith('Default datasource does not support annotations'); + }); + it('should add a new annotation and group it with the other annotations', () => { const dataLayers = dashboardSceneGraph.getDataLayers(annotationsView.getDashboard()); expect(dataLayers?.state.annotationLayers.length).toBe(1); - annotationsView.onNew(); expect(dataLayers?.state.annotationLayers.length).toBe(2); diff --git a/public/app/features/dashboard-scene/settings/AnnotationsEditView.tsx b/public/app/features/dashboard-scene/settings/AnnotationsEditView.tsx index 40d836c7148..72510de5130 100644 --- a/public/app/features/dashboard-scene/settings/AnnotationsEditView.tsx +++ b/public/app/features/dashboard-scene/settings/AnnotationsEditView.tsx @@ -1,4 +1,4 @@ -import { AnnotationQuery, NavModel, NavModelItem, PageLayoutType, getDataSourceRef } from '@grafana/data'; +import { AnnotationQuery, getDataSourceRef, NavModel, NavModelItem, PageLayoutType } from '@grafana/data'; import { getDataSourceSrv } from '@grafana/runtime'; import { SceneComponentProps, SceneObjectBase, VizPanel, dataLayers } from '@grafana/scenes'; import { Page } from 'app/core/components/Page/Page'; @@ -51,11 +51,23 @@ export class AnnotationsEditView extends SceneObjectBase { + public getDataSourceRefForAnnotation = () => { + // get current default datasource ref from instance settings + // null is passed to get the default datasource + const defaultInstanceDS = getDataSourceSrv().getInstanceSettings(null); + // check for an annotation flag in the plugin json to see if it supports annotations + if (!defaultInstanceDS || !defaultInstanceDS.meta.annotations) { + console.error('Default datasource does not support annotations'); + return undefined; + } + return getDataSourceRef(defaultInstanceDS); + }; + + public onNew = async () => { const newAnnotationQuery: AnnotationQuery = { name: newAnnotationName, enable: true, - datasource: getDataSourceRef(getDataSourceSrv().getInstanceSettings(null)!), + datasource: this.getDataSourceRefForAnnotation(), iconColor: 'red', }; @@ -69,7 +81,6 @@ export class AnnotationsEditView extends SceneObjectBase + {!ds?.meta.annotations && ( + + + The selected data source does not support annotations. Please select a different data source. + + + )} { + {!ds?.meta.annotations && ( + + + The selected data source does not support annotations. Please select a different data source. + + + )} diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 8cbbe18cd25..ba9a51a6a84 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -716,6 +716,13 @@ "time-range-label": "Lock time range" } }, + "errors": { + "dashboard-settings": { + "annotations": { + "datasource": "The selected data source does not support annotations. Please select a different data source." + } + } + }, "explore": { "add-to-dashboard": "Add to dashboard", "logs": { diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json index f6aee62fb9c..28726d4ec22 100644 --- a/public/locales/pseudo-LOCALE/grafana.json +++ b/public/locales/pseudo-LOCALE/grafana.json @@ -716,6 +716,13 @@ "time-range-label": "Ŀőčĸ ŧįmę řäʼnģę" } }, + "errors": { + "dashboard-settings": { + "annotations": { + "datasource": "Ŧĥę şęľęčŧęđ đäŧä şőūřčę đőęş ʼnőŧ şūppőřŧ äʼnʼnőŧäŧįőʼnş. Pľęäşę şęľęčŧ ä đįƒƒęřęʼnŧ đäŧä şőūřčę." + } + } + }, "explore": { "add-to-dashboard": "Åđđ ŧő đäşĥþőäřđ", "logs": {