The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/features/dashboard-scene/scene/setDashboardPanelContext.te...

238 lines
7.7 KiB

import { EventBusSrv } from '@grafana/data';
import { BackendSrv, setBackendSrv } from '@grafana/runtime';
import { PanelContext } from '@grafana/ui';
import { transformSaveModelToScene } from '../serialization/transformSaveModelToScene';
import { findVizPanelByKey } from '../utils/utils';
import { getAdHocFilterVariableFor, setDashboardPanelContext } from './setDashboardPanelContext';
const postFn = jest.fn();
const putFn = jest.fn();
const deleteFn = jest.fn();
setBackendSrv({
post: postFn,
put: putFn,
delete: deleteFn,
} as unknown as BackendSrv);
describe('setDashboardPanelContext', () => {
describe('canAddAnnotations', () => {
it('Can add when builtIn is enabled and permissions allow', () => {
const { context } = buildTestScene({ builtInAnnotationsEnabled: true, dashboardCanEdit: true, canAdd: true });
expect(context.canAddAnnotations!()).toBe(true);
});
it('Can not when builtIn is disabled', () => {
const { context } = buildTestScene({ builtInAnnotationsEnabled: false, dashboardCanEdit: true, canAdd: true });
expect(context.canAddAnnotations!()).toBe(false);
});
it('Can not when permission do not allow', () => {
const { context } = buildTestScene({ builtInAnnotationsEnabled: true, dashboardCanEdit: true, canAdd: false });
expect(context.canAddAnnotations!()).toBe(false);
});
});
describe('canEditAnnotations', () => {
it('Can edit global event when user has org permission', () => {
const { context } = buildTestScene({ dashboardCanEdit: true, orgCanEdit: true });
expect(context.canEditAnnotations!()).toBe(true);
});
it('Can not edit global event when has no org permission', () => {
const { context } = buildTestScene({ dashboardCanEdit: true, orgCanEdit: false });
expect(context.canEditAnnotations!()).toBe(false);
});
it('Can edit dashboard event when has dashboard permission', () => {
const { context } = buildTestScene({ dashboardCanEdit: true, canEdit: true });
expect(context.canEditAnnotations!('dash-uid')).toBe(true);
});
it('Can not edit dashboard event when has no dashboard permission', () => {
const { context } = buildTestScene({ dashboardCanEdit: true, canEdit: false });
expect(context.canEditAnnotations!('dash-uid')).toBe(false);
});
});
describe('canDeleteAnnotations', () => {
it('Can delete global event when user has org permission', () => {
const { context } = buildTestScene({ dashboardCanEdit: true, canDelete: true });
expect(context.canDeleteAnnotations!()).toBe(true);
});
it('Can not delete global event when has no org permission', () => {
const { context } = buildTestScene({ dashboardCanEdit: true, canDelete: false });
expect(context.canDeleteAnnotations!()).toBe(false);
});
it('Can delete dashboard event when has dashboard permission', () => {
const { context } = buildTestScene({ dashboardCanEdit: true, canDelete: true });
expect(context.canDeleteAnnotations!('dash-uid')).toBe(true);
});
it('Can not delete dashboard event when has no dashboard permission', () => {
const { context } = buildTestScene({ dashboardCanEdit: true, canDelete: false });
expect(context.canDeleteAnnotations!('dash-uid')).toBe(false);
});
});
describe('onAnnotationCreate', () => {
it('should create annotation', () => {
const { context } = buildTestScene({ dashboardCanEdit: true, canAdd: true });
context.onAnnotationCreate!({ from: 100, to: 200, description: 'save it', tags: [] });
expect(postFn).toHaveBeenCalledWith('/api/annotations', {
dashboardUID: 'dash-1',
isRegion: true,
panelId: 4,
tags: [],
text: 'save it',
time: 100,
timeEnd: 200,
});
});
});
describe('onAnnotationUpdate', () => {
it('should update annotation', () => {
const { context } = buildTestScene({ dashboardCanEdit: true, canAdd: true });
context.onAnnotationUpdate!({ from: 100, to: 200, id: 'event-id-123', description: 'updated', tags: [] });
expect(putFn).toHaveBeenCalledWith('/api/annotations/event-id-123', {
id: 'event-id-123',
dashboardUID: 'dash-1',
isRegion: true,
panelId: 4,
tags: [],
text: 'updated',
time: 100,
timeEnd: 200,
});
});
});
describe('onAnnotationDelete', () => {
it('should update annotation', () => {
const { context } = buildTestScene({ dashboardCanEdit: true, canAdd: true });
context.onAnnotationDelete!('I-do-not-want-you');
expect(deleteFn).toHaveBeenCalledWith('/api/annotations/I-do-not-want-you');
});
});
describe('onAddAdHocFilter', () => {
it('Should add new filter set', () => {
const { scene, context } = buildTestScene({});
context.onAddAdHocFilter!({ key: 'hello', value: 'world', operator: '=' });
const variable = getAdHocFilterVariableFor(scene, { uid: 'my-ds-uid' });
expect(variable.state.filters).toEqual([{ key: 'hello', value: 'world', operator: '=' }]);
});
it('Should update and add filter to existing set', () => {
const { scene, context } = buildTestScene({ existingFilterVariable: true });
const variable = getAdHocFilterVariableFor(scene, { uid: 'my-ds-uid' });
variable.setState({ filters: [{ key: 'existing', value: 'world', operator: '=' }] });
context.onAddAdHocFilter!({ key: 'hello', value: 'world', operator: '=' });
expect(variable.state.filters.length).toBe(2);
// Can update existing filter value without adding a new filter
context.onAddAdHocFilter!({ key: 'hello', value: 'world2', operator: '=' });
// Verify existing filter value updated
expect(variable.state.filters[1].value).toBe('world2');
});
});
});
interface SceneOptions {
builtInAnnotationsEnabled?: boolean;
dashboardCanEdit?: boolean;
canAdd?: boolean;
canEdit?: boolean;
canDelete?: boolean;
orgCanEdit?: boolean;
existingFilterVariable?: boolean;
}
function buildTestScene(options: SceneOptions) {
const scene = transformSaveModelToScene({
dashboard: {
title: 'hello',
uid: 'dash-1',
schemaVersion: 38,
annotations: {
list: [
{
builtIn: 1,
datasource: {
type: 'grafana',
uid: '-- Grafana --',
},
enable: options.builtInAnnotationsEnabled ?? false,
hide: true,
iconColor: 'rgba(0, 211, 255, 1)',
name: 'Annotations & Alerts',
target: { refId: 'A' },
type: 'dashboard',
},
],
},
panels: [
{
type: 'timeseries',
id: 4,
datasource: { uid: 'my-ds-uid', type: 'prometheus' },
targets: [],
},
],
templating: {
list: options.existingFilterVariable
? [
{
type: 'adhoc',
name: 'Filters',
datasource: { uid: 'my-ds-uid' },
},
]
: [],
},
},
meta: {
canEdit: options.dashboardCanEdit,
annotationsPermissions: {
dashboard: {
canAdd: options.canAdd ?? false,
canEdit: options.canEdit ?? false,
canDelete: options.canDelete ?? false,
},
organization: {
canAdd: false,
canEdit: options.orgCanEdit ?? false,
canDelete: options.canDelete ?? false,
},
},
},
});
const vizPanel = findVizPanelByKey(scene, 'panel-4')!;
const context: PanelContext = {
eventBus: new EventBusSrv(),
eventsScope: 'global',
};
setDashboardPanelContext(vizPanel, context);
return { scene, vizPanel, context };
}