From 5b8bb388dbd826c15a6800bdbb455eba84e2dd3c Mon Sep 17 00:00:00 2001 From: mlogclub Date: Tue, 2 Jun 2026 16:17:20 +0800 Subject: [PATCH] feat: add context menu functionality to DirectoryNode for enhanced user interaction --- .../_components/knowledge-directory-panel.tsx | 157 +++++++++++------- 1 file changed, 99 insertions(+), 58 deletions(-) diff --git a/web/app/dashboard/knowledge/_components/knowledge-directory-panel.tsx b/web/app/dashboard/knowledge/_components/knowledge-directory-panel.tsx index 5e1c8fe..a68ad06 100644 --- a/web/app/dashboard/knowledge/_components/knowledge-directory-panel.tsx +++ b/web/app/dashboard/knowledge/_components/knowledge-directory-panel.tsx @@ -18,6 +18,12 @@ import { toast } from "sonner"; import { OptionCombobox } from "@/components/option-combobox"; import { ProjectDialog } from "@/components/project-dialog"; import { Button } from "@/components/ui/button"; +import { + ContextMenu, + ContextMenuContent, + ContextMenuItem, + ContextMenuTrigger, +} from "@/components/ui/context-menu"; import { DropdownMenu, DropdownMenuContent, @@ -80,6 +86,7 @@ export function KnowledgeDirectoryPanel({ const t = useI18n(); const [directories, setDirectories] = useState([]); const [expandedIds, setExpandedIds] = useState>(new Set()); + const [contextMenuDirectoryId, setContextMenuDirectoryId] = useState(null); const [loading, setLoading] = useState(false); const [saving, setSaving] = useState(false); const [dialog, setDialog] = useState({ @@ -230,9 +237,13 @@ export function KnowledgeDirectoryPanel({ depth={0} expandedIds={expandedIds} selectedDirectoryId={selectedDirectoryId} + contextMenuDirectoryId={contextMenuDirectoryId} saving={saving} onToggle={toggleDirectory} onSelect={onSelectDirectory} + onContextMenuOpenChange={(directoryId, open) => + setContextMenuDirectoryId(open ? directoryId : null) + } onCreate={openCreate} onEdit={openEdit} onDelete={(directory) => void handleDelete(directory)} @@ -339,9 +350,11 @@ type DirectoryNodeProps = { depth: number; expandedIds: Set; selectedDirectoryId: number | null; + contextMenuDirectoryId: number | null; saving: boolean; onToggle: (id: number) => void; onSelect: (id: number) => void; + onContextMenuOpenChange: (id: number, open: boolean) => void; onCreate: (parentId: number) => void; onEdit: (item: KnowledgeDirectory) => void; onDelete: (item: KnowledgeDirectory) => void; @@ -355,9 +368,11 @@ function DirectoryNode({ depth, expandedIds, selectedDirectoryId, + contextMenuDirectoryId, saving, onToggle, onSelect, + onContextMenuOpenChange, onCreate, onEdit, onDelete, @@ -365,69 +380,93 @@ function DirectoryNode({ }: DirectoryNodeProps) { const expanded = expandedIds.has(item.id); const hasChildren = (item.children || []).length > 0; + const active = selectedDirectoryId === item.id || contextMenuDirectoryId === item.id; return (
-
- - - - - - } - aria-label={t("knowledge.moreActions", { name: item.name })} + onContextMenuOpenChange(item.id, open)}> + +
- - - - {item.parentId === 0 ? ( - onCreate(item.id)}> - - {t("knowledge.createSubDirectory")} - - ) : null} - onEdit(item)}> - - {t("knowledge.edit")} - - onDelete(item)} - className="text-destructive focus:text-destructive" +
+ {expanded ? : } + + + + + + } + aria-label={t("knowledge.moreActions", { name: item.name })} + > + + + + {item.parentId === 0 ? ( + onCreate(item.id)}> + + {t("knowledge.createSubDirectory")} + + ) : null} + onEdit(item)}> + + {t("knowledge.edit")} + + onDelete(item)} + className="text-destructive focus:text-destructive" + > + + {t("knowledge.delete")} + + + +
+ + + {item.parentId === 0 ? ( + onCreate(item.id)}> + + {t("knowledge.createSubDirectory")} + + ) : null} + onEdit(item)}> + + {t("knowledge.edit")} + + onDelete(item)} + variant="destructive" + > + + {t("knowledge.delete")} + + + {expanded ? (item.children || []).map((child) => (