feat: add project-aware agent workspace
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
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} />
|
||||
</>;
|
||||
}
|
||||
Reference in New Issue
Block a user