From e9f44daa7e4442e03b36ac37be5f1ca2e9961e35 Mon Sep 17 00:00:00 2001 From: Yunwen Zheng Date: Thu, 2 Oct 2025 08:38:27 -0400 Subject: [PATCH] FolderActionsButton: Move folder action set up for provisioned folders (#111913) --- .../components/FolderActionsButton.tsx | 32 +++++++++++++++++-- public/locales/en-US/grafana.json | 1 + 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/public/app/features/browse-dashboards/components/FolderActionsButton.tsx b/public/app/features/browse-dashboards/components/FolderActionsButton.tsx index dd88bf2679d..ec093e3aa69 100644 --- a/public/app/features/browse-dashboards/components/FolderActionsButton.tsx +++ b/public/app/features/browse-dashboards/components/FolderActionsButton.tsx @@ -7,7 +7,9 @@ import { Button, Drawer, Dropdown, Icon, Menu, MenuItem } from '@grafana/ui'; import { Permissions } from 'app/core/components/AccessControl'; import { appEvents } from 'app/core/core'; import { RepoType } from 'app/features/provisioning/Wizard/types'; +import { BulkMoveProvisionedResource } from 'app/features/provisioning/components/BulkActions/BulkMoveProvisionedResource'; import { DeleteProvisionedFolderForm } from 'app/features/provisioning/components/Folders/DeleteProvisionedFolderForm'; +import { useIsProvisionedInstance } from 'app/features/provisioning/hooks/useIsProvisionedInstance'; import { getReadOnlyTooltipText } from 'app/features/provisioning/utils/repository'; import { ShowModalReactEvent } from 'app/types/events'; import { FolderDTO } from 'app/types/folders'; @@ -29,14 +31,18 @@ export function FolderActionsButton({ folder, repoType, isReadOnlyRepo }: Props) const [isOpen, setIsOpen] = useState(false); const [showPermissionsDrawer, setShowPermissionsDrawer] = useState(false); const [showDeleteProvisionedFolderDrawer, setShowDeleteProvisionedFolderDrawer] = useState(false); + const [showMoveProvisionedFolderDrawer, setShowMoveProvisionedFolderDrawer] = useState(false); const [moveFolder] = useMoveFolderMutationFacade(); + const isProvisionedInstance = useIsProvisionedInstance(); const deleteFolder = useDeleteFolderMutationFacade(); const { canEditFolders, canDeleteFolders, canViewPermissions, canSetPermissions } = getFolderPermissions(folder); const isProvisionedFolder = folder.managedBy === ManagerKind.Repo; + // When its single provisioned folder, cannot move the root repository folder + const isProvisionedRootFolder = isProvisionedFolder && !isProvisionedInstance && folder.parentUid === undefined; // Can only move folders when the folder is not provisioned - const canMoveFolder = canEditFolders && !isProvisionedFolder; + const canMoveFolder = canEditFolders && !isProvisionedRootFolder; const onMove = async (destinationUID: string) => { await moveFolder({ folderUID: folder.uid, destinationUID: destinationUID }); @@ -115,6 +121,10 @@ export function FolderActionsButton({ folder, repoType, isReadOnlyRepo }: Props) setShowDeleteProvisionedFolderDrawer(true); }; + const handleShowMoveProvisionedFolderDrawer = () => { + setShowMoveProvisionedFolderDrawer(true); + }; + const managePermissionsLabel = t('browse-dashboards.folder-actions-button.manage-permissions', 'Manage permissions'); const moveLabel = t('browse-dashboards.folder-actions-button.move', 'Move'); const deleteLabel = t('browse-dashboards.folder-actions-button.delete', 'Delete'); @@ -122,7 +132,12 @@ export function FolderActionsButton({ folder, repoType, isReadOnlyRepo }: Props) const menu = ( {canViewPermissions && setShowPermissionsDrawer(true)} label={managePermissionsLabel} />} - {canMoveFolder && !isReadOnlyRepo && } + {canMoveFolder && !isReadOnlyRepo && ( + + )} {canDeleteFolders && !isReadOnlyRepo && ( )} + {showMoveProvisionedFolderDrawer && ( + setShowMoveProvisionedFolderDrawer(false)} + > + setShowMoveProvisionedFolderDrawer(false)} + /> + + )} ); } diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index e2a9045c77d..d86e265b519 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -3496,6 +3496,7 @@ "move-modal-field-label": "Folder name", "move-modal-text": "This action will move the following content:", "move-modal-title": "Move", + "move-provisioned-folder": "Move provisioned folder", "moving": "Moving...", "new-folder-name-required-phrase": "Folder name is required.", "selected-mix-resources-modal-text": "You have selected both provisioned and non-provisioned resources. These cannot be processed together. Please select only provisioned resources or only non-provisioned resources and try again.",