mirror of
https://github.com/grafana/grafana.git
synced 2024-11-29 12:14:08 -06:00
Browse Dashboards: Use correct permissions checks (#74811)
* use correct permissions checks + update unit tests * fix rest of the unit tests
This commit is contained in:
parent
5e9f252962
commit
8874a8d398
@ -99,6 +99,14 @@ jest.mock('app/features/browse-dashboards/api/services', () => {
|
|||||||
describe('browse-dashboards BrowseDashboardsPage', () => {
|
describe('browse-dashboards BrowseDashboardsPage', () => {
|
||||||
let props: Props;
|
let props: Props;
|
||||||
let server: SetupServer;
|
let server: SetupServer;
|
||||||
|
const mockPermissions = {
|
||||||
|
canCreateDashboards: true,
|
||||||
|
canCreateFolder: true,
|
||||||
|
canDeleteFolder: true,
|
||||||
|
canEditFolder: true,
|
||||||
|
canViewPermissions: true,
|
||||||
|
canSetPermissions: true,
|
||||||
|
};
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
server = setupServer(
|
server = setupServer(
|
||||||
@ -135,13 +143,7 @@ describe('browse-dashboards BrowseDashboardsPage', () => {
|
|||||||
...getRouteComponentProps(),
|
...getRouteComponentProps(),
|
||||||
};
|
};
|
||||||
|
|
||||||
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => mockPermissions);
|
||||||
return {
|
|
||||||
canEditInFolder: true,
|
|
||||||
canCreateDashboards: true,
|
|
||||||
canCreateFolder: true,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true);
|
jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -169,7 +171,7 @@ describe('browse-dashboards BrowseDashboardsPage', () => {
|
|||||||
it('does not show the "New" button if the user does not have permissions', async () => {
|
it('does not show the "New" button if the user does not have permissions', async () => {
|
||||||
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
canEditInFolder: false,
|
...mockPermissions,
|
||||||
canCreateDashboards: false,
|
canCreateDashboards: false,
|
||||||
canCreateFolder: false,
|
canCreateFolder: false,
|
||||||
};
|
};
|
||||||
@ -273,7 +275,7 @@ describe('browse-dashboards BrowseDashboardsPage', () => {
|
|||||||
it('does not show the "New" button if the user does not have permissions', async () => {
|
it('does not show the "New" button if the user does not have permissions', async () => {
|
||||||
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
canEditInFolder: false,
|
...mockPermissions,
|
||||||
canCreateDashboards: false,
|
canCreateDashboards: false,
|
||||||
canCreateFolder: false,
|
canCreateFolder: false,
|
||||||
};
|
};
|
||||||
@ -289,7 +291,15 @@ describe('browse-dashboards BrowseDashboardsPage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not show the "Folder actions" button if the user does not have permissions', async () => {
|
it('does not show the "Folder actions" button if the user does not have permissions', async () => {
|
||||||
jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false);
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
...mockPermissions,
|
||||||
|
canDeleteFolder: false,
|
||||||
|
canEditFolder: false,
|
||||||
|
canSetPermissions: false,
|
||||||
|
canViewPermissions: false,
|
||||||
|
};
|
||||||
|
});
|
||||||
render(<BrowseDashboardsPage {...props} />);
|
render(<BrowseDashboardsPage {...props} />);
|
||||||
expect(await screen.findByRole('heading', { name: folderA.item.title })).toBeInTheDocument();
|
expect(await screen.findByRole('heading', { name: folderA.item.title })).toBeInTheDocument();
|
||||||
expect(screen.queryByRole('button', { name: 'Folder actions' })).not.toBeInTheDocument();
|
expect(screen.queryByRole('button', { name: 'Folder actions' })).not.toBeInTheDocument();
|
||||||
@ -303,9 +313,8 @@ describe('browse-dashboards BrowseDashboardsPage', () => {
|
|||||||
it('does not show the "Edit title" button if the user does not have permissions', async () => {
|
it('does not show the "Edit title" button if the user does not have permissions', async () => {
|
||||||
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
canEditInFolder: false,
|
...mockPermissions,
|
||||||
canCreateDashboards: false,
|
canEditFolder: false,
|
||||||
canCreateFolder: false,
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
render(<BrowseDashboardsPage {...props} />);
|
render(<BrowseDashboardsPage {...props} />);
|
||||||
|
@ -78,9 +78,9 @@ const BrowseDashboardsPage = memo(({ match }: Props) => {
|
|||||||
|
|
||||||
const hasSelection = useHasSelection();
|
const hasSelection = useHasSelection();
|
||||||
|
|
||||||
const { canEditInFolder, canCreateDashboards, canCreateFolder } = getFolderPermissions(folderDTO);
|
const { canEditFolder, canCreateDashboards, canCreateFolder } = getFolderPermissions(folderDTO);
|
||||||
|
|
||||||
const showEditTitle = canEditInFolder && folderUID;
|
const showEditTitle = canEditFolder && folderUID;
|
||||||
const onEditTitle = async (newValue: string) => {
|
const onEditTitle = async (newValue: string) => {
|
||||||
if (folderDTO) {
|
if (folderDTO) {
|
||||||
const result = await saveFolder({
|
const result = await saveFolder({
|
||||||
@ -125,9 +125,9 @@ const BrowseDashboardsPage = memo(({ match }: Props) => {
|
|||||||
<AutoSizer>
|
<AutoSizer>
|
||||||
{({ width, height }) =>
|
{({ width, height }) =>
|
||||||
isSearching ? (
|
isSearching ? (
|
||||||
<SearchView canSelect={canEditInFolder} width={width} height={height} />
|
<SearchView canSelect={canEditFolder} width={width} height={height} />
|
||||||
) : (
|
) : (
|
||||||
<BrowseView canSelect={canEditInFolder} width={width} height={height} folderUID={folderUID} />
|
<BrowseView canSelect={canEditFolder} width={width} height={height} folderUID={folderUID} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</AutoSizer>
|
</AutoSizer>
|
||||||
|
@ -11,6 +11,7 @@ import { backendSrv } from 'app/core/services/backend_srv';
|
|||||||
|
|
||||||
import BrowseFolderAlertingPage, { OwnProps } from './BrowseFolderAlertingPage';
|
import BrowseFolderAlertingPage, { OwnProps } from './BrowseFolderAlertingPage';
|
||||||
import { getPrometheusRulesResponse, getRulerRulesResponse } from './fixtures/alertRules.fixture';
|
import { getPrometheusRulesResponse, getRulerRulesResponse } from './fixtures/alertRules.fixture';
|
||||||
|
import * as permissions from './permissions';
|
||||||
|
|
||||||
function render(...[ui, options]: Parameters<typeof rtlRender>) {
|
function render(...[ui, options]: Parameters<typeof rtlRender>) {
|
||||||
rtlRender(<TestProvider>{ui}</TestProvider>, options);
|
rtlRender(<TestProvider>{ui}</TestProvider>, options);
|
||||||
@ -34,6 +35,14 @@ const mockPrometheusRulesResponse = getPrometheusRulesResponse(mockFolderName);
|
|||||||
describe('browse-dashboards BrowseFolderAlertingPage', () => {
|
describe('browse-dashboards BrowseFolderAlertingPage', () => {
|
||||||
let props: OwnProps;
|
let props: OwnProps;
|
||||||
let server: SetupServer;
|
let server: SetupServer;
|
||||||
|
const mockPermissions = {
|
||||||
|
canCreateDashboards: true,
|
||||||
|
canCreateFolder: true,
|
||||||
|
canDeleteFolder: true,
|
||||||
|
canEditFolder: true,
|
||||||
|
canViewPermissions: true,
|
||||||
|
canSetPermissions: true,
|
||||||
|
};
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
server = setupServer(
|
server = setupServer(
|
||||||
@ -61,6 +70,7 @@ describe('browse-dashboards BrowseFolderAlertingPage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => mockPermissions);
|
||||||
jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true);
|
jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true);
|
||||||
props = {
|
props = {
|
||||||
...getRouteComponentProps({
|
...getRouteComponentProps({
|
||||||
@ -92,7 +102,15 @@ describe('browse-dashboards BrowseFolderAlertingPage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not display the "Folder actions" button if the user does not have permissions', async () => {
|
it('does not display the "Folder actions" button if the user does not have permissions', async () => {
|
||||||
jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false);
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
...mockPermissions,
|
||||||
|
canDeleteFolder: false,
|
||||||
|
canEditFolder: false,
|
||||||
|
canViewPermissions: false,
|
||||||
|
canSetPermissions: false,
|
||||||
|
};
|
||||||
|
});
|
||||||
render(<BrowseFolderAlertingPage {...props} />);
|
render(<BrowseFolderAlertingPage {...props} />);
|
||||||
expect(await screen.findByRole('heading', { name: mockFolderName })).toBeInTheDocument();
|
expect(await screen.findByRole('heading', { name: mockFolderName })).toBeInTheDocument();
|
||||||
expect(screen.queryByRole('button', { name: 'Folder actions' })).not.toBeInTheDocument();
|
expect(screen.queryByRole('button', { name: 'Folder actions' })).not.toBeInTheDocument();
|
||||||
|
@ -11,6 +11,7 @@ import { backendSrv } from 'app/core/services/backend_srv';
|
|||||||
|
|
||||||
import BrowseFolderLibraryPanelsPage, { OwnProps } from './BrowseFolderLibraryPanelsPage';
|
import BrowseFolderLibraryPanelsPage, { OwnProps } from './BrowseFolderLibraryPanelsPage';
|
||||||
import { getLibraryElementsResponse } from './fixtures/libraryElements.fixture';
|
import { getLibraryElementsResponse } from './fixtures/libraryElements.fixture';
|
||||||
|
import * as permissions from './permissions';
|
||||||
|
|
||||||
function render(...[ui, options]: Parameters<typeof rtlRender>) {
|
function render(...[ui, options]: Parameters<typeof rtlRender>) {
|
||||||
rtlRender(<TestProvider>{ui}</TestProvider>, options);
|
rtlRender(<TestProvider>{ui}</TestProvider>, options);
|
||||||
@ -34,6 +35,14 @@ const mockLibraryElementsResponse = getLibraryElementsResponse(1, {
|
|||||||
describe('browse-dashboards BrowseFolderLibraryPanelsPage', () => {
|
describe('browse-dashboards BrowseFolderLibraryPanelsPage', () => {
|
||||||
let props: OwnProps;
|
let props: OwnProps;
|
||||||
let server: SetupServer;
|
let server: SetupServer;
|
||||||
|
const mockPermissions = {
|
||||||
|
canCreateDashboards: true,
|
||||||
|
canCreateFolder: true,
|
||||||
|
canDeleteFolder: true,
|
||||||
|
canEditFolder: true,
|
||||||
|
canViewPermissions: true,
|
||||||
|
canSetPermissions: true,
|
||||||
|
};
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
server = setupServer(
|
server = setupServer(
|
||||||
@ -66,6 +75,7 @@ describe('browse-dashboards BrowseFolderLibraryPanelsPage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => mockPermissions);
|
||||||
jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true);
|
jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true);
|
||||||
props = {
|
props = {
|
||||||
...getRouteComponentProps({
|
...getRouteComponentProps({
|
||||||
@ -97,7 +107,15 @@ describe('browse-dashboards BrowseFolderLibraryPanelsPage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not display the "Folder actions" button if the user does not have permissions', async () => {
|
it('does not display the "Folder actions" button if the user does not have permissions', async () => {
|
||||||
jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false);
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
...mockPermissions,
|
||||||
|
canDeleteFolder: false,
|
||||||
|
canEditFolder: false,
|
||||||
|
canViewPermissions: false,
|
||||||
|
canSetPermissions: false,
|
||||||
|
};
|
||||||
|
});
|
||||||
render(<BrowseFolderLibraryPanelsPage {...props} />);
|
render(<BrowseFolderLibraryPanelsPage {...props} />);
|
||||||
expect(await screen.findByRole('heading', { name: mockFolderName })).toBeInTheDocument();
|
expect(await screen.findByRole('heading', { name: mockFolderName })).toBeInTheDocument();
|
||||||
expect(screen.queryByRole('button', { name: 'Folder actions' })).not.toBeInTheDocument();
|
expect(screen.queryByRole('button', { name: 'Folder actions' })).not.toBeInTheDocument();
|
||||||
|
@ -4,11 +4,11 @@ import React from 'react';
|
|||||||
import { TestProvider } from 'test/helpers/TestProvider';
|
import { TestProvider } from 'test/helpers/TestProvider';
|
||||||
|
|
||||||
import { config } from '@grafana/runtime';
|
import { config } from '@grafana/runtime';
|
||||||
import { appEvents, contextSrv } from 'app/core/core';
|
import { appEvents } from 'app/core/core';
|
||||||
import { AccessControlAction } from 'app/types';
|
|
||||||
import { ShowModalReactEvent } from 'app/types/events';
|
import { ShowModalReactEvent } from 'app/types/events';
|
||||||
|
|
||||||
import { mockFolderDTO } from '../fixtures/folder.fixture';
|
import { mockFolderDTO } from '../fixtures/folder.fixture';
|
||||||
|
import * as permissions from '../permissions';
|
||||||
|
|
||||||
import { DeleteModal } from './BrowseActions/DeleteModal';
|
import { DeleteModal } from './BrowseActions/DeleteModal';
|
||||||
import { MoveModal } from './BrowseActions/MoveModal';
|
import { MoveModal } from './BrowseActions/MoveModal';
|
||||||
@ -25,9 +25,17 @@ jest.mock('app/core/components/AccessControl', () => ({
|
|||||||
|
|
||||||
describe('browse-dashboards FolderActionsButton', () => {
|
describe('browse-dashboards FolderActionsButton', () => {
|
||||||
const mockFolder = mockFolderDTO();
|
const mockFolder = mockFolderDTO();
|
||||||
|
const mockPermissions = {
|
||||||
|
canCreateDashboards: true,
|
||||||
|
canCreateFolder: true,
|
||||||
|
canDeleteFolder: true,
|
||||||
|
canEditFolder: true,
|
||||||
|
canViewPermissions: true,
|
||||||
|
canSetPermissions: true,
|
||||||
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true);
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => mockPermissions);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@ -44,7 +52,15 @@ describe('browse-dashboards FolderActionsButton', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not render anything when the user has no permissions to do anything', () => {
|
it('does not render anything when the user has no permissions to do anything', () => {
|
||||||
jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false);
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
...mockPermissions,
|
||||||
|
canDeleteFolder: false,
|
||||||
|
canEditFolder: false,
|
||||||
|
canViewPermissions: false,
|
||||||
|
canSetPermissions: false,
|
||||||
|
};
|
||||||
|
});
|
||||||
render(<FolderActionsButton folder={mockFolder} />);
|
render(<FolderActionsButton folder={mockFolder} />);
|
||||||
expect(screen.queryByRole('button', { name: 'Folder actions' })).not.toBeInTheDocument();
|
expect(screen.queryByRole('button', { name: 'Folder actions' })).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
@ -64,9 +80,12 @@ describe('browse-dashboards FolderActionsButton', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not render the "Manage permissions" option if the user does not have permission to view permissions', async () => {
|
it('does not render the "Manage permissions" option if the user does not have permission to view permissions', async () => {
|
||||||
jest
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
||||||
.spyOn(contextSrv, 'hasPermission')
|
return {
|
||||||
.mockImplementation((permission: string) => permission !== AccessControlAction.FoldersPermissionsRead);
|
...mockPermissions,
|
||||||
|
canViewPermissions: false,
|
||||||
|
};
|
||||||
|
});
|
||||||
render(<FolderActionsButton folder={mockFolder} />);
|
render(<FolderActionsButton folder={mockFolder} />);
|
||||||
|
|
||||||
await userEvent.click(screen.getByRole('button', { name: 'Folder actions' }));
|
await userEvent.click(screen.getByRole('button', { name: 'Folder actions' }));
|
||||||
@ -76,9 +95,12 @@ describe('browse-dashboards FolderActionsButton', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not render the "Move" option if the user does not have permission to edit', async () => {
|
it('does not render the "Move" option if the user does not have permission to edit', async () => {
|
||||||
jest
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
||||||
.spyOn(contextSrv, 'hasPermission')
|
return {
|
||||||
.mockImplementation((permission: string) => permission !== AccessControlAction.FoldersWrite);
|
...mockPermissions,
|
||||||
|
canEditFolder: false,
|
||||||
|
};
|
||||||
|
});
|
||||||
render(<FolderActionsButton folder={mockFolder} />);
|
render(<FolderActionsButton folder={mockFolder} />);
|
||||||
|
|
||||||
await userEvent.click(screen.getByRole('button', { name: 'Folder actions' }));
|
await userEvent.click(screen.getByRole('button', { name: 'Folder actions' }));
|
||||||
@ -88,9 +110,12 @@ describe('browse-dashboards FolderActionsButton', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not render the "Delete" option if the user does not have permission to delete', async () => {
|
it('does not render the "Delete" option if the user does not have permission to delete', async () => {
|
||||||
jest
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
||||||
.spyOn(contextSrv, 'hasPermission')
|
return {
|
||||||
.mockImplementation((permission: string) => permission !== AccessControlAction.FoldersDelete);
|
...mockPermissions,
|
||||||
|
canDeleteFolder: false,
|
||||||
|
};
|
||||||
|
});
|
||||||
render(<FolderActionsButton folder={mockFolder} />);
|
render(<FolderActionsButton folder={mockFolder} />);
|
||||||
|
|
||||||
await userEvent.click(screen.getByRole('button', { name: 'Folder actions' }));
|
await userEvent.click(screen.getByRole('button', { name: 'Folder actions' }));
|
||||||
@ -140,7 +165,15 @@ describe('browse-dashboards FolderActionsButton', () => {
|
|||||||
|
|
||||||
describe('with nestedFolders disabled', () => {
|
describe('with nestedFolders disabled', () => {
|
||||||
it('does not render anything when the user has no permissions to do anything', () => {
|
it('does not render anything when the user has no permissions to do anything', () => {
|
||||||
jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false);
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
||||||
|
return {
|
||||||
|
...mockPermissions,
|
||||||
|
canDeleteFolder: false,
|
||||||
|
canEditFolder: false,
|
||||||
|
canViewPermissions: false,
|
||||||
|
canSetPermissions: false,
|
||||||
|
};
|
||||||
|
});
|
||||||
render(<FolderActionsButton folder={mockFolder} />);
|
render(<FolderActionsButton folder={mockFolder} />);
|
||||||
expect(screen.queryByRole('button', { name: 'Folder actions' })).not.toBeInTheDocument();
|
expect(screen.queryByRole('button', { name: 'Folder actions' })).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
@ -166,9 +199,12 @@ describe('browse-dashboards FolderActionsButton', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not render the "Manage permissions" option if the user does not have permission to view permissions', async () => {
|
it('does not render the "Manage permissions" option if the user does not have permission to view permissions', async () => {
|
||||||
jest
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
||||||
.spyOn(contextSrv, 'hasPermission')
|
return {
|
||||||
.mockImplementation((permission: string) => permission !== AccessControlAction.FoldersPermissionsRead);
|
...mockPermissions,
|
||||||
|
canViewPermissions: false,
|
||||||
|
};
|
||||||
|
});
|
||||||
render(<FolderActionsButton folder={mockFolder} />);
|
render(<FolderActionsButton folder={mockFolder} />);
|
||||||
|
|
||||||
await userEvent.click(screen.getByRole('button', { name: 'Folder actions' }));
|
await userEvent.click(screen.getByRole('button', { name: 'Folder actions' }));
|
||||||
@ -177,9 +213,12 @@ describe('browse-dashboards FolderActionsButton', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not render the "Move" option if the user does not have permission to edit', async () => {
|
it('does not render the "Move" option if the user does not have permission to edit', async () => {
|
||||||
jest
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
||||||
.spyOn(contextSrv, 'hasPermission')
|
return {
|
||||||
.mockImplementation((permission: string) => permission !== AccessControlAction.FoldersWrite);
|
...mockPermissions,
|
||||||
|
canEditFolder: false,
|
||||||
|
};
|
||||||
|
});
|
||||||
render(<FolderActionsButton folder={mockFolder} />);
|
render(<FolderActionsButton folder={mockFolder} />);
|
||||||
|
|
||||||
await userEvent.click(screen.getByRole('button', { name: 'Folder actions' }));
|
await userEvent.click(screen.getByRole('button', { name: 'Folder actions' }));
|
||||||
@ -188,9 +227,12 @@ describe('browse-dashboards FolderActionsButton', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not render the "Delete" option if the user does not have permission to delete', async () => {
|
it('does not render the "Delete" option if the user does not have permission to delete', async () => {
|
||||||
jest
|
jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => {
|
||||||
.spyOn(contextSrv, 'hasPermission')
|
return {
|
||||||
.mockImplementation((permission: string) => permission !== AccessControlAction.FoldersDelete);
|
...mockPermissions,
|
||||||
|
canDeleteFolder: false,
|
||||||
|
};
|
||||||
|
});
|
||||||
render(<FolderActionsButton folder={mockFolder} />);
|
render(<FolderActionsButton folder={mockFolder} />);
|
||||||
|
|
||||||
await userEvent.click(screen.getByRole('button', { name: 'Folder actions' }));
|
await userEvent.click(screen.getByRole('button', { name: 'Folder actions' }));
|
||||||
|
@ -3,12 +3,13 @@ import React, { useState } from 'react';
|
|||||||
import { config, locationService, reportInteraction } from '@grafana/runtime';
|
import { config, locationService, reportInteraction } from '@grafana/runtime';
|
||||||
import { Button, Drawer, Dropdown, Icon, Menu, MenuItem } from '@grafana/ui';
|
import { Button, Drawer, Dropdown, Icon, Menu, MenuItem } from '@grafana/ui';
|
||||||
import { Permissions } from 'app/core/components/AccessControl';
|
import { Permissions } from 'app/core/components/AccessControl';
|
||||||
import { appEvents, contextSrv } from 'app/core/core';
|
import { appEvents } from 'app/core/core';
|
||||||
import { t, Trans } from 'app/core/internationalization';
|
import { t, Trans } from 'app/core/internationalization';
|
||||||
import { AccessControlAction, FolderDTO } from 'app/types';
|
import { FolderDTO } from 'app/types';
|
||||||
import { ShowModalReactEvent } from 'app/types/events';
|
import { ShowModalReactEvent } from 'app/types/events';
|
||||||
|
|
||||||
import { useDeleteFolderMutation, useMoveFolderMutation } from '../api/browseDashboardsAPI';
|
import { useDeleteFolderMutation, useMoveFolderMutation } from '../api/browseDashboardsAPI';
|
||||||
|
import { getFolderPermissions } from '../permissions';
|
||||||
|
|
||||||
import { DeleteModal } from './BrowseActions/DeleteModal';
|
import { DeleteModal } from './BrowseActions/DeleteModal';
|
||||||
import { MoveModal } from './BrowseActions/MoveModal';
|
import { MoveModal } from './BrowseActions/MoveModal';
|
||||||
@ -22,12 +23,9 @@ export function FolderActionsButton({ folder }: Props) {
|
|||||||
const [showPermissionsDrawer, setShowPermissionsDrawer] = useState(false);
|
const [showPermissionsDrawer, setShowPermissionsDrawer] = useState(false);
|
||||||
const [moveFolder] = useMoveFolderMutation();
|
const [moveFolder] = useMoveFolderMutation();
|
||||||
const [deleteFolder] = useDeleteFolderMutation();
|
const [deleteFolder] = useDeleteFolderMutation();
|
||||||
const canViewPermissions = contextSrv.hasPermission(AccessControlAction.FoldersPermissionsRead);
|
const { canEditFolder, canDeleteFolder, canViewPermissions, canSetPermissions } = getFolderPermissions(folder);
|
||||||
const canSetPermissions = contextSrv.hasPermission(AccessControlAction.FoldersPermissionsWrite);
|
|
||||||
// Can only move folders when nestedFolders is enabled
|
// Can only move folders when nestedFolders is enabled
|
||||||
const canMoveFolder =
|
const canMoveFolder = config.featureToggles.nestedFolders && canEditFolder;
|
||||||
config.featureToggles.nestedFolders && contextSrv.hasPermission(AccessControlAction.FoldersWrite);
|
|
||||||
const canDeleteFolder = contextSrv.hasPermission(AccessControlAction.FoldersDelete);
|
|
||||||
|
|
||||||
const onMove = async (destinationUID: string) => {
|
const onMove = async (destinationUID: string) => {
|
||||||
await moveFolder({ folder, destinationUID });
|
await moveFolder({ folder, destinationUID });
|
||||||
|
@ -2,30 +2,27 @@ import { config } from '@grafana/runtime';
|
|||||||
import { contextSrv } from 'app/core/core';
|
import { contextSrv } from 'app/core/core';
|
||||||
import { AccessControlAction, FolderDTO } from 'app/types';
|
import { AccessControlAction, FolderDTO } from 'app/types';
|
||||||
|
|
||||||
function checkFolderPermission(action: AccessControlAction, fallback: boolean, folderDTO?: FolderDTO) {
|
function checkFolderPermission(action: AccessControlAction, folderDTO?: FolderDTO) {
|
||||||
return folderDTO
|
return folderDTO ? contextSrv.hasPermissionInMetadata(action, folderDTO) : contextSrv.hasPermission(action);
|
||||||
? contextSrv.hasAccessInMetadata(action, folderDTO, fallback)
|
|
||||||
: contextSrv.hasAccess(action, fallback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFolderPermissions(folderDTO?: FolderDTO) {
|
export function getFolderPermissions(folderDTO?: FolderDTO) {
|
||||||
// It is possible to have edit permissions for folders and dashboards, without being able to save, hence 'canSave'
|
const canEditFolder = checkFolderPermission(AccessControlAction.FoldersWrite, folderDTO);
|
||||||
const canEditInFolderFallback = folderDTO ? folderDTO.canSave : contextSrv.hasEditPermissionInFolders;
|
|
||||||
|
|
||||||
const canEditInFolder = checkFolderPermission(AccessControlAction.FoldersWrite, canEditInFolderFallback, folderDTO);
|
|
||||||
// Can only create a folder if we have permissions and either we're at root or nestedFolders is enabled
|
// Can only create a folder if we have permissions and either we're at root or nestedFolders is enabled
|
||||||
const canCreateFolder = Boolean(
|
const canCreateFolder = Boolean(
|
||||||
(!folderDTO || config.featureToggles.nestedFolders) &&
|
(!folderDTO || config.featureToggles.nestedFolders) && checkFolderPermission(AccessControlAction.FoldersCreate)
|
||||||
checkFolderPermission(AccessControlAction.FoldersCreate, contextSrv.isEditor)
|
|
||||||
);
|
|
||||||
const canCreateDashboards = checkFolderPermission(
|
|
||||||
AccessControlAction.DashboardsCreate,
|
|
||||||
canEditInFolderFallback || !!folderDTO?.canSave
|
|
||||||
);
|
);
|
||||||
|
const canCreateDashboards = checkFolderPermission(AccessControlAction.DashboardsCreate, folderDTO);
|
||||||
|
const canDeleteFolder = checkFolderPermission(AccessControlAction.FoldersDelete, folderDTO);
|
||||||
|
const canViewPermissions = checkFolderPermission(AccessControlAction.FoldersPermissionsRead, folderDTO);
|
||||||
|
const canSetPermissions = checkFolderPermission(AccessControlAction.FoldersPermissionsWrite, folderDTO);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
canEditInFolder,
|
|
||||||
canCreateDashboards,
|
canCreateDashboards,
|
||||||
canCreateFolder,
|
canCreateFolder,
|
||||||
|
canDeleteFolder,
|
||||||
|
canEditFolder,
|
||||||
|
canSetPermissions,
|
||||||
|
canViewPermissions,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user