mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Graph: Fixes so only users with correct permissions can add annotations (#30419)
* Graph: Fixes so only users with edit permissions can add annotations * Tests: corrects test message text * Chore: changes after PR comments
This commit is contained in:
parent
433fb505f0
commit
e1243e07ca
@ -59,7 +59,7 @@ export function annotationTooltipDirective(
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
// Show edit icon only for users with at least Editor role
|
// Show edit icon only for users with at least Editor role
|
||||||
if (event.id && dashboard.meta.canEdit) {
|
if (event.id && dashboard.canAddAnnotations()) {
|
||||||
header += `
|
header += `
|
||||||
<span class="pointer graph-annotation__edit-icon" ng-click="onEdit()">
|
<span class="pointer graph-annotation__edit-icon" ng-click="onEdit()">
|
||||||
<i class="fa fa-pencil-square"></i>
|
<i class="fa fa-pencil-square"></i>
|
||||||
|
@ -684,4 +684,25 @@ describe('DashboardModel', () => {
|
|||||||
expect(legendsOn.length).toBe(0);
|
expect(legendsOn.length).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('canAddAnnotations', () => {
|
||||||
|
it.each`
|
||||||
|
canEdit | canMakeEditable | expected
|
||||||
|
${false} | ${false} | ${false}
|
||||||
|
${false} | ${true} | ${true}
|
||||||
|
${true} | ${false} | ${true}
|
||||||
|
${true} | ${true} | ${true}
|
||||||
|
`(
|
||||||
|
'when called with canEdit:{$canEdit}, canMakeEditable:{$canMakeEditable} and expected:{$expected}',
|
||||||
|
({ canEdit, canMakeEditable, expected }) => {
|
||||||
|
const dashboard = new DashboardModel({});
|
||||||
|
dashboard.meta.canEdit = canEdit;
|
||||||
|
dashboard.meta.canMakeEditable = canMakeEditable;
|
||||||
|
|
||||||
|
const result = dashboard.canAddAnnotations();
|
||||||
|
|
||||||
|
expect(result).toBe(expected);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1016,6 +1016,10 @@ export class DashboardModel {
|
|||||||
return this.getVariablesFromState();
|
return this.getVariablesFromState();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
canAddAnnotations() {
|
||||||
|
return this.meta.canEdit || this.meta.canMakeEditable;
|
||||||
|
}
|
||||||
|
|
||||||
private getPanelRepeatVariable(panel: PanelModel) {
|
private getPanelRepeatVariable(panel: PanelModel) {
|
||||||
return this.getVariablesFromState().find((variable) => variable.name === panel.repeat);
|
return this.getVariablesFromState().find((variable) => variable.name === panel.repeat);
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,7 @@ class GraphElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ranges.ctrlKey || ranges.metaKey) && (this.dashboard.meta.canEdit || this.dashboard.meta.canMakeEditable)) {
|
if ((ranges.ctrlKey || ranges.metaKey) && this.dashboard.canAddAnnotations()) {
|
||||||
// Add annotation
|
// Add annotation
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.eventManager.updateTime(ranges.xaxis);
|
this.eventManager.updateTime(ranges.xaxis);
|
||||||
@ -201,7 +201,7 @@ class GraphElement {
|
|||||||
): (() => MenuItemsGroup[]) => {
|
): (() => MenuItemsGroup[]) => {
|
||||||
return () => {
|
return () => {
|
||||||
// Fixed context menu items
|
// Fixed context menu items
|
||||||
const items: MenuItemsGroup[] = this.dashboard?.editable
|
const items: MenuItemsGroup[] = this.dashboard.canAddAnnotations()
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
items: [
|
items: [
|
||||||
@ -253,7 +253,7 @@ class GraphElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// skip if dashboard is not saved yet (exists in db) or user cannot edit
|
// skip if dashboard is not saved yet (exists in db) or user cannot edit
|
||||||
if (!this.dashboard.id || (!this.dashboard.meta.canEdit && !this.dashboard.meta.canMakeEditable)) {
|
if (!this.dashboard.id || !this.dashboard.canAddAnnotations()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,15 @@
|
|||||||
|
import '../module';
|
||||||
|
import { GraphCtrl } from '../module';
|
||||||
|
import { MetricsPanelCtrl } from 'app/features/panel/metrics_panel_ctrl';
|
||||||
|
import { PanelCtrl } from 'app/features/panel/panel_ctrl';
|
||||||
|
import config from 'app/core/config';
|
||||||
|
|
||||||
|
import TimeSeries from 'app/core/time_series2';
|
||||||
|
import $ from 'jquery';
|
||||||
|
import { graphDirective, GraphElement } from '../graph';
|
||||||
|
import { dateTime, EventBusSrv } from '@grafana/data';
|
||||||
|
import { DashboardModel } from '../../../../features/dashboard/state';
|
||||||
|
|
||||||
jest.mock('app/features/annotations/all', () => ({
|
jest.mock('app/features/annotations/all', () => ({
|
||||||
EventManager: () => {
|
EventManager: () => {
|
||||||
return {
|
return {
|
||||||
@ -16,17 +28,6 @@ jest.mock('app/core/core', () => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
import '../module';
|
|
||||||
import { GraphCtrl } from '../module';
|
|
||||||
import { MetricsPanelCtrl } from 'app/features/panel/metrics_panel_ctrl';
|
|
||||||
import { PanelCtrl } from 'app/features/panel/panel_ctrl';
|
|
||||||
import config from 'app/core/config';
|
|
||||||
|
|
||||||
import TimeSeries from 'app/core/time_series2';
|
|
||||||
import $ from 'jquery';
|
|
||||||
import { graphDirective, GraphElement } from '../graph';
|
|
||||||
import { dateTime, EventBusSrv } from '@grafana/data';
|
|
||||||
|
|
||||||
const ctx = {} as any;
|
const ctx = {} as any;
|
||||||
let ctrl: any;
|
let ctrl: any;
|
||||||
const scope = {
|
const scope = {
|
||||||
@ -1288,25 +1289,9 @@ describe('grafanaGraph', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('getContextMenuItemsSupplier', () => {
|
describe('getContextMenuItemsSupplier', () => {
|
||||||
function getGraphElement({ editable }: { editable?: boolean } = {}) {
|
describe('when called and user can edit the dashboard', () => {
|
||||||
const element = new GraphElement(
|
|
||||||
{
|
|
||||||
ctrl: {
|
|
||||||
contextMenuCtrl: {},
|
|
||||||
dashboard: { editable, events: { on: jest.fn() } },
|
|
||||||
events: { on: jest.fn() },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{ mouseleave: jest.fn(), bind: jest.fn() } as any,
|
|
||||||
{} as any
|
|
||||||
);
|
|
||||||
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('when called and dashboard is editable', () => {
|
|
||||||
it('then the correct menu items should be returned', () => {
|
it('then the correct menu items should be returned', () => {
|
||||||
const element = getGraphElement({ editable: true });
|
const element = getGraphElement({ canEdit: true, canMakeEditable: false });
|
||||||
|
|
||||||
const result = element.getContextMenuItemsSupplier({ x: 1, y: 1 })();
|
const result = element.getContextMenuItemsSupplier({ x: 1, y: 1 })();
|
||||||
|
|
||||||
@ -1318,9 +1303,23 @@ describe('grafanaGraph', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when called and dashboard is not editable', () => {
|
describe('when called and user can make the dashboard editable', () => {
|
||||||
it('then the correct menu items should be returned', () => {
|
it('then the correct menu items should be returned', () => {
|
||||||
const element = getGraphElement({ editable: false });
|
const element = getGraphElement({ canEdit: false, canMakeEditable: true });
|
||||||
|
|
||||||
|
const result = element.getContextMenuItemsSupplier({ x: 1, y: 1 })();
|
||||||
|
|
||||||
|
expect(result.length).toEqual(1);
|
||||||
|
expect(result[0].items.length).toEqual(1);
|
||||||
|
expect(result[0].items[0].label).toEqual('Add annotation');
|
||||||
|
expect(result[0].items[0].icon).toEqual('comment-alt');
|
||||||
|
expect(result[0].items[0].onClick).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when called and user can not edit the dashboard and can not make the dashboard editable', () => {
|
||||||
|
it('then the correct menu items should be returned', () => {
|
||||||
|
const element = getGraphElement({ canEdit: false, canMakeEditable: false });
|
||||||
|
|
||||||
const result = element.getContextMenuItemsSupplier({ x: 1, y: 1 })();
|
const result = element.getContextMenuItemsSupplier({ x: 1, y: 1 })();
|
||||||
|
|
||||||
@ -1329,3 +1328,23 @@ describe('grafanaGraph', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getGraphElement({ canEdit, canMakeEditable }: { canEdit?: boolean; canMakeEditable?: boolean } = {}) {
|
||||||
|
const dashboard = new DashboardModel({});
|
||||||
|
dashboard.events.on = jest.fn();
|
||||||
|
dashboard.meta.canEdit = canEdit;
|
||||||
|
dashboard.meta.canMakeEditable = canMakeEditable;
|
||||||
|
const element = new GraphElement(
|
||||||
|
{
|
||||||
|
ctrl: {
|
||||||
|
contextMenuCtrl: {},
|
||||||
|
dashboard,
|
||||||
|
events: { on: jest.fn() },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ mouseleave: jest.fn(), bind: jest.fn() } as any,
|
||||||
|
{} as any
|
||||||
|
);
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user