From c63086822d3be2bd1b8d97ffa7de80a058e979e8 Mon Sep 17 00:00:00 2001 From: Nathan Rodman Date: Thu, 14 Apr 2022 05:19:15 -0700 Subject: [PATCH] Alerting: Add FGAC to alerts tab in panel editor (#47732) * add FGAC for alert panel tab * add test for panel tabs * Refactor condition Co-authored-by: Konrad Lalik --- .../alerting/unified/PanelAlertTabContent.tsx | 8 +++- .../PanelEditor/state/selectors.test.ts | 39 +++++++++++++++++++ .../components/PanelEditor/state/selectors.ts | 15 +++++-- 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/public/app/features/alerting/unified/PanelAlertTabContent.tsx b/public/app/features/alerting/unified/PanelAlertTabContent.tsx index 7460af80219..6832a62b200 100644 --- a/public/app/features/alerting/unified/PanelAlertTabContent.tsx +++ b/public/app/features/alerting/unified/PanelAlertTabContent.tsx @@ -7,6 +7,8 @@ import { NewRuleFromPanelButton } from './components/panel-alerts-tab/NewRuleFro import { RulesTable } from './components/rules/RulesTable'; import { usePanelCombinedRules } from './hooks/usePanelCombinedRules'; import { selectors } from '@grafana/e2e-selectors'; +import { getRulesPermissions } from './utils/access-control'; +import { contextSrv } from 'app/core/services/context_srv'; interface Props { dashboard: DashboardModel; @@ -20,6 +22,8 @@ export const PanelAlertTabContent: FC = ({ dashboard, panel }) => { panel, poll: true, }); + const permissions = getRulesPermissions('grafana'); + const canCreateRules = contextSrv.hasPermission(permissions.create); const alert = errors.length ? ( @@ -44,7 +48,7 @@ export const PanelAlertTabContent: FC = ({ dashboard, panel }) => {
{alert} - {!!dashboard.meta.canSave && ( + {!!dashboard.meta.canSave && canCreateRules && ( )}
@@ -58,7 +62,7 @@ export const PanelAlertTabContent: FC = ({ dashboard, panel }) => { {!!dashboard.uid && ( <>

There are no alert rules linked to this panel.

- {!!dashboard.meta.canSave && } + {!!dashboard.meta.canSave && canCreateRules && } )} {!dashboard.uid && !!dashboard.meta.canSave && ( diff --git a/public/app/features/dashboard/components/PanelEditor/state/selectors.test.ts b/public/app/features/dashboard/components/PanelEditor/state/selectors.test.ts index 5768728b784..0bab17d32f9 100644 --- a/public/app/features/dashboard/components/PanelEditor/state/selectors.test.ts +++ b/public/app/features/dashboard/components/PanelEditor/state/selectors.test.ts @@ -2,6 +2,13 @@ import { getPanelEditorTabs } from './selectors'; import { PanelPlugin } from '@grafana/data'; import { PanelEditorTabId } from '../types'; import { updateConfig } from '../../../../../core/config'; +import { contextSrv } from 'app/core/services/context_srv'; + +jest.mock('app/core/services/context_srv'); + +const mocks = { + contextSrv: jest.mocked(contextSrv), +}; describe('getPanelEditorTabs selector', () => { it('return no tabs when no plugin provided', () => { @@ -79,5 +86,37 @@ describe('getPanelEditorTabs selector', () => { expect(tabs[1].id).toEqual(PanelEditorTabId.Transform); }); }); + + describe('with unified alerting enabled', () => { + beforeAll(() => { + updateConfig({ unifiedAlertingEnabled: true }); + }); + + it('shows the alert tab for users with read permission', () => { + mocks.contextSrv.hasPermission.mockReturnValue(true); + + const tabs = getPanelEditorTabs(undefined, { + meta: { + id: 'graph', + }, + } as PanelPlugin); + + expect(tabs.length).toEqual(3); + expect(tabs[2].id).toEqual(PanelEditorTabId.Alert); + }); + + it('hides the alert tab for users with read permission', () => { + mocks.contextSrv.hasPermission.mockReturnValue(false); + + const tabs = getPanelEditorTabs(undefined, { + meta: { + id: 'graph', + }, + } as PanelPlugin); + + expect(tabs.length).toEqual(2); + expect(tabs[1].id).toEqual(PanelEditorTabId.Transform); + }); + }); }); }); diff --git a/public/app/features/dashboard/components/PanelEditor/state/selectors.ts b/public/app/features/dashboard/components/PanelEditor/state/selectors.ts index 64ce72c531f..007945700da 100644 --- a/public/app/features/dashboard/components/PanelEditor/state/selectors.ts +++ b/public/app/features/dashboard/components/PanelEditor/state/selectors.ts @@ -2,6 +2,9 @@ import memoizeOne from 'memoize-one'; import { PanelPlugin } from '@grafana/data'; import { PanelEditorTab, PanelEditorTabId } from '../types'; import { getConfig } from 'app/core/config'; +import { getRulesPermissions } from 'app/features/alerting/unified/utils/access-control'; +import { contextSrv } from 'app/core/services/context_srv'; +import { GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting/unified/utils/datasource'; export const getPanelEditorTabs = memoizeOne((tab?: string, plugin?: PanelPlugin) => { const tabs: PanelEditorTab[] = []; @@ -34,10 +37,14 @@ export const getPanelEditorTabs = memoizeOne((tab?: string, plugin?: PanelPlugin }); } - if ( - ((getConfig().alertingEnabled || getConfig().unifiedAlertingEnabled) && plugin.meta.id === 'graph') || - plugin.meta.id === 'timeseries' - ) { + const { alertingEnabled, unifiedAlertingEnabled } = getConfig(); + const hasRuleReadPermissions = contextSrv.hasPermission(getRulesPermissions(GRAFANA_RULES_SOURCE_NAME).read); + const isAlertingAvailable = alertingEnabled || (unifiedAlertingEnabled && hasRuleReadPermissions); + + const isGraph = plugin.meta.id === 'graph'; + const isTimeseries = plugin.meta.id === 'timeseries'; + + if ((isAlertingAvailable && isGraph) || isTimeseries) { tabs.push({ id: PanelEditorTabId.Alert, text: 'Alert',