From 4becfe84527f9d5b9c6ca6aa53369dae6dbac95a Mon Sep 17 00:00:00 2001 From: Lukas May Date: Wed, 4 Feb 2026 21:32:56 +0100 Subject: [PATCH] feat(18-02): create TaskRow component MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renders a single task row with Unicode tree connectors (├── / └──), StatusBadge, inline agent name, and DependencyIndicator for blocked tasks. Entire row is clickable with hover feedback. --- packages/web/src/components/TaskRow.tsx | 73 +++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 packages/web/src/components/TaskRow.tsx diff --git a/packages/web/src/components/TaskRow.tsx b/packages/web/src/components/TaskRow.tsx new file mode 100644 index 0000000..90ea692 --- /dev/null +++ b/packages/web/src/components/TaskRow.tsx @@ -0,0 +1,73 @@ +import { StatusBadge } from "@/components/StatusBadge"; +import { DependencyIndicator } from "@/components/DependencyIndicator"; +import { cn } from "@/lib/utils"; + +/** Task shape as returned by tRPC (Date fields serialized to string over JSON) */ +export interface SerializedTask { + id: string; + planId: string; + name: string; + description: string | null; + type: string; + priority: string; + status: string; + order: number; + createdAt: string; + updatedAt: string; +} + +interface TaskRowProps { + task: SerializedTask; + agentName: string | null; + blockedBy: Array<{ name: string; status: string }>; + isLast: boolean; + onClick: () => void; +} + +export function TaskRow({ + task, + agentName, + blockedBy, + isLast, + onClick, +}: TaskRowProps) { + const connector = isLast ? "└──" : "├──"; + + return ( +
+ {/* Task row */} +
+ {/* Tree connector */} + + {connector} + + + {/* Task name */} + {task.name} + + {/* Agent assignment */} + {agentName && ( + [{agentName}] + )} + + {/* Status badge */} + +
+ + {/* Dependency indicator below the row */} + {blockedBy.length > 0 && ( + + )} +
+ ); +}