43 lines
1.5 KiB
TypeScript
43 lines
1.5 KiB
TypeScript
|
|
import type { StateResponse } from "../api";
|
|||
|
|
|
|||
|
|
interface Props {
|
|||
|
|
state: StateResponse | null;
|
|||
|
|
connected: boolean;
|
|||
|
|
generatedAt: string | null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const CHIPS: Array<{ key: keyof StateResponse["summary"]; label: string; cls: string }> =
|
|||
|
|
[
|
|||
|
|
{ key: "active", label: "Active", cls: "active" },
|
|||
|
|
{ key: "waiting", label: "Awaiting human", cls: "waiting" },
|
|||
|
|
{ key: "parked", label: "Parked", cls: "parked" },
|
|||
|
|
{ key: "open_questions", label: "Open questions", cls: "open" },
|
|||
|
|
{ key: "total", label: "Total", cls: "total" },
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// Top status bar: summary chips, a connection/health dot, and the snapshot clock.
|
|||
|
|
export function TopBar({ state, connected, generatedAt }: Props) {
|
|||
|
|
const summary = state?.summary;
|
|||
|
|
return (
|
|||
|
|
<header className="topbar" role="banner">
|
|||
|
|
<div className="brand">
|
|||
|
|
<span className="brand-dot" aria-hidden />
|
|||
|
|
<span className="brand-name">agent-team</span>
|
|||
|
|
<span className="brand-sub">pipeline</span>
|
|||
|
|
</div>
|
|||
|
|
<div className="chips" role="list">
|
|||
|
|
{CHIPS.map((c) => (
|
|||
|
|
<div className={`chip chip-${c.cls}`} role="listitem" key={c.key}>
|
|||
|
|
<span className="chip-num">{summary ? summary[c.key] : "–"}</span>
|
|||
|
|
<span className="chip-lbl">{c.label}</span>
|
|||
|
|
</div>
|
|||
|
|
))}
|
|||
|
|
</div>
|
|||
|
|
<div className="health" title={connected ? "live" : "disconnected"}>
|
|||
|
|
<span className={`health-dot ${connected ? "ok" : "down"}`} aria-hidden />
|
|||
|
|
<span className="health-clock">{generatedAt ?? "—"}</span>
|
|||
|
|
</div>
|
|||
|
|
</header>
|
|||
|
|
);
|
|||
|
|
}
|