import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"; import { Button } from "@/components/ui/button"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Menu, LayoutDashboard, Plus, MoreVertical, User, Search, Wrench, Settings, Brain, Trash2, Pencil } from "lucide-react"; import { useState, useRef, useEffect } from "react"; import { Link, useNavigate, useLocation } from "react-router-dom"; import { useAuthStore } from "@/store/authStore"; import { api } from "@/lib/api"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; interface SessionInfo { key: string; created_at: string; updated_at: string; metadata?: { title?: string; }; } function Section({ title, count, items, onSelect, onDelete, onRename, activeKey }: { title: string; count: number; items: SessionInfo[]; onSelect: (key: string) => void; onDelete: (key: string) => void; onRename: (key: string, currentTitle: string) => void; activeKey: string | null; }) { return (
{title} ({count})
{items.map((item) => { const displayTitle = item.metadata?.title || item.key.replace("api:", ""); const isActive = activeKey === item.key; return (
onSelect(item.key)} > {displayTitle} e.stopPropagation()} className="h-6 w-6 flex items-center justify-center rounded hover:bg-zinc-200 text-zinc-400 opacity-0 group-hover:opacity-100 transition-opacity outline-none"> { e.stopPropagation(); onRename(item.key, displayTitle); }}> 重命名 { e.stopPropagation(); onDelete(item.key); }} className="text-red-600 focus:text-red-600 focus:bg-red-50"> 删除会话
); })}
); } function SidebarBody() { const navigate = useNavigate(); const location = useLocation(); const { user, logout } = useAuthStore(); const [showUserMenu, setShowUserMenu] = useState(false); const menuRef = useRef(null); // Session management state const [sessions, setSessions] = useState([]); const [renameDialogOpen, setRenameDialogOpen] = useState(false); const [sessionToRename, setSessionToRename] = useState<{key: string, title: string} | null>(null); const [newTitle, setNewTitle] = useState(""); // Try to parse active session from URL query const queryParams = new URLSearchParams(location.search); const activeSessionKey = queryParams.get("session") || "api:default"; const fetchSessions = async () => { try { const data = await api.get("/nanobot/sessions"); setSessions(data); } catch (e) { console.error("Failed to fetch sessions", e); } }; useEffect(() => { fetchSessions(); // Set up polling to refresh session list const interval = setInterval(fetchSessions, 5000); return () => clearInterval(interval); }, []); useEffect(() => { function handleClickOutside(event: MouseEvent) { if (menuRef.current && !menuRef.current.contains(event.target as Node)) { setShowUserMenu(false); } } document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); }, []); const handleLogout = () => { logout(); navigate("/login"); }; const handleSelectSession = (key: string) => { navigate(`/?session=${encodeURIComponent(key)}`); }; const handleNewThread = () => { const newSessionId = `api:${Date.now()}`; navigate(`/?session=${encodeURIComponent(newSessionId)}`); }; const handleDeleteSession = async (key: string) => { if (!window.confirm("确定要删除这个会话吗?")) return; try { await api.delete(`/nanobot/sessions/${key}`); if (activeSessionKey === key) { navigate("/"); } fetchSessions(); } catch (e) { console.error("Failed to delete session", e); } }; const openRenameDialog = (key: string, currentTitle: string) => { setSessionToRename({ key, title: currentTitle }); setNewTitle(currentTitle); setRenameDialogOpen(true); }; const handleRename = async () => { if (!sessionToRename || !newTitle.trim()) return; try { await api.put(`/nanobot/sessions/${sessionToRename.key}`, { title: newTitle.trim() }); setRenameDialogOpen(false); fetchSessions(); } catch (e) { console.error("Failed to rename session", e); } }; return (
{/* Header */}
🦞 龙虾问数
重命名会话
setNewTitle(e.target.value)} placeholder="输入新的会话标题" autoFocus onKeyDown={(e) => { if (e.key === 'Enter') { handleRename(); } }} />
{/* User Settings Popover Menu */} {showUserMenu && (

{user?.username}

{user?.email}

{user?.is_admin && ( <> )}
)}
); } export function Sidebar() { const [isOpen, setIsOpen] = useState(false); return ( <> } />
); }