From d46208b28a0d92e182475bdd8ee71104b7a2412e Mon Sep 17 00:00:00 2001 From: Ieva Date: Wed, 6 Sep 2023 16:07:49 +0100 Subject: [PATCH] Chore: remove legacy AC fallback from frontend access control checks (#74385) * don't use legacy AC fallback for frontend access control checks * extend tests * more test fixes * more test fixes * more test fixes * final test fix * team test fix * finally fix tests --- .../Select/OldFolderPicker.test.tsx | 8 +-- .../components/Select/OldFolderPicker.tsx | 4 +- .../app/features/admin/ServerStats.test.tsx | 1 + public/app/features/admin/ServerStats.tsx | 8 +-- .../app/features/admin/UserListPage.test.tsx | 67 +++++-------------- public/app/features/admin/UserListPage.tsx | 2 +- .../unified/NotificationPolicies.test.tsx | 3 +- .../notification-policies/Policy.tsx | 3 +- .../components/receivers/ReceiversTable.tsx | 6 +- .../SmartAlertTypeDetector.tsx | 7 +- .../rules/RuleDetailsActionButtons.tsx | 2 +- .../components/silences/NoSilencesCTA.tsx | 2 +- .../unified/hooks/useIsRuleEditable.ts | 4 +- .../alerting/unified/utils/access-control.ts | 19 +++--- public/app/features/api-keys/ApiKeysPage.tsx | 2 +- .../components/HelpWizard/HelpWizard.tsx | 3 +- .../ConfigPublicDashboard.tsx | 3 +- .../CreatePublicDashboard.tsx | 3 +- .../SharePublicDashboard.test.tsx | 5 +- .../AddToDashboard/AddToDashboardForm.tsx | 4 +- .../getAddToDashboardTitle.test.ts | 10 +-- .../AddToDashboard/getAddToDashboardTitle.ts | 4 +- .../extensions/AddToDashboard/index.test.tsx | 8 +-- .../extensions/ToolbarExtensionPoint.test.tsx | 4 +- .../extensions/ToolbarExtensionPoint.tsx | 4 +- .../getExploreExtensionConfigs.test.tsx | 6 +- .../extensions/getExploreExtensionConfigs.tsx | 4 +- .../PublicDashboardListTable.test.tsx | 10 +-- .../PublicDashboardListTable.tsx | 3 +- .../InstallControlsWarning.tsx | 3 +- public/app/features/plugins/admin/helpers.ts | 3 +- .../admin/pages/PluginDetails.test.tsx | 1 + .../components/ManageDashboards.test.tsx | 4 ++ .../search/components/ManageDashboardsNew.tsx | 4 +- .../support-bundles/SupportBundles.tsx | 7 +- public/app/features/teams/TeamList.test.tsx | 67 ++++++++++--------- public/app/features/teams/TeamList.tsx | 7 +- 37 files changed, 129 insertions(+), 176 deletions(-) diff --git a/public/app/core/components/Select/OldFolderPicker.test.tsx b/public/app/core/components/Select/OldFolderPicker.test.tsx index e75e65e1982..2b27a1fbfd7 100644 --- a/public/app/core/components/Select/OldFolderPicker.test.tsx +++ b/public/app/core/components/Select/OldFolderPicker.test.tsx @@ -84,7 +84,7 @@ describe('OldFolderPicker', () => { { title: 'Dash 2', uid: 'wfTJJL5Wz' } as DashboardSearchHit, ]); - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(true); + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true); const onChangeFn = jest.fn(); render(); @@ -105,7 +105,7 @@ describe('OldFolderPicker', () => { { title: 'Dash 2', uid: 'wfTJJL5Wz' } as DashboardSearchHit, ]); - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(true); + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true); const onChangeFn = jest.fn(); render(); @@ -126,7 +126,7 @@ describe('OldFolderPicker', () => { { title: 'Dash 2', uid: 'wfTJJL5Wz' } as DashboardSearchHit, ]); - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(false); + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false); const onChangeFn = jest.fn(); render(); @@ -148,7 +148,7 @@ describe('OldFolderPicker', () => { ].filter((dash) => dash.title.indexOf(query) > -1) ); }); - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(false); + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false); const onChangeFn = jest.fn(); render(); diff --git a/public/app/core/components/Select/OldFolderPicker.tsx b/public/app/core/components/Select/OldFolderPicker.tsx index 99495140545..9f2dc87bb1d 100644 --- a/public/app/core/components/Select/OldFolderPicker.tsx +++ b/public/app/core/components/Select/OldFolderPicker.tsx @@ -104,8 +104,8 @@ export function OldFolderPicker(props: Props) { }); const hasAccess = - contextSrv.hasAccess(AccessControlAction.DashboardsWrite, contextSrv.isEditor) || - contextSrv.hasAccess(AccessControlAction.DashboardsCreate, contextSrv.isEditor); + contextSrv.hasPermission(AccessControlAction.DashboardsWrite) || + contextSrv.hasPermission(AccessControlAction.DashboardsCreate); if (hasAccess && rootName?.toLowerCase().startsWith(query.toLowerCase()) && showRoot) { options.unshift({ label: rootName, value: '' }); diff --git a/public/app/features/admin/ServerStats.test.tsx b/public/app/features/admin/ServerStats.test.tsx index eddea4f6068..a6d586c4222 100644 --- a/public/app/features/admin/ServerStats.test.tsx +++ b/public/app/features/admin/ServerStats.test.tsx @@ -30,6 +30,7 @@ jest.mock('./state/apis', () => ({ jest.mock('../../core/services/context_srv', () => ({ contextSrv: { hasAccess: () => true, + hasPermission: () => true, }, })); diff --git a/public/app/features/admin/ServerStats.tsx b/public/app/features/admin/ServerStats.tsx index 80f8854ef3e..116fc8e2f32 100644 --- a/public/app/features/admin/ServerStats.tsx +++ b/public/app/features/admin/ServerStats.tsx @@ -15,11 +15,11 @@ export const ServerStats = () => { const [isLoading, setIsLoading] = useState(false); const styles = useStyles2(getStyles); - const hasAccessToDataSources = contextSrv.hasAccess(AccessControlAction.DataSourcesRead, contextSrv.isGrafanaAdmin); - const hasAccessToAdminUsers = contextSrv.hasAccess(AccessControlAction.UsersRead, contextSrv.isGrafanaAdmin); + const hasAccessToDataSources = contextSrv.hasPermission(AccessControlAction.DataSourcesRead); + const hasAccessToAdminUsers = contextSrv.hasPermission(AccessControlAction.UsersRead); useEffect(() => { - if (contextSrv.hasAccess(AccessControlAction.ActionServerStatsRead, contextSrv.isGrafanaAdmin)) { + if (contextSrv.hasPermission(AccessControlAction.ActionServerStatsRead)) { setIsLoading(true); getServerStats().then((stats) => { setStats(stats); @@ -28,7 +28,7 @@ export const ServerStats = () => { } }, []); - if (!contextSrv.hasAccess(AccessControlAction.ActionServerStatsRead, contextSrv.isGrafanaAdmin)) { + if (!contextSrv.hasPermission(AccessControlAction.ActionServerStatsRead)) { return null; } diff --git a/public/app/features/admin/UserListPage.test.tsx b/public/app/features/admin/UserListPage.test.tsx index 1f917648f49..274c15f4fdd 100644 --- a/public/app/features/admin/UserListPage.test.tsx +++ b/public/app/features/admin/UserListPage.test.tsx @@ -56,7 +56,6 @@ afterEach(() => { describe('Tabs rendering', () => { it('should render All and Org Users tabs when user has permissions to read to org users and is admin', async () => { - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(true); jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true); renderPage(); @@ -66,7 +65,6 @@ describe('Tabs rendering', () => { expect(screen.queryByTestId(tabsSelector.publicDashboardsUsers)).not.toBeInTheDocument(); }); it('should render All, Org and Public dashboard tabs when user has permissions to read org users, is admin and has email sharing enabled', async () => { - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(true); jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true); enableEmailSharing(); @@ -77,61 +75,34 @@ describe('Tabs rendering', () => { expect(screen.getByTestId(tabsSelector.publicDashboardsUsers)).toBeInTheDocument(); }); describe('No permissions to read org users or not admin', () => { - [ - { - hasOrgReadPermissions: false, - isAdmin: true, - }, - { - hasOrgReadPermissions: true, - isAdmin: false, - }, - ].forEach((scenario) => { - it('should render no tabs when user has no permissions to read org users or is not admin', async () => { - jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(scenario.hasOrgReadPermissions); - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(scenario.isAdmin); + it('should render no tabs when user has no permissions to read org users', async () => { + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false); - renderPage(); + renderPage(); - expect(screen.queryByTestId(tabsSelector.allUsers)).not.toBeInTheDocument(); - expect(screen.queryByTestId(tabsSelector.orgUsers)).not.toBeInTheDocument(); - expect(screen.queryByTestId(tabsSelector.publicDashboardsUsers)).not.toBeInTheDocument(); - }); + expect(screen.queryByTestId(tabsSelector.allUsers)).not.toBeInTheDocument(); + expect(screen.queryByTestId(tabsSelector.orgUsers)).not.toBeInTheDocument(); + expect(screen.queryByTestId(tabsSelector.publicDashboardsUsers)).not.toBeInTheDocument(); }); }); - describe('No permissions to read org users or not admin but email sharing enabled', () => { - [ - { - title: 'user has no permissions to read org users', - hasOrgReadPermissions: false, - isAdmin: true, - }, - { - title: 'user is not admin', - hasOrgReadPermissions: true, - isAdmin: false, - }, - ].forEach((scenario) => { - it(`should render User and Public dashboard tabs when ${scenario.title} but has email sharing enabled`, async () => { - jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(scenario.hasOrgReadPermissions); - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(scenario.isAdmin); + describe('No permissions to read org users but email sharing enabled', () => { + it(`should render User and Public dashboard tabs when no permissions to read org users but has email sharing enabled`, async () => { + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false); - enableEmailSharing(); - renderPage(); + enableEmailSharing(); + renderPage(); - expect(screen.queryByTestId(tabsSelector.allUsers)).not.toBeInTheDocument(); - expect(screen.queryByTestId(tabsSelector.orgUsers)).not.toBeInTheDocument(); + expect(screen.queryByTestId(tabsSelector.allUsers)).not.toBeInTheDocument(); + expect(screen.queryByTestId(tabsSelector.orgUsers)).not.toBeInTheDocument(); - expect(screen.getByTestId(tabsSelector.users)).toBeInTheDocument(); - expect(screen.getByTestId(tabsSelector.publicDashboardsUsers)).toBeInTheDocument(); - }); + expect(screen.getByTestId(tabsSelector.users)).toBeInTheDocument(); + expect(screen.getByTestId(tabsSelector.publicDashboardsUsers)).toBeInTheDocument(); }); }); }); describe('Tables rendering', () => { it('should render UserListAdminPage when user is admin', () => { - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(true); jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true); renderPage(); @@ -142,7 +113,6 @@ describe('Tables rendering', () => { expect(screen.getByTestId(selectors.UserListAdminPage.container)).toBeInTheDocument(); }); it('should render UsersListPage when user is admin and has org read permissions', async () => { - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(true); jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true); renderPage(); @@ -156,8 +126,7 @@ describe('Tables rendering', () => { expect(screen.getByTestId(selectors.UsersListPage.container)).toBeInTheDocument(); }); it('should render UsersListPage when user has org read permissions and is not admin', async () => { - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(false); - jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true); + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false); renderPage(); @@ -169,8 +138,7 @@ describe('Tables rendering', () => { expect(screen.getByTestId(selectors.UsersListPage.container)).toBeInTheDocument(); }); it('should render UserListPublicDashboardPage when user has email sharing enabled and is not admin', async () => { - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(false); - jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true); + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false); enableEmailSharing(); renderPage(); @@ -186,7 +154,6 @@ describe('Tables rendering', () => { expect(screen.getByTestId(selectors.UsersListPublicDashboardsPage.container)).toBeInTheDocument(); }); it('should render UsersListPage when user is not admin and does not have nor org read perms neither email sharing enabled', async () => { - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(false); jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false); renderPage(); diff --git a/public/app/features/admin/UserListPage.tsx b/public/app/features/admin/UserListPage.tsx index 90764f9b40a..17bf9ab28bf 100644 --- a/public/app/features/admin/UserListPage.tsx +++ b/public/app/features/admin/UserListPage.tsx @@ -40,7 +40,7 @@ const TAB_PAGE_MAP: Record = { export default function UserListPage() { const styles = useStyles2(getStyles); - const hasAccessToAdminUsers = contextSrv.hasAccess(AccessControlAction.UsersRead, contextSrv.isGrafanaAdmin); + const hasAccessToAdminUsers = contextSrv.hasPermission(AccessControlAction.UsersRead); const hasAccessToOrgUsers = contextSrv.hasPermission(AccessControlAction.OrgUsersRead); const hasEmailSharingEnabled = Boolean(config.featureToggles.publicDashboards) && diff --git a/public/app/features/alerting/unified/NotificationPolicies.test.tsx b/public/app/features/alerting/unified/NotificationPolicies.test.tsx index 06ff0e59a56..459ea8e4e67 100644 --- a/public/app/features/alerting/unified/NotificationPolicies.test.tsx +++ b/public/app/features/alerting/unified/NotificationPolicies.test.tsx @@ -196,7 +196,6 @@ describe('NotificationPolicies', () => { beforeEach(() => { mocks.getAllDataSourcesMock.mockReturnValue(Object.values(dataSources)); - mocks.contextSrv.hasAccess.mockImplementation(() => true); mocks.contextSrv.hasPermission.mockImplementation(() => true); mocks.contextSrv.evaluatePermission.mockImplementation(() => []); mocks.api.discoverAlertmanagerFeatures.mockResolvedValue({ lazyConfigInit: false }); @@ -384,7 +383,7 @@ describe('NotificationPolicies', () => { }); it('hides create and edit button if user does not have permission', async () => { - mocks.contextSrv.hasAccess.mockImplementation((action) => + mocks.contextSrv.hasPermission.mockImplementation((action) => [AccessControlAction.AlertingNotificationsRead, AccessControlAction.AlertingNotificationsRead].includes( action as AccessControlAction ) diff --git a/public/app/features/alerting/unified/components/notification-policies/Policy.tsx b/public/app/features/alerting/unified/components/notification-policies/Policy.tsx index 374ce66ad89..c1c6a40ef20 100644 --- a/public/app/features/alerting/unified/components/notification-policies/Policy.tsx +++ b/public/app/features/alerting/unified/components/notification-policies/Policy.tsx @@ -12,7 +12,6 @@ import ConditionalWrap from 'app/features/alerting/components/ConditionalWrap'; import { RouteWithID, Receiver, ObjectMatcher, AlertmanagerGroup } from 'app/plugins/datasource/alertmanager/types'; import { ReceiversState } from 'app/types'; -import { isOrgAdmin } from '../../../../plugins/admin/permissions'; import { INTEGRATION_ICONS } from '../../types/contact-points'; import { getNotificationsPermissions } from '../../utils/access-control'; import { GRAFANA_RULES_SOURCE_NAME } from '../../utils/datasource'; @@ -75,7 +74,7 @@ const Policy: FC = ({ const canEditRoutes = contextSrv.hasPermission(permissions.update); const canDeleteRoutes = contextSrv.hasPermission(permissions.delete); const canReadProvisioning = - contextSrv.hasAccess(permissions.provisioning.read, isOrgAdmin()) || + contextSrv.hasPermission(permissions.provisioning.read) || contextSrv.hasPermission(permissions.provisioning.readSecrets); const contactPoint = currentRoute.receiver; diff --git a/public/app/features/alerting/unified/components/receivers/ReceiversTable.tsx b/public/app/features/alerting/unified/components/receivers/ReceiversTable.tsx index 9f1e8e5b173..a283792577c 100644 --- a/public/app/features/alerting/unified/components/receivers/ReceiversTable.tsx +++ b/public/app/features/alerting/unified/components/receivers/ReceiversTable.tsx @@ -89,7 +89,7 @@ function ViewAction({ permissions, alertManagerName, receiverName }: ActionProps } function ExportAction({ permissions, receiverName }: ActionProps) { - const canReadSecrets = contextSrv.hasAccess(permissions.provisioning.readSecrets, isOrgAdmin()); + const canReadSecrets = contextSrv.hasPermission(permissions.provisioning.readSecrets); return ( { const isGrafanaAM = alertManagerName === GRAFANA_RULES_SOURCE_NAME; const showExport = isGrafanaAM && - (contextSrv.hasAccess(permissions.provisioning.read, isOrgAdmin()) || - contextSrv.hasAccess(permissions.provisioning.readSecrets, isOrgAdmin())); + (contextSrv.hasPermission(permissions.provisioning.read) || + contextSrv.hasPermission(permissions.provisioning.readSecrets)); const onClickDeleteReceiver = (receiverName: string): void => { if (isReceiverUsed(receiverName, config)) { diff --git a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/SmartAlertTypeDetector.tsx b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/SmartAlertTypeDetector.tsx index 5800c5b00b4..86144503a02 100644 --- a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/SmartAlertTypeDetector.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/SmartAlertTypeDetector.tsx @@ -14,11 +14,8 @@ import { RuleFormType, RuleFormValues } from '../../../types/rule-form'; import { NeedHelpInfo } from '../NeedHelpInfo'; function getAvailableRuleTypes() { - const canCreateGrafanaRules = contextSrv.hasAccess( - AccessControlAction.AlertingRuleCreate, - contextSrv.hasEditPermissionInFolders - ); - const canCreateCloudRules = contextSrv.hasAccess(AccessControlAction.AlertingRuleExternalWrite, contextSrv.isEditor); + const canCreateGrafanaRules = contextSrv.hasPermission(AccessControlAction.AlertingRuleCreate); + const canCreateCloudRules = contextSrv.hasPermission(AccessControlAction.AlertingRuleExternalWrite); const defaultRuleType = canCreateGrafanaRules ? RuleFormType.grafana : RuleFormType.cloudAlerting; const enabledRuleTypes: RuleFormType[] = []; diff --git a/public/app/features/alerting/unified/components/rules/RuleDetailsActionButtons.tsx b/public/app/features/alerting/unified/components/rules/RuleDetailsActionButtons.tsx index a93c11a7644..959c41dea8a 100644 --- a/public/app/features/alerting/unified/components/rules/RuleDetailsActionButtons.tsx +++ b/public/app/features/alerting/unified/components/rules/RuleDetailsActionButtons.tsx @@ -291,7 +291,7 @@ function useCanSilence(rule: CombinedRule) { return false; } - const hasPermissions = contextSrv.hasAccess(AccessControlAction.AlertingInstanceCreate, contextSrv.isEditor); + const hasPermissions = contextSrv.hasPermission(AccessControlAction.AlertingInstanceCreate); const interactsOnlyWithExternalAMs = amConfigStatus?.alertmanagersChoice === AlertmanagerChoice.External; const interactsWithAll = amConfigStatus?.alertmanagersChoice === AlertmanagerChoice.All; diff --git a/public/app/features/alerting/unified/components/silences/NoSilencesCTA.tsx b/public/app/features/alerting/unified/components/silences/NoSilencesCTA.tsx index 3e4bbb4595d..b754f5b4fdb 100644 --- a/public/app/features/alerting/unified/components/silences/NoSilencesCTA.tsx +++ b/public/app/features/alerting/unified/components/silences/NoSilencesCTA.tsx @@ -14,7 +14,7 @@ type Props = { export const NoSilencesSplash = ({ alertManagerSourceName }: Props) => { const permissions = getInstancesPermissions(alertManagerSourceName); - if (contextSrv.hasAccess(permissions.create, contextSrv.isEditor)) { + if (contextSrv.hasPermission(permissions.create)) { return ( { - const permissionFallback = - rulesSourceName === GRAFANA_RULES_SOURCE_NAME ? contextSrv.hasEditPermissionInFolders : contextSrv.isEditor; - return contextSrv.hasAccess(getRulesPermissions(rulesSourceName).update, permissionFallback); + return contextSrv.hasPermission(getRulesPermissions(rulesSourceName).update); }, canReadProvisioning: - contextSrv.hasAccess(provisioningPermissions.read, isOrgAdmin()) || - contextSrv.hasAccess(provisioningPermissions.readSecrets, isOrgAdmin()), + contextSrv.hasPermission(provisioningPermissions.read) || + contextSrv.hasPermission(provisioningPermissions.readSecrets), }; } diff --git a/public/app/features/api-keys/ApiKeysPage.tsx b/public/app/features/api-keys/ApiKeysPage.tsx index db12d5e1ccf..db06645a2fa 100644 --- a/public/app/features/api-keys/ApiKeysPage.tsx +++ b/public/app/features/api-keys/ApiKeysPage.tsx @@ -16,7 +16,7 @@ import { setSearchQuery } from './state/reducers'; import { getApiKeys, getApiKeysCount, getIncludeExpired, getIncludeExpiredDisabled } from './state/selectors'; function mapStateToProps(state: StoreState) { - const canCreate = contextSrv.hasAccess(AccessControlAction.ActionAPIKeysCreate, true); + const canCreate = contextSrv.hasPermission(AccessControlAction.ActionAPIKeysCreate); return { apiKeys: getApiKeys(state.apiKeys), searchQuery: state.apiKeys.searchQuery, diff --git a/public/app/features/dashboard/components/HelpWizard/HelpWizard.tsx b/public/app/features/dashboard/components/HelpWizard/HelpWizard.tsx index 4f9fa35d360..d0d1a9a444b 100644 --- a/public/app/features/dashboard/components/HelpWizard/HelpWizard.tsx +++ b/public/app/features/dashboard/components/HelpWizard/HelpWizard.tsx @@ -66,8 +66,7 @@ export function HelpWizard({ panel, plugin, onClose }: Props) { ]; const hasSupportBundleAccess = - config.supportBundlesEnabled && - contextSrv.hasAccess(AccessControlAction.ActionSupportBundlesCreate, contextSrv.isGrafanaAdmin); + config.supportBundlesEnabled && contextSrv.hasPermission(AccessControlAction.ActionSupportBundlesCreate); return ( { const isDesktop = useIsDesktop(); const { showModal, hideModal } = useContext(ModalsContext); - const hasWritePermissions = contextSrv.hasAccess(AccessControlAction.DashboardsPublicWrite, isOrgAdmin()); + const hasWritePermissions = contextSrv.hasPermission(AccessControlAction.DashboardsPublicWrite); const hasEmailSharingEnabled = !!config.featureToggles.publicDashboardsEmailSharing && featureEnabled('publicDashboardsEmailSharing'); const dashboardState = useSelector((store) => store.dashboard); diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/CreatePublicDashboard.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/CreatePublicDashboard.tsx index 515ab6fa6ae..47d19c2cfa5 100644 --- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/CreatePublicDashboard.tsx +++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/CreatePublicDashboard.tsx @@ -8,7 +8,6 @@ import { Button, Form, Spinner, useStyles2 } from '@grafana/ui/src'; import { contextSrv } from '../../../../../../core/services/context_srv'; import { AccessControlAction, useSelector } from '../../../../../../types'; -import { isOrgAdmin } from '../../../../../plugins/admin/permissions'; import { useCreatePublicDashboardMutation } from '../../../../api/publicDashboardApi'; import { trackDashboardSharingActionPerType } from '../../analytics'; import { shareDashboardType } from '../../utils'; @@ -29,7 +28,7 @@ export type SharePublicDashboardAcknowledgmentInputs = { const CreatePublicDashboard = ({ isError }: { isError: boolean }) => { const styles = useStyles2(getStyles); - const hasWritePermissions = contextSrv.hasAccess(AccessControlAction.DashboardsPublicWrite, isOrgAdmin()); + const hasWritePermissions = contextSrv.hasPermission(AccessControlAction.DashboardsPublicWrite); const dashboardState = useSelector((store) => store.dashboard); const dashboard = dashboardState.getModel()!; const unsupportedDataSources = getUnsupportedDashboardDatasources(dashboard.panels); diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.test.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.test.tsx index 55d7aec8c27..640ad444457 100644 --- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.test.tsx +++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.test.tsx @@ -69,7 +69,6 @@ beforeAll(() => { beforeEach(() => { config.featureToggles.publicDashboards = true; - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(true); jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true); jest.spyOn(contextSrv, 'hasRole').mockReturnValue(true); }); @@ -103,7 +102,7 @@ const getErrorPublicDashboardResponse = () => const alertTests = () => { it('when user has no write permissions, warning is shown', async () => { - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(false); + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false); await renderSharePublicDashboard(); expect(screen.queryByTestId(selectors.NoUpsertPermissionsWarningAlert)).toBeInTheDocument(); @@ -251,7 +250,7 @@ describe('SharePublic - Already persisted', () => { expect(screen.getByTestId(selectors.DeleteButton)).toBeEnabled(); }); it('inputs and delete button are disabled because of lack of permissions', async () => { - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(false); + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false); await renderSharePublicDashboard(); await userEvent.click(screen.getByText('Settings')); diff --git a/public/app/features/explore/extensions/AddToDashboard/AddToDashboardForm.tsx b/public/app/features/explore/extensions/AddToDashboard/AddToDashboardForm.tsx index 33b76cf1b52..83924809dcb 100644 --- a/public/app/features/explore/extensions/AddToDashboard/AddToDashboardForm.tsx +++ b/public/app/features/explore/extensions/AddToDashboard/AddToDashboardForm.tsx @@ -73,8 +73,8 @@ export function AddToDashboardForm(props: Props): ReactElement { defaultValues: { saveTarget: SaveTarget.NewDashboard }, }); - const canCreateDashboard = contextSrv.hasAccess(AccessControlAction.DashboardsCreate, contextSrv.isEditor); - const canWriteDashboard = contextSrv.hasAccess(AccessControlAction.DashboardsWrite, contextSrv.isEditor); + const canCreateDashboard = contextSrv.hasPermission(AccessControlAction.DashboardsCreate); + const canWriteDashboard = contextSrv.hasPermission(AccessControlAction.DashboardsWrite); const saveTargets: Array> = []; if (canCreateDashboard) { diff --git a/public/app/features/explore/extensions/AddToDashboard/getAddToDashboardTitle.test.ts b/public/app/features/explore/extensions/AddToDashboard/getAddToDashboardTitle.test.ts index 9485138e1d5..d2e6c54bf5c 100644 --- a/public/app/features/explore/extensions/AddToDashboard/getAddToDashboardTitle.test.ts +++ b/public/app/features/explore/extensions/AddToDashboard/getAddToDashboardTitle.test.ts @@ -8,22 +8,22 @@ jest.mock('app/core/services/context_srv'); const contextSrvMock = jest.mocked(contextSrv); describe('getAddToDashboardTitle', () => { - beforeEach(() => contextSrvMock.hasAccess.mockReset()); + beforeEach(() => contextSrvMock.hasPermission.mockReset()); it('should return title ending with "dashboard" if user has full access', () => { - contextSrvMock.hasAccess.mockReturnValue(true); + contextSrvMock.hasPermission.mockReturnValue(true); expect(getAddToDashboardTitle()).toBe('Add panel to dashboard'); }); it('should return title ending with "dashboard" if user has no access', () => { - contextSrvMock.hasAccess.mockReturnValue(false); + contextSrvMock.hasPermission.mockReturnValue(false); expect(getAddToDashboardTitle()).toBe('Add panel to dashboard'); }); it('should return title ending with "new dashboard" if user only has access to create dashboards', () => { - contextSrvMock.hasAccess.mockImplementation((action) => { + contextSrvMock.hasPermission.mockImplementation((action) => { return action === AccessControlAction.DashboardsCreate; }); @@ -31,7 +31,7 @@ describe('getAddToDashboardTitle', () => { }); it('should return title ending with "existing dashboard" if user only has access to edit dashboards', () => { - contextSrvMock.hasAccess.mockImplementation((action) => { + contextSrvMock.hasPermission.mockImplementation((action) => { return action === AccessControlAction.DashboardsWrite; }); diff --git a/public/app/features/explore/extensions/AddToDashboard/getAddToDashboardTitle.ts b/public/app/features/explore/extensions/AddToDashboard/getAddToDashboardTitle.ts index 65c03793e30..d528956cb9f 100644 --- a/public/app/features/explore/extensions/AddToDashboard/getAddToDashboardTitle.ts +++ b/public/app/features/explore/extensions/AddToDashboard/getAddToDashboardTitle.ts @@ -2,8 +2,8 @@ import { contextSrv } from 'app/core/services/context_srv'; import { AccessControlAction } from 'app/types'; export function getAddToDashboardTitle(): string { - const canCreateDashboard = contextSrv.hasAccess(AccessControlAction.DashboardsCreate, contextSrv.isEditor); - const canWriteDashboard = contextSrv.hasAccess(AccessControlAction.DashboardsWrite, contextSrv.isEditor); + const canCreateDashboard = contextSrv.hasPermission(AccessControlAction.DashboardsCreate); + const canWriteDashboard = contextSrv.hasPermission(AccessControlAction.DashboardsWrite); if (canCreateDashboard && !canWriteDashboard) { return 'Add panel to new dashboard'; diff --git a/public/app/features/explore/extensions/AddToDashboard/index.test.tsx b/public/app/features/explore/extensions/AddToDashboard/index.test.tsx index 7067186dfe4..fec15005448 100644 --- a/public/app/features/explore/extensions/AddToDashboard/index.test.tsx +++ b/public/app/features/explore/extensions/AddToDashboard/index.test.tsx @@ -73,7 +73,7 @@ describe('AddToDashboardButton', () => { beforeEach(() => { jest.spyOn(api, 'setDashboardInLocalStorage').mockReturnValue(addToDashboardResponse); - mocks.contextSrv.hasAccess.mockImplementation(() => true); + mocks.contextSrv.hasPermission.mockImplementation(() => true); }); afterEach(() => { @@ -283,7 +283,7 @@ describe('AddToDashboardButton', () => { }); it('Should only show existing dashboard option with no access to create', async () => { - mocks.contextSrv.hasAccess.mockImplementation((action) => { + mocks.contextSrv.hasPermission.mockImplementation((action) => { if (action === 'dashboards:create') { return false; } else { @@ -296,7 +296,7 @@ describe('AddToDashboardButton', () => { }); it('Should only show new dashboard option with no access to write', async () => { - mocks.contextSrv.hasAccess.mockImplementation((action) => { + mocks.contextSrv.hasPermission.mockImplementation((action) => { if (action === 'dashboards:write') { return false; } else { @@ -311,7 +311,7 @@ describe('AddToDashboardButton', () => { describe('Error handling', () => { beforeEach(() => { - mocks.contextSrv.hasAccess.mockImplementation(() => true); + mocks.contextSrv.hasPermission.mockImplementation(() => true); }); afterEach(() => { diff --git a/public/app/features/explore/extensions/ToolbarExtensionPoint.test.tsx b/public/app/features/explore/extensions/ToolbarExtensionPoint.test.tsx index 893a391da3b..20c58516d90 100644 --- a/public/app/features/explore/extensions/ToolbarExtensionPoint.test.tsx +++ b/public/app/features/explore/extensions/ToolbarExtensionPoint.test.tsx @@ -215,7 +215,7 @@ describe('ToolbarExtensionPoint', () => { describe('without extension points', () => { beforeAll(() => { - contextSrvMock.hasAccess.mockReturnValue(true); + contextSrvMock.hasPermission.mockReturnValue(true); getPluginLinkExtensionsMock.mockReturnValue({ extensions: [] }); }); @@ -233,7 +233,7 @@ describe('ToolbarExtensionPoint', () => { describe('with insufficient permissions', () => { beforeAll(() => { - contextSrvMock.hasAccess.mockReturnValue(false); + contextSrvMock.hasPermission.mockReturnValue(false); getPluginLinkExtensionsMock.mockReturnValue({ extensions: [] }); }); diff --git a/public/app/features/explore/extensions/ToolbarExtensionPoint.tsx b/public/app/features/explore/extensions/ToolbarExtensionPoint.tsx index 17a09c7ca95..568ab9a66db 100644 --- a/public/app/features/explore/extensions/ToolbarExtensionPoint.tsx +++ b/public/app/features/explore/extensions/ToolbarExtensionPoint.tsx @@ -35,8 +35,8 @@ export function ToolbarExtensionPoint(props: Props): ReactElement | null { // adding a query to a dashboard. if (extensions.length <= 1) { const canAddPanelToDashboard = - contextSrv.hasAccess(AccessControlAction.DashboardsCreate, contextSrv.isEditor) || - contextSrv.hasAccess(AccessControlAction.DashboardsWrite, contextSrv.isEditor); + contextSrv.hasPermission(AccessControlAction.DashboardsCreate) || + contextSrv.hasPermission(AccessControlAction.DashboardsWrite); if (!canAddPanelToDashboard) { return null; diff --git a/public/app/features/explore/extensions/getExploreExtensionConfigs.test.tsx b/public/app/features/explore/extensions/getExploreExtensionConfigs.test.tsx index 402f80bdf83..2726bf57ad2 100644 --- a/public/app/features/explore/extensions/getExploreExtensionConfigs.test.tsx +++ b/public/app/features/explore/extensions/getExploreExtensionConfigs.test.tsx @@ -28,10 +28,10 @@ describe('getExploreExtensionConfigs', () => { }); describe('configure function for "add to dashboard" extension', () => { - afterEach(() => contextSrvMock.hasAccess.mockRestore()); + afterEach(() => contextSrvMock.hasPermission.mockRestore()); it('should return undefined if insufficient permissions', () => { - contextSrvMock.hasAccess.mockReturnValue(false); + contextSrvMock.hasPermission.mockReturnValue(false); const extensions = getExploreExtensionConfigs(); const [extension] = extensions; @@ -40,7 +40,7 @@ describe('getExploreExtensionConfigs', () => { }); it('should return empty object if sufficient permissions', () => { - contextSrvMock.hasAccess.mockReturnValue(true); + contextSrvMock.hasPermission.mockReturnValue(true); const extensions = getExploreExtensionConfigs(); const [extension] = extensions; diff --git a/public/app/features/explore/extensions/getExploreExtensionConfigs.tsx b/public/app/features/explore/extensions/getExploreExtensionConfigs.tsx index 7f95f4e714f..8be3ec9d955 100644 --- a/public/app/features/explore/extensions/getExploreExtensionConfigs.tsx +++ b/public/app/features/explore/extensions/getExploreExtensionConfigs.tsx @@ -21,8 +21,8 @@ export function getExploreExtensionConfigs(): PluginExtensionLinkConfig[] { category: 'Dashboards', configure: () => { const canAddPanelToDashboard = - contextSrv.hasAccess(AccessControlAction.DashboardsCreate, contextSrv.isEditor) || - contextSrv.hasAccess(AccessControlAction.DashboardsWrite, contextSrv.isEditor); + contextSrv.hasPermission(AccessControlAction.DashboardsCreate) || + contextSrv.hasPermission(AccessControlAction.DashboardsWrite); // hide option if user has insufficient permissions if (!canAddPanelToDashboard) { diff --git a/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.test.tsx b/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.test.tsx index 8506a4b8753..0b1337781cb 100644 --- a/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.test.tsx +++ b/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.test.tsx @@ -128,7 +128,7 @@ describe('Show table', () => { expect(screen.queryAllByRole('listitem')).toHaveLength(0); }); it('renders public dashboards in a good way without trashcan', async () => { - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(false); + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false); await renderPublicDashboardTable(true); publicDashboardListResponse.forEach((pd, idx) => { @@ -136,7 +136,7 @@ describe('Show table', () => { }); }); it('renders public dashboards in a good way with trashcan', async () => { - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(true); + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true); await renderPublicDashboardTable(true); publicDashboardListResponse.forEach((pd, idx) => { @@ -147,13 +147,13 @@ describe('Show table', () => { describe('Delete public dashboard', () => { it('when user does not have public dashboard write permissions, then dashboards are listed without delete button', async () => { - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(false); + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false); await renderPublicDashboardTable(true); expect(screen.queryAllByTestId(selectors.ListItem.trashcanButton)).toHaveLength(0); }); it('when user has public dashboard write permissions, then dashboards are listed with delete button', async () => { - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(true); + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true); await renderPublicDashboardTable(true); expect(screen.getAllByTestId(selectors.ListItem.trashcanButton)).toHaveLength(publicDashboardListResponse.length); @@ -171,7 +171,7 @@ describe('Orphaned public dashboard', () => { return res(ctx.status(200), ctx.json(response)); }) ); - jest.spyOn(contextSrv, 'hasAccess').mockReturnValue(true); + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true); await renderPublicDashboardTable(true); response.publicDashboards.forEach((pd, idx) => { diff --git a/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.tsx b/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.tsx index eb9184b868a..0129b64e244 100644 --- a/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.tsx +++ b/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.tsx @@ -27,7 +27,6 @@ import { generatePublicDashboardConfigUrl, generatePublicDashboardUrl, } from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils'; -import { isOrgAdmin } from 'app/features/plugins/admin/permissions'; import { AccessControlAction } from 'app/types'; import { PublicDashboardListResponse } from '../../types'; @@ -42,7 +41,7 @@ const PublicDashboardCard = ({ pd }: { pd: PublicDashboardListResponse }) => { const [update, { isLoading: isUpdateLoading }] = useUpdatePublicDashboardMutation(); const selectors = e2eSelectors.pages.PublicDashboards; - const hasWritePermissions = contextSrv.hasAccess(AccessControlAction.DashboardsPublicWrite, isOrgAdmin()); + const hasWritePermissions = contextSrv.hasPermission(AccessControlAction.DashboardsPublicWrite); const isOrphaned = !pd.dashboardUid; const onTogglePause = (pd: PublicDashboardListResponse, isPaused: boolean) => { diff --git a/public/app/features/plugins/admin/components/InstallControls/InstallControlsWarning.tsx b/public/app/features/plugins/admin/components/InstallControls/InstallControlsWarning.tsx index 7a2f86c1386..278950fedac 100644 --- a/public/app/features/plugins/admin/components/InstallControls/InstallControlsWarning.tsx +++ b/public/app/features/plugins/admin/components/InstallControls/InstallControlsWarning.tsx @@ -8,7 +8,6 @@ import { contextSrv } from 'app/core/core'; import { AccessControlAction } from 'app/types'; import { getExternalManageLink } from '../../helpers'; -import { isGrafanaAdmin } from '../../permissions'; import { useIsRemotePluginsAvailable } from '../../state/hooks'; import { CatalogPlugin, PluginStatus, Version } from '../../types'; @@ -21,7 +20,7 @@ interface Props { export const InstallControlsWarning = ({ plugin, pluginStatus, latestCompatibleVersion }: Props) => { const styles = useStyles2(getStyles); const isExternallyManaged = config.pluginAdminExternalManageEnabled; - const hasPermission = contextSrv.hasAccess(AccessControlAction.PluginsInstall, isGrafanaAdmin()); + const hasPermission = contextSrv.hasPermission(AccessControlAction.PluginsInstall); const isRemotePluginsAvailable = useIsRemotePluginsAvailable(); const isCompatible = Boolean(latestCompatibleVersion); diff --git a/public/app/features/plugins/admin/helpers.ts b/public/app/features/plugins/admin/helpers.ts index 2aef24cb1e7..084440256a1 100644 --- a/public/app/features/plugins/admin/helpers.ts +++ b/public/app/features/plugins/admin/helpers.ts @@ -5,7 +5,6 @@ import { contextSrv } from 'app/core/core'; import { getBackendSrv } from 'app/core/services/backend_srv'; import { AccessControlAction } from 'app/types'; -import { isGrafanaAdmin } from './permissions'; import { CatalogPlugin, LocalPlugin, RemotePlugin, Version } from './types'; export function mergeLocalsAndRemotes( @@ -283,7 +282,7 @@ export const hasInstallControlWarning = ( latestCompatibleVersion?: Version ) => { const isExternallyManaged = config.pluginAdminExternalManageEnabled; - const hasPermission = contextSrv.hasAccess(AccessControlAction.PluginsInstall, isGrafanaAdmin()); + const hasPermission = contextSrv.hasPermission(AccessControlAction.PluginsInstall); const isCompatible = Boolean(latestCompatibleVersion); return ( plugin.type === PluginType.renderer || diff --git a/public/app/features/plugins/admin/pages/PluginDetails.test.tsx b/public/app/features/plugins/admin/pages/PluginDetails.test.tsx index ba4a8774fd5..c447f626359 100644 --- a/public/app/features/plugins/admin/pages/PluginDetails.test.tsx +++ b/public/app/features/plugins/admin/pages/PluginDetails.test.tsx @@ -53,6 +53,7 @@ jest.mock('../helpers.ts', () => ({ jest.mock('app/core/core', () => ({ contextSrv: { hasAccess: (action: string, fallBack: boolean) => true, + hasPermission: (action: string) => true, hasAccessInMetadata: (action: string, object: WithAccessControlMetadata, fallBack: boolean) => true, }, })); diff --git a/public/app/features/search/components/ManageDashboards.test.tsx b/public/app/features/search/components/ManageDashboards.test.tsx index efc97f732e5..52a062dd6b5 100644 --- a/public/app/features/search/components/ManageDashboards.test.tsx +++ b/public/app/features/search/components/ManageDashboards.test.tsx @@ -15,6 +15,7 @@ jest.mock('app/core/services/context_srv', () => { ...originMock.context_srv, user: {}, hasAccess: jest.fn(() => false), + hasPermission: jest.fn(() => false), }, }; }); @@ -32,16 +33,19 @@ jest.spyOn(console, 'error').mockImplementation(); describe('ManageDashboards', () => { beforeEach(() => { (contextSrv.hasAccess as jest.Mock).mockClear(); + (contextSrv.hasPermission as jest.Mock).mockClear(); }); it("should hide and show dashboard actions based on user's permissions", async () => { (contextSrv.hasAccess as jest.Mock).mockReturnValue(false); + (contextSrv.hasPermission as jest.Mock).mockReturnValue(false); const { rerender } = await setup(); expect(screen.queryByRole('button', { name: /new/i })).not.toBeInTheDocument(); (contextSrv.hasAccess as jest.Mock).mockReturnValue(true); + (contextSrv.hasPermission as jest.Mock).mockReturnValue(true); await waitFor(() => rerender()); expect(screen.getByRole('button', { name: /new/i })).toBeInTheDocument(); diff --git a/public/app/features/search/components/ManageDashboardsNew.tsx b/public/app/features/search/components/ManageDashboardsNew.tsx index a2065e5c953..3f9363be520 100644 --- a/public/app/features/search/components/ManageDashboardsNew.tsx +++ b/public/app/features/search/components/ManageDashboardsNew.tsx @@ -30,11 +30,11 @@ export const ManageDashboardsNew = React.memo(({ folder }: Props) => { const canSave = folder?.canSave; const { isEditor } = contextSrv; const hasEditPermissionInFolders = folder ? canSave : contextSrv.hasEditPermissionInFolders; - const canCreateFolders = contextSrv.hasAccess(AccessControlAction.FoldersCreate, isEditor); + const canCreateFolders = contextSrv.hasPermission(AccessControlAction.FoldersCreate); const canCreateDashboardsFallback = hasEditPermissionInFolders || !!canSave; const canCreateDashboards = folderUid ? contextSrv.hasAccessInMetadata(AccessControlAction.DashboardsCreate, folder, canCreateDashboardsFallback) - : contextSrv.hasAccess(AccessControlAction.DashboardsCreate, canCreateDashboardsFallback); + : contextSrv.hasPermission(AccessControlAction.DashboardsCreate); const viewActions = (folder === undefined && canCreateFolders) || canCreateDashboards; useEffect(() => stateManager.initStateFromUrl(folder?.uid), [folder?.uid, stateManager]); diff --git a/public/app/features/support-bundles/SupportBundles.tsx b/public/app/features/support-bundles/SupportBundles.tsx index a3e2d4a62ab..989b8d4119d 100644 --- a/public/app/features/support-bundles/SupportBundles.tsx +++ b/public/app/features/support-bundles/SupportBundles.tsx @@ -52,11 +52,8 @@ const SupportBundlesUnconnected = ({ supportBundles, isLoading, loadBundles, rem } }); - const hasAccess = contextSrv.hasAccess(AccessControlAction.ActionSupportBundlesCreate, contextSrv.isGrafanaAdmin); - const hasDeleteAccess = contextSrv.hasAccess( - AccessControlAction.ActionSupportBundlesDelete, - contextSrv.isGrafanaAdmin - ); + const hasAccess = contextSrv.hasPermission(AccessControlAction.ActionSupportBundlesCreate); + const hasDeleteAccess = contextSrv.hasPermission(AccessControlAction.ActionSupportBundlesDelete); const actions = hasAccess ? NewBundleButton : undefined; diff --git a/public/app/features/teams/TeamList.test.tsx b/public/app/features/teams/TeamList.test.tsx index 85d1636e367..5d8e45066e4 100644 --- a/public/app/features/teams/TeamList.test.tsx +++ b/public/app/features/teams/TeamList.test.tsx @@ -10,9 +10,11 @@ import { OrgRole, Team } from '../../types'; import { Props, TeamList } from './TeamList'; import { getMockTeam, getMultipleMockTeams } from './__mocks__/teamMocks'; -jest.mock('app/core/config', () => ({ - ...jest.requireActual('app/core/config'), - featureToggles: { accesscontrol: false }, +jest.mock('app/core/core', () => ({ + contextSrv: { + hasPermission: (action: string) => true, + licensedAccessControlEnabled: () => false, + }, })); const setup = (propOverrides?: object) => { @@ -51,39 +53,39 @@ describe('TeamList', () => { expect(screen.getAllByRole('row')).toHaveLength(6); // 5 teams plus table header row }); - describe('when feature toggle editorsCanAdmin is turned on', () => { - describe('and signed in user is not viewer', () => { - it('should enable the new team button', () => { - setup({ - teams: getMultipleMockTeams(1), - totalCount: 1, - hasFetched: true, - editorsCanAdmin: true, - signedInUser: { - id: 1, - orgRole: OrgRole.Editor, - } as User, - }); - - expect(screen.getByRole('link', { name: /new team/i })).not.toHaveStyle('pointer-events: none'); + describe('when user has access to create a team', () => { + it('should enable the new team button', () => { + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true); + setup({ + teams: getMultipleMockTeams(1), + totalCount: 1, + hasFetched: true, + editorsCanAdmin: true, + signedInUser: { + id: 1, + orgRole: OrgRole.Editor, + } as User, }); + + expect(screen.getByRole('link', { name: /new team/i })).not.toHaveStyle('pointer-events: none'); }); + }); - describe('and signed in user is a viewer', () => { - it('should disable the new team button', () => { - setup({ - teams: getMultipleMockTeams(1), - totalCount: 1, - hasFetched: true, - editorsCanAdmin: true, - signedInUser: { - id: 1, - orgRole: OrgRole.Viewer, - } as User, - }); - - expect(screen.getByRole('link', { name: /new team/i })).toHaveStyle('pointer-events: none'); + describe('when user does not have access to create a team', () => { + it('should disable the new team button', () => { + jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false); + setup({ + teams: getMultipleMockTeams(1), + totalCount: 1, + hasFetched: true, + editorsCanAdmin: true, + signedInUser: { + id: 1, + orgRole: OrgRole.Viewer, + } as User, }); + + expect(screen.getByRole('link', { name: /new team/i })).toHaveStyle('pointer-events: none'); }); }); }); @@ -91,6 +93,7 @@ describe('TeamList', () => { it('should call delete team', async () => { const mockDelete = jest.fn(); const mockTeam = getMockTeam(); + jest.spyOn(contextSrv, 'hasAccessInMetadata').mockReturnValue(true); setup({ deleteTeam: mockDelete, teams: [mockTeam], totalCount: 1, hasFetched: true }); await userEvent.click(screen.getByRole('button', { name: `Delete team ${mockTeam.name}` })); await userEvent.click(screen.getByRole('button', { name: 'Delete' })); diff --git a/public/app/features/teams/TeamList.tsx b/public/app/features/teams/TeamList.tsx index d52f9728bfe..4957ed429f3 100644 --- a/public/app/features/teams/TeamList.tsx +++ b/public/app/features/teams/TeamList.tsx @@ -60,7 +60,7 @@ export const TeamList = ({ } }, []); - const canCreate = canCreateTeam(editorsCanAdmin); + const canCreate = contextSrv.hasPermission(AccessControlAction.ActionTeamsCreate); const displayRolePicker = shouldDisplayRolePicker(); return ( @@ -137,11 +137,6 @@ export const TeamList = ({ ); }; -function canCreateTeam(editorsCanAdmin: boolean): boolean { - const teamAdmin = contextSrv.hasRole('Admin') || (editorsCanAdmin && contextSrv.hasRole('Editor')); - return contextSrv.hasAccess(AccessControlAction.ActionTeamsCreate, teamAdmin); -} - function shouldDisplayRolePicker(): boolean { return ( contextSrv.licensedAccessControlEnabled() &&