// — the agent detail panel from `/agents`, in a dialog, for // a page that is already showing the agent's terminal and should not be left // to read or change its details. It carries the same body (`AgentDetail`) and // the same actions (`useAgentActions`) as the panel, minus the terminal // preview the page itself already is. // // The row comes from `GET /api/agents/status` when the dialog opens, found by // name: the panel on `/agents` has the whole roster in hand, this page does // not. A wanted-state change patches the row in place from the PUT's answer. import { useEffect, useState } from "preact/hooks"; import { ApiErrorPanel } from "@hive/shared/api-error-panel.js"; import { readApiError, type ProblemDetails } from "@hive/shared/api-error.js"; import { Dialog } from "../../ui/dialog/Dialog.js"; import { Panel } from "../../ui/panel/Panel.js"; import { useAgentActions } from "./AgentActions.js"; import { AgentDetail } from "./AgentDetail.js"; import type { AgentRow } from "./AgentTypes.js"; export function AgentDetailDialog({ agent, open, onClose, }: { agent: string; open: boolean; onClose: () => void; }) { // `undefined` until the roster has answered; `null` when it has and the // agent is not in it. const [row, setRow] = useState(undefined); const [error, setError] = useState(null); const actions = useAgentActions((declaredRow, declared) => { const state = declared.find((d) => d.agent === declaredRow.name)?.state; if (state !== undefined) { setRow((prev) => (prev ? { ...prev, wanted: state } : prev)); } }); // Fetched on each open, so what the dialog shows is current rather than // what the page last saw. useEffect(() => { if (!open) return; let cancelled = false; (async () => { const res = await fetch("/api/agents/status"); if (!res.ok) { if (!cancelled) setError(await readApiError(res)); return; } const rows = (await res.json()) as AgentRow[]; if (cancelled) return; setRow(rows.find((r) => r.name === agent) ?? null); setError(null); })().catch((e: unknown) => { if (!cancelled) setError({ detail: String(e) }); }); return () => { cancelled = true; }; }, [open, agent]); return ( <> {open ? ( {error ? ( ) : row ? ( ) : row === null ? (

{agent} is not in the swarm's agent roster

) : (

loading…

)}
) : null}
{actions.dialogs} ); }