diff --git a/src/components/documents/folder-actions-menu.tsx b/src/components/documents/folder-actions-menu.tsx index 643f4805..d9f37633 100644 --- a/src/components/documents/folder-actions-menu.tsx +++ b/src/components/documents/folder-actions-menu.tsx @@ -21,14 +21,30 @@ import { import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { ConfirmationDialog } from '@/components/shared/confirmation-dialog'; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from '@/components/ui/tooltip'; import { toastError } from '@/lib/api/toast-error'; import { useCreateFolder, useDeleteFolder, useRenameFolder, useDocumentFolders, + type FolderNode, } from '@/hooks/use-document-folders'; +function findInTree(nodes: FolderNode[], id: string): FolderNode | null { + for (const node of nodes) { + if (node.id === id) return node; + const found = findInTree(node.children, id); + if (found) return found; + } + return null; +} + interface FolderActionsMenuProps { /** The folder these actions apply to. `null` means root → only the * Create-new-folder action is available. */ @@ -61,6 +77,9 @@ export function FolderActionsMenu({ selectedFolderId, onAfterDelete }: FolderAct return find(tree) ?? ''; })(); + const selectedNode = isFolderSelected ? findInTree(tree, selectedFolderId as string) : null; + const isSystem = selectedNode?.systemManaged ?? false; + return ( <> @@ -81,41 +100,62 @@ export function FolderActionsMenu({ selectedFolderId, onAfterDelete }: FolderAct New folder {isFolderSelected ? 'inside this' : 'at root'} {isFolderSelected ? ( - <> - { - setName(currentName); - setRenameOpen(true); - }} - > - - Rename - - e.preventDefault()} - className="text-destructive" - > - - Delete - - } - title="Delete folder?" - description="Subfolders and documents inside will move up to the parent. The folder itself is removed." - confirmLabel="Delete folder" - loading={deleteMutation.isPending} - onConfirm={async () => { - try { - await deleteMutation.mutateAsync(selectedFolderId as string); - toast.success('Folder deleted; contents moved to parent.'); - onAfterDelete?.(); - } catch (err) { - toastError(err); - } - }} - /> - + + + + + { + if (isSystem) return; + setName(currentName); + setRenameOpen(true); + }} + > + + Rename + + + + {isSystem ? ( + System folders can't be renamed. + ) : null} + + + + + e.preventDefault()} + className="text-destructive" + > + + Delete + + } + title="Delete folder?" + description="Subfolders and documents inside will move up to the parent. The folder itself is removed." + confirmLabel="Delete folder" + loading={deleteMutation.isPending} + onConfirm={async () => { + try { + await deleteMutation.mutateAsync(selectedFolderId as string); + toast.success('Folder deleted; contents moved to parent.'); + onAfterDelete?.(); + } catch (err) { + toastError(err); + } + }} + /> + + + {isSystem ? ( + System folders can't be deleted. + ) : null} + + ) : null} diff --git a/src/components/documents/folder-tree-sidebar.tsx b/src/components/documents/folder-tree-sidebar.tsx index 663cb33e..327a623c 100644 --- a/src/components/documents/folder-tree-sidebar.tsx +++ b/src/components/documents/folder-tree-sidebar.tsx @@ -1,7 +1,7 @@ 'use client'; import { useState } from 'react'; -import { ChevronRight, Folder, FolderOpen, Inbox } from 'lucide-react'; +import { ChevronRight, Folder, FolderOpen, Inbox, Lock } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { cn } from '@/lib/utils'; @@ -135,7 +135,10 @@ function FolderRow({ {open