236 lines
7.6 KiB
TypeScript
236 lines
7.6 KiB
TypeScript
import { map, of } from 'rxjs';
|
|
import { MockDataSourceApi } from 'test/mocks/datasource_srv';
|
|
|
|
import {
|
|
AnnotationQuery,
|
|
DataQueryRequest,
|
|
DataSourceApi,
|
|
DataSourceInstanceSettings,
|
|
DataSourcePluginMeta,
|
|
getDataSourceUID,
|
|
LoadingState,
|
|
PanelData,
|
|
} from '@grafana/data';
|
|
import { SceneTimeRange, dataLayers } from '@grafana/scenes';
|
|
import { DataSourceRef } from '@grafana/schema';
|
|
|
|
import { DashboardAnnotationsDataLayer } from '../scene/DashboardAnnotationsDataLayer';
|
|
import { DashboardDataLayerSet } from '../scene/DashboardDataLayerSet';
|
|
import { DashboardScene } from '../scene/DashboardScene';
|
|
import { dashboardSceneGraph } from '../utils/dashboardSceneGraph';
|
|
import { activateFullSceneTree } from '../utils/test-utils';
|
|
|
|
import { AnnotationsEditView, MoveDirection } from './AnnotationsEditView';
|
|
import { newAnnotationName } from './annotations/AnnotationSettingsEdit';
|
|
|
|
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;
|
|
})
|
|
);
|
|
});
|
|
|
|
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 {
|
|
//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) => {
|
|
return runRequestMock(ds, request);
|
|
},
|
|
config: {
|
|
...jest.requireActual('@grafana/runtime').config,
|
|
publicDashboardAccessToken: 'ac123',
|
|
},
|
|
}));
|
|
|
|
describe('AnnotationsEditView', () => {
|
|
describe('Dashboard annotations state', () => {
|
|
let annotationsView: 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);
|
|
expect(dataLayers?.state.annotationLayers[1].state.name).toBe(newAnnotationName);
|
|
expect(dataLayers?.state.annotationLayers[1].isActive).toBe(true);
|
|
});
|
|
|
|
it('should move an annotation up one position', () => {
|
|
const dataLayers = dashboardSceneGraph.getDataLayers(annotationsView.getDashboard());
|
|
|
|
annotationsView.onNew();
|
|
|
|
expect(dataLayers?.state.annotationLayers.length).toBe(2);
|
|
expect(dataLayers?.state.annotationLayers[0].state.name).toBe('test');
|
|
|
|
annotationsView.onMove(1, MoveDirection.UP);
|
|
|
|
expect(dataLayers?.state.annotationLayers.length).toBe(2);
|
|
expect(dataLayers?.state.annotationLayers[0].state.name).toBe(newAnnotationName);
|
|
});
|
|
|
|
it('should move an annotation down one position', () => {
|
|
const dataLayers = dashboardSceneGraph.getDataLayers(annotationsView.getDashboard());
|
|
|
|
annotationsView.onNew();
|
|
|
|
expect(dataLayers?.state.annotationLayers.length).toBe(2);
|
|
expect(dataLayers?.state.annotationLayers[0].state.name).toBe('test');
|
|
|
|
annotationsView.onMove(0, MoveDirection.DOWN);
|
|
|
|
expect(dataLayers?.state.annotationLayers.length).toBe(2);
|
|
expect(dataLayers?.state.annotationLayers[0].state.name).toBe(newAnnotationName);
|
|
});
|
|
|
|
it('should delete annotation at index', () => {
|
|
const dataLayers = dashboardSceneGraph.getDataLayers(annotationsView.getDashboard());
|
|
|
|
expect(dataLayers?.state.annotationLayers.length).toBe(1);
|
|
|
|
annotationsView.onDelete(0);
|
|
|
|
expect(dataLayers?.state.annotationLayers.length).toBe(0);
|
|
});
|
|
|
|
it('should update an annotation at index', () => {
|
|
const dataLayers = dashboardSceneGraph.getDataLayers(annotationsView.getDashboard());
|
|
|
|
expect(dataLayers?.state.annotationLayers[0].state.name).toBe('test');
|
|
|
|
const annotation: AnnotationQuery = {
|
|
...(dataLayers?.state.annotationLayers[0] as dataLayers.AnnotationsDataLayer).state.query,
|
|
};
|
|
|
|
annotation.name = 'new name';
|
|
annotation.hide = true;
|
|
annotation.enable = false;
|
|
annotation.iconColor = 'blue';
|
|
annotationsView.onUpdate(annotation, 0);
|
|
|
|
expect(dataLayers?.state.annotationLayers.length).toBe(1);
|
|
expect(dataLayers?.state.annotationLayers[0].state.name).toBe('new name');
|
|
expect((dataLayers?.state.annotationLayers[0] as dataLayers.AnnotationsDataLayer).state.query.name).toBe(
|
|
'new name'
|
|
);
|
|
expect((dataLayers?.state.annotationLayers[0] as dataLayers.AnnotationsDataLayer).state.query.hide).toBe(true);
|
|
expect((dataLayers?.state.annotationLayers[0] as dataLayers.AnnotationsDataLayer).state.query.enable).toBe(false);
|
|
expect((dataLayers?.state.annotationLayers[0] as dataLayers.AnnotationsDataLayer).state.query.iconColor).toBe(
|
|
'blue'
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
async function buildTestScene() {
|
|
const annotationsView = new AnnotationsEditView({});
|
|
const dashboard = new DashboardScene({
|
|
$timeRange: new SceneTimeRange({}),
|
|
title: 'hello',
|
|
uid: 'dash-1',
|
|
version: 4,
|
|
meta: {
|
|
canEdit: true,
|
|
},
|
|
$data: new DashboardDataLayerSet({
|
|
annotationLayers: [
|
|
new DashboardAnnotationsDataLayer({
|
|
key: `annotations-test`,
|
|
query: {
|
|
enable: true,
|
|
iconColor: 'red',
|
|
name: 'test',
|
|
datasource: {
|
|
type: 'grafana',
|
|
uid: '-- Grafana --',
|
|
},
|
|
},
|
|
name: 'test',
|
|
isEnabled: true,
|
|
isHidden: false,
|
|
}),
|
|
],
|
|
}),
|
|
editview: annotationsView,
|
|
});
|
|
|
|
activateFullSceneTree(dashboard);
|
|
|
|
await new Promise((r) => setTimeout(r, 1));
|
|
|
|
dashboard.onEnterEditMode();
|
|
annotationsView.activate();
|
|
|
|
return { dashboard, annotationsView };
|
|
}
|