diff --git a/public/app/features/browse-dashboards/BrowseDashboardsPage.test.tsx b/public/app/features/browse-dashboards/BrowseDashboardsPage.test.tsx
index 3cd8b448e51..4c7a4741afb 100644
--- a/public/app/features/browse-dashboards/BrowseDashboardsPage.test.tsx
+++ b/public/app/features/browse-dashboards/BrowseDashboardsPage.test.tsx
@@ -1,4 +1,4 @@
-import { render as rtlRender, screen } from '@testing-library/react';
+import { render as rtlRender, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React, { ComponentProps } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
@@ -10,7 +10,7 @@ import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps
import BrowseDashboardsPage, { Props } from './BrowseDashboardsPage';
import { wellFormedTree } from './fixtures/dashboardsTreeItem.fixture';
import * as permissions from './permissions';
-const [mockTree, { dashbdD }] = wellFormedTree();
+const [mockTree, { dashbdD, folderA }] = wellFormedTree();
jest.mock('react-virtualized-auto-sizer', () => {
return {
@@ -98,4 +98,23 @@ describe('browse-dashboards BrowseDashboardsPage', () => {
expect(screen.getByRole('button', { name: 'Move' })).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Delete' })).toBeInTheDocument();
});
+
+ it('navigating into a child item resets the selected state', async () => {
+ render();
+
+ const checkbox = await screen.findByTestId(selectors.pages.BrowseDashbards.table.checkbox(folderA.item.uid));
+ await userEvent.click(checkbox);
+
+ // Check the actions are now visible
+ expect(screen.getByRole('button', { name: 'Move' })).toBeInTheDocument();
+ expect(screen.getByRole('button', { name: 'Delete' })).toBeInTheDocument();
+
+ await userEvent.click(screen.getByRole('link', { name: folderA.item.title }));
+
+ // Check the actions are no longer visible
+ waitFor(() => {
+ expect(screen.queryByRole('button', { name: 'Move' })).not.toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: 'Delete' })).not.toBeInTheDocument();
+ });
+ });
});
diff --git a/public/app/features/browse-dashboards/BrowseDashboardsPage.tsx b/public/app/features/browse-dashboards/BrowseDashboardsPage.tsx
index ac10735a8a7..53ed0989428 100644
--- a/public/app/features/browse-dashboards/BrowseDashboardsPage.tsx
+++ b/public/app/features/browse-dashboards/BrowseDashboardsPage.tsx
@@ -6,6 +6,7 @@ import { GrafanaTheme2 } from '@grafana/data';
import { FilterInput, useStyles2 } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
+import { useDispatch } from 'app/types';
import { buildNavModel } from '../folders/state/navModel';
import { useSearchStateManager } from '../search/state/SearchStateManager';
@@ -18,7 +19,7 @@ import { BrowseView } from './components/BrowseView';
import { CreateNewButton } from './components/CreateNewButton';
import { SearchView } from './components/SearchView';
import { getFolderPermissions } from './permissions';
-import { useHasSelection } from './state';
+import { setAllSelection, useHasSelection } from './state';
export interface BrowseDashboardsPageRouteParams {
uid?: string;
@@ -31,12 +32,22 @@ export interface Props extends GrafanaRouteComponentProps {
const { uid: folderUID } = match.params;
+ const dispatch = useDispatch();
const styles = useStyles2(getStyles);
const [searchState, stateManager] = useSearchStateManager();
const isSearching = stateManager.hasSearchFilters();
- useEffect(() => stateManager.initStateFromUrl(folderUID), [folderUID, stateManager]);
+ useEffect(() => {
+ stateManager.initStateFromUrl(folderUID);
+
+ // Clear selected state when folderUID changes
+ dispatch(
+ setAllSelection({
+ isSelected: false,
+ })
+ );
+ }, [dispatch, folderUID, stateManager]);
useEffect(() => {
// Clear the search results when we leave SearchView to prevent old results flashing
diff --git a/public/app/features/browse-dashboards/fixtures/dashboardsTreeItem.fixture.ts b/public/app/features/browse-dashboards/fixtures/dashboardsTreeItem.fixture.ts
index a40bd2264c0..18fcd6139d4 100644
--- a/public/app/features/browse-dashboards/fixtures/dashboardsTreeItem.fixture.ts
+++ b/public/app/features/browse-dashboards/fixtures/dashboardsTreeItem.fixture.ts
@@ -48,12 +48,14 @@ export function wellFormedFolder(
itemPartial?: Partial
): DashboardsTreeItem {
const random = Chance(seed);
+ const uid = random.guid();
return {
item: {
kind: 'folder',
title: random.sentence({ words: 3 }),
- uid: random.guid(),
+ uid,
+ url: `/dashboards/f/${uid}`,
...itemPartial,
},
level: 0,