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:
parent
bf5d259dfd
commit
751a6787f6
3 changed files with 16 additions and 10 deletions
|
|
@ -187,12 +187,12 @@ export function Board({
|
||||||
)}
|
)}
|
||||||
</div>
|
</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
|
<div
|
||||||
className="flex gap-3 overflow-x-auto pb-2 flex-1 min-h-0 px-1"
|
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-label="pipeline stages"
|
||||||
aria-multiselectable="false"
|
|
||||||
>
|
>
|
||||||
{filteredStages.map((stage) => (
|
{filteredStages.map((stage) => (
|
||||||
<KanbanColumn
|
<KanbanColumn
|
||||||
|
|
@ -229,9 +229,10 @@ function KanbanColumn({ stage, topology, selectedId, onSelect }: ColumnProps) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
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",
|
inert && "opacity-60",
|
||||||
)}
|
)}
|
||||||
|
role="listitem"
|
||||||
aria-label={`Stage: ${stage.label}`}
|
aria-label={`Stage: ${stage.label}`}
|
||||||
>
|
>
|
||||||
{/* Column header */}
|
{/* Column header */}
|
||||||
|
|
@ -262,9 +263,14 @@ function KanbanColumn({ stage, topology, selectedId, onSelect }: ColumnProps) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Task cards — scrollable vertically */}
|
{/* Task cards — scrollable vertically. flex-1 + min-h-0 lets the list cap
|
||||||
<ScrollArea className="flex-1" style={{ maxHeight: "calc(100vh - 220px)" }}>
|
at the real column height (no magic viewport math). */}
|
||||||
<div className="flex flex-col gap-1.5 pr-1">
|
<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 ? (
|
{stage.tasks.length === 0 ? (
|
||||||
<p className="text-xs text-muted-foreground py-3 text-center">—</p>
|
<p className="text-xs text-muted-foreground py-3 text-center">—</p>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
||||||
|
|
@ -112,8 +112,8 @@ export function TopBar({ state, connected, generatedAt }: Props) {
|
||||||
className={cn(
|
className={cn(
|
||||||
"w-2.5 h-2.5 rounded-full",
|
"w-2.5 h-2.5 rounded-full",
|
||||||
connected
|
connected
|
||||||
? "bg-green-500 shadow-[0_0_6px_2px_rgba(34,197,94,0.45)]"
|
? "bg-status-active shadow-[0_0_6px_2px_hsl(var(--status-active)/0.45)]"
|
||||||
: "bg-red-500",
|
: "bg-status-failed",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<span className="text-xs text-muted-foreground tabular-nums">
|
<span className="text-xs text-muted-foreground tabular-nums">
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ function Badge({ className, variant, ...props }: BadgeProps) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map a backend task status / verdict string to a Badge variant. Centralized so
|
* 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(
|
export function statusVariant(
|
||||||
status: string,
|
status: string,
|
||||||
|
|
|
||||||
Reference in a new issue