From 4facd4aedf39f3157822cd888f171ea005066ce6 Mon Sep 17 00:00:00 2001 From: "Grot (@grafanabot)" <43478413+grafanabot@users.noreply.github.com> Date: Fri, 8 Oct 2021 10:48:26 +0100 Subject: [PATCH] Folders: Prevents deletion of General folder (#40192) (#40200) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 70e759e0c0a4879aff1e0d6312b27fc30d087289) Co-authored-by: Hugo Häggmark --- .../search/hooks/useManageDashboards.test.ts | 106 +++++++++++++++++- .../search/hooks/useManageDashboards.ts | 18 +-- 2 files changed, 113 insertions(+), 11 deletions(-) diff --git a/public/app/features/search/hooks/useManageDashboards.test.ts b/public/app/features/search/hooks/useManageDashboards.test.ts index 7a6ddc2297a..6f34fdb7645 100644 --- a/public/app/features/search/hooks/useManageDashboards.test.ts +++ b/public/app/features/search/hooks/useManageDashboards.test.ts @@ -53,12 +53,83 @@ describe('useManageDashboards', () => { }); describe('when called and General folder and another folder are selected', () => { - it('then canDelete should be true', () => { + it('then canDelete should be false', () => { const results: DashboardSection[] = [ - { id: 1, checked: true, items: [], title: 'One', type: DashboardSearchItemType.DashFolder, toggle, url: '/' }, + { + id: 1, + checked: true, + items: [ + { + id: 11, + checked: true, + title: 'Eleven', + type: DashboardSearchItemType.DashDB, + url: '/', + isStarred: false, + tags: [], + uri: '', + }, + ], + title: 'One', + type: DashboardSearchItemType.DashFolder, + toggle, + url: '/', + }, { id: GENERAL_FOLDER_ID, checked: true, + items: [ + { + id: 10, + checked: true, + title: 'Ten', + type: DashboardSearchItemType.DashDB, + url: '/', + isStarred: false, + tags: [], + uri: '', + }, + ], + title: 'General', + type: DashboardSearchItemType.DashFolder, + toggle, + url: '/', + }, + { id: 2, checked: false, items: [], title: 'Two', type: DashboardSearchItemType.DashFolder, toggle, url: '/' }, + ]; + + const { result } = setupTestContext({ results }); + + expect(result.current.canDelete).toBe(false); + }); + }); + + describe('when called on an empty General folder that is not selected but another folder is selected', () => { + it('then canDelete should be true', () => { + const results: DashboardSection[] = [ + { + id: 1, + checked: true, + items: [ + { + id: 11, + checked: true, + title: 'Eleven', + type: DashboardSearchItemType.DashDB, + url: '/', + isStarred: false, + tags: [], + uri: '', + }, + ], + title: 'One', + type: DashboardSearchItemType.DashFolder, + toggle, + url: '/', + }, + { + id: GENERAL_FOLDER_ID, + checked: false, items: [], title: 'General', type: DashboardSearchItemType.DashFolder, @@ -74,6 +145,37 @@ describe('useManageDashboards', () => { }); }); + describe('when called on a non empty General folder that is not selected dashboard in General folder is selected', () => { + it('then canDelete should be true', () => { + const results: DashboardSection[] = [ + { + id: GENERAL_FOLDER_ID, + checked: false, + items: [ + { + id: 10, + checked: true, + title: 'Ten', + type: DashboardSearchItemType.DashDB, + url: '/', + isStarred: false, + tags: [], + uri: '', + }, + ], + title: 'General', + type: DashboardSearchItemType.DashFolder, + toggle, + url: '/', + }, + ]; + + const { result } = setupTestContext({ results }); + + expect(result.current.canDelete).toBe(true); + }); + }); + describe('when called and no folder is selected', () => { it('then canDelete should be false', () => { const results: DashboardSection[] = [ diff --git a/public/app/features/search/hooks/useManageDashboards.ts b/public/app/features/search/hooks/useManageDashboards.ts index 7561e5ec9e0..e5512b8b53f 100644 --- a/public/app/features/search/hooks/useManageDashboards.ts +++ b/public/app/features/search/hooks/useManageDashboards.ts @@ -1,7 +1,7 @@ import { useCallback, useMemo, useReducer } from 'react'; import { FolderDTO } from 'app/types'; import { contextSrv } from 'app/core/services/context_srv'; -import { DashboardQuery, DashboardSection, OnDeleteItems, OnMoveItems, OnToggleChecked } from '../types'; +import { DashboardQuery, OnDeleteItems, OnMoveItems, OnToggleChecked } from '../types'; import { DELETE_ITEMS, MOVE_ITEMS, TOGGLE_ALL_CHECKED, TOGGLE_CHECKED } from '../reducers/actionTypes'; import { manageDashboardsReducer, manageDashboardsState, ManageDashboardsState } from '../reducers/manageDashboards'; import { useSearch } from './useSearch'; @@ -42,14 +42,14 @@ export const useManageDashboards = ( dispatch({ type: MOVE_ITEMS, payload: { dashboards: selectedDashboards, folder } }); }; - const canMove = useMemo( - () => results.some((result: DashboardSection) => result.items && result.items.some((item) => item.checked)), - [results] - ); - const canDelete = useMemo( - () => canMove || results.some((result: DashboardSection) => result.checked && result.id !== GENERAL_FOLDER_ID), - [canMove, results] - ); + const canMove = useMemo(() => results.some((result) => result.items && result.items.some((item) => item.checked)), [ + results, + ]); + + const canDelete = useMemo(() => { + const includesGeneralFolder = results.find((result) => result.checked && result.id === GENERAL_FOLDER_ID); + return canMove && !includesGeneralFolder; + }, [canMove, results]); const canSave = folder?.canSave; const hasEditPermissionInFolders = folder ? canSave : contextSrv.hasEditPermissionInFolders;