fix(agent-team): address UI review (column flex height, ARIA, token consistency)

Fresh-context deep review verdict was SHIP-WITH-FIXES (all hard constraints held:
read-only, inert gate panel, XSS posture, no backend, gate-vs-inert semantics).
Resolved:
- Board columns: replace magic calc(100vh-220px) ScrollArea cap with a proper
  flex chain (h-full/min-h-0) so card lists size to real column height at any
  window size / wrapped toolbar.
- Valid ARIA: stage row is role=list, each column a role=listitem wrapping a
  role=listbox of task-card options (no malformed listbox nesting).
- TopBar health dot uses status-active/status-failed tokens (no hardcoded Tailwind
  palette colors).
- Stale TaskList reference in badge.tsx comment.

Typecheck + 36 tests + build all green.
This commit is contained in:
Adam Moussa 2026-06-24 13:50:00 -04:00
parent bf5d259dfd
commit 751a6787f6
3 changed files with 16 additions and 10 deletions

View file

@ -187,12 +187,12 @@ export function Board({
)}
</div>
{/* Kanban columns — horizontal scroll */}
{/* Kanban columns — horizontal scroll. Each column is its own listbox of
task cards (valid ARIA nesting), so this row is just a labelled list. */}
<div
className="flex gap-3 overflow-x-auto pb-2 flex-1 min-h-0 px-1"
role="listbox"
role="list"
aria-label="pipeline stages"
aria-multiselectable="false"
>
{filteredStages.map((stage) => (
<KanbanColumn
@ -229,9 +229,10 @@ function KanbanColumn({ stage, topology, selectedId, onSelect }: ColumnProps) {
return (
<div
className={cn(
"flex flex-col gap-1.5 w-52 shrink-0 rounded-lg bg-muted/40 border border-border p-2",
"flex h-full min-h-0 w-52 shrink-0 flex-col gap-1.5 rounded-lg border border-border bg-muted/40 p-2",
inert && "opacity-60",
)}
role="listitem"
aria-label={`Stage: ${stage.label}`}
>
{/* Column header */}
@ -262,9 +263,14 @@ function KanbanColumn({ stage, topology, selectedId, onSelect }: ColumnProps) {
</div>
</div>
{/* Task cards — scrollable vertically */}
<ScrollArea className="flex-1" style={{ maxHeight: "calc(100vh - 220px)" }}>
<div className="flex flex-col gap-1.5 pr-1">
{/* Task cards — scrollable vertically. flex-1 + min-h-0 lets the list cap
at the real column height (no magic viewport math). */}
<ScrollArea className="min-h-0 flex-1">
<div
className="flex flex-col gap-1.5 pr-1"
role="listbox"
aria-label={`${stage.label} tasks`}
>
{stage.tasks.length === 0 ? (
<p className="text-xs text-muted-foreground py-3 text-center">—</p>
) : (

View file

@ -112,8 +112,8 @@ export function TopBar({ state, connected, generatedAt }: Props) {
className={cn(
"w-2.5 h-2.5 rounded-full",
connected
? "bg-green-500 shadow-[0_0_6px_2px_rgba(34,197,94,0.45)]"
: "bg-red-500",
? "bg-status-active shadow-[0_0_6px_2px_hsl(var(--status-active)/0.45)]"
: "bg-status-failed",
)}
/>
<span className="text-xs text-muted-foreground tabular-nums">

View file

@ -35,7 +35,7 @@ function Badge({ className, variant, ...props }: BadgeProps) {
/**
* Map a backend task status / verdict string to a Badge variant. Centralized so
* TaskCard, TaskList, and TaskDrawer agree on color.
* TaskCard, the Board, and TaskDrawer agree on color.
*/
export function statusVariant(
status: string,