--- phase: 18-initiative-detail plan: 02 type: execute wave: 1 depends_on: [] files_modified: - packages/web/src/components/PhaseAccordion.tsx - packages/web/src/components/TaskRow.tsx - packages/web/src/components/DependencyIndicator.tsx autonomous: true --- Create PhaseAccordion, TaskRow, and DependencyIndicator components for the initiative detail hierarchy view. Purpose: The core of the detail page — renders the phase → task tree with expand/collapse, status indicators, agent assignments, and dependency annotations. The UI flattens the Phase → Plan → Task hierarchy by hiding the Plan layer (per decision 15-02). Output: Three interconnected components ready for page assembly in Plan 04. @~/.claude/get-shit-done/workflows/execute-plan.md @~/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md # Wireframe spec — the primary reference for this plan @docs/wireframes/initiative-detail.md # Prior phase components to follow patterns @packages/web/src/components/StatusBadge.tsx @packages/web/src/components/ProgressBar.tsx @packages/web/src/components/InitiativeCard.tsx # tRPC client and existing types @packages/web/src/lib/trpc.ts @packages/shared/src/types.ts # tRPC router — need to understand listPlans, listTasks, getPhaseDependencies signatures @src/trpc/router.ts Task 1: Create DependencyIndicator component packages/web/src/components/DependencyIndicator.tsx Create a component that renders dependency annotations for blocked tasks/phases. Props interface: - `blockedBy`: `Array<{ name: string; status: string }>` — the items blocking this one - `type`: `'task' | 'phase'` — for display text Layout (matching wireframe): - Renders a line with `^` prefix and text: "blocked by: {name1}, {name2}" - Text is muted/orange color (`text-orange-500` or `text-amber-600`) - Indented to align with parent tree structure (use `pl-8` or similar) - If `blockedBy` is empty, render nothing (return null) This is a pure presentational component. npx tsc --noEmit -p packages/web/tsconfig.app.json passes DependencyIndicator renders blocked-by annotations with ^ prefix. Compiles cleanly. Task 2: Create TaskRow component packages/web/src/components/TaskRow.tsx Create a component for a single task row in the phase tree. Props interface: - `task`: serialized Task object from tRPC (`{ id, name, status, type, priority, order }` — dates are strings) - `agentName`: `string | null` — agent assigned to this task (if any) - `blockedBy`: `Array<{ name: string; status: string }>` — blocking dependencies - `isLast`: `boolean` — whether this is the last sibling (affects tree connector) - `onClick`: `() => void` — opens task detail modal Layout (matching wireframe): - Row with tree connector: `|--` for siblings, `+--` for last item (use `├──` and `└──` Unicode) - Task name as main text - StatusBadge showing task status (reuse existing component) - If `agentName` is set, show `[agentName]` inline in blue/muted text - If `blockedBy` has items, render DependencyIndicator below the row (indented) - Entire row is clickable (calls `onClick`) - Use hover state: `hover:bg-accent` for clickability feedback Tree connectors: Use a left-side border or pseudo-element pattern. Keep it simple — a `border-l-2` on a wrapper div with connector characters as inline text. Do NOT add "Spawn Agent" button yet — that comes in Plan 04 with queue actions. npx tsc --noEmit -p packages/web/tsconfig.app.json passes TaskRow renders task with tree connectors, status badge, agent name, and dependency indicator. Compiles cleanly. Task 3: Create PhaseAccordion component packages/web/src/components/PhaseAccordion.tsx Create an expandable/collapsible phase container that holds TaskRow components. Props interface: - `phase`: serialized Phase object (`{ id, number, name, status, description }`) - `tasks`: `Array<{ task: SerializedTask; agentName: string | null; blockedBy: Array<{ name: string; status: string }> }>` — tasks with their metadata, already fetched and assembled by parent - `defaultExpanded`: `boolean` — whether to start expanded - `onTaskClick`: `(taskId: string) => void` — callback when a task row is clicked Behavior (matching wireframe): - Header row: `v`/`>` expand indicator (use `ChevronDown`/`ChevronRight` from lucide-react), phase number + name, task count `(completed/total)`, and StatusBadge for phase status - Click header to toggle expand/collapse (internal state with `useState`, initialized from `defaultExpanded`) - When expanded, render all tasks as TaskRow components - Phase with status 'blocked' shows DependencyIndicator below header (needs additional prop `phaseDependencies`: `Array<{ name: string; status: string }>`) Add `phaseDependencies` prop: `Array<{ name: string; status: string }>` — for phase-level blocked-by display. Use Tailwind for styling. Border-bottom between phases for visual separation. npx tsc --noEmit -p packages/web/tsconfig.app.json passes PhaseAccordion renders expandable phase with task list, status, and dependency indicators. Compiles cleanly. Before declaring plan complete: - [ ] `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes - [ ] `npx vite build` in packages/web succeeds - [ ] All three components export correctly - [ ] Components follow existing codebase patterns (functional components, named exports, Tailwind) - PhaseAccordion renders expandable phases with task counts and status - TaskRow renders tasks with tree connectors, status, agent names - DependencyIndicator renders blocked-by annotations - All components are presentational (data assembled by parent) - TypeScript and Vite build pass After completion, create `.planning/phases/18-initiative-detail/18-02-SUMMARY.md`