feat(browse-dashboards): select all dashboards when folder is selected

- Add selectFolderWithAllDashboards async thunk to recursively collect all dashboards
- Update BrowseView to use the new thunk when selecting folders
- When a folder is selected, all dashboards in that folder and subfolders are automatically selected
- Similar behavior to folder export functionality
This commit is contained in:
Roberto Jimenez Sanchez
2025-12-02 19:00:59 +01:00
parent 960d4de505
commit 4c5ac79399
2 changed files with 66 additions and 1 deletions
@@ -22,6 +22,7 @@ import {
useLoadNextChildrenPage,
rootItemsSelector,
} from '../state/hooks';
import { selectFolderWithAllDashboards } from '../state/actions';
import { setFolderOpenState, setItemSelectionState, setAllSelection } from '../state/slice';
import { BrowseDashboardsState, DashboardTreeSelection, SelectionState, BrowseDashboardsPermissions } from '../types';
@@ -81,7 +82,13 @@ export function BrowseView({ folderUID, width, height, permissions, isReadOnlyRe
const handleItemSelectionChange = useCallback(
(item: DashboardViewItem, isSelected: boolean) => {
dispatch(setItemSelectionState({ item, isSelected }));
// If selecting a folder, use the async thunk to collect all dashboards recursively
// When deselecting, the normal reducer will handle deselecting all children
if (item.kind === 'folder') {
dispatch(selectFolderWithAllDashboards({ folderUID: item.uid, isSelected }));
} else {
dispatch(setItemSelectionState({ item, isSelected }));
}
},
[dispatch]
);
@@ -5,6 +5,7 @@ import { createAsyncThunk } from 'app/types/store';
import { listDashboards, listFolders, PAGE_SIZE } from '../api/services';
import { DashboardViewItemWithUIItems, UIDashboardViewItem } from '../types';
import { setItemSelectionState } from './slice';
import { findItem } from './utils';
interface FetchNextChildrenPageArgs {
@@ -88,6 +89,63 @@ export const refetchChildren = createAsyncThunk(
}
);
export const selectFolderWithAllDashboards = createAsyncThunk(
'browseDashboards/selectFolderWithAllDashboards',
async (
{ folderUID, isSelected }: { folderUID: string; isSelected: boolean },
{ dispatch, getState }
) => {
const state = getState().browseDashboards;
// Find the folder item to get its parentUID and managedBy
const folderItem = findItem(state.rootItems?.items ?? [], state.childrenByParentUID, folderUID);
if (!isSelected) {
// When deselecting, use the normal action - it will handle deselecting all children recursively
dispatch(setItemSelectionState({
item: {
kind: 'folder',
uid: folderUID,
parentUID: folderItem?.parentUID,
managedBy: folderItem?.managedBy
},
isSelected: false
}));
return;
}
// When selecting, collect all dashboards recursively
const { collectAllDashboardsUnderFolder } = await import('app/features/provisioning/utils/collectFolderDashboards');
const dashboardUIDs = await collectAllDashboardsUnderFolder(folderUID);
// First, select the folder itself
dispatch(setItemSelectionState({
item: {
kind: 'folder',
uid: folderUID,
parentUID: folderItem?.parentUID,
managedBy: folderItem?.managedBy
},
isSelected: true
}));
// Then select all dashboards found
// We need to get the parentUID for each dashboard from the state
for (const dashboardUID of dashboardUIDs) {
const dashboardItem = findItem(state.rootItems?.items ?? [], state.childrenByParentUID, dashboardUID);
dispatch(setItemSelectionState({
item: {
kind: 'dashboard',
uid: dashboardUID,
parentUID: dashboardItem?.parentUID,
managedBy: dashboardItem?.managedBy
},
isSelected: true
}));
}
}
);
export const fetchNextChildrenPage = createAsyncThunk(
'browseDashboards/fetchNextChildrenPage',
async (