56 lines
3.6 KiB
TypeScript
56 lines
3.6 KiB
TypeScript
import { ChevronsUpDown, Folder, FolderPlus, Settings2 } from "lucide-react";
|
|
import { useRef, useState } from "react";
|
|
import type { AgentTopic } from "../api/client";
|
|
import { Button } from "@/shared/ui/button";
|
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/shared/ui/dropdown-menu";
|
|
|
|
import { AgentTopicDialog } from "./agent-topic-dialog";
|
|
|
|
export type AgentTopicControlsProps = {
|
|
topics: AgentTopic[];
|
|
topicId?: string | null;
|
|
loading?: boolean;
|
|
error?: string;
|
|
onOpen: () => Promise<unknown>;
|
|
onSelect: (id: string | null) => void;
|
|
onCreate: (name: string) => Promise<unknown>;
|
|
onRename: (id: string, name: string) => Promise<unknown>;
|
|
onDelete: (id: string) => Promise<unknown>;
|
|
};
|
|
|
|
export function AgentTopicControls({ topics, topicId, loading, error, onOpen, onSelect, onCreate, onRename, onDelete }: AgentTopicControlsProps) {
|
|
const triggerRef = useRef<HTMLButtonElement>(null);
|
|
const [open, setOpen] = useState(false);
|
|
const [mode, setMode] = useState<"create" | "manage">("create");
|
|
const [dialogKey, setDialogKey] = useState(0);
|
|
const current = topics.find((topic) => topic.id === topicId);
|
|
const begin = (next: "create" | "manage") => {
|
|
setMode(next);
|
|
setDialogKey((key) => key + 1);
|
|
setOpen(true);
|
|
};
|
|
return <>
|
|
<DropdownMenu onOpenChange={(next) => { if (next) void onOpen().catch(() => {}); }}>
|
|
<DropdownMenuTrigger asChild><Button ref={triggerRef} variant="outline" size="sm" aria-label="选择主题" aria-description={current?.name ?? "未分类"} title={`主题:${current?.name ?? "未分类"}`} className="min-w-0 max-w-full justify-start gap-1.5 px-1.5 text-xs font-medium text-foreground">
|
|
<Folder aria-hidden="true" className="text-muted-foreground" /><span className="truncate">{current?.name ?? "未分类"}</span><ChevronsUpDown aria-hidden="true" className="ml-auto text-muted-foreground" />
|
|
</Button></DropdownMenuTrigger>
|
|
<DropdownMenuContent data-agent-theme="chat" align="start" side="bottom" className="w-[var(--radix-dropdown-menu-trigger-width)] min-w-56 max-w-[min(20rem,calc(100vw-1rem))]">
|
|
<DropdownMenuLabel className="text-xs font-normal text-muted-foreground">切换主题</DropdownMenuLabel>
|
|
<DropdownMenuRadioGroup value={current?.id ?? "unclassified"} onValueChange={(id) => onSelect(id === "unclassified" ? null : id)} className="max-h-[min(45dvh,15rem)] overflow-y-auto">
|
|
<DropdownMenuRadioItem value="unclassified">未分类</DropdownMenuRadioItem>
|
|
{topics.map((topic) => <DropdownMenuRadioItem key={topic.id} value={topic.id}>
|
|
<span className="min-w-0 line-clamp-2 break-words" title={topic.name}>{topic.name}</span>
|
|
</DropdownMenuRadioItem>)}
|
|
</DropdownMenuRadioGroup>
|
|
{loading ? <p role="status" className="px-2 py-2 text-xs text-muted-foreground">正在加载主题…</p> : null}
|
|
{error ? <p role="alert" className="px-2 py-2 text-xs text-destructive">{error}</p> : null}
|
|
<DropdownMenuSeparator className="bg-border/50" />
|
|
<DropdownMenuItem onSelect={() => begin("create")}><FolderPlus size={15} />新建主题</DropdownMenuItem>
|
|
<DropdownMenuItem onSelect={() => begin("manage")}><Settings2 size={15} />管理主题</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
<AgentTopicDialog key={dialogKey} open={open} initialMode={mode} onOpenChange={setOpen} triggerRef={triggerRef}
|
|
topics={topics} onCreate={onCreate} onRename={onRename} onDelete={onDelete} />
|
|
</>;
|
|
}
|