From 89757cf58fcfe39b111672ceffca241dc395d992 Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Thu, 24 Mar 2022 09:43:25 +0000 Subject: [PATCH] ManageDashboards: Fix error when deleting all dashboards from folder view (#46877) * user essentials mob! :trident: * draft tests * tests! * better default ids for test data --- .../search/components/ConfirmDeleteModal.tsx | 3 - public/app/features/search/testData.ts | 253 +++++++++++++++--- public/app/features/search/utils.test.ts | 30 ++- public/app/features/search/utils.ts | 2 +- 4 files changed, 244 insertions(+), 44 deletions(-) diff --git a/public/app/features/search/components/ConfirmDeleteModal.tsx b/public/app/features/search/components/ConfirmDeleteModal.tsx index 16ba770452d..d4882e1a2eb 100644 --- a/public/app/features/search/components/ConfirmDeleteModal.tsx +++ b/public/app/features/search/components/ConfirmDeleteModal.tsx @@ -2,7 +2,6 @@ import React, { FC } from 'react'; import { css } from '@emotion/css'; import { GrafanaTheme } from '@grafana/data'; import { ConfirmModal, stylesFactory, useTheme } from '@grafana/ui'; -import { locationService } from '@grafana/runtime'; import { DashboardSection, OnDeleteItems } from '../types'; import { getCheckedUids } from '../utils'; import { deleteFoldersAndDashboards } from 'app/features/manage-dashboards/state/actions'; @@ -40,8 +39,6 @@ export const ConfirmDeleteModal: FC = ({ results, onDeleteItems, isOpen, const deleteItems = () => { deleteFoldersAndDashboards(folders, dashboards).then(() => { onDismiss(); - // Redirect to /dashboard in case folder was deleted from f/:folder.uid - locationService.push('/dashboards'); onDeleteItems(folders, dashboards); }); }; diff --git a/public/app/features/search/testData.ts b/public/app/features/search/testData.ts index 0975d68f8f0..bf6f11315e8 100644 --- a/public/app/features/search/testData.ts +++ b/public/app/features/search/testData.ts @@ -1,4 +1,31 @@ -import { DashboardSearchItemType, DashboardSection } from './types'; +import { DashboardSearchItemType, DashboardSection, DashboardSectionItem } from './types'; + +function makeSection(sectionPartial: Partial): DashboardSection { + return { + title: 'Default title', + id: Number.MAX_SAFE_INTEGER - 1, + score: -99, + expanded: true, + type: DashboardSearchItemType.DashFolder, + items: [], + url: '/default-url', + ...sectionPartial, + }; +} + +const makeSectionItem = (itemPartial: Partial): DashboardSectionItem => { + return { + id: Number.MAX_SAFE_INTEGER - 2, + uid: 'default-uid', + title: 'Default dashboard title', + type: DashboardSearchItemType.DashDB, + isStarred: false, + tags: [], + uri: 'db/default-slug', + url: '/d/default-uid/default-slug', + ...itemPartial, + }; +}; export const generalFolder: DashboardSection = { id: 0, @@ -52,61 +79,62 @@ export const searchResults: DashboardSection[] = [ ]; // Search results with more info -export const sections = [ - { +export const sections: DashboardSection[] = [ + makeSection({ title: 'Starred', score: -2, expanded: true, items: [ - { + makeSectionItem({ id: 1, uid: 'lBdLINUWk', title: 'Prom dash', type: DashboardSearchItemType.DashDB, - }, + }), ], - }, - { + }), + + makeSection({ title: 'Recent', icon: 'clock-o', score: -1, - removable: true, expanded: false, items: [ - { + makeSectionItem({ id: 4072, uid: 'OzAIf_rWz', title: 'New dashboard Copy 3', type: DashboardSearchItemType.DashDB, isStarred: false, - }, - { + }), + makeSectionItem({ id: 46, uid: '8DY63kQZk', title: 'Stocks', type: DashboardSearchItemType.DashDB, isStarred: false, - }, - { + }), + makeSectionItem({ id: 20, uid: '7MeksYbmk', title: 'Alerting with TestData', type: DashboardSearchItemType.DashDB, isStarred: false, folderId: 2, - }, - { + }), + makeSectionItem({ id: 4073, uid: 'j9SHflrWk', title: 'New dashboard Copy 4', type: DashboardSearchItemType.DashDB, isStarred: false, folderId: 2, - }, + }), ], - }, - { + }), + + makeSection({ id: 2, uid: 'JB_zdOUWk', title: 'gdev dashboards', @@ -115,8 +143,9 @@ export const sections = [ icon: 'folder', score: 2, items: [], - }, - { + }), + + makeSection({ id: 2568, uid: 'search-test-data', title: 'Search test data folder', @@ -125,8 +154,9 @@ export const sections = [ url: '/dashboards/f/search-test-data/search-test-data-folder', icon: 'folder', score: 3, - }, - { + }), + + makeSection({ id: 4074, uid: 'iN5TFj9Zk', title: 'Test', @@ -135,38 +165,197 @@ export const sections = [ url: '/dashboards/f/iN5TFj9Zk/test', icon: 'folder', score: 4, - }, - { + }), + + makeSection({ id: 0, title: 'General', icon: 'folder-open', score: 5, expanded: true, items: [ - { + makeSectionItem({ id: 4069, uid: 'LCFWfl9Zz', title: 'New dashboard Copy', uri: 'db/new-dashboard-copy', url: '/d/LCFWfl9Zz/new-dashboard-copy', - slug: '', type: DashboardSearchItemType.DashDB, isStarred: false, - }, - { + }), + makeSectionItem({ id: 4072, uid: 'OzAIf_rWz', title: 'New dashboard Copy 3', type: DashboardSearchItemType.DashDB, isStarred: false, - }, - { + }), + makeSectionItem({ id: 1, uid: 'lBdLINUWk', title: 'Prom dash', type: DashboardSearchItemType.DashDB, isStarred: true, - }, + }), ], - }, + }), +]; + +export const checkedGeneralFolder: DashboardSection[] = [ + makeSection({ + id: 4074, + uid: 'other-folder-dash', + title: 'Test', + expanded: false, + type: DashboardSearchItemType.DashFolder, + items: [ + makeSectionItem({ + id: 4072, + uid: 'other-folder-dash-abc', + title: 'New dashboard Copy 3', + type: DashboardSearchItemType.DashDB, + isStarred: false, + }), + makeSectionItem({ + id: 46, + uid: 'other-folder-dash-def', + title: 'Stocks', + type: DashboardSearchItemType.DashDB, + isStarred: false, + }), + ], + url: '/dashboards/f/iN5TFj9Zk/test', + icon: 'folder', + score: 4, + }), + + makeSection({ + id: 0, + title: 'General', + uid: 'other-folder-abc', + score: 5, + expanded: true, + checked: true, + type: DashboardSearchItemType.DashFolder, + items: [ + makeSectionItem({ + id: 4069, + uid: 'general-abc', + title: 'New dashboard Copy', + uri: 'db/new-dashboard-copy', + url: '/d/LCFWfl9Zz/new-dashboard-copy', + type: DashboardSearchItemType.DashDB, + isStarred: false, + checked: true, + }), + makeSectionItem({ + id: 4072, + uid: 'general-def', + title: 'New dashboard Copy 3', + type: DashboardSearchItemType.DashDB, + isStarred: false, + checked: true, + }), + makeSectionItem({ + id: 1, + uid: 'general-ghi', + title: 'Prom dash', + type: DashboardSearchItemType.DashDB, + isStarred: true, + checked: true, + }), + ], + }), +]; + +export const checkedOtherFolder: DashboardSection[] = [ + makeSection({ + id: 4074, + uid: 'other-folder-abc', + title: 'Test', + expanded: false, + checked: true, + type: DashboardSearchItemType.DashFolder, + items: [ + makeSectionItem({ + id: 4072, + uid: 'other-folder-dash-abc', + title: 'New dashboard Copy 3', + type: DashboardSearchItemType.DashDB, + isStarred: false, + checked: true, + }), + makeSectionItem({ + id: 46, + uid: 'other-folder-dash-def', + title: 'Stocks', + type: DashboardSearchItemType.DashDB, + isStarred: false, + checked: true, + }), + ], + url: '/dashboards/f/iN5TFj9Zk/test', + icon: 'folder', + score: 4, + }), + + makeSection({ + id: 0, + title: 'General', + icon: 'folder-open', + score: 5, + expanded: true, + type: DashboardSearchItemType.DashFolder, + items: [ + makeSectionItem({ + id: 4069, + uid: 'general-abc', + title: 'New dashboard Copy', + uri: 'db/new-dashboard-copy', + url: '/d/LCFWfl9Zz/new-dashboard-copy', + type: DashboardSearchItemType.DashDB, + isStarred: false, + }), + makeSectionItem({ + id: 4072, + uid: 'general-def', + title: 'New dashboard Copy 3', + type: DashboardSearchItemType.DashDB, + isStarred: false, + }), + makeSectionItem({ + id: 1, + uid: 'general-ghi', + title: 'Prom dash', + type: DashboardSearchItemType.DashDB, + isStarred: true, + }), + ], + }), +]; + +export const folderViewAllChecked: DashboardSection[] = [ + makeSection({ + checked: true, + selected: true, + title: '', + items: [ + makeSectionItem({ + id: 4072, + uid: 'other-folder-dash-abc', + title: 'New dashboard Copy 3', + type: DashboardSearchItemType.DashDB, + isStarred: false, + checked: true, + }), + makeSectionItem({ + id: 46, + uid: 'other-folder-dash-def', + title: 'Stocks', + type: DashboardSearchItemType.DashDB, + isStarred: false, + checked: true, + }), + ], + }), ]; diff --git a/public/app/features/search/utils.test.ts b/public/app/features/search/utils.test.ts index 3fb1cccb703..8f7f3a8af03 100644 --- a/public/app/features/search/utils.test.ts +++ b/public/app/features/search/utils.test.ts @@ -7,7 +7,7 @@ import { mergeReducers, parseRouteParams, } from './utils'; -import { sections, searchResults } from './testData'; +import { sections, searchResults, checkedGeneralFolder, checkedOtherFolder, folderViewAllChecked } from './testData'; import { SearchQueryParams } from './types'; describe('Search utils', () => { @@ -131,21 +131,35 @@ describe('Search utils', () => { }); describe('getCheckedUids', () => { - it('should return object with empty arrays if no checked items are available', () => { - expect(getCheckedUids(sections as any[])).toEqual({ folders: [], dashboards: [] }); + it('should not return any UIDs if no items are checked', () => { + expect(getCheckedUids(sections)).toEqual({ folders: [], dashboards: [] }); }); - it('should return uids for all checked items', () => { - expect(getCheckedUids(searchResults as any[])).toEqual({ - folders: ['JB_zdOUWk'], - dashboards: ['lBdLINUWk', '8DY63kQZk'], + it('should return only dashboard UIDs if the General folder is checked', () => { + expect(getCheckedUids(checkedGeneralFolder)).toEqual({ + folders: [], + dashboards: ['general-abc', 'general-def', 'general-ghi'], + }); + }); + + it('should return only dashboard UIDs if all items are checked when viewing a folder', () => { + expect(getCheckedUids(folderViewAllChecked)).toEqual({ + folders: [], + dashboards: ['other-folder-dash-abc', 'other-folder-dash-def'], + }); + }); + + it('should return folder + dashboard UIDs when folder is checked in the root view', () => { + expect(getCheckedUids(checkedOtherFolder)).toEqual({ + folders: ['other-folder-abc'], + dashboards: ['other-folder-dash-abc', 'other-folder-dash-def'], }); }); }); describe('getCheckedDashboardsUids', () => { it('should get uids of all checked dashboards', () => { - expect(getCheckedDashboardsUids(searchResults as any[])).toEqual(['lBdLINUWk', '8DY63kQZk']); + expect(getCheckedDashboardsUids(searchResults)).toEqual(['lBdLINUWk', '8DY63kQZk']); }); }); diff --git a/public/app/features/search/utils.ts b/public/app/features/search/utils.ts index 8a0e986befb..3d09fa56265 100644 --- a/public/app/features/search/utils.ts +++ b/public/app/features/search/utils.ts @@ -165,7 +165,7 @@ export const getCheckedUids = (sections: DashboardSection[]): UidsToDelete => { } return sections.reduce((result, section) => { - if (section?.id !== 0 && section.checked) { + if (section?.id !== 0 && section.checked && section.uid) { return { ...result, folders: [...result.folders, section.uid] } as UidsToDelete; } else { return { ...result, dashboards: getCheckedDashboardsUids(sections) } as UidsToDelete;