diff --git a/surfsense_web/components/documents/DocumentNode.tsx b/surfsense_web/components/documents/DocumentNode.tsx index 20a40cc34..e56bcdbb7 100644 --- a/surfsense_web/components/documents/DocumentNode.tsx +++ b/surfsense_web/components/documents/DocumentNode.tsx @@ -10,14 +10,12 @@ import { ContextMenu, ContextMenuContent, ContextMenuItem, - ContextMenuSeparator, ContextMenuTrigger, } from "@/components/ui/context-menu"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, - DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import type { DocumentTypeEnum } from "@/contracts/types/document.types"; @@ -41,6 +39,8 @@ interface DocumentNodeProps { onEdit: (doc: DocumentNodeDoc) => void; onDelete: (doc: DocumentNodeDoc) => void; onMove: (doc: DocumentNodeDoc) => void; + contextMenuOpen?: boolean; + onContextMenuOpenChange?: (open: boolean) => void; } export const DocumentNode = React.memo(function DocumentNode({ @@ -52,6 +52,8 @@ export const DocumentNode = React.memo(function DocumentNode({ onEdit, onDelete, onMove, + contextMenuOpen, + onContextMenuOpenChange, }: DocumentNodeProps) { const statusState = doc.status?.state ?? "ready"; const isSelectable = statusState !== "pending" && statusState !== "processing"; @@ -76,7 +78,7 @@ export const DocumentNode = React.memo(function DocumentNode({ const isProcessing = statusState === "pending" || statusState === "processing"; return ( - + {/* biome-ignore lint/a11y/useSemanticElements: div required for drag ref */}
e.stopPropagation()} > @@ -152,7 +154,6 @@ export const DocumentNode = React.memo(function DocumentNode({ Move to... - - - onPreview(doc)}> - - Open - - {isEditable && ( - onEdit(doc)}> - - Edit + {contextMenuOpen && ( + + onPreview(doc)}> + + Open - )} - onMove(doc)}> - - Move to... - - - onDelete(doc)} - > - - Delete - - + {isEditable && ( + onEdit(doc)}> + + Edit + + )} + onMove(doc)}> + + Move to... + + onDelete(doc)} + > + + Delete + + + )} ); }); diff --git a/surfsense_web/components/documents/FolderNode.tsx b/surfsense_web/components/documents/FolderNode.tsx index 9dc3b4034..edc685d99 100644 --- a/surfsense_web/components/documents/FolderNode.tsx +++ b/surfsense_web/components/documents/FolderNode.tsx @@ -66,6 +66,8 @@ interface FolderNodeProps { onReorderFolder?: (folderId: number, beforePos: string | null, afterPos: string | null) => void; siblingPositions?: { before: string | null; after: string | null }; disabledDropIds?: Set; + contextMenuOpen?: boolean; + onContextMenuOpenChange?: (open: boolean) => void; } function getDropZone( @@ -99,6 +101,8 @@ export const FolderNode = React.memo(function FolderNode({ onReorderFolder, siblingPositions, disabledDropIds, + contextMenuOpen, + onContextMenuOpenChange, }: FolderNodeProps) { const [renameValue, setRenameValue] = useState(folder.name); const inputRef = useRef(null); @@ -213,7 +217,7 @@ export const FolderNode = React.memo(function FolderNode({ const FolderIcon = isExpanded ? FolderOpen : Folder; return ( - + {/* biome-ignore lint/a11y/useSemanticElements: div required for drag/drop refs */}
e.stopPropagation()} > @@ -313,7 +317,6 @@ export const FolderNode = React.memo(function FolderNode({ Move to... - { @@ -330,7 +333,7 @@ export const FolderNode = React.memo(function FolderNode({
- {!isRenaming && ( + {!isRenaming && contextMenuOpen && ( onCreateSubfolder(folder.id)}> @@ -344,7 +347,6 @@ export const FolderNode = React.memo(function FolderNode({ Move to... - onDelete(folder)} diff --git a/surfsense_web/components/documents/FolderTreeView.tsx b/surfsense_web/components/documents/FolderTreeView.tsx index ca64ab1e0..4c41db0ed 100644 --- a/surfsense_web/components/documents/FolderTreeView.tsx +++ b/surfsense_web/components/documents/FolderTreeView.tsx @@ -2,7 +2,7 @@ import { useAtom } from "jotai"; import { TreePine } from "lucide-react"; -import { useCallback, useMemo } from "react"; +import { useCallback, useMemo, useState } from "react"; import { DndProvider } from "react-dnd"; import { HTML5Backend } from "react-dnd-html5-backend"; import { renamingFolderIdAtom } from "@/atoms/documents/folder.atoms"; @@ -80,6 +80,8 @@ export function FolderTreeView({ return counts; }, [folders, foldersByParent, docsByFolder]); + const [openContextMenuId, setOpenContextMenuId] = useState(null); + // Single subscription for rename state — derived boolean passed to each FolderNode const [renamingFolderId, setRenamingFolderId] = useAtom(renamingFolderIdAtom); const handleStartRename = useCallback( @@ -157,6 +159,8 @@ export function FolderTreeView({ onDropIntoFolder={onDropIntoFolder} onReorderFolder={onReorderFolder} siblingPositions={siblingPositions} + contextMenuOpen={openContextMenuId === `folder-${f.id}`} + onContextMenuOpenChange={(open) => setOpenContextMenuId(open ? `folder-${f.id}` : null)} /> ); @@ -177,6 +181,8 @@ export function FolderTreeView({ onEdit={onEditDocument} onDelete={onDeleteDocument} onMove={onMoveDocument} + contextMenuOpen={openContextMenuId === `doc-${d.id}`} + onContextMenuOpenChange={(open) => setOpenContextMenuId(open ? `doc-${d.id}` : null)} /> ); }