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
pull/92827/head
Alexa V 9 months ago committed by GitHub
parent 0df5a6aefc
commit f8cd448441
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 63
      public/app/features/dashboard-scene/settings/AnnotationsEditView.test.tsx
  2. 19
      public/app/features/dashboard-scene/settings/AnnotationsEditView.tsx
  3. 10
      public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsEdit.tsx
  4. 9
      public/app/features/dashboard/components/AnnotationSettings/AnnotationSettingsEdit.tsx
  5. 7
      public/locales/en-US/grafana.json
  6. 7
      public/locales/pseudo-LOCALE/grafana.json

@ -1,7 +1,18 @@
import { map, of } from 'rxjs';
import { AnnotationQuery, DataQueryRequest, DataSourceApi, LoadingState, PanelData } from '@grafana/data';
import { MockDataSourceApi } from 'test/mocks/datasource_srv';
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);

@ -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<AnnotationsEditViewStat
return this._dashboard;
}
public onNew = () => {
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<AnnotationsEditViewStat
const data = dashboardSceneGraph.getDataLayers(this._dashboard);
data.addAnnotationLayer(newAnnotation);
this.setState({ editIndex: data.state.annotationLayers.length - 1 });
};

@ -14,8 +14,9 @@ import { selectors } from '@grafana/e2e-selectors';
import { config, getDataSourceSrv } from '@grafana/runtime';
import { VizPanel } from '@grafana/scenes';
import { AnnotationPanelFilter } from '@grafana/schema/src/raw/dashboard/x/dashboard_types.gen';
import { Button, Checkbox, Field, FieldSet, Input, MultiSelect, Select, useStyles2, Stack } from '@grafana/ui';
import { Button, Checkbox, Field, FieldSet, Input, MultiSelect, Select, useStyles2, Stack, Alert } from '@grafana/ui';
import { ColorValueEditor } from 'app/core/components/OptionsUI/color';
import { Trans } from 'app/core/internationalization';
import StandardAnnotationQueryEditor from 'app/features/annotations/components/StandardAnnotationQueryEditor';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
@ -183,6 +184,13 @@ export const AnnotationSettingsEdit = ({ annotation, editIndex, panels, onUpdate
<Field label="Data source" htmlFor="data-source-picker">
<DataSourcePicker annotations variables current={annotation.datasource} onChange={onDataSourceChange} />
</Field>
{!ds?.meta.annotations && (
<Alert title="No annotation support for this data source" severity="error">
<Trans i18nKey="errors.dashboard-settings.annotations.datasource">
The selected data source does not support annotations. Please select a different data source.
</Trans>
</Alert>
)}
<Field label="Enabled" description="When enabled the annotation query is issued every dashboard refresh">
<Checkbox
name="enable"

@ -24,9 +24,11 @@ import {
Select,
useStyles2,
Stack,
Alert,
} from '@grafana/ui';
import { ColorValueEditor } from 'app/core/components/OptionsUI/color';
import config from 'app/core/config';
import { Trans } from 'app/core/internationalization';
import StandardAnnotationQueryEditor from 'app/features/annotations/components/StandardAnnotationQueryEditor';
import { AngularEditorLoader } from 'app/features/dashboard-scene/settings/annotations/AngularEditorLoader';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
@ -189,6 +191,13 @@ export const AnnotationSettingsEdit = ({ editIdx, dashboard }: Props) => {
<Field label="Data source" htmlFor="data-source-picker">
<DataSourcePicker annotations variables current={annotation.datasource} onChange={onDataSourceChange} />
</Field>
{!ds?.meta.annotations && (
<Alert title="No annotation support for this data source" severity="error">
<Trans i18nKey="errors.dashboard-settings.annotations.datasource">
The selected data source does not support annotations. Please select a different data source.
</Trans>
</Alert>
)}
<Field label="Enabled" description="When enabled the annotation query is issued every dashboard refresh">
<Checkbox name="enable" id="enable" value={annotation.enable} onChange={onChange} />
</Field>

@ -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": {

@ -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": {

Loading…
Cancel
Save