diff --git a/public/app/features/browse-dashboards/components/BrowseActions/BrowseActions.tsx b/public/app/features/browse-dashboards/components/BrowseActions/BrowseActions.tsx
index 1c89c3c6dd4..d881d07f863 100644
--- a/public/app/features/browse-dashboards/components/BrowseActions/BrowseActions.tsx
+++ b/public/app/features/browse-dashboards/components/BrowseActions/BrowseActions.tsx
@@ -6,8 +6,10 @@ import { Button, Drawer, Stack, Text } from '@grafana/ui';
import { appEvents } from 'app/core/app_events';
import { ManagerKind } from 'app/features/apiserver/types';
import { BulkDeleteProvisionedResource } from 'app/features/provisioning/components/BulkActions/BulkDeleteProvisionedResource';
+import { BulkExportProvisionedResource } from 'app/features/provisioning/components/BulkActions/BulkExportProvisionedResource';
import { BulkMoveProvisionedResource } from 'app/features/provisioning/components/BulkActions/BulkMoveProvisionedResource';
import { useSelectionProvisioningStatus } from 'app/features/provisioning/hooks/useSelectionProvisioningStatus';
+import { useSelectionUnmanagedStatus } from 'app/features/provisioning/hooks/useSelectionUnmanagedStatus';
import { useSearchStateManager } from 'app/features/search/state/SearchStateManager';
import { ShowModalReactEvent } from 'app/types/events';
import { FolderDTO } from 'app/types/folders';
@@ -18,7 +20,7 @@ import {
useMoveMultipleFoldersMutationFacade,
} from '../../../../api/clients/folder/v1beta1/hooks';
import { useDeleteDashboardsMutation, useMoveDashboardsMutation } from '../../api/browseDashboardsAPI';
-import { useActionSelectionState } from '../../state/hooks';
+import { useActionSelectionState, useCheckboxSelectionState } from '../../state/hooks';
import { setAllSelection } from '../../state/slice';
import { DashboardTreeSelection } from '../../types';
@@ -33,9 +35,11 @@ export interface Props {
export function BrowseActions({ folderDTO }: Props) {
const [showBulkDeleteProvisionedResource, setShowBulkDeleteProvisionedResource] = useState(false);
const [showBulkMoveProvisionedResource, setShowBulkMoveProvisionedResource] = useState(false);
+ const [showBulkExportProvisionedResource, setShowBulkExportProvisionedResource] = useState(false);
const dispatch = useDispatch();
- const selectedItems = useActionSelectionState();
+ const selectedItemsForActions = useActionSelectionState(); // For move/delete - filters out children
+ const selectedItems = useCheckboxSelectionState(); // For export - includes all selected items
const [deleteDashboards] = useDeleteDashboardsMutation();
const deleteFolders = useDeleteMultipleFoldersMutationFacade();
const [moveFolders] = useMoveMultipleFoldersMutationFacade();
@@ -44,9 +48,10 @@ export function BrowseActions({ folderDTO }: Props) {
const provisioningEnabled = config.featureToggles.provisioning;
const { hasProvisioned, hasNonProvisioned } = useSelectionProvisioningStatus(
- selectedItems,
+ selectedItemsForActions,
folderDTO?.managedBy === ManagerKind.Repo
);
+ const { hasUnmanaged, isLoading: isLoadingUnmanaged } = useSelectionUnmanagedStatus(selectedItems);
const isSearching = stateManager.hasSearchFilters();
@@ -60,21 +65,29 @@ export function BrowseActions({ folderDTO }: Props) {
};
const onDelete = async () => {
- const selectedDashboards = Object.keys(selectedItems.dashboard).filter((uid) => selectedItems.dashboard[uid]);
- const selectedFolders = Object.keys(selectedItems.folder).filter((uid) => selectedItems.folder[uid]);
+ const selectedDashboards = Object.keys(selectedItemsForActions.dashboard).filter(
+ (uid) => selectedItemsForActions.dashboard[uid]
+ );
+ const selectedFolders = Object.keys(selectedItemsForActions.folder).filter(
+ (uid) => selectedItemsForActions.folder[uid]
+ );
await deleteDashboards({ dashboardUIDs: selectedDashboards });
await deleteFolders({ folderUIDs: selectedFolders });
- trackAction('delete', selectedItems);
+ trackAction('delete', selectedItemsForActions);
onActionComplete();
};
const onMove = async (destinationUID: string) => {
- const selectedDashboards = Object.keys(selectedItems.dashboard).filter((uid) => selectedItems.dashboard[uid]);
- const selectedFolders = Object.keys(selectedItems.folder).filter((uid) => selectedItems.folder[uid]);
+ const selectedDashboards = Object.keys(selectedItemsForActions.dashboard).filter(
+ (uid) => selectedItemsForActions.dashboard[uid]
+ );
+ const selectedFolders = Object.keys(selectedItemsForActions.folder).filter(
+ (uid) => selectedItemsForActions.folder[uid]
+ );
await moveFolders({ folderUIDs: selectedFolders, destinationUID });
await moveDashboards({ dashboardUIDs: selectedDashboards, destinationUID });
- trackAction('move', selectedItems);
+ trackAction('move', selectedItemsForActions);
onActionComplete();
};
@@ -140,10 +153,26 @@ export function BrowseActions({ folderDTO }: Props) {
);
+ // Check if any dashboards are selected (export only supports dashboards, not folders)
+ // Use raw selectedItems (not selectedItemsForActions) to include all selected dashboards
+ const hasSelectedDashboards =
+ Object.keys(selectedItems.dashboard || {}).filter((uid) => selectedItems.dashboard[uid]).length > 0;
+
+ const pushButton = (
+
+ );
+
return (
<>
{moveButton}
+ {provisioningEnabled && pushButton}
+ {showExportToRepositoryDrawer && (
+
+ {t('share-modal.export.export-to-repository-title', 'Export Dashboard to Repository')}
+
+ }
+ subtitle={dashboard.title}
+ onClose={() => setShowExportToRepositoryDrawer(false)}
+ size="md"
+ >
+ {
+ setShowExportToRepositoryDrawer(false);
+ onDismiss?.();
+ }}
+ />
+
+ )}
>
);
});