DesignX
Agent Ops@paxeer/agent-ops/agent-rosterimplemented

Agent roster

Selectable agent table with MD3 status chips.

Install

$pnpm exec designx add @paxeer/agent-ops/agent-roster

Preview

Loading preview...

Source code

components/designx/agent-ops/agent-roster.tsxtsx
"use client";

import {
  Card,
  CardContent,
  CardHeader,
  CardTitle,
  Empty,
  EmptyDescription,
  EmptyHeader,
  EmptyTitle,
  StatusChip,
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
  cn,
} from "@paxeer/core";

export type AgentStatus = "idle" | "running" | "blocked" | "offline";

export interface AgentRecord {
  id: string;
  name: string;
  role: string;
  status: AgentStatus;
  lastBeat: string;
}

export interface AgentRosterProps {
  agents: AgentRecord[];
  selectedId?: string;
  onSelect?: (agent: AgentRecord) => void;
}

const statusTone: Record<AgentStatus, "surface" | "primary" | "error" | "secondary"> = {
  idle: "secondary",
  running: "primary",
  blocked: "error",
  offline: "surface",
};

export function AgentRoster({ agents, selectedId, onSelect }: AgentRosterProps) {
  return (
    <Card className="gap-0 py-0 overflow-hidden" data-slot="agent-roster">
      <CardHeader className="border-b border-outline-variant px-3 py-2">
        <CardTitle className="text-[length:var(--md-sys-typescale-label-large-size)]">
          Agent roster
        </CardTitle>
      </CardHeader>
      <CardContent className="p-0">
        {agents.length === 0 ? (
          <Empty className="p-6">
            <EmptyHeader>
              <EmptyTitle>No agents</EmptyTitle>
              <EmptyDescription>No agents registered in this workspace.</EmptyDescription>
            </EmptyHeader>
          </Empty>
        ) : (
          <Table>
            <TableHeader>
              <TableRow>
                <TableHead>Agent</TableHead>
                <TableHead>Status</TableHead>
                <TableHead>Beat</TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {agents.map((agent) => {
                const selected = agent.id === selectedId;
                return (
                  <TableRow
                    key={agent.id}
                    data-state={selected ? "selected" : undefined}
                    className={cn("cursor-pointer")}
                    onClick={() => onSelect?.(agent)}
                  >
                    <TableCell>
                      <div className="flex flex-col">
                        <span>{agent.name}</span>
                        <span className="text-on-surface-variant">{agent.role}</span>
                      </div>
                    </TableCell>
                    <TableCell>
                      <StatusChip tone={statusTone[agent.status]} dot>
                        {agent.status}
                      </StatusChip>
                    </TableCell>
                    <TableCell className="font-[family-name:var(--md-ref-typeface-mono)] text-on-surface-variant">
                      {agent.lastBeat}
                    </TableCell>
                  </TableRow>
                );
              })}
            </TableBody>
          </Table>
        )}
      </CardContent>
    </Card>
  );
}