Some checks failed
ci/woodpecker/push/web Pipeline failed
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
242 lines
5.4 KiB
TypeScript
242 lines
5.4 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import type { ReactElement } from "react";
|
|
import { Card, SectionHeader, Badge, Dot } from "@mosaic/ui";
|
|
|
|
interface AgentNode {
|
|
id: string;
|
|
initials: string;
|
|
avatarColor: string;
|
|
name: string;
|
|
task: string;
|
|
status: "teal" | "blue" | "amber" | "red" | "muted";
|
|
}
|
|
|
|
interface OrchestratorSession {
|
|
id: string;
|
|
orchId: string;
|
|
name: string;
|
|
badge: string;
|
|
badgeVariant:
|
|
| "badge-teal"
|
|
| "badge-amber"
|
|
| "badge-red"
|
|
| "badge-blue"
|
|
| "badge-muted"
|
|
| "badge-purple"
|
|
| "badge-pulse";
|
|
duration: string;
|
|
agents: AgentNode[];
|
|
}
|
|
|
|
const sessions: OrchestratorSession[] = [
|
|
{
|
|
id: "s1",
|
|
orchId: "ORCH-001",
|
|
name: "infra-refactor",
|
|
badge: "running",
|
|
badgeVariant: "badge-teal",
|
|
duration: "2h 14m",
|
|
agents: [
|
|
{
|
|
id: "a1",
|
|
initials: "PL",
|
|
avatarColor: "rgba(47,128,255,0.15)",
|
|
name: "planner-agent",
|
|
task: "Analyzing network topology",
|
|
status: "blue",
|
|
},
|
|
{
|
|
id: "a2",
|
|
initials: "EX",
|
|
avatarColor: "rgba(20,184,166,0.15)",
|
|
name: "executor-agent",
|
|
task: "Applying Terraform modules",
|
|
status: "teal",
|
|
},
|
|
{
|
|
id: "a3",
|
|
initials: "QA",
|
|
avatarColor: "rgba(245,158,11,0.15)",
|
|
name: "reviewer-agent",
|
|
task: "Waiting for executor output",
|
|
status: "amber",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: "s2",
|
|
orchId: "ORCH-002",
|
|
name: "api-v3-migration",
|
|
badge: "running",
|
|
badgeVariant: "badge-teal",
|
|
duration: "45m",
|
|
agents: [
|
|
{
|
|
id: "a4",
|
|
initials: "MG",
|
|
avatarColor: "rgba(139,92,246,0.15)",
|
|
name: "migrator-agent",
|
|
task: "Rewriting endpoint handlers",
|
|
status: "blue",
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
interface AgentNodeItemProps {
|
|
agent: AgentNode;
|
|
}
|
|
|
|
function AgentNodeItem({ agent }: AgentNodeItemProps): ReactElement {
|
|
const [hovered, setHovered] = useState(false);
|
|
|
|
return (
|
|
<div
|
|
onMouseEnter={(): void => {
|
|
setHovered(true);
|
|
}}
|
|
onMouseLeave={(): void => {
|
|
setHovered(false);
|
|
}}
|
|
style={{
|
|
display: "flex",
|
|
alignItems: "center",
|
|
gap: 10,
|
|
padding: "7px 10px",
|
|
borderRadius: "var(--r-sm)",
|
|
border: `1px solid ${hovered ? "var(--ms-border-700)" : "var(--border)"}`,
|
|
background: hovered ? "var(--surface)" : "var(--bg-mid)",
|
|
transition: "border-color 0.15s, background 0.15s",
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
width: 30,
|
|
height: 30,
|
|
borderRadius: 6,
|
|
flexShrink: 0,
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
fontWeight: 700,
|
|
fontFamily: "var(--mono)",
|
|
fontSize: "0.7rem",
|
|
background: agent.avatarColor,
|
|
color: "var(--text)",
|
|
}}
|
|
>
|
|
{agent.initials}
|
|
</div>
|
|
<div style={{ flex: 1, minWidth: 0 }}>
|
|
<div
|
|
style={{
|
|
fontSize: "0.8rem",
|
|
fontWeight: 600,
|
|
color: "var(--text)",
|
|
whiteSpace: "nowrap",
|
|
overflow: "hidden",
|
|
textOverflow: "ellipsis",
|
|
}}
|
|
>
|
|
{agent.name}
|
|
</div>
|
|
<div
|
|
style={{
|
|
fontSize: "0.72rem",
|
|
color: "var(--muted)",
|
|
whiteSpace: "nowrap",
|
|
overflow: "hidden",
|
|
textOverflow: "ellipsis",
|
|
}}
|
|
>
|
|
{agent.task}
|
|
</div>
|
|
</div>
|
|
<Dot variant={agent.status} />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
interface OrchCardProps {
|
|
session: OrchestratorSession;
|
|
}
|
|
|
|
function OrchCard({ session }: OrchCardProps): ReactElement {
|
|
return (
|
|
<div
|
|
style={{
|
|
background: "var(--bg-mid)",
|
|
border: "1px solid var(--border)",
|
|
borderRadius: "var(--r-md)",
|
|
padding: "12px 14px",
|
|
marginBottom: 10,
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
alignItems: "center",
|
|
gap: 8,
|
|
marginBottom: 10,
|
|
}}
|
|
>
|
|
<Dot variant="teal" />
|
|
<span
|
|
style={{
|
|
fontFamily: "var(--mono)",
|
|
fontSize: "0.75rem",
|
|
color: "var(--ms-purple-400)",
|
|
fontWeight: 700,
|
|
}}
|
|
>
|
|
{session.orchId}
|
|
</span>
|
|
<span
|
|
style={{
|
|
fontSize: "0.8rem",
|
|
fontWeight: 600,
|
|
color: "var(--text)",
|
|
}}
|
|
>
|
|
{session.name}
|
|
</span>
|
|
<Badge variant={session.badgeVariant}>{session.badge}</Badge>
|
|
<span
|
|
style={{
|
|
marginLeft: "auto",
|
|
fontSize: "0.72rem",
|
|
fontFamily: "var(--mono)",
|
|
color: "var(--muted)",
|
|
}}
|
|
>
|
|
{session.duration}
|
|
</span>
|
|
</div>
|
|
<div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
|
|
{session.agents.map((agent) => (
|
|
<AgentNodeItem key={agent.id} agent={agent} />
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function OrchestratorSessions(): ReactElement {
|
|
return (
|
|
<Card>
|
|
<SectionHeader
|
|
title="Active Orchestrator Sessions"
|
|
subtitle="3 of 8 projects running"
|
|
actions={<Badge variant="badge-teal">3 active</Badge>}
|
|
/>
|
|
<div>
|
|
{sessions.map((session) => (
|
|
<OrchCard key={session.id} session={session} />
|
|
))}
|
|
</div>
|
|
</Card>
|
|
);
|
|
}
|