mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-16 19:00:38 +09:00
80 lines
2.8 KiB
TypeScript
80 lines
2.8 KiB
TypeScript
|
|
import { useState } from "react";
|
||
|
|
import { NavLink, useLocation } from "react-router-dom";
|
||
|
|
import { useQuery } from "@tanstack/react-query";
|
||
|
|
import { ChevronRight } from "lucide-react";
|
||
|
|
import { useCompany } from "../context/CompanyContext";
|
||
|
|
import { useSidebar } from "../context/SidebarContext";
|
||
|
|
import { agentsApi } from "../api/agents";
|
||
|
|
import { queryKeys } from "../lib/queryKeys";
|
||
|
|
import { cn } from "../lib/utils";
|
||
|
|
import { AgentIcon } from "./AgentIconPicker";
|
||
|
|
import {
|
||
|
|
Collapsible,
|
||
|
|
CollapsibleContent,
|
||
|
|
CollapsibleTrigger,
|
||
|
|
} from "@/components/ui/collapsible";
|
||
|
|
import type { Agent } from "@paperclip/shared";
|
||
|
|
|
||
|
|
export function SidebarAgents() {
|
||
|
|
const [open, setOpen] = useState(true);
|
||
|
|
const { selectedCompanyId } = useCompany();
|
||
|
|
const { isMobile, setSidebarOpen } = useSidebar();
|
||
|
|
const location = useLocation();
|
||
|
|
|
||
|
|
const { data: agents } = useQuery({
|
||
|
|
queryKey: queryKeys.agents.list(selectedCompanyId!),
|
||
|
|
queryFn: () => agentsApi.list(selectedCompanyId!),
|
||
|
|
enabled: !!selectedCompanyId,
|
||
|
|
});
|
||
|
|
|
||
|
|
const visibleAgents = (agents ?? []).filter(
|
||
|
|
(a: Agent) => a.status !== "terminated"
|
||
|
|
);
|
||
|
|
|
||
|
|
const agentMatch = location.pathname.match(/^\/agents\/([^/]+)/);
|
||
|
|
const activeAgentId = agentMatch?.[1] ?? null;
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Collapsible open={open} onOpenChange={setOpen}>
|
||
|
|
<div className="group">
|
||
|
|
<div className="flex items-center px-3 py-1.5">
|
||
|
|
<CollapsibleTrigger className="flex items-center gap-1 flex-1 min-w-0">
|
||
|
|
<ChevronRight
|
||
|
|
className={cn(
|
||
|
|
"h-3 w-3 text-muted-foreground/60 transition-transform opacity-0 group-hover:opacity-100",
|
||
|
|
open && "rotate-90"
|
||
|
|
)}
|
||
|
|
/>
|
||
|
|
<span className="text-[10px] font-medium uppercase tracking-widest font-mono text-muted-foreground/60">
|
||
|
|
Agents
|
||
|
|
</span>
|
||
|
|
</CollapsibleTrigger>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<CollapsibleContent>
|
||
|
|
<div className="flex flex-col gap-0.5 mt-0.5">
|
||
|
|
{visibleAgents.map((agent: Agent) => (
|
||
|
|
<NavLink
|
||
|
|
key={agent.id}
|
||
|
|
to={`/agents/${agent.id}`}
|
||
|
|
onClick={() => {
|
||
|
|
if (isMobile) setSidebarOpen(false);
|
||
|
|
}}
|
||
|
|
className={cn(
|
||
|
|
"flex items-center gap-2.5 px-3 py-1.5 text-[13px] font-medium transition-colors",
|
||
|
|
activeAgentId === agent.id
|
||
|
|
? "bg-accent text-foreground"
|
||
|
|
: "text-foreground/80 hover:bg-accent/50 hover:text-foreground"
|
||
|
|
)}
|
||
|
|
>
|
||
|
|
<AgentIcon icon={agent.icon} className="shrink-0 h-3.5 w-3.5 text-muted-foreground" />
|
||
|
|
<span className="flex-1 truncate">{agent.name}</span>
|
||
|
|
</NavLink>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</CollapsibleContent>
|
||
|
|
</Collapsible>
|
||
|
|
);
|
||
|
|
}
|