import { useState } from "react"; import { useNavigate } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; import { LayoutTemplate, Cpu, Package } from "lucide-react"; import { Badge, Button, Card, Input, Spinner } from "@/components/ui"; import { templatesApi, type TemplateDetail, type TemplateSummary } from "@/api/templates"; import { agentsApi } from "@/api/agents"; import { apiErrorMessage } from "@/api/client"; import { useAuthStore } from "@/store/auth"; import { toast } from "sonner"; const selectClass = "w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm dark:border-slate-600 dark:bg-slate-800"; export function Templates() { const isAdmin = useAuthStore((s) => s.user?.role === "admin"); const [selected, setSelected] = useState(null); const { data, isLoading } = useQuery({ queryKey: ["templates"], queryFn: templatesApi.list }); const open = async (t: TemplateSummary) => { try { setSelected(await templatesApi.get(t.id)); } catch (e) { toast.error(apiErrorMessage(e)); } }; if (isLoading) return ; return (
{data?.map((t) => (
{t.source === "custom" ? ( ) : ( )} {t.name} {t.source === "custom" && custom}
{t.description &&

{t.description}

}
{t.tags.map((tag) => ( {tag} ))} {t.gpu && ( {t.gpu} )}
{isAdmin && ( )}
))}
{selected && ( setSelected(null)} /> )}
); } function UseTemplateDialog({ template, onClose, }: { template: TemplateDetail; onClose: () => void; }) { const navigate = useNavigate(); const [name, setName] = useState(template.name); const [values, setValues] = useState>( Object.fromEntries(template.variables.map((v) => [v.name, v.default])) ); const [host, setHost] = useState("local"); const [busy, setBusy] = useState(false); const agents = useQuery({ queryKey: ["agents"], queryFn: () => agentsApi.list() }); const onlineAgents = (agents.data ?? []).filter((a) => a.status === "online"); const create = async () => { if (!name.trim()) { toast.error("Stack name required"); return; } setBusy(true); try { const agentId = host === "local" ? null : Number(host); const res = await templatesApi.instantiate(template.id, name, values, agentId); toast.success(`Stack '${res.name}' created`); if (res.agent_id != null) navigate(`/hosts/${res.agent_id}/stacks/${res.id}`); else navigate(`/stacks/${res.id}/edit`); } catch (e) { toast.error(apiErrorMessage(e)); } finally { setBusy(false); } }; return (

Use “{template.name}”

{onlineAgents.length > 0 && ( )} {template.variables.map((v) => ( ))}
); }