Skip to content

Commit

Permalink
Alerting: Add Alerting menu in getPanelMenu (grafana#76618)
Browse files Browse the repository at this point in the history
* Add Alerting menu in getPanelMenu

* Add translations

* Allow alert tab, heart icon in all panel types, and not show warning in DashobardPicker panels

* Fix tests

* Move alerting submenu under 'More...' item

* Move create alert menu item to More... without submenu

* Update translations

* Revert "Allow alert tab, heart icon in all panel types, and not show warning in DashobardPicker panels"

This reverts commit 225da3f.

* Revert allowing alert tab and health icon for all panel types

* use onCreateAlert method name in onClick instead of new function

Co-authored-by: Torkel Ödegaard <[email protected]>

* Move getAlertingMenuAvailability method to a /features/alerting folder and rename it to getCreateAlertInMenuAvailability

* Use onCreate direclty instead of a new method

* Make getCreateAlertInMenuAvailability to return a boolean

---------

Co-authored-by: Torkel Ödegaard <[email protected]>
  • Loading branch information
soniaAguilarPeiron and torkelo authored Oct 18, 2023
1 parent a851750 commit 1de65bb
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -296,37 +296,37 @@ describe('AnnotationsField', function () {
expect(annotationKeyElements[1]).toHaveTextContent('Panel ID');
expect(annotationValueElements[1]).toHaveTextContent('3');
});
});
});

it('should render warning icon for panels of type other than graph and timeseries', async function () {
mockSearchApiResponse(server, [
mockDashboardSearchItem({ title: 'My dashboard', uid: 'dash-test-uid', type: DashboardSearchItemType.DashDB }),
]);

mockGetDashboardResponse(
mockDashboardDto({
title: 'My dashboard',
uid: 'dash-test-uid',
panels: [
{ id: 1, title: 'First panel', type: 'bar' },
{ id: 2, title: 'Second panel', type: 'graph' },
],
})
);
it('should render warning icon for panels of type other than graph and timeseries', async function () {
mockSearchApiResponse(server, [
mockDashboardSearchItem({ title: 'My dashboard', uid: 'dash-test-uid', type: DashboardSearchItemType.DashDB }),
]);

mockGetDashboardResponse(
mockDashboardDto({
title: 'My dashboard',
uid: 'dash-test-uid',
panels: [
{ id: 1, title: 'First panel', type: 'bar' },
{ id: 2, title: 'Second panel', type: 'graph' },
],
})
);

const user = userEvent.setup();
const user = userEvent.setup();

render(<FormWrapper formValues={{ annotations: [] }} />);
render(<FormWrapper formValues={{ annotations: [] }} />);

const { dialog } = ui.dashboardPicker;
const { dialog } = ui.dashboardPicker;

await user.click(ui.setDashboardButton.get());
await user.click(await findByTitle(dialog.get(), 'My dashboard'));
await user.click(ui.setDashboardButton.get());
await user.click(await findByTitle(dialog.get(), 'My dashboard'));

const warnedPanel = await findByRole(dialog.get(), 'button', { name: /First panel/ });
const warnedPanel = await findByRole(dialog.get(), 'button', { name: /First panel/ });

expect(getByTestId(warnedPanel, 'warning-icon')).toBeInTheDocument();
});
});
expect(getByTestId(warnedPanel, 'warning-icon')).toBeInTheDocument();
});

function mockGetDashboardResponse(dashboard: DashboardDTO) {
Expand Down
12 changes: 11 additions & 1 deletion public/app/features/alerting/unified/utils/access-control.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { getConfig } from 'app/core/config';
import { contextSrv } from 'app/core/services/context_srv';
import { AccessControlAction } from 'app/types';

import { isGrafanaRulesSource } from './datasource';
import { GRAFANA_RULES_SOURCE_NAME, isGrafanaRulesSource } from './datasource';

type RulesSourceType = 'grafana' | 'external';

Expand Down Expand Up @@ -128,3 +129,12 @@ export function getRulesAccess() {
contextSrv.hasPermission(provisioningPermissions.readSecrets),
};
}

export function getCreateAlertInMenuAvailability() {
const { unifiedAlertingEnabled } = getConfig();
const hasRuleReadPermissions = contextSrv.hasPermission(getRulesPermissions(GRAFANA_RULES_SOURCE_NAME).read);
const hasRuleUpdatePermissions = contextSrv.hasPermission(getRulesPermissions(GRAFANA_RULES_SOURCE_NAME).update);
const isAlertingAvailableForRead = unifiedAlertingEnabled && hasRuleReadPermissions;

return isAlertingAvailableForRead && hasRuleUpdatePermissions;
}
58 changes: 58 additions & 0 deletions public/app/features/dashboard/utils/getPanelMenu.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import {
} from '@grafana/data';
import { AngularComponent, getPluginLinkExtensions } from '@grafana/runtime';
import config from 'app/core/config';
import { grantUserPermissions } from 'app/features/alerting/unified/mocks';
import * as actions from 'app/features/explore/state/main';
import { setStore } from 'app/store/store';
import { AccessControlAction } from 'app/types';

import { PanelModel } from '../state';
import { createDashboardModelFixture } from '../state/__fixtures__/dashboardFixtures';
Expand All @@ -23,6 +25,7 @@ import { getPanelMenu } from './getPanelMenu';
jest.mock('app/core/services/context_srv', () => ({
contextSrv: {
hasAccessToExplore: () => true,
hasPermission: jest.fn(),
},
}));

Expand All @@ -38,6 +41,8 @@ describe('getPanelMenu()', () => {
beforeEach(() => {
getPluginLinkExtensionsMock.mockRestore();
getPluginLinkExtensionsMock.mockReturnValue({ extensions: [] });
grantUserPermissions([AccessControlAction.AlertingRuleRead, AccessControlAction.AlertingRuleUpdate]);
config.unifiedAlertingEnabled = false;
});

it('should return the correct panel menu items', () => {
Expand Down Expand Up @@ -619,4 +624,57 @@ describe('getPanelMenu()', () => {
expect(windowOpen).toHaveBeenLastCalledWith(`${testSubUrl}${testUrl}`);
});
});
describe('Alerting menu', () => {
it('should render Create alert menu item if user has permissions to read and update alerts ', () => {
const panel = new PanelModel({});

const dashboard = createDashboardModelFixture({});
config.unifiedAlertingEnabled = true;
grantUserPermissions([AccessControlAction.AlertingRuleRead, AccessControlAction.AlertingRuleUpdate]);
const menuItems = getPanelMenu(dashboard, panel);
const moreSubMenu = menuItems.find((i) => i.text === 'More...')?.subMenu;

expect(moreSubMenu).toEqual(
expect.arrayContaining([
expect.objectContaining({
text: 'Create alert',
}),
])
);
});

it('should not render Create alert menu item, if user does not have permissions to update alerts ', () => {
const panel = new PanelModel({});
const dashboard = createDashboardModelFixture({});

grantUserPermissions([AccessControlAction.AlertingRuleRead]);
config.unifiedAlertingEnabled = true;

const menuItems = getPanelMenu(dashboard, panel);

const moreSubMenu = menuItems.find((i) => i.text === 'More...')?.subMenu;

expect(moreSubMenu).toEqual(
expect.arrayContaining([
expect.not.objectContaining({
text: 'Create alert',
}),
])
);
});
it('should not render Create alert menu item, if user does not have permissions to read update alerts ', () => {
const panel = new PanelModel({});

const dashboard = createDashboardModelFixture({});
grantUserPermissions([]);
config.unifiedAlertingEnabled = true;

const menuItems = getPanelMenu(dashboard, panel);

const moreSubMenu = menuItems.find((i) => i.text === 'More...')?.subMenu;
const createAlertOption = moreSubMenu?.find((i) => i.text === 'Create alert')?.subMenu;

expect(createAlertOption).toBeUndefined();
});
});
});
37 changes: 36 additions & 1 deletion public/app/features/dashboard/utils/getPanelMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ import {
PanelMenuItem,
PluginExtensionLink,
PluginExtensionPoints,
urlUtil,
type PluginExtensionPanelContext,
} from '@grafana/data';
import { AngularComponent, locationService, reportInteraction, getPluginLinkExtensions } from '@grafana/runtime';
import { AngularComponent, getPluginLinkExtensions, locationService, reportInteraction } from '@grafana/runtime';
import { PanelCtrl } from 'app/angular/panel/panel_ctrl';
import config from 'app/core/config';
import { t } from 'app/core/internationalization';
import { contextSrv } from 'app/core/services/context_srv';
import { getExploreUrl } from 'app/core/utils/explore';
import { panelToRuleFormValues } from 'app/features/alerting/unified/utils/rule-form';
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
import { PanelModel } from 'app/features/dashboard/state/PanelModel';
import {
Expand All @@ -28,6 +30,7 @@ import { truncateTitle } from 'app/features/plugins/extensions/utils';
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
import { store } from 'app/store/store';

import { getCreateAlertInMenuAvailability } from '../../alerting/unified/utils/access-control';
import { navigateToExplore } from '../../explore/state/main';
import { getTimeSrv } from '../services/TimeSrv';

Expand Down Expand Up @@ -202,8 +205,27 @@ export function getPanelMenu(
subMenu: inspectMenu,
});

const createAlert = async () => {
const formValues = await panelToRuleFormValues(panel, dashboard);

const ruleFormUrl = urlUtil.renderUrl('/alerting/new', {
defaults: JSON.stringify(formValues),
returnTo: location.pathname + location.search,
});

locationService.push(ruleFormUrl);
};

const onCreateAlert = (event: React.MouseEvent) => {
event.preventDefault();
createAlert();
reportInteraction('dashboards_panelheader_menu', { item: 'create-alert' });
};

const subMenu: PanelMenuItem[] = [];
const canEdit = dashboard.canEditPanel(panel);
const isCreateAlertMenuOptionAvailable = getCreateAlertInMenuAvailability();

if (!(panel.isViewing || panel.isEditing)) {
if (canEdit) {
subMenu.push({
Expand Down Expand Up @@ -237,6 +259,13 @@ export function getPanelMenu(
}
}

if (isCreateAlertMenuOptionAvailable) {
subMenu.push({
text: t('panel.header-menu.create-alert', `Create alert`),
onClick: onCreateAlert,
});
}

// add old angular panel options
if (angularComponent) {
const scope = angularComponent.getScope();
Expand Down Expand Up @@ -273,6 +302,12 @@ export function getPanelMenu(
// When editing hide most actions
if (panel.isEditing) {
subMenu.length = 0;
if (isCreateAlertMenuOptionAvailable) {
subMenu.push({
text: t('panel.header-menu.create-alert', `Create alert`),
onClick: onCreateAlert,
});
}
}

if (canEdit && panel.plugin && !panel.plugin.meta.skipDataQuery) {
Expand Down
1 change: 1 addition & 0 deletions public/locales/de-DE/grafana.json
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,7 @@
"panel": {
"header-menu": {
"copy": "Kopieren",
"create-alert": "",
"create-library-panel": "Bibliotheksleiste erstellen",
"duplicate": "Duplikat",
"edit": "Bearbeiten",
Expand Down
1 change: 1 addition & 0 deletions public/locales/en-US/grafana.json
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,7 @@
"panel": {
"header-menu": {
"copy": "Copy",
"create-alert": "Create alert",
"create-library-panel": "Create library panel",
"duplicate": "Duplicate",
"edit": "Edit",
Expand Down
1 change: 1 addition & 0 deletions public/locales/es-ES/grafana.json
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,7 @@
"panel": {
"header-menu": {
"copy": "Copiar",
"create-alert": "",
"create-library-panel": "Crear panel de librería",
"duplicate": "Duplicar",
"edit": "Editar",
Expand Down
1 change: 1 addition & 0 deletions public/locales/fr-FR/grafana.json
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,7 @@
"panel": {
"header-menu": {
"copy": "Copier",
"create-alert": "",
"create-library-panel": "Créer un panneau Bibliothèque",
"duplicate": "Dupliquer",
"edit": "Modifier",
Expand Down
1 change: 1 addition & 0 deletions public/locales/pseudo-LOCALE/grafana.json
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,7 @@
"panel": {
"header-menu": {
"copy": "Cőpy",
"create-alert": "Cřęäŧę äľęřŧ",
"create-library-panel": "Cřęäŧę ľįþřäřy päʼnęľ",
"duplicate": "Đūpľįčäŧę",
"edit": "Ēđįŧ",
Expand Down
1 change: 1 addition & 0 deletions public/locales/zh-Hans/grafana.json
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,7 @@
"panel": {
"header-menu": {
"copy": "复制",
"create-alert": "",
"create-library-panel": "创建库面板",
"duplicate": "复制",
"edit": "编辑",
Expand Down

0 comments on commit 1de65bb

Please sign in to comment.