diff --git a/.specflow/orchestration-state.json b/.specflow/orchestration-state.json index 78af217..b5e268e 100644 --- a/.specflow/orchestration-state.json +++ b/.specflow/orchestration-state.json @@ -5,7 +5,7 @@ "name": "specflow", "path": "/Users/ppatterson/dev/specflow" }, - "last_updated": "2026-01-20T04:25:45.064Z", + "last_updated": "2026-01-20T06:34:58.277Z", "orchestration": { "phase": { "number": null, @@ -281,6 +281,15 @@ "completed_at": "2026-01-20T04:25:45.063Z", "tasks_completed": 0, "tasks_total": 0 + }, + { + "type": "phase_completed", + "phase_number": "1054", + "phase_name": "Project Details Redesign", + "branch": "1054-project-details-redesign", + "completed_at": "2026-01-20T06:34:58.276Z", + "tasks_completed": 0, + "tasks_total": 0 } ] } diff --git a/.specify/archive/1054-project-details-redesign/checklists/implementation.md b/.specify/archive/1054-project-details-redesign/checklists/implementation.md new file mode 100644 index 0000000..482ed63 --- /dev/null +++ b/.specify/archive/1054-project-details-redesign/checklists/implementation.md @@ -0,0 +1,91 @@ +# Implementation Checklist: Comprehensive Dashboard UI Redesign + +**Purpose**: Guide implementation quality and ensure requirements are correctly addressed +**Created**: 2026-01-19 +**Feature**: [spec.md](../spec.md) + +## Design System Foundation + +- [ ] I-001 Tailwind color palette matches mockup exactly (surface-50 through surface-500, accent, success, warning, danger) +- [ ] I-002 All animation keyframes are defined (glow-pulse, slide-up, beam, float) with correct timing +- [ ] I-003 StatusPill component supports all 4 states with correct colors and glow effects +- [ ] I-004 GlassCard uses backdrop-filter with webkit prefix for Safari support +- [ ] I-005 GridBackground pattern matches mockup (32px grid, subtle indigo color) +- [ ] I-006 FloatingOrbs use absolute positioning with z-index 0 to stay behind content + +## Layout Structure + +- [ ] I-007 Icon sidebar is exactly 64px wide (w-16) +- [ ] I-008 Header is exactly 56px tall (h-14) +- [ ] I-009 Context drawer is 288px wide (w-72) when open +- [ ] I-010 Sidebar nav items have tooltip with label AND keyboard shortcut +- [ ] I-011 Active nav item shows left pip indicator (4px wide, accent color) +- [ ] I-012 Session nav item shows pulsing green dot when workflow running +- [ ] I-013 Session nav item shows pulsing amber dot when workflow waiting +- [ ] I-014 Header status pill is centered using absolute positioning +- [ ] I-015 Status pill timer counts up in MM:SS format + +## Views Implementation + +- [ ] I-016 Dashboard welcome view only shows when activeView='dashboard' AND status='idle' +- [ ] I-017 Primary action card shows current task from project context +- [ ] I-018 Secondary action buttons trigger correct workflow skills (implement, orchestrate, design, verify) +- [ ] I-019 Session console uses existing use-session-messages hook for data +- [ ] I-020 Session messages show timestamp in HH:MM:SS format +- [ ] I-021 Agent attribution uses @name format with accent color +- [ ] I-022 Reasoning badge is accent/indigo colored +- [ ] I-023 Action badge is green/success colored +- [ ] I-024 Tool call blocks have syntax highlighting (use existing code styling) +- [ ] I-025 Tasks kanban has exactly 2 columns (To Do, Done) - no In Progress +- [ ] I-026 Completed tasks show strikethrough text and check icon + +## Input & Notifications + +- [ ] I-027 OmniBox shows different placeholder for each state (idle=Ready, running=Live, waiting=Waiting, failed=Failed) +- [ ] I-028 OmniBox gradient glow appears on focus/hover +- [ ] I-029 OmniBox state badge matches current workflow status +- [ ] I-030 Decision toast positions at bottom-center (fixed positioning) +- [ ] I-031 Decision toast has animated beam progress indicator +- [ ] I-032 Decision toast option buttons are in 2-column grid +- [ ] I-033 Failed toast shows error message in code block styling +- [ ] I-034 Failed toast Retry button restarts workflow + +## History & Context + +- [ ] I-035 History timeline shows phases in chronological order (newest first) +- [ ] I-036 Selected phase updates detail panel on right +- [ ] I-037 Phase detail shows summary, sessions list, and artifact links +- [ ] I-038 Context drawer has 2 tabs: Context and Activity +- [ ] I-039 Context tab shows current task with progress bar +- [ ] I-040 Touched files show file path and +/- line counts +- [ ] I-041 Phase progress stepper has 4 steps: Discovery, Design, Implement, Verify + +## Project List + +- [ ] I-042 Project cards use GlassCard component +- [ ] I-043 Project cards show status pill matching project state +- [ ] I-044 Project list page uses same layout shell as project details +- [ ] I-045 Visual styling is consistent between list and details pages + +## Keyboard Shortcuts + +- [ ] I-046 ⌘K focuses omni-box from any view +- [ ] I-047 ⌘1 navigates to Dashboard view +- [ ] I-048 ⌘2 navigates to Session view +- [ ] I-049 ⌘3 navigates to Tasks view +- [ ] I-050 ⌘4 navigates to History view +- [ ] I-051 Keyboard shortcuts work with Ctrl as well as Cmd (Windows/Linux) + +## Data Integration + +- [ ] I-052 Workflow status comes from use-workflow-execution hook +- [ ] I-053 Session messages come from use-session-messages hook +- [ ] I-054 Tasks data comes from ConnectionContext (tasks Map) +- [ ] I-055 Project data comes from ConnectionContext (registry, states) +- [ ] I-056 Answer submission uses existing workflow answer API + +## Notes + +- Check items off as completed: `[x]` +- Reference mockup at `mockups/project-details-redesign/index-v3.html` for visual verification +- Use browser dev tools to verify exact measurements and colors diff --git a/.specify/archive/1054-project-details-redesign/checklists/verification.md b/.specify/archive/1054-project-details-redesign/checklists/verification.md new file mode 100644 index 0000000..00fad4c --- /dev/null +++ b/.specify/archive/1054-project-details-redesign/checklists/verification.md @@ -0,0 +1,159 @@ +# Verification Checklist: Comprehensive Dashboard UI Redesign + +**Purpose**: Post-implementation verification and user acceptance testing +**Created**: 2026-01-19 +**Feature**: [spec.md](../spec.md) + +## User Story Verification + +### US1 - Design System Foundation + +- [ ] V-001 Tailwind colors render correctly (test by inspecting computed styles) +- [ ] V-002 Animations run smoothly at 60fps (no jank or stuttering) +- [ ] V-003 StatusPill component displays all 4 states correctly + +### US2 - Icon Sidebar Navigation + +- [ ] V-004 All 4 navigation icons (Dashboard, Session, Tasks, History) are visible +- [ ] V-005 Clicking each icon switches to the corresponding view +- [ ] V-006 Tooltips appear on hover showing label and keyboard shortcut +- [ ] V-007 Active icon has white text, background, and left pip indicator +- [ ] V-008 Inactive icons are zinc/gray colored +- [ ] V-009 Live indicator (green dot) appears on Session icon when workflow running +- [ ] V-010 Warning indicator (amber dot) appears on Session icon when workflow waiting + +### US3 - Header with Status Pill + +- [ ] V-011 Status pill is centered in header +- [ ] V-012 "Ready" state shows gray styling, no timer +- [ ] V-013 "Running" state shows green glow, pulsing dot, and timer counting up +- [ ] V-014 "Input Needed" state shows amber glow, pulsing dot, and timer +- [ ] V-015 "Failed" state shows red glow, static dot, no timer + +### US4 - Dashboard Welcome View + +- [ ] V-016 Dashboard view shows when idle (no active workflow) +- [ ] V-017 "Ready to build?" greeting is displayed +- [ ] V-018 Current phase number and completion percentage shown +- [ ] V-019 Primary action card (Resume Implementation) is clickable +- [ ] V-020 Secondary action buttons (Orchestrate, Design, Verify) are clickable +- [ ] V-021 Stats row shows correct Done/Pending/Progress numbers + +### US5 - Session Console View + +- [ ] V-022 Session view displays when Session icon clicked +- [ ] V-023 Messages show timestamps, agent names, and badges +- [ ] V-024 Reasoning messages have indigo "reasoning" badge +- [ ] V-025 Action messages have green "action" badge +- [ ] V-026 Tool calls display as syntax-highlighted code blocks +- [ ] V-027 Typing indicator shows when workflow is processing +- [ ] V-028 Empty state shows when no workflow running with "Start Workflow" CTA + +### US6 - Omni-Box Input + +- [ ] V-029 Omni-box is visible at bottom of Session view +- [ ] V-030 State badge matches current workflow status +- [ ] V-031 Placeholder text changes based on state +- [ ] V-032 Gradient glow appears when input is focused +- [ ] V-033 Pressing Enter sends message to workflow +- [ ] V-034 ⌘K focuses the omni-box from anywhere + +### US7 - Decision Toast + +- [ ] V-035 Toast appears when workflow enters "waiting_for_input" state +- [ ] V-036 Toast is positioned at bottom-center of screen +- [ ] V-037 Animated beam progress indicator is visible +- [ ] V-038 Question text is displayed +- [ ] V-039 Option buttons are arranged in 2 columns +- [ ] V-040 Clicking an option submits answer and dismisses toast +- [ ] V-041 "Provide custom instructions" expands for text input + +### US8 - Failed Toast + +- [ ] V-042 Toast appears when workflow status is "failed" +- [ ] V-043 Toast has red theme with error icon +- [ ] V-044 Error message is displayed in code block +- [ ] V-045 Dismiss button hides toast and sets status to idle +- [ ] V-046 Retry button restarts the workflow + +### US9 - Tasks Kanban View + +- [ ] V-047 Tasks view shows 2 columns: "To Do" and "Done" +- [ ] V-048 Progress bar shows in header (X of Y complete) +- [ ] V-049 Task cards show ID, priority badge (if applicable), description +- [ ] V-050 Completed tasks show strikethrough text and check icon +- [ ] V-051 Column counts are correct + +### US10 - History Timeline View + +- [ ] V-052 History view shows timeline on left, detail panel on right +- [ ] V-053 Phases are listed in timeline with number and name +- [ ] V-054 Clicking a phase selects it and updates detail panel +- [ ] V-055 Detail panel shows summary text +- [ ] V-056 Detail panel shows sessions list with date, skill, cost +- [ ] V-057 Detail panel shows artifact links (spec.md, plan.md, etc.) + +### US11 - Context Drawer + +- [ ] V-058 Context button in header toggles drawer open/closed +- [ ] V-059 Drawer has two tabs: Context and Activity +- [ ] V-060 Context tab shows current task card with progress +- [ ] V-061 Context tab shows touched files with +/- line counts +- [ ] V-062 Context tab shows phase progress stepper (4 steps) +- [ ] V-063 Activity tab shows recent activity with colored dots + +### US12 - Project List Redesign + +- [ ] V-064 Project list page uses icon sidebar +- [ ] V-065 Project cards use glass morphism styling +- [ ] V-066 Status indicators on cards match new design +- [ ] V-067 Visual consistency with project details page + +### US13 - Visual Polish + +- [ ] V-068 Grid background pattern is visible on all pages +- [ ] V-069 Floating orbs are visible and animating slowly +- [ ] V-070 View transitions are animated (fade/slide) +- [ ] V-071 Glass effects (backdrop-blur) work correctly +- [ ] V-072 Custom scrollbars are styled + +## UI Design Verification + +- [ ] V-UI1 UI implementation matches ui-design.md mockups +- [ ] V-UI2 All components from Component Inventory are implemented +- [ ] V-UI3 All interactions from Interactions table work as specified +- [ ] V-UI4 Design constraints from ui-design.md are respected +- [ ] V-UI5 Color palette matches mockup exactly + +## Keyboard Shortcuts + +- [ ] V-073 ⌘K focuses omni-box from any view +- [ ] V-074 ⌘1 navigates to Dashboard +- [ ] V-075 ⌘2 navigates to Session +- [ ] V-076 ⌘3 navigates to Tasks +- [ ] V-077 ⌘4 navigates to History +- [ ] V-078 Shortcuts work in Safari, Chrome, and Firefox + +## Regression Testing + +- [ ] V-079 Starting a workflow still works (via Dashboard or existing mechanisms) +- [ ] V-080 Cancelling a workflow still works +- [ ] V-081 Answering questions via toast or omni-box works +- [ ] V-082 Real-time message updates in Session view work +- [ ] V-083 Task completion updates in Tasks view work +- [ ] V-084 No console errors during normal operation +- [ ] V-085 Page loads without hydration errors + +## Performance + +- [ ] V-086 Initial page load is under 3 seconds +- [ ] V-087 View transitions feel instant (<300ms) +- [ ] V-088 Animations run at 60fps (no dropped frames) +- [ ] V-089 No memory leaks during extended use + +## Notes + +- Check items off as completed: `[x]` +- Test in both Chrome and Safari +- Use mockup as reference: `mockups/project-details-redesign/index-v3.html` +- Report any discrepancies with expected behavior diff --git a/.specify/archive/1054-project-details-redesign/discovery.md b/.specify/archive/1054-project-details-redesign/discovery.md new file mode 100644 index 0000000..719d0c2 --- /dev/null +++ b/.specify/archive/1054-project-details-redesign/discovery.md @@ -0,0 +1,228 @@ +# Discovery: Project Details Redesign + +**Phase**: `1054-project-details-redesign` +**Created**: 2026-01-19 +**Status**: Complete + +## Phase Context + +**Source**: ROADMAP Phase 1054 + User clarification +**Goal**: Comprehensive UI overhaul transforming both the project list and project details pages to match the v3 mockup design, while establishing reusable design patterns for the entire dashboard. + +--- + +## Codebase Examination + +### Related Implementations + +| Location | Description | Relevance | +|----------|-------------|-----------| +| `packages/dashboard/app/projects/[id]/page.tsx` | Project details page | Primary redesign target | +| `packages/dashboard/app/page.tsx` | Projects listing page | Secondary redesign target | +| `packages/dashboard/components/layout/` | Header, Sidebar, MainLayout | Will be replaced/refactored | +| `packages/dashboard/components/projects/` | 24 project-related components | Many will be refactored | +| `packages/dashboard/components/ui/` | 10 shadcn/ui components | Foundation to build upon | +| `packages/dashboard/hooks/` | 9 data fetching hooks | Will be reused as-is | +| `packages/dashboard/contexts/` | ConnectionContext | State management stays | +| `mockups/project-details-redesign/index-v3.html` | Target design mockup | Design reference | + +### Existing Patterns & Conventions + +- **Component Structure**: "use client" directive, Props interface at top, cn() for className merging +- **Data Fetching**: Custom hooks with polling (3s intervals), SSE for real-time updates +- **Styling**: Tailwind CSS with `dark:` prefix for dark mode, neutral color palette +- **State Management**: React Context (ConnectionContext) distributes project/state data +- **UI Components**: shadcn/ui primitives (Button, Card, Sheet, Dialog, etc.) + +### Integration Points + +- **SSE Events**: `/api/events` stream for real-time updates - unchanged +- **API Endpoints**: All existing endpoints remain unchanged +- **Hooks**: All existing hooks (use-workflow-execution, use-session-messages, etc.) remain +- **ConnectionContext**: Core state distribution - unchanged + +### Constraints Discovered + +- **React 19 + Next.js 16**: Must use current React patterns (server/client components) +- **shadcn/ui**: Build on existing primitives, don't replace +- **Dark Mode Only**: Mockup is dark-only, current app supports light/dark - decision: dark-mode first +- **Tailwind 3.x**: Use standard Tailwind config extension patterns + +--- + +## Requirements Sources + +### From ROADMAP/Phase File + +1. Icon-only sidebar navigation with tooltips and hotkeys (⌘1-4) +2. Centered status pill in header (idle/running/waiting/failed states) +3. Dashboard view (idle state welcome) with quick actions +4. Session view (inline console) with agent attribution +5. Omni-box unified input with state-aware styling +6. Decision toast for questions (replaces modal) +7. Failed state toast for errors +8. Tasks view (2-column Kanban) +9. History view (master-detail timeline) +10. Context drawer (right-side collapsible) +11. Visual polish (glass morphism, grid, orbs, animations) +12. Keyboard shortcuts (⌘K, ⌘1-4) + +### From User Clarification + +- **Comprehensive UI overhaul** - not just project details +- **Reusable design patterns** - establish design system foundation +- **Project list view redesign** - apply new patterns to listing page + +### From Memory Documents + +- **Constitution Principle VII**: Three-Line Output Rule (less relevant for UI) +- **Tech Stack**: Next.js 16, React 19, Tailwind 3.x, shadcn/ui +- **Coding Standards**: TypeScript strict mode, Zod validation + +--- + +## Scope Clarification + +### Questions Asked + +#### Question 1: Navigation Approach + +**Context**: Current app has a full left sidebar with project list. Mockup shows icon-only sidebar. + +**Question**: How should we handle the mockup's sidebar navigation vs the current left sidebar? + +**Options Presented**: +- A (Recommended): Replace entirely - Remove current sidebar, use new icon-only sidebar +- B: Keep both - Icon sidebar for views, existing sidebar for project list +- C: Adapt existing - Modify current sidebar to match mockup style + +**User Answer**: Replace entirely (Recommended) + +--- + +#### Question 2: Design System Foundation + +**Context**: Need to establish reusable patterns for the UI overhaul. + +**Question**: For the design system foundation, what level of abstraction do you want? + +**Options Presented**: +- A (Recommended): Tailwind config + primitives - Extend config with colors/animations, create reusable components +- B: Full design tokens - Comprehensive CSS variables system +- C: Minimal - Focus on components only + +**User Answer**: Tailwind config + primitives (Recommended) + +--- + +#### Question 3: Project List Layout + +**Context**: Current project list uses card layout. Could use different pattern. + +**Question**: For the project list view, should we use the card-based layout or introduce a different pattern? + +**Options Presented**: +- A (Recommended): Enhanced cards - Keep cards but apply new design styling +- B: Table/list view - Switch to table format +- C: Both with toggle - Support both views + +**User Answer**: Enhanced cards (Recommended) + +--- + +#### Question 4: Visual Polish Level + +**Context**: Mockup includes decorative elements (floating orbs, grid background). + +**Question**: Should we include the floating orbs and grid background from the mockup? + +**Options Presented**: +- A (Recommended): Yes - full visual polish matching mockup +- B: Subtle version - Grid yes, tone down orbs +- C: No decorative elements - Focus on functionality + +**User Answer**: Yes - full visual polish (Recommended) + +--- + +### Confirmed Understanding + +**What the user wants to achieve**: +A comprehensive UI overhaul that transforms both the project list and project details pages to match the polished v3 mockup design. This includes establishing reusable design patterns (design system primitives) that can be used throughout the dashboard. + +**How it relates to existing code**: +- Replace current layout structure (sidebar, header) with new icon-based navigation +- Refactor existing components to use new design patterns +- Keep all data hooks and API integration unchanged +- Build on existing shadcn/ui foundation + +**Key constraints and requirements**: +- Maintain full functionality during redesign +- Reuse existing hooks and state management +- Create reusable primitives for consistent styling +- Support keyboard shortcuts (⌘K, ⌘1-4) +- Full visual polish (glass effects, orbs, grid, animations) + +**Technical approach**: +1. Extend Tailwind config with mockup's color palette and animations +2. Create design system primitives (StatusPill, GlassCard, etc.) +3. Build new layout components (IconSidebar, redesigned Header) +4. Refactor existing views to use new primitives +5. Apply consistent styling to project list page + +**User confirmed**: Yes - 2026-01-19 + +--- + +## Recommendations for SPECIFY + +### Should Include in Spec + +1. **Design System Foundation** + - Extended Tailwind config (colors, animations, keyframes) + - Primitive components (StatusPill, GlassCard, OmniBox, Toast variants) + - Background elements (grid, floating orbs) + +2. **Layout Components** + - IconSidebar with tooltips and indicators + - Redesigned Header with centered status + - Context drawer (right panel) + +3. **Project Details Views** + - Dashboard (idle welcome) + - Session (inline console) + - Tasks (2-column Kanban) + - History (master-detail timeline) + +4. **Interactive Components** + - OmniBox input + - DecisionToast (questions) + - FailedToast (errors) + - Notification panel + +5. **Project List Page** + - Enhanced project cards with new styling + - Consistent visual language + +6. **Keyboard Shortcuts** + - ⌘K: Focus omni-box + - ⌘1-4: View navigation + +### Should Exclude from Spec (Non-Goals) + +- Light mode support (focus on dark mode first) +- Settings page implementation +- User avatar/profile functionality +- Attachment upload (paperclip button - UI only, no backend) +- Mobile responsive design (desktop-only per tech stack) + +### Potential Risks + +- **Breaking existing functionality**: Mitigation - comprehensive testing of data flows +- **Scope creep**: Mitigation - strict adherence to mockup as source of truth +- **Performance impact from animations**: Mitigation - use CSS animations, hardware acceleration +- **Accessibility**: Mitigation - maintain keyboard navigation, proper ARIA attributes + +### Questions to Address in CLARIFY + +- None remaining - scope is clear diff --git a/.specify/archive/1054-project-details-redesign/plan.md b/.specify/archive/1054-project-details-redesign/plan.md new file mode 100644 index 0000000..aae1146 --- /dev/null +++ b/.specify/archive/1054-project-details-redesign/plan.md @@ -0,0 +1,242 @@ +# Implementation Plan: Comprehensive Dashboard UI Redesign + +**Branch**: `1054-project-details-redesign` | **Date**: 2026-01-19 | **Spec**: [spec.md](spec.md) +**Input**: Feature specification from `/specs/1054-project-details-redesign/spec.md` + +## Summary + +Transform the SpecFlow dashboard with a comprehensive UI overhaul covering both the project list and project details pages. This includes establishing a reusable design system foundation (extended Tailwind config, primitive components), replacing the current sidebar with icon-only navigation, adding a centered status pill in the header, implementing four distinct views (Dashboard, Session, Tasks, History), and applying consistent visual polish (glass morphism, grid background, floating orbs) throughout. + +## Technical Context + +**Language/Version**: TypeScript 5.7+ (strict mode) +**Primary Dependencies**: Next.js 16, React 19, Tailwind CSS 3.x, shadcn/ui, lucide-react, @radix-ui/* +**Storage**: N/A (frontend changes only, uses existing API endpoints) +**Testing**: Vitest (for any utility functions), manual visual testing +**Target Platform**: Desktop browsers (Chrome, Firefox, Safari) +**Project Type**: Monorepo web application (packages/dashboard) +**Performance Goals**: Animations at 60fps, view transitions <300ms +**Constraints**: Must preserve all existing workflow functionality, dark mode only +**Scale/Scope**: 2 pages (project list, project details), ~20 components + +## Constitution Check + +| Principle | Status | Notes | +|-----------|--------|-------| +| I. Developer Experience First | ✓ Pass | New design improves UX | +| IIa. TypeScript for CLI | ✓ Pass | Dashboard is TypeScript | +| III. CLI Over Direct Edits | ✓ N/A | Frontend UI changes | +| IV. Simplicity Over Cleverness | ✓ Pass | Uses standard Tailwind patterns | +| V. Helpful Error Messages | ✓ Pass | Error states clearly displayed | +| VII. Three-Line Output Rule | ✓ N/A | Visual UI, not CLI | +| VIII. Repo vs Operational | ✓ N/A | Frontend code | + +## Project Structure + +### Documentation (this feature) + +```text +specs/1054-project-details-redesign/ +├── discovery.md # Codebase findings and decisions +├── spec.md # Feature specification +├── requirements.md # Requirements checklist +├── ui-design.md # Visual mockups and rationale +├── plan.md # This file +├── tasks.md # Task breakdown +└── checklists/ + ├── implementation.md # Implementation guidance + └── verification.md # Verification checklist +``` + +### Source Code (repository root) + +```text +packages/dashboard/ +├── app/ +│ ├── page.tsx # Project list page (REFACTOR) +│ ├── projects/[id]/page.tsx # Project details page (REFACTOR) +│ └── globals.css # Global styles (EXTEND) +├── components/ +│ ├── ui/ # shadcn primitives (EXISTING) +│ ├── design-system/ # NEW: Reusable design primitives +│ │ ├── status-pill.tsx +│ │ ├── glass-card.tsx +│ │ ├── grid-background.tsx +│ │ ├── floating-orbs.tsx +│ │ └── index.ts +│ ├── layout/ # REFACTOR: New layout +│ │ ├── icon-sidebar.tsx +│ │ ├── redesigned-header.tsx +│ │ ├── context-drawer.tsx +│ │ └── app-layout.tsx +│ ├── views/ # NEW: View components +│ │ ├── dashboard-welcome.tsx +│ │ ├── session-console.tsx +│ │ ├── tasks-kanban.tsx +│ │ └── history-timeline.tsx +│ ├── session/ # REFACTOR: Session components +│ │ ├── session-message.tsx +│ │ ├── tool-call-block.tsx +│ │ └── typing-indicator.tsx +│ ├── input/ # NEW: Input components +│ │ ├── omni-box.tsx +│ │ ├── decision-toast.tsx +│ │ └── failed-toast.tsx +│ └── projects/ # REFACTOR: Project components +│ └── project-card.tsx +├── hooks/ # EXISTING: Data hooks (unchanged) +│ ├── use-workflow-execution.ts +│ ├── use-session-messages.ts +│ └── ... +├── contexts/ # EXISTING: State (unchanged) +│ └── connection-context.tsx +└── tailwind.config.js # EXTEND: Design tokens +``` + +**Structure Decision**: Extend existing dashboard structure. Create new `design-system/` directory for reusable primitives. Create new `views/` directory for the four main views. Refactor existing `layout/` components. + +## Implementation Phases + +### Phase 1: Design System Foundation (P1 - US1) + +Establish the design tokens and primitive components that all other work depends on. + +**Files to modify/create:** +- `tailwind.config.js` - Extend with mockup colors and animations +- `app/globals.css` - Add custom CSS for glass, grid, etc. +- `components/design-system/status-pill.tsx` - NEW +- `components/design-system/glass-card.tsx` - NEW +- `components/design-system/grid-background.tsx` - NEW +- `components/design-system/floating-orbs.tsx` - NEW +- `components/design-system/index.ts` - NEW (barrel export) + +**Key decisions:** +- Use Tailwind `extend` for colors, not CSS variables (per user choice) +- Animations defined in Tailwind config for consistency +- Glass effect uses `backdrop-blur` with vendor prefixes + +### Phase 2: Layout Structure (P1 - US2, US3) + +Build the new layout shell: icon sidebar, redesigned header, context drawer. + +**Files to modify/create:** +- `components/layout/icon-sidebar.tsx` - NEW +- `components/layout/redesigned-header.tsx` - NEW +- `components/layout/context-drawer.tsx` - NEW +- `components/layout/app-layout.tsx` - NEW (replaces main-layout) +- `app/projects/[id]/page.tsx` - REFACTOR to use new layout + +**Key decisions:** +- Icon sidebar is 64px wide (w-16) +- Header is 56px tall (h-14) +- Context drawer is 288px wide (w-72) when open +- Use framer-motion or CSS transitions for drawer animation + +### Phase 3: Core Views (P2 - US4, US5, US9) + +Implement the main view components: Dashboard, Session, Tasks. + +**Files to modify/create:** +- `components/views/dashboard-welcome.tsx` - NEW +- `components/views/session-console.tsx` - NEW +- `components/views/tasks-kanban.tsx` - REFACTOR from existing kanban-view +- `components/session/session-message.tsx` - REFACTOR for new styling +- `components/session/tool-call-block.tsx` - NEW +- `components/session/typing-indicator.tsx` - NEW + +**Key decisions:** +- Session console reuses existing `use-session-messages` hook +- Tasks kanban simplifies to 2 columns (no In Progress) +- Dashboard welcome shows data from `ConnectionContext` + +### Phase 4: Input & Notifications (P2 - US6, US7, US8) + +Implement the omni-box input and toast notifications. + +**Files to modify/create:** +- `components/input/omni-box.tsx` - NEW +- `components/input/decision-toast.tsx` - NEW (replaces question-drawer) +- `components/input/failed-toast.tsx` - NEW + +**Key decisions:** +- Omni-box integrates with existing workflow answer submission +- Decision toast uses fixed positioning (bottom-center) +- Failed toast uses same positioning pattern + +### Phase 5: History & Context (P3 - US10, US11) + +Implement History view and Context drawer content. + +**Files to modify/create:** +- `components/views/history-timeline.tsx` - REFACTOR from existing +- `components/layout/context-drawer.tsx` - ADD content (tabs, task, files) + +**Key decisions:** +- History uses existing `use-session-history` hook +- Context drawer has two tabs: Context and Activity +- Phase progress stepper is hardcoded to 4 steps + +### Phase 6: Project List & Polish (P3 - US12, US13) + +Apply design system to project list page and add visual polish. + +**Files to modify/create:** +- `app/page.tsx` - REFACTOR for new styling +- `components/projects/project-card.tsx` - REFACTOR for glass styling +- Verify grid background and orbs render on all pages + +**Key decisions:** +- Project list uses same layout shell (icon sidebar, header) +- Project cards use GlassCard primitive +- Status pills on cards match header status pill + +### Phase 7: Keyboard Shortcuts & Integration + +Wire up keyboard shortcuts and ensure all pieces work together. + +**Files to modify/create:** +- Add keyboard event handlers for ⌘K, ⌘1-4 +- Integration testing of full workflow + +## Dependencies Graph + +``` +Phase 1 (Design System) + ↓ +Phase 2 (Layout) ─────────────────────────┐ + ↓ │ +Phase 3 (Views) ──────────────────────────┤ + ↓ │ +Phase 4 (Input/Notifications) ────────────┤ + ↓ │ +Phase 5 (History/Context) ────────────────┤ + ↓ │ +Phase 6 (Project List) ───────────────────┘ + ↓ +Phase 7 (Integration) +``` + +## Risk Mitigation + +| Risk | Mitigation | +|------|------------| +| Breaking existing workflows | Keep all hooks and API calls unchanged | +| Performance from animations | Use CSS transforms, will-change hints | +| Scope creep | Strict adherence to mockup as source of truth | +| Component sprawl | Organize into clear directories, barrel exports | + +## Testing Strategy + +1. **Visual testing**: Compare rendered UI against mockup +2. **Functional testing**: Verify workflows still work (start, answer, cancel) +3. **Keyboard testing**: Test all shortcuts (⌘K, ⌘1-4) +4. **State testing**: Verify UI updates correctly for all workflow states + +## Definition of Done + +- [ ] All 13 user stories have passing acceptance scenarios +- [ ] Design system primitives are documented in components/design-system/ +- [ ] No regressions in workflow functionality +- [ ] Visual match with mockup at >90% fidelity +- [ ] Keyboard shortcuts functional +- [ ] Project list and project details both use new design diff --git a/.specify/archive/1054-project-details-redesign/requirements.md b/.specify/archive/1054-project-details-redesign/requirements.md new file mode 100644 index 0000000..8409e76 --- /dev/null +++ b/.specify/archive/1054-project-details-redesign/requirements.md @@ -0,0 +1,75 @@ +# Requirements Checklist: Comprehensive Dashboard UI Redesign + +**Phase**: 1054-project-details-redesign +**Created**: 2026-01-19 + +## Requirements Quality Assessment + +### Requirement Completeness + +- [x] R-001: All user stories from phase file are addressed +- [x] R-002: Design system foundation requirements are specified +- [x] R-003: Navigation requirements are complete (sidebar, shortcuts) +- [x] R-004: All view requirements are documented (Dashboard, Session, Tasks, History) +- [x] R-005: Input/interaction requirements are specified (Omni-box, toasts) +- [x] R-006: Visual polish requirements are documented +- [x] R-007: Project list redesign scope is included +- [x] R-008: Edge cases are identified + +### Requirement Clarity + +- [x] R-009: Each FR uses "MUST" for mandatory requirements +- [x] R-010: User stories follow Given/When/Then format +- [x] R-011: Success criteria are measurable +- [x] R-012: No ambiguous terminology ("appropriate", "reasonable", etc.) +- [x] R-013: State names are consistent (idle/running/waiting/failed) +- [x] R-014: Keyboard shortcuts are explicitly specified (⌘K, ⌘1-4) + +### Scenario Coverage + +- [x] R-015: All 4 workflow states have UI handling defined +- [x] R-016: All 4 views have requirements documented +- [x] R-017: Empty states are addressed +- [x] R-018: Error states have recovery paths (Failed toast with Retry) +- [x] R-019: Loading/transition states are considered + +### Dependency Clarity + +- [x] R-020: Existing hooks to be reused are identified +- [x] R-021: shadcn/ui components to build upon are noted +- [x] R-022: API endpoints remain unchanged (no backend work) +- [x] R-023: State management approach is preserved (ConnectionContext) + +### Non-Goals Clarity + +- [x] R-024: Light mode is explicitly out of scope +- [x] R-025: Mobile responsive is explicitly out of scope +- [x] R-026: Settings/profile functionality is out of scope +- [x] R-027: File attachment functionality is UI-only (no backend) + +## Traceability Matrix + +| User Story | Functional Requirements | +|------------|------------------------| +| US1 - Design System | FR-001, FR-002, FR-003 | +| US2 - Icon Sidebar | FR-004, FR-005, FR-006, FR-007 | +| US3 - Header Status | FR-008, FR-009 | +| US4 - Dashboard Welcome | FR-010, FR-011, FR-012, FR-013 | +| US5 - Session Console | FR-014, FR-015, FR-016, FR-017 | +| US6 - Omni-Box | FR-018, FR-019, FR-020, FR-021, FR-022 | +| US7 - Decision Toast | FR-023, FR-024, FR-025 | +| US8 - Failed Toast | FR-026, FR-027 | +| US9 - Tasks Kanban | FR-028, FR-029 | +| US10 - History Timeline | FR-030, FR-031 | +| US11 - Context Drawer | FR-032, FR-033, FR-034 | +| US12 - Project List | FR-039, FR-040 | +| US13 - Visual Polish | FR-035, FR-036, FR-037, FR-038 | + +## Risk Assessment + +| Risk | Likelihood | Impact | Mitigation | +|------|------------|--------|------------| +| Breaking existing workflows | Low | High | Preserve all hooks and API calls | +| Performance impact from animations | Medium | Medium | Use CSS animations, will-change | +| Scope creep | Medium | Medium | Strict adherence to mockup | +| Accessibility regression | Medium | Medium | Maintain ARIA, keyboard nav | diff --git a/.specify/archive/1054-project-details-redesign/spec.md b/.specify/archive/1054-project-details-redesign/spec.md new file mode 100644 index 0000000..02f6e4e --- /dev/null +++ b/.specify/archive/1054-project-details-redesign/spec.md @@ -0,0 +1,334 @@ +# Feature Specification: Comprehensive Dashboard UI Redesign + +**Feature Branch**: `1054-project-details-redesign` +**Created**: 2026-01-19 +**Status**: Draft +**Input**: Phase 1054 from ROADMAP + User clarification for comprehensive UI overhaul + +--- + +## User Scenarios & Testing + +### User Story 1 - Design System Foundation (Priority: P1) + +As a developer maintaining the dashboard, I want a consistent design system with reusable primitives so that all UI components share the same visual language. + +**Why this priority**: This is the foundation. All other work depends on having the design tokens and primitives established first. + +**Independent Test**: Can be tested by viewing a Storybook-style demo page showing all primitives rendered correctly with consistent styling. + +**Acceptance Scenarios**: + +1. **Given** the Tailwind config is extended, **When** I use `bg-surface-50` or `text-accent`, **Then** the correct mockup colors are applied. +2. **Given** primitive components exist, **When** I render a StatusPill with status="running", **Then** it shows green glow with "Running" text. +3. **Given** animation keyframes are defined, **When** I apply `animate-glow-pulse`, **Then** the element pulses as in mockup. + +--- + +### User Story 2 - Icon Sidebar Navigation (Priority: P1) + +As a user viewing a project, I want an icon-only sidebar so I can quickly navigate between Dashboard, Session, Tasks, and History views with keyboard shortcuts. + +**Why this priority**: Core navigation is essential for accessing all other features. + +**Independent Test**: Can be tested by clicking icons and using ⌘1-4 shortcuts to switch views. + +**Acceptance Scenarios**: + +1. **Given** I'm on the project details page, **When** I click the Session icon, **Then** the Session view is displayed. +2. **Given** the sidebar is visible, **When** I hover over an icon, **Then** a tooltip shows the label and hotkey (e.g., "Session ⌘2"). +3. **Given** a workflow is running, **When** I view the Session icon, **Then** a green pulsing dot appears. +4. **Given** a workflow is waiting for input, **When** I view the Session icon, **Then** an amber pulsing dot appears. +5. **Given** I'm anywhere in the app, **When** I press ⌘2, **Then** the Session view is activated. + +--- + +### User Story 3 - Header with Status Pill (Priority: P1) + +As a user, I want to see the current workflow status prominently centered in the header so I immediately know if something is running, waiting, or failed. + +**Why this priority**: Status visibility is critical for workflow-driven UX. + +**Independent Test**: Can be tested by triggering different workflow states and observing header changes. + +**Acceptance Scenarios**: + +1. **Given** no workflow is running, **When** viewing the header, **Then** the status pill shows "Ready" in gray. +2. **Given** a workflow is running, **When** viewing the header, **Then** the status pill shows "Running" in green with timer. +3. **Given** a workflow is waiting for input, **When** viewing the header, **Then** the status pill shows "Input Needed" in amber with timer. +4. **Given** a workflow has failed, **When** viewing the header, **Then** the status pill shows "Failed" in red. +5. **Given** any active state, **When** viewing the timer, **Then** it counts up in MM:SS format. + +--- + +### User Story 4 - Dashboard Welcome View (Priority: P2) + +As a user with no active workflow, I want a welcoming dashboard showing my current phase progress and quick action buttons so I can easily resume work or start new workflows. + +**Why this priority**: Provides friendly entry point and quick access to common actions. + +**Independent Test**: Can be tested by navigating to Dashboard view while idle and clicking action buttons. + +**Acceptance Scenarios**: + +1. **Given** I'm in idle state on Dashboard view, **When** viewing the page, **Then** I see "Ready to build?" greeting and phase progress. +2. **Given** the dashboard shows actions, **When** I click "Resume Implementation", **Then** the implement workflow starts. +3. **Given** the dashboard shows secondary actions, **When** I click "Orchestrate", **Then** the orchestrate workflow starts. +4. **Given** the dashboard shows stats, **When** viewing, **Then** I see Done/Pending/Progress percentages. + +--- + +### User Story 5 - Session Console View (Priority: P2) + +As a user running a workflow, I want to see a live console with agent messages, tool calls, and reasoning so I can follow what Claude is doing. + +**Why this priority**: Transparency into agent actions is core to the product. + +**Independent Test**: Can be tested by starting a workflow and observing messages appear with correct formatting. + +**Acceptance Scenarios**: + +1. **Given** a workflow is running, **When** I view Session, **Then** I see timestamped messages with agent attribution (@Implementer, @Designer). +2. **Given** messages are displayed, **When** Claude shows reasoning, **Then** it has a "reasoning" badge in accent color. +3. **Given** messages are displayed, **When** Claude shows an action, **Then** it has an "action" badge in green. +4. **Given** a tool call occurs, **When** viewing Session, **Then** I see a code block with syntax highlighting. +5. **Given** no workflow is running, **When** viewing Session, **Then** I see empty state with "Start Workflow" CTA. + +--- + +### User Story 6 - Omni-Box Input (Priority: P2) + +As a user, I want a unified input box at the bottom of the session view that adapts to the current state so I can type responses, interventions, or new prompts. + +**Why this priority**: Single point of input simplifies interaction model. + +**Independent Test**: Can be tested by focusing input and typing in different workflow states. + +**Acceptance Scenarios**: + +1. **Given** the workflow is idle, **When** viewing omni-box, **Then** it shows "Ready" badge and "Ask SpecFlow to do something..." placeholder. +2. **Given** the workflow is running, **When** viewing omni-box, **Then** it shows "Live" badge and "Type to intervene or guide..." placeholder. +3. **Given** the workflow is waiting, **When** viewing omni-box, **Then** it shows "Waiting" badge and "Respond to the question..." placeholder. +4. **Given** the workflow is failed, **When** viewing omni-box, **Then** it shows "Failed" badge with red styling. +5. **Given** I focus the input, **When** typing, **Then** a gradient glow effect appears. +6. **Given** I'm anywhere on the page, **When** I press ⌘K, **Then** the omni-box is focused. +7. **Given** the workflow is running or idle, **When** I press Enter in omni-box with text, **Then** the message is sent to start or intervene in the workflow. + +--- + +### User Story 7 - Decision Toast (Priority: P2) + +As a user whose workflow needs input, I want a floating toast showing the question and options so I can quickly respond without disrupting my view. + +**Why this priority**: Questions are the primary interaction during workflows; needs to be prominent yet non-intrusive. + +**Independent Test**: Can be tested by triggering a workflow that asks a question and selecting an option. + +**Acceptance Scenarios**: + +1. **Given** workflow status is "waiting", **When** viewing the page, **Then** a decision toast appears at bottom-center. +2. **Given** the toast is visible, **When** viewing, **Then** I see question text, 2-column option buttons, and animated beam progress. +3. **Given** the toast is visible, **When** I click an option, **Then** the answer is submitted and toast dismisses. +4. **Given** the toast is visible, **When** I type in the omni-box, **Then** the toast can auto-resolve (my response becomes the answer). +5. **Given** the toast is visible, **When** I click "Provide custom instructions", **Then** I can type a custom response. + +--- + +### User Story 8 - Failed Toast (Priority: P2) + +As a user whose workflow has failed, I want to see a clear error notification with retry option so I can understand what went wrong and try again. + +**Why this priority**: Error recovery is essential for good UX. + +**Independent Test**: Can be tested by triggering a failed workflow and clicking retry. + +**Acceptance Scenarios**: + +1. **Given** workflow status is "failed", **When** viewing the page, **Then** a red-themed toast appears with error details. +2. **Given** the failed toast is visible, **When** I click "Retry", **Then** the workflow is restarted. +3. **Given** the failed toast is visible, **When** I click "Dismiss", **Then** the toast hides and status returns to idle. + +--- + +### User Story 9 - Tasks Kanban View (Priority: P2) + +As a user, I want to see my tasks in a 2-column Kanban (To Do / Done) so I can track implementation progress visually. + +**Why this priority**: Task visibility supports workflow transparency. + +**Independent Test**: Can be tested by navigating to Tasks view and observing correct task placement. + +**Acceptance Scenarios**: + +1. **Given** I navigate to Tasks view, **When** viewing, **Then** I see 2 columns: "To Do" and "Done". +2. **Given** tasks exist, **When** viewing a task card, **Then** I see task ID, priority badge (if high), and description. +3. **Given** completed tasks exist, **When** viewing Done column, **Then** tasks show strikethrough text and check icon. +4. **Given** the header shows progress, **When** viewing, **Then** I see "X of Y complete" with progress bar. + +--- + +### User Story 10 - History Timeline View (Priority: P3) + +As a user, I want to see my phase history in a master-detail layout so I can review past work and access artifacts. + +**Why this priority**: Historical context is valuable but not critical path. + +**Independent Test**: Can be tested by navigating to History and clicking phase items. + +**Acceptance Scenarios**: + +1. **Given** I navigate to History view, **When** viewing, **Then** I see a timeline on the left and detail panel on the right. +2. **Given** phases exist, **When** I click a phase in timeline, **Then** the detail panel updates with that phase's info. +3. **Given** a phase is selected, **When** viewing details, **Then** I see summary, sessions list, and artifact links. + +--- + +### User Story 11 - Context Drawer (Priority: P3) + +As a user, I want a collapsible right-side drawer showing current task, touched files, and phase progress so I have context while working. + +**Why this priority**: Provides helpful context but not essential for core functionality. + +**Independent Test**: Can be tested by toggling drawer and observing content updates. + +**Acceptance Scenarios**: + +1. **Given** I click the Context toggle in header, **When** the drawer opens, **Then** I see Context and Activity tabs. +2. **Given** Context tab is active, **When** viewing, **Then** I see current task card, touched files list, and phase progress stepper. +3. **Given** Activity tab is active, **When** viewing, **Then** I see recent activity feed with colored dots. + +--- + +### User Story 12 - Project List Redesign (Priority: P3) + +As a user on the home page, I want to see my projects with the new design system styling so the visual experience is consistent across the app. + +**Why this priority**: Consistency is important but project list works fine currently. + +**Independent Test**: Can be tested by viewing home page and observing card styling matches design system. + +**Acceptance Scenarios**: + +1. **Given** I'm on the home page, **When** viewing project cards, **Then** they use new glass morphism styling. +2. **Given** a project has an active workflow, **When** viewing its card, **Then** status indicators match the new design. +3. **Given** the page loads, **When** viewing background, **Then** I see grid pattern and floating orbs. + +--- + +### User Story 13 - Visual Polish (Priority: P3) + +As a user, I want the app to have polished visual effects (glass morphism, grid background, floating orbs, smooth transitions) so it feels premium and modern. + +**Why this priority**: Polish elevates experience but functionality comes first. + +**Independent Test**: Can be tested visually by navigating through app and observing effects. + +**Acceptance Scenarios**: + +1. **Given** any page loads, **When** viewing background, **Then** I see a subtle grid pattern. +2. **Given** the background is visible, **When** looking carefully, **Then** I see floating orbs with slow animation. +3. **Given** I switch views, **When** the transition occurs, **Then** it animates smoothly (fade/slide). +4. **Given** glass components render, **When** viewing, **Then** they have backdrop-blur effect. + +--- + +### Edge Cases + +- What happens when workflow state changes mid-view-transition? +- How does the UI handle extremely long task descriptions in Kanban? +- What happens when many messages flood the Session console rapidly? +- How does the Decision toast behave with very long question text? +- What happens when there are 5+ pending questions? +- How does the History view handle 100+ phases? +- What if the Context drawer is open when screen is too narrow? + +--- + +## Requirements + +### Functional Requirements + +**Design System** +- **FR-001**: System MUST provide Tailwind config extension with mockup color palette (surface, accent, success, warning, danger). +- **FR-002**: System MUST provide animation keyframes (glow-pulse, slide-up, beam, float). +- **FR-003**: System MUST provide reusable primitive components (StatusPill, GlassCard). + +**Navigation & Layout** +- **FR-004**: System MUST render icon-only sidebar with 4 navigation items (Dashboard, Session, Tasks, History). +- **FR-005**: Each sidebar icon MUST show tooltip on hover with label and keyboard shortcut. +- **FR-006**: Sidebar MUST show live indicator (pulsing dot) on Session icon when workflow is running. +- **FR-007**: Sidebar MUST show warning indicator on Session icon when workflow is waiting. +- **FR-008**: Header MUST show centered status pill with state-specific styling and timer. +- **FR-009**: Header MUST show Context drawer toggle button on the right. + +**Dashboard View** +- **FR-010**: Dashboard view MUST show welcome greeting when idle with phase progress. +- **FR-011**: Dashboard MUST provide primary action card (Resume Implementation) with context. +- **FR-012**: Dashboard MUST provide secondary action buttons (Orchestrate, Design, Verify). +- **FR-013**: Dashboard MUST show stats row (Done/Pending/Progress). + +**Session View** +- **FR-014**: Session view MUST render messages with timestamps, agent attribution, and badges. +- **FR-015**: Session view MUST display tool calls as syntax-highlighted code blocks. +- **FR-016**: Session view MUST show typing indicator when Claude is processing. +- **FR-017**: Session view MUST show empty state with CTA when idle. + +**Input & Interaction** +- **FR-018**: Omni-box MUST show state badge (Ready/Live/Waiting/Failed). +- **FR-019**: Omni-box MUST show gradient glow on focus. +- **FR-020**: Omni-box placeholder MUST change based on workflow state. +- **FR-021**: ⌘K MUST focus the omni-box from anywhere. +- **FR-022**: ⌘1-4 MUST navigate to respective views. + +**Notifications** +- **FR-023**: Decision toast MUST appear when workflow status is "waiting_for_input". +- **FR-024**: Decision toast MUST display question text and option buttons. +- **FR-025**: Decision toast MUST have animated beam progress indicator. +- **FR-026**: Failed toast MUST appear when workflow status is "failed". +- **FR-027**: Failed toast MUST show error message and Retry/Dismiss buttons. + +**Tasks & History** +- **FR-028**: Tasks view MUST show 2-column Kanban (To Do, Done). +- **FR-029**: Task cards MUST show ID, priority badge (if applicable), and description. +- **FR-030**: History view MUST show master-detail layout with timeline and detail panel. +- **FR-031**: History timeline MUST allow clicking phases to select them. + +**Context Drawer** +- **FR-032**: Context drawer MUST be collapsible via header toggle. +- **FR-033**: Context drawer MUST have two tabs: Context and Activity. +- **FR-034**: Context tab MUST show current task, touched files, and phase progress. + +**Visual Polish** +- **FR-035**: App MUST render grid background pattern. +- **FR-036**: App MUST render floating orb animations. +- **FR-037**: Glass components MUST use backdrop-blur effect. +- **FR-038**: View transitions MUST be animated (opacity, transform). + +**Project List** +- **FR-039**: Project cards MUST use new design system styling (glass, status pills). +- **FR-040**: Project list page MUST have consistent visual language with project details. + +--- + +### Key Entities + +- **NavigationItem**: {id, label, icon, hotkey} - Sidebar navigation items +- **WorkflowStatus**: idle | running | waiting | failed - Current workflow state +- **ViewType**: dashboard | session | tasks | history - Active view +- **SessionMessage**: {timestamp, agent, type, content} - Console message +- **Toast**: {type, title, content, actions} - Notification toast + +--- + +## Success Criteria + +### Measurable Outcomes + +- **SC-001**: All 4 views (Dashboard, Session, Tasks, History) are navigable via sidebar and keyboard shortcuts. +- **SC-002**: Status pill correctly reflects all 4 workflow states (idle, running, waiting, failed). +- **SC-003**: Decision toast appears within 500ms of workflow entering waiting state. +- **SC-004**: Omni-box responds to ⌘K focus from any view. +- **SC-005**: Session messages render with correct agent attribution and badges. +- **SC-006**: Visual polish elements (grid, orbs, glass effects) render without performance degradation. +- **SC-007**: Project list page uses same design system primitives as project details. +- **SC-008**: All existing workflow functionality (start, cancel, answer) continues to work. diff --git a/.specify/archive/1054-project-details-redesign/tasks.md b/.specify/archive/1054-project-details-redesign/tasks.md new file mode 100644 index 0000000..573f8b4 --- /dev/null +++ b/.specify/archive/1054-project-details-redesign/tasks.md @@ -0,0 +1,224 @@ +# Tasks: Comprehensive Dashboard UI Redesign + +## Progress Dashboard + +> Last updated: 2026-01-19 | Run `specflow status` to refresh + +| Phase | Status | Progress | +|-------|--------|----------| +| Setup | PENDING | 0/3 | +| Design System (US1) | PENDING | 0/6 | +| Layout & Navigation (US2, US3) | PENDING | 0/8 | +| Core Views (US4, US5, US9) | PENDING | 0/10 | +| Input & Notifications (US6, US7, US8) | PENDING | 0/7 | +| History & Context (US10, US11) | PENDING | 0/6 | +| Project List & Polish (US12, US13) | PENDING | 0/8 | +| Integration | PENDING | 0/4 | + +**Overall**: 0/52 (0%) | **Current**: None + +--- + +**Input**: Design documents from `/specs/1054-project-details-redesign/` +**Prerequisites**: plan.md (required), spec.md (required), ui-design.md (required) + +## Phase 1: Setup (Shared Infrastructure) + +**Purpose**: Extend Tailwind configuration and prepare project structure + +- [x] T001 Extend Tailwind config with mockup color palette (surface, accent, success, warning, danger) in packages/dashboard/tailwind.config.js +- [x] T002 Add animation keyframes (glow-pulse, slide-up, beam, float) to Tailwind config in packages/dashboard/tailwind.config.js +- [x] T003 [P] Add custom CSS classes (glass, bg-grid, omni-glow, cursor-blink) to packages/dashboard/app/globals.css + +--- + +## Phase 2: Design System Foundation (US1) - Priority P1 + +**Goal**: Establish reusable design primitives that all other components depend on + +**Independent Test**: Render all primitives on a test page and verify styling matches mockup + +- [x] T004 [US1] Create StatusPill component with 4 states (idle, running, waiting, failed) in packages/dashboard/components/design-system/status-pill.tsx +- [x] T005 [P] [US1] Create GlassCard component with backdrop-blur and border styling in packages/dashboard/components/design-system/glass-card.tsx +- [x] T006 [P] [US1] Create GridBackground component with CSS grid pattern in packages/dashboard/components/design-system/grid-background.tsx +- [x] T007 [P] [US1] Create FloatingOrbs component with animated background orbs in packages/dashboard/components/design-system/floating-orbs.tsx +- [x] T008 [US1] Create barrel export for design system in packages/dashboard/components/design-system/index.ts +- [x] T009 [US1] Verify all design system primitives render correctly with mockup colors and animations + +**Checkpoint**: Design system foundation ready - layout and views can now use primitives + +--- + +## Phase 3: Layout & Navigation (US2, US3) - Priority P1 + +**Goal**: Build the new layout shell with icon sidebar and redesigned header + +**Independent Test**: Navigate between views using sidebar and keyboard shortcuts, verify status pill updates + +### Navigation (US2) + +- [x] T010 [US2] Create SidebarNavItem component with active state, tooltip, and indicator in packages/dashboard/components/layout/sidebar-nav-item.tsx +- [x] T011 [US2] Create IconSidebar component with 4 nav items and bottom actions in packages/dashboard/components/layout/icon-sidebar.tsx +- [x] T012 [US2] Add live/warning indicators to Session nav item based on workflow status in packages/dashboard/components/layout/icon-sidebar.tsx + +### Header (US3) + +- [x] T013 [US3] Create RedesignedHeader component with breadcrumb, branch pill, and context toggle in packages/dashboard/components/layout/redesigned-header.tsx +- [x] T014 [US3] Integrate StatusPill in header center with workflow state binding in packages/dashboard/components/layout/redesigned-header.tsx +- [x] T015 [US3] Add timer display to StatusPill when workflow is running or waiting in packages/dashboard/components/design-system/status-pill.tsx + +### Layout Shell + +- [x] T016 Create AppLayout component composing sidebar, header, and content area in packages/dashboard/components/layout/app-layout.tsx +- [x] T017 Update project details page to use new AppLayout in packages/dashboard/app/projects/[id]/page.tsx + +**Checkpoint**: Navigation and header functional - views can now be built within layout + +--- + +## Phase 4: Core Views (US4, US5, US9) - Priority P2 + +**Goal**: Implement Dashboard welcome, Session console, and Tasks kanban views + +### Dashboard Welcome (US4) + +- [x] T018 [US4] Create DashboardWelcome component with greeting and phase progress in packages/dashboard/components/views/dashboard-welcome.tsx +- [x] T019 [US4] Add primary action card (Resume Implementation) with context in packages/dashboard/components/views/dashboard-welcome.tsx +- [x] T020 [US4] Add secondary action buttons (Orchestrate, Design, Verify) in packages/dashboard/components/views/dashboard-welcome.tsx +- [x] T021 [US4] Add stats row (Done, Pending, Progress) in packages/dashboard/components/views/dashboard-welcome.tsx + +### Session Console (US5) + +- [x] T022 [US5] Create SessionMessage component with timestamp, agent attribution, and badges in packages/dashboard/components/session/session-message.tsx +- [x] T023 [P] [US5] Create ToolCallBlock component with syntax highlighting in packages/dashboard/components/session/tool-call-block.tsx +- [x] T024 [P] [US5] Create TypingIndicator component for processing state in packages/dashboard/components/session/typing-indicator.tsx +- [x] T025 [US5] Create SessionConsole view composing messages, tools, and typing indicator in packages/dashboard/components/views/session-console.tsx +- [x] T026 [US5] Add empty state with Start Workflow CTA when idle in packages/dashboard/components/views/session-console.tsx + +### Tasks Kanban (US9) + +- [x] T027 [US9] Refactor TasksKanban to 2-column layout (To Do, Done) in packages/dashboard/components/views/tasks-kanban.tsx + +**Checkpoint**: Core views functional - can navigate Dashboard, Session, Tasks + +--- + +## Phase 5: Input & Notifications (US6, US7, US8) - Priority P2 + +**Goal**: Implement OmniBox input and toast notifications + +### OmniBox (US6) + +- [x] T028 [US6] Create OmniBox component with state badge and gradient glow in packages/dashboard/components/input/omni-box.tsx +- [x] T029 [US6] Add state-aware placeholder text to OmniBox in packages/dashboard/components/input/omni-box.tsx +- [x] T030 [US6] Wire OmniBox to workflow answer submission in packages/dashboard/components/input/omni-box.tsx +- [x] T031 [US6] Integrate OmniBox at bottom of session view in packages/dashboard/components/views/session-console.tsx + +### Decision Toast (US7) + +- [x] T032 [US7] Create DecisionToast component with beam animation and options in packages/dashboard/components/input/decision-toast.tsx +- [x] T033 [US7] Wire DecisionToast to question state and answer submission in packages/dashboard/components/input/decision-toast.tsx + +### Failed Toast (US8) + +- [x] T034 [US8] Create FailedToast component with error display and retry button in packages/dashboard/components/input/failed-toast.tsx + +**Checkpoint**: Input and notifications functional - full workflow interaction possible + +--- + +## Phase 6: History & Context (US10, US11) - Priority P3 + +**Goal**: Implement History timeline view and Context drawer + +### History Timeline (US10) + +- [x] T035 [US10] Create PhaseTimelineItem component with status badge in packages/dashboard/components/views/phase-timeline-item.tsx +- [x] T036 [US10] Create HistoryTimeline view with master-detail layout in packages/dashboard/components/views/history-timeline.tsx +- [x] T037 [US10] Add detail panel showing summary, sessions, and artifacts in packages/dashboard/components/views/history-timeline.tsx + +### Context Drawer (US11) + +- [x] T038 [US11] Create ContextDrawer component with tabs (Context, Activity) in packages/dashboard/components/layout/context-drawer.tsx +- [x] T039 [US11] Add Context tab content (current task, touched files, phase progress) in packages/dashboard/components/layout/context-drawer.tsx +- [x] T040 [US11] Add Activity tab content (recent activity feed) in packages/dashboard/components/layout/context-drawer.tsx + +**Checkpoint**: All 4 views and context drawer complete + +--- + +## Phase 7: Project List & Visual Polish (US12, US13) - Priority P3 + +**Goal**: Apply design system to project list and ensure visual polish throughout + +### Project List (US12) + +- [x] T041 [US12] Refactor ProjectCard to use GlassCard and StatusPill in packages/dashboard/components/projects/project-card.tsx +- [x] T042 [US12] Update project list page to use AppLayout with sidebar in packages/dashboard/app/page.tsx +- [x] T043 [US12] Apply consistent styling to project list header in packages/dashboard/app/page.tsx + +### Visual Polish (US13) + +- [x] T044 [P] [US13] Add GridBackground to AppLayout in packages/dashboard/components/layout/app-layout.tsx +- [x] T045 [P] [US13] Add FloatingOrbs to AppLayout in packages/dashboard/components/layout/app-layout.tsx +- [x] T046 [US13] Add view transition animations (opacity, transform) in packages/dashboard/components/layout/app-layout.tsx +- [x] T047 [US13] Verify glass morphism effects render correctly on all cards +- [x] T048 [US13] Custom scrollbar styling for all scrollable areas in packages/dashboard/app/globals.css + +**Checkpoint**: Visual polish complete - full mockup fidelity achieved + +--- + +## Phase 8: Integration & Keyboard Shortcuts + +**Purpose**: Wire up keyboard shortcuts and verify complete integration + +- [x] T049 Add keyboard event handler for ⌘K (focus omni-box) in packages/dashboard/components/layout/app-layout.tsx +- [x] T050 Add keyboard event handlers for ⌘1 (Dashboard), ⌘2 (Session), ⌘3 (Tasks), ⌘4 (History) view navigation in packages/dashboard/components/layout/app-layout.tsx +- [x] T051 Verify all workflow states (idle, running, waiting, failed) display correctly across all components +- [x] T052 End-to-end integration test: start workflow, answer question, complete workflow + +--- + +## Dependencies & Execution Order + +### Phase Dependencies + +- **Phase 1 (Setup)**: No dependencies - start immediately +- **Phase 2 (Design System)**: Depends on Phase 1 - creates primitives all other phases use +- **Phase 3 (Layout)**: Depends on Phase 2 - uses StatusPill, GlassCard +- **Phase 4 (Core Views)**: Depends on Phase 3 - renders within AppLayout +- **Phase 5 (Input/Notifications)**: Depends on Phase 4 - integrates with Session view +- **Phase 6 (History/Context)**: Depends on Phase 3 - uses layout components +- **Phase 7 (Project List)**: Depends on Phases 2, 3 - uses design system and layout +- **Phase 8 (Integration)**: Depends on all previous phases + +### Parallel Opportunities + +```bash +# Phase 1: All can run in parallel +T001, T002, T003 + +# Phase 2: GlassCard, GridBackground, FloatingOrbs can run in parallel +T005, T006, T007 + +# Phase 3: SidebarNavItem before IconSidebar, Header can run parallel to Sidebar +T010 → T011 → T012 (sequential) +T013, T014, T015 (can parallel with sidebar tasks) + +# Phase 4: Tool blocks and typing indicator can run in parallel +T023, T024 + +# Phase 7: Grid and orbs can run in parallel +T044, T045 +``` + +--- + +## Notes + +- [P] tasks = different files, no dependencies +- [US#] label maps task to specific user story +- Verify mockup at each checkpoint before proceeding +- Commit after each task or logical group +- Keep existing hooks (use-workflow-execution, etc.) unchanged diff --git a/.specify/archive/1054-project-details-redesign/ui-design.md b/.specify/archive/1054-project-details-redesign/ui-design.md new file mode 100644 index 0000000..2279820 --- /dev/null +++ b/.specify/archive/1054-project-details-redesign/ui-design.md @@ -0,0 +1,436 @@ +# UI/UX Design: Comprehensive Dashboard Redesign + +**Phase**: 1054 +**Created**: 2026-01-19 +**Status**: Complete +**Reference Mockup**: `mockups/project-details-redesign/index-v3.html` + +--- + +## Current State (Before) + +### Project Details Page +- **Layout**: Full left sidebar with project list, main content area with tabs +- **Navigation**: Tab-based (Status/Kanban/Timeline) +- **Session Viewer**: Slide-out drawer (Sheet component) +- **Questions**: Modal dialog approach +- **Styling**: Basic Tailwind with neutral colors, functional but plain + +### Project List Page +- **Layout**: Grid of project cards +- **Cards**: Simple white/dark cards with basic info +- **No decorative elements**: Functional but not visually distinctive + +--- + +## Proposed Design (After) + +A comprehensive redesign with Linear-inspired dark theme, glass morphism effects, and polished interactions. The design prioritizes workflow status visibility and quick actions. + +### Main Layout Structure + +``` +┌─────────────────────────────────────────────────────────────────────────────────┐ +│ BACKGROUND: Grid + Floating Orbs │ +├────┬────────────────────────────────────────────────────────────────────────────┤ +│ │ HEADER │ +│ I │ ┌───────────────────────┐ ┌─────────────────┐ ┌──────────┐ │ +│ C │ │ ~/dev/proj > branch │ │ ● RUNNING 02:34 │ │ Context │ │ +│ O │ └───────────────────────┘ └─────────────────┘ └──────────┘ │ +│ N ├────────────────────────────────────────────────────────────────┬───────────┤ +│ │ │ │ +│ S │ MAIN CONTENT │ CONTEXT │ +│ I │ │ DRAWER │ +│ D │ (Dashboard / Session / Tasks / History view) │ │ +│ E │ │ Current │ +│ B │ │ Task │ +│ A │ │ │ +│ R │ │ Files │ +│ │ │ │ +│ ● ─┤────────────────────────────────────────────────────────────────┤ Progress │ +│ ⚙ │ ┌─────────────────────────────────────────────────────────┐ │ │ +│ 👤 │ │ [Ready] │ Ask SpecFlow to do something... │ 📎 │ → │ │ │ │ +│ │ └─────────────────────────────────────────────────────────┘ │ │ +└────┴────────────────────────────────────────────────────────────────┴───────────┘ +``` + +### Icon Sidebar Detail + +``` +┌────┐ +│ SF │ Logo (gradient) +├────┤ +│ 🏠 │ Dashboard (⌘1) +│ 💻 │ Session (⌘2) ● ← live/warning indicator +│ ☑️ │ Tasks (⌘3) +│ 🕐 │ History (⌘4) +│ │ +│ │ (spacer) +│ │ +│ 🔔 │ Notifications ● +│ ⚙️ │ Settings +│ 👤 │ Avatar +└────┘ + +Icon states: +- Inactive: zinc-500, no background +- Active: white, bg-white/10, left pip indicator +- Hover: tooltip appears to right +``` + +### Header Detail + +``` +┌────────────────────────────────────────────────────────────────────────────────┐ +│ │ +│ ~/dev/specflow > feature/1054 ● RUNNING 02:34 [⬚ Context] │ +│ └─ breadcrumb ─┘ └─ branch pill ─┘ └── status pill ──┘ └─ toggle ─┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────────────┘ + +Status Pill States: +┌───────────────────┐ +│ ○ READY │ gray, no glow, no timer +├───────────────────┤ +│ ● RUNNING 02:34 │ green glow, pulsing dot, timer +├───────────────────┤ +│ ● INPUT NEEDED │ amber glow, pulsing dot, timer +├───────────────────┤ +│ ● FAILED │ red glow, static dot, no timer +└───────────────────┘ +``` + +### Dashboard View (Idle State) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ │ +│ Ready to build? │ +│ │ +│ Phase 0042 is 80% complete. 3 tasks remaining. │ +│ │ +│ ┌───────────────────────────────────────────────────────────┐ │ +│ │ ▶ Resume Implementation │ │ +│ │ Continue working on T013 - Input validation → │ │ +│ └───────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ Orchestrate │ │ Design │ │ Verify │ │ +│ │ End-to-end │ │ Spec & plan │ │ Checklists │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +│ │ +│ 12 Done │ 3 Pending │ 80% Progress │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Session View (Console) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 14:02:11 System Initializing context analysis... │ +│ 14:02:15 Glob Found 12 files matching src/**/*.ts │ +│ │ +│ ●──────────────────────────────────────────────────────────────│ +│ │ @Implementer [reasoning] │ +│ │ │ +│ │ I need to locate the authentication middleware... │ +│ │ src/middleware/auth.ts │ +│ └──────────────────────────────────────────────────────────────│ +│ │ +│ ┌─ Read ──────────────────────────────────────────────────────┐│ +│ │ src/middleware/auth.ts ││ +│ ├──────────────────────────────────────────────────────────────┤│ +│ │ export const authMiddleware = (req, res, next) => { ││ +│ │ const token = req.headers.authorization; ││ +│ │ ... ││ +│ └──────────────────────────────────────────────────────────────┘│ +│ │ +│ ●──────────────────────────────────────────────────────────────│ +│ │ @Implementer [action] │ +│ │ │ +│ │ I'll implement the Zod validation schema: │ +│ │ ┌─ src/auth/validation.ts ────────────────── +24 lines ─┐ │ +│ │ │ import { z } from 'zod'; │ │ +│ │ │ export const loginSchema = z.object({... │ │ +│ │ └────────────────────────────────────────────────────────┘ │ +│ └──────────────────────────────────────────────────────────────│ +│ │ +│ 🤖 Analyzing dependencies ▋ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Decision Toast + +``` + ┌─════════════════════════════════════┐ + │████████████████░░░░░░░░░░░░░░░░░░░░│ ← animated beam + ├─────────────────────────────────────┤ + │ │ + │ ❓ Decision Required 1 of 2 │ + │ │ + │ I found a discrepancy in the API │ + │ spec regarding user roles... │ + │ │ + │ ┌────────────┐ ┌────────────────┐ │ + │ │ Use Default │ │ Enforce Strict │ │ + │ └────────────┘ └────────────────┘ │ + │ │ + │ ✏️ Provide custom instructions │ + │ │ + └─────────────────────────────────────┘ +``` + +### Failed Toast + +``` + ┌─────────────────────────────────────┐ + │▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓│ ← red bar + ├─────────────────────────────────────┤ + │ │ + │ ⚠️ Workflow Failed │ + │ │ + │ An error occurred while executing │ + │ the task. │ + │ │ + │ ┌─────────────────────────────────┐│ + │ │ Error: Invalid token format ││ + │ └─────────────────────────────────┘│ + │ │ + │ ┌─────────┐ ┌─────────────────┐ │ + │ │ Dismiss │ │ 🔄 Retry │ │ + │ └─────────┘ └─────────────────┘ │ + │ │ + └─────────────────────────────────────┘ +``` + +### Tasks View (2-Column Kanban) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Tasks 12 of 15 complete ████░ │ +├────────────────────────────────┬────────────────────────────────┤ +│ ○ To Do 3 │ ✓ Done 12 │ +├────────────────────────────────┼────────────────────────────────┤ +│ ┌──────────────────────────┐ │ ┌──────────────────────────┐ │ +│ │ T013 [HIGH] │ │ │ T012 ✓ │ │ +│ │ Add input validation │ │ │ ~~JWT token generation~~ │ │ +│ │ for user forms │ │ └──────────────────────────┘ │ +│ └──────────────────────────┘ │ │ +│ │ ┌──────────────────────────┐ │ +│ ┌──────────────────────────┐ │ │ T011 ✓ │ │ +│ │ T014 │ │ │ ~~User model/migrations~~│ │ +│ │ Write unit tests for │ │ └──────────────────────────┘ │ +│ │ auth module │ │ │ +│ └──────────────────────────┘ │ ┌──────────────────────────┐ │ +│ │ │ T010 ✓ │ │ +│ ┌──────────────────────────┐ │ │ ~~Database connection~~ │ │ +│ │ T015 │ │ └──────────────────────────┘ │ +│ │ Update API documentation │ │ │ +│ └──────────────────────────┘ │ │ +└────────────────────────────────┴────────────────────────────────┘ +``` + +### History View (Master-Detail) + +``` +┌──────────────────────────────┬──────────────────────────────────────────┐ +│ Phase History │ ┌────────────────────────────────────┐ │ +│ │ │ 📁 API Design │ │ +│ ●───────────────── │ │ Phase 0042 │ │ +│ │ 0042 [Current] │ └────────────────────────────────────┘ │ +│ │ API Design │ │ +│ │ 80% • 3 tasks │ Summary │ +│ └───────────────── │ Designing and implementing the RESTful │ +│ │ API for user authentication... │ +│ ●───────────────── │ │ +│ │ 0041 [Merged] │ Sessions │ +│ │ Core Engine │ ┌────────────────────────────────────┐ │ +│ │ Jan 10-14 • $12.40 │ │ Today Implement $1.23 │ │ +│ └───────────────── │ │ Yesterday Design $0.42 │ │ +│ │ └────────────────────────────────────┘ │ +│ ●───────────────── │ │ +│ │ 0040 [Merged] │ Artifacts │ +│ │ Project Setup │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ Jan 5-9 • $5.20 │ │ spec.md │ │ plan.md │ │ tasks.md │ │ +│ └───────────────── │ └──────────┘ └──────────┘ └──────────┘ │ +│ │ │ +└──────────────────────────────┴──────────────────────────────────────────┘ +``` + +### Context Drawer + +``` +┌────────────────────────────────┐ +│ Context │ Activity │ ← tabs +├────────────────────────────────┤ +│ │ +│ Current Task │ +│ ┌──────────────────────────┐ │ +│ │ T013 [HIGH] │ │ +│ │ Add input validation │ │ +│ │ ████████████░░░░░ 65% │ │ +│ └──────────────────────────┘ │ +│ │ +│ Touched Files │ +│ 📄 src/middleware/auth.ts +12 │ +│ 📄 src/auth/validation.ts +24 │ +│ 📄 src/types/express.d.ts ~2 │ +│ │ +│ Phase Progress │ +│ ✓ Discovery │ +│ ✓ Design │ +│ ● Implement 80% │ +│ ○ Verify │ +│ │ +└────────────────────────────────┘ +``` + +### Project List Page + +``` +┌─────────────────────────────────────────────────────────────────────────────────┐ +│ BACKGROUND: Grid + Floating Orbs │ +├────┬────────────────────────────────────────────────────────────────────────────┤ +│ │ HEADER │ +│ I │ ┌───────────────────────┐ ┌──────────────┐ │ +│ C │ │ SpecFlow Dashboard │ │ + New Project│ │ +│ O │ └───────────────────────┘ └──────────────┘ │ +│ N ├────────────────────────────────────────────────────────────────────────────┤ +│ │ │ +│ S │ ┌──────────────────────────────┐ ┌──────────────────────────────┐ │ +│ I │ │ specflow │ │ my-project │ │ +│ D │ │ Phase 1054 • 80% │ │ Phase 0042 • 40% │ │ +│ E │ │ ● Running 02:34 │ │ ○ Ready │ │ +│ B │ │ feature/1054-details │ │ main │ │ +│ A │ └──────────────────────────────┘ └──────────────────────────────┘ │ +│ R │ │ +│ │ ┌──────────────────────────────┐ ┌──────────────────────────────┐ │ +│ │ │ another-app │ │ demo-project │ │ +│ │ │ Phase 0010 • 100% │ │ Not initialized │ │ +│ │ │ ✓ Complete │ │ ○ Setup needed │ │ +│ │ │ main │ │ main │ │ +│ │ └──────────────────────────────┘ └──────────────────────────────┘ │ +│ │ │ +└────┴────────────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## Rationale + +### Why this layout? + +- **Icon sidebar**: Maximizes content area while maintaining quick navigation. Linear-inspired pattern familiar to developers. +- **Centered status pill**: Status is the most important information during workflows. Centering it creates visual hierarchy and immediate awareness. +- **Omni-box at bottom**: Consistent with modern chat/terminal interfaces. Users expect input at bottom. +- **Context drawer**: Provides contextual information without cluttering main view. Collapsible for focus when needed. + +### User flow + +1. User lands on Dashboard (idle) → sees phase progress and quick actions +2. User starts workflow → status pill turns green, auto-switches to Session view +3. User monitors progress in Session → sees agent reasoning and tool calls +4. If question arises → Decision toast appears, user can respond +5. User can switch views (Tasks, History) while workflow runs +6. Workflow completes → status returns to Ready, user can verify in Tasks/History + +### Accessibility considerations + +- Keyboard shortcuts for all navigation (⌘1-4, ⌘K) +- Tooltips on all icons with hotkey hints +- High contrast status colors (green, amber, red) for colorblind users +- Focus management on omni-box +- Proper ARIA labels for interactive elements + +--- + +## Component Inventory + +| Component | Type | Purpose | Notes | +|-----------|------|---------|-------| +| `IconSidebar` | navigation | Primary view navigation | 4 nav items + bottom actions | +| `SidebarNavItem` | button | Individual nav icon | Active state, tooltip, indicator | +| `StatusPill` | badge | Workflow status display | 4 states, timer, glow effects | +| `GlassCard` | container | Reusable card with blur | backdrop-filter, border | +| `OmniBox` | input | Unified command input | State badge, glow, placeholder | +| `DecisionToast` | toast | Question notification | Beam animation, options | +| `FailedToast` | toast | Error notification | Error display, retry button | +| `DashboardWelcome` | view | Idle state landing | Greeting, actions, stats | +| `SessionConsole` | view | Message stream display | Timestamps, agents, tools | +| `SessionMessage` | card | Individual message | Agent badge, type badge | +| `ToolCallBlock` | code | Tool execution display | Syntax highlighting | +| `TasksKanban` | view | 2-column task board | To Do, Done columns | +| `TaskCard` | card | Individual task | ID, priority, description | +| `HistoryTimeline` | view | Master-detail phases | Timeline, detail panel | +| `PhaseTimelineItem` | card | Phase in timeline | Selectable, status badge | +| `ContextDrawer` | panel | Right-side context | Tabs, current task, files | +| `GridBackground` | decorator | Subtle grid pattern | CSS background | +| `FloatingOrbs` | decorator | Animated orbs | CSS animations | +| `ProjectCard` | card | Project in list | Glass styling, status | + +--- + +## Interactions + +| Action | Trigger | Result | +|--------|---------|--------| +| Navigate to view | Click sidebar icon | View changes, icon shows active state | +| Navigate to view | Press ⌘1-4 | View changes to corresponding view | +| Focus omni-box | Press ⌘K | Omni-box receives focus, glow appears | +| Send message | Type + Enter in omni-box | Message sent to workflow | +| Answer question | Click option in DecisionToast | Answer submitted, toast dismisses | +| Retry workflow | Click Retry in FailedToast | Workflow restarts | +| Toggle context | Click Context button | Drawer opens/closes | +| Select phase | Click phase in History | Detail panel updates | +| Start workflow | Click action on Dashboard | Workflow starts, switches to Session | + +--- + +## Design Constraints + +- **Dark mode only**: No light mode variant in initial implementation +- **Desktop only**: No mobile responsive design (per tech stack) +- **Performance**: Animations must use CSS transforms/opacity for GPU acceleration +- **Existing hooks**: Must work with current data fetching infrastructure +- **shadcn/ui base**: Build on existing primitives, don't replace + +--- + +## Color Palette (from mockup) + +| Name | Value | Usage | +|------|-------|-------| +| `surface-50` | `#09090b` | Page background | +| `surface-100` | `#0c0c0e` | Sidebar background | +| `surface-200` | `#18181b` | Card backgrounds | +| `surface-300` | `#27272a` | Borders, dividers | +| `surface-400` | `#3f3f46` | Hover states | +| `surface-500` | `#52525b` | Muted text | +| `accent` | `#6366f1` | Primary accent (indigo) | +| `accent-light` | `#818cf8` | Accent hover | +| `accent-dark` | `#4f46e5` | Accent active | +| `success` | `#10b981` | Running state, done | +| `warning` | `#f59e0b` | Waiting state | +| `danger` | `#ef4444` | Failed state | + +--- + +## Animation Keyframes (from mockup) + +| Name | Duration | Effect | +|------|----------|--------| +| `glow-pulse` | 2s infinite | Opacity 0.4 → 0.8 → 0.4 | +| `slide-up` | 0.3s ease-out | translateY(10px) → 0 | +| `beam` | 1.5s linear infinite | translateX(-100%) → 100% | +| `float` | 6s ease-in-out infinite | translateY(0) → -20px → 0 | + +--- + +## Open Questions + +- [x] Navigation approach → Replace entirely with icon sidebar +- [x] Design system level → Tailwind config + primitives +- [x] Project list styling → Enhanced cards +- [x] Visual polish level → Full (grid, orbs, glass) diff --git a/.specify/history/HISTORY.md b/.specify/history/HISTORY.md index 55bc1cf..6eda19c 100644 --- a/.specify/history/HISTORY.md +++ b/.specify/history/HISTORY.md @@ -4,6 +4,193 @@ --- +## 1054 - Project Details Redesign + +**Completed**: 2026-01-20 + +### 1054 - Project Details Redesign + +**Goal**: Transform the project details page to match the polished v3 mockup design. + +**Context**: Phase 1053 created interactive HTML mockups for a major UI redesign. The v3 mockup (`mockups/project-details-redesign/index-v3.html`) represents the final design combining best practices from multiple iterations. This phase implements that design in the actual React dashboard. + +**Reference**: Open `mockups/project-details-redesign/index-v3.html` in browser to see the target design. + +--- + +**Scope:** + +### 1. Icon-Only Sidebar Navigation + +Replace the current tab-based navigation with an icon-only vertical sidebar: + +- Icons: Dashboard, Session, Tasks, History (with hotkey hints in tooltips) +- Active state: left pip indicator + background highlight +- Live indicator: pulsing dot on Session icon when workflow running +- Warning indicator: pulsing dot when waiting for user input +- Bottom section: Notifications bell, Settings gear, User avatar +- Tooltips with keyboard shortcuts (⌘1-4) + +### 2. Header Redesign + +- **Left**: Breadcrumb path + branch indicator pill +- **Center**: Status pill with state-specific styling + - Idle: gray, "Ready" + - Running: green glow, "Running" + timer + - Waiting: amber glow, "Input Needed" + timer + - Failed: red glow, "Failed" +- **Right**: Context drawer toggle button + +### 3. Dashboard View (Idle State) + +Welcome/landing view when no workflow is active: + +- Large greeting: "Ready to build?" +- Phase context: current phase, completion percentage +- Primary action card: "Resume Implementation" with context +- Secondary action grid: Orchestrate, Design, Verify buttons +- Stats row: Done / Pending / Progress percentage + +### 4. Session View (Console) + +Replace the drawer-based session viewer with inline console: + +- Full-height console with message stream +- Agent attribution: `@Implementer`, `@Designer` with role badges +- Reasoning vs Action badges on messages +- Tool call blocks with syntax highlighting +- Typing indicator when Claude is processing +- Empty state with "Start Workflow" CTA when idle + +### 5. Omni-Box Input + +Unified input at bottom of session view: + +- State badge (Live/Waiting/Ready/Error) +- Gradient glow effect on focus +- Placeholder changes based on state +- Paperclip attachment button +- Send button with arrow icon +- ⌘K hint below + +### 6. Decision Toast (Questions) + +Replace question modal with floating toast: + +- Appears at bottom-center when waiting for input +- Animated beam progress indicator +- Question icon + "Decision Required" header +- Question counter (1 of N) +- 2-column option buttons +- "Provide custom instructions" expand option +- Auto-resolves when user types in omni-box + +### 7. Failed State Toast + +Error notification for failed workflows: + +- Red-themed toast at bottom-center +- Error icon + "Workflow Failed" header +- Error message with code block for stack trace +- Dismiss and Retry buttons + +### 8. Tasks View + +2-column Kanban (no In Progress column): + +- **To Do**: Task cards with ID, priority badge, description +- **Done**: Completed tasks with strikethrough, check icon +- Progress bar in header +- Click task for detail (future: side panel) + +### 9. History View + +Master-detail layout: + +- **Left**: Timeline with phase cards + - Phase number, name, status badge + - Click to select + - Active pip indicator +- **Right**: Phase detail panel + - Summary text + - Sessions list with date, skill, cost + - Artifacts links (spec.md, plan.md, etc.) + +### 10. Context Drawer + +Right-side collapsible panel: + +- Tabs: Context | Activity +- **Context tab**: + - Current task card with progress + - Touched files list with +/- line counts + - Phase progress stepper (Discovery → Design → Implement → Verify) +- **Activity tab**: + - Recent activity feed with colored dots + +### 11. Visual Polish + +- Glass morphism effects (backdrop-blur) +- Grid background pattern +- Floating animated orbs (subtle) +- Smooth view transitions +- Custom scrollbar styling +- Dark theme throughout + +### 12. Keyboard Shortcuts + +- ⌘K: Focus omni-box +- ⌘1: Dashboard +- ⌘2: Session +- ⌘3: Tasks +- ⌘4: History + +--- + +**Deliverables:** + +| Component | Type | Notes | +|-----------|------|-------| +| `IconSidebar.tsx` | New | Vertical nav with tooltips | +| `StatusPill.tsx` | New | Centered header status | +| `OmniBox.tsx` | New | Unified input component | +| `DecisionToast.tsx` | New | Question toast (replaces modal) | +| `FailedToast.tsx` | New | Error toast | +| `SessionConsole.tsx` | Refactor | Inline console (was drawer) | +| `DashboardWelcome.tsx` | New | Idle state landing | +| `TasksKanban.tsx` | Refactor | 2-column layout | +| `HistoryTimeline.tsx` | Refactor | Master-detail layout | +| `ContextDrawer.tsx` | New | Right-side panel | +| `page.tsx` | Refactor | New layout structure | + +**Migration Notes:** +- Keep existing data hooks (`use-workflow-execution`, `use-session-messages`, etc.) +- Reuse shadcn/ui primitives where possible +- May need to add Tailwind animations for orbs, glow effects +- Remove old tab navigation and drawer components + +**Dependencies:** +- Phase 1053 (mockups created) +- Existing workflow/session infrastructure + +**Verification Gate: USER** +- [ ] Icon sidebar navigation works with all 4 views +- [ ] Status pill reflects workflow state correctly (idle/running/waiting/failed) +- [ ] Can start workflow from Dashboard welcome view +- [ ] Session console shows messages with agent attribution +- [ ] Decision toast appears when workflow needs input +- [ ] Failed toast appears with retry option on error +- [ ] Omni-box input works for follow-ups and question responses +- [ ] Tasks view shows 2-column Kanban +- [ ] History view shows timeline with detail panel +- [ ] Context drawer toggles and shows current task info +- [ ] Keyboard shortcuts work (⌘K, ⌘1-4) +- [ ] Visual polish matches mockup (glass effects, animations) + +**Estimated Complexity**: High (significant UI refactor) + +--- + ## 1053 - Workflow-Session Unification **Completed**: 2026-01-20 diff --git a/.specify/phases/1054-project-details-redesign.md b/.specify/phases/1054-project-details-redesign.md deleted file mode 100644 index 5ec9ccb..0000000 --- a/.specify/phases/1054-project-details-redesign.md +++ /dev/null @@ -1,188 +0,0 @@ ---- -phase: 1054 -name: project-details-redesign -status: not_started -created: 2026-01-19 -mockup: mockups/project-details-redesign/index-v3.html ---- - -### 1054 - Project Details Redesign - -**Goal**: Transform the project details page to match the polished v3 mockup design. - -**Context**: Phase 1053 created interactive HTML mockups for a major UI redesign. The v3 mockup (`mockups/project-details-redesign/index-v3.html`) represents the final design combining best practices from multiple iterations. This phase implements that design in the actual React dashboard. - -**Reference**: Open `mockups/project-details-redesign/index-v3.html` in browser to see the target design. - ---- - -**Scope:** - -### 1. Icon-Only Sidebar Navigation - -Replace the current tab-based navigation with an icon-only vertical sidebar: - -- Icons: Dashboard, Session, Tasks, History (with hotkey hints in tooltips) -- Active state: left pip indicator + background highlight -- Live indicator: pulsing dot on Session icon when workflow running -- Warning indicator: pulsing dot when waiting for user input -- Bottom section: Notifications bell, Settings gear, User avatar -- Tooltips with keyboard shortcuts (⌘1-4) - -### 2. Header Redesign - -- **Left**: Breadcrumb path + branch indicator pill -- **Center**: Status pill with state-specific styling - - Idle: gray, "Ready" - - Running: green glow, "Running" + timer - - Waiting: amber glow, "Input Needed" + timer - - Failed: red glow, "Failed" -- **Right**: Context drawer toggle button - -### 3. Dashboard View (Idle State) - -Welcome/landing view when no workflow is active: - -- Large greeting: "Ready to build?" -- Phase context: current phase, completion percentage -- Primary action card: "Resume Implementation" with context -- Secondary action grid: Orchestrate, Design, Verify buttons -- Stats row: Done / Pending / Progress percentage - -### 4. Session View (Console) - -Replace the drawer-based session viewer with inline console: - -- Full-height console with message stream -- Agent attribution: `@Implementer`, `@Designer` with role badges -- Reasoning vs Action badges on messages -- Tool call blocks with syntax highlighting -- Typing indicator when Claude is processing -- Empty state with "Start Workflow" CTA when idle - -### 5. Omni-Box Input - -Unified input at bottom of session view: - -- State badge (Live/Waiting/Ready/Error) -- Gradient glow effect on focus -- Placeholder changes based on state -- Paperclip attachment button -- Send button with arrow icon -- ⌘K hint below - -### 6. Decision Toast (Questions) - -Replace question modal with floating toast: - -- Appears at bottom-center when waiting for input -- Animated beam progress indicator -- Question icon + "Decision Required" header -- Question counter (1 of N) -- 2-column option buttons -- "Provide custom instructions" expand option -- Auto-resolves when user types in omni-box - -### 7. Failed State Toast - -Error notification for failed workflows: - -- Red-themed toast at bottom-center -- Error icon + "Workflow Failed" header -- Error message with code block for stack trace -- Dismiss and Retry buttons - -### 8. Tasks View - -2-column Kanban (no In Progress column): - -- **To Do**: Task cards with ID, priority badge, description -- **Done**: Completed tasks with strikethrough, check icon -- Progress bar in header -- Click task for detail (future: side panel) - -### 9. History View - -Master-detail layout: - -- **Left**: Timeline with phase cards - - Phase number, name, status badge - - Click to select - - Active pip indicator -- **Right**: Phase detail panel - - Summary text - - Sessions list with date, skill, cost - - Artifacts links (spec.md, plan.md, etc.) - -### 10. Context Drawer - -Right-side collapsible panel: - -- Tabs: Context | Activity -- **Context tab**: - - Current task card with progress - - Touched files list with +/- line counts - - Phase progress stepper (Discovery → Design → Implement → Verify) -- **Activity tab**: - - Recent activity feed with colored dots - -### 11. Visual Polish - -- Glass morphism effects (backdrop-blur) -- Grid background pattern -- Floating animated orbs (subtle) -- Smooth view transitions -- Custom scrollbar styling -- Dark theme throughout - -### 12. Keyboard Shortcuts - -- ⌘K: Focus omni-box -- ⌘1: Dashboard -- ⌘2: Session -- ⌘3: Tasks -- ⌘4: History - ---- - -**Deliverables:** - -| Component | Type | Notes | -|-----------|------|-------| -| `IconSidebar.tsx` | New | Vertical nav with tooltips | -| `StatusPill.tsx` | New | Centered header status | -| `OmniBox.tsx` | New | Unified input component | -| `DecisionToast.tsx` | New | Question toast (replaces modal) | -| `FailedToast.tsx` | New | Error toast | -| `SessionConsole.tsx` | Refactor | Inline console (was drawer) | -| `DashboardWelcome.tsx` | New | Idle state landing | -| `TasksKanban.tsx` | Refactor | 2-column layout | -| `HistoryTimeline.tsx` | Refactor | Master-detail layout | -| `ContextDrawer.tsx` | New | Right-side panel | -| `page.tsx` | Refactor | New layout structure | - -**Migration Notes:** -- Keep existing data hooks (`use-workflow-execution`, `use-session-messages`, etc.) -- Reuse shadcn/ui primitives where possible -- May need to add Tailwind animations for orbs, glow effects -- Remove old tab navigation and drawer components - -**Dependencies:** -- Phase 1053 (mockups created) -- Existing workflow/session infrastructure - -**Verification Gate: USER** -- [ ] Icon sidebar navigation works with all 4 views -- [ ] Status pill reflects workflow state correctly (idle/running/waiting/failed) -- [ ] Can start workflow from Dashboard welcome view -- [ ] Session console shows messages with agent attribution -- [ ] Decision toast appears when workflow needs input -- [ ] Failed toast appears with retry option on error -- [ ] Omni-box input works for follow-ups and question responses -- [ ] Tasks view shows 2-column Kanban -- [ ] History view shows timeline with detail panel -- [ ] Context drawer toggles and shows current task info -- [ ] Keyboard shortcuts work (⌘K, ⌘1-4) -- [ ] Visual polish matches mockup (glass effects, animations) - -**Estimated Complexity**: High (significant UI refactor) diff --git a/ROADMAP.md b/ROADMAP.md index 5958ef8..b31724b 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -58,7 +58,7 @@ This allows inserting urgent work without renumbering existing phases. | 1051 | Questions & Notifications | ✅ Complete | **USER GATE**: Browser notification, question drawer | | 1052 | Session Viewer | ✅ Complete | **USER GATE**: View session JSONL, real-time streaming | | 1053 | Workflow-Session Unification | ✅ Complete | **USER GATE**: Session detected immediately on workflow start | -| 1054 | Project Details Redesign | ⬜ Not Started | **USER GATE**: New UI matches v3 mockup, all states work | +| 1054 | Project Details Redesign | ✅ Complete | **USER GATE**: New UI matches v3 mockup, all states work | | 1055 | Smart Batching & Orchestration | ⬜ Not Started | **USER GATE**: Auto-batch tasks, state machine, auto-healing | | 1060 | Stats & Operations | ⬜ Not Started | **USER GATE**: Costs on cards, operations page, basic chart | | 1070 | Cost Analytics | ⬜ Not Started | **USER GATE**: Advanced charts, projections, export | diff --git a/packages/dashboard/package.json b/packages/dashboard/package.json index deda6fb..e216f42 100644 --- a/packages/dashboard/package.json +++ b/packages/dashboard/package.json @@ -24,6 +24,7 @@ "next-themes": "^0.4.6", "react": "19.2.3", "react-dom": "19.2.3", + "react-markdown": "^10.1.0", "sonner": "^1.7.0", "tailwind-merge": "^3.4.0", "zod": "^3.25.76" diff --git a/packages/dashboard/src/app/api/artifacts/route.ts b/packages/dashboard/src/app/api/artifacts/route.ts new file mode 100644 index 0000000..d19b560 --- /dev/null +++ b/packages/dashboard/src/app/api/artifacts/route.ts @@ -0,0 +1,62 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { readFile } from 'node:fs/promises'; +import { existsSync } from 'node:fs'; +import { resolve, normalize } from 'node:path'; + +/** + * GET /api/artifacts?path= + * Returns the content of an artifact file + */ +export async function GET(request: NextRequest) { + const { searchParams } = new URL(request.url); + const filePath = searchParams.get('path'); + + if (!filePath) { + return NextResponse.json({ error: 'Missing path parameter' }, { status: 400 }); + } + + // Normalize and resolve the path to prevent traversal attacks + const normalizedPath = normalize(resolve(filePath)); + + // Basic security check: ensure path contains expected directories + const allowedPatterns = ['/specs/', '/.specify/archive/', '/.specify/phases/']; + const hasAllowedPattern = allowedPatterns.some((pattern) => + normalizedPath.includes(pattern) + ); + + if (!hasAllowedPattern) { + return NextResponse.json( + { error: 'Access denied: path not in allowed directories' }, + { status: 403 } + ); + } + + // Ensure file ends with .md + if (!normalizedPath.endsWith('.md')) { + return NextResponse.json( + { error: 'Only markdown files are allowed' }, + { status: 403 } + ); + } + + if (!existsSync(normalizedPath)) { + return NextResponse.json({ error: 'File not found' }, { status: 404 }); + } + + try { + const content = await readFile(normalizedPath, 'utf-8'); + + // Extract title from first heading if present + const titleMatch = content.match(/^#\s+(.+)$/m); + const title = titleMatch ? titleMatch[1].trim() : filePath.split('/').pop() ?? 'Artifact'; + + return NextResponse.json({ + path: normalizedPath, + title, + content, + }); + } catch (error) { + console.error('Error reading artifact:', error); + return NextResponse.json({ error: 'Failed to read file' }, { status: 500 }); + } +} diff --git a/packages/dashboard/src/app/api/git/activity/route.ts b/packages/dashboard/src/app/api/git/activity/route.ts new file mode 100644 index 0000000..1505ad5 --- /dev/null +++ b/packages/dashboard/src/app/api/git/activity/route.ts @@ -0,0 +1,81 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { exec } from 'node:child_process'; +import { promisify } from 'node:util'; +import { existsSync } from 'node:fs'; +import { join } from 'node:path'; + +const execAsync = promisify(exec); + +interface GitActivity { + type: 'commit' | 'task' | 'file'; + description: string; + timestamp: string; + hash?: string; + author?: string; +} + +/** + * GET /api/git/activity?projectPath=&limit= + * Returns recent git activity (commits) for the project + */ +export async function GET(request: NextRequest) { + const { searchParams } = new URL(request.url); + const projectPath = searchParams.get('projectPath'); + const limit = parseInt(searchParams.get('limit') || '20', 10); + + if (!projectPath) { + return NextResponse.json({ error: 'Missing projectPath parameter' }, { status: 400 }); + } + + // Verify it's a git repo + const gitDir = join(projectPath, '.git'); + if (!existsSync(gitDir)) { + return NextResponse.json({ error: 'Not a git repository' }, { status: 400 }); + } + + try { + // Get recent commits with timestamp + // Format: hash|subject|author|relative_date + const { stdout } = await execAsync( + `git log --oneline -n ${limit} --format="%h|%s|%an|%ar" 2>/dev/null || echo ""`, + { cwd: projectPath } + ); + + const activities: GitActivity[] = []; + + const lines = stdout.trim().split('\n').filter(Boolean); + for (const line of lines) { + const [hash, subject, author, relativeDate] = line.split('|'); + if (hash && subject) { + // Detect activity type from commit message + let type: GitActivity['type'] = 'commit'; + let description = subject; + + // Check for task completion patterns + if (/^(feat|fix|chore|docs|refactor|test):/i.test(subject)) { + type = 'commit'; + // Clean up conventional commit prefix for display + description = subject.replace(/^(feat|fix|chore|docs|refactor|test):\s*/i, ''); + } + + // Check if it mentions task IDs like T001, T002 + if (/T\d{3}/i.test(subject)) { + type = 'task'; + } + + activities.push({ + type, + description, + timestamp: relativeDate || 'Unknown', + hash, + author, + }); + } + } + + return NextResponse.json({ activities }); + } catch (error) { + console.error('Error getting git activity:', error); + return NextResponse.json({ error: 'Failed to get git activity' }, { status: 500 }); + } +} diff --git a/packages/dashboard/src/app/api/git/changes/route.ts b/packages/dashboard/src/app/api/git/changes/route.ts new file mode 100644 index 0000000..83e5aec --- /dev/null +++ b/packages/dashboard/src/app/api/git/changes/route.ts @@ -0,0 +1,150 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { exec } from 'node:child_process'; +import { promisify } from 'node:util'; +import { existsSync } from 'node:fs'; +import { join } from 'node:path'; + +const execAsync = promisify(exec); + +interface FileChange { + path: string; + filename: string; + directory: string; + additions: number; + deletions: number; + status: 'added' | 'modified' | 'deleted' | 'renamed'; +} + +interface GitChangesResponse { + files: FileChange[]; + totalAdditions: number; + totalDeletions: number; + totalFiles: number; +} + +/** + * GET /api/git/changes?projectPath=&base= + * Returns file changes with line stats from git diff + */ +export async function GET(request: NextRequest) { + const { searchParams } = new URL(request.url); + const projectPath = searchParams.get('projectPath'); + const baseBranch = searchParams.get('base') || 'main'; + + if (!projectPath) { + return NextResponse.json({ error: 'Missing projectPath parameter' }, { status: 400 }); + } + + // Verify it's a git repo + const gitDir = join(projectPath, '.git'); + if (!existsSync(gitDir)) { + return NextResponse.json({ error: 'Not a git repository' }, { status: 400 }); + } + + try { + // Get all changes: working directory (unstaged + staged) + // This shows what would be committed if you did `git add . && git commit` + const [unstagedResult, stagedResult] = await Promise.all([ + execAsync('git diff --numstat 2>/dev/null', { cwd: projectPath, maxBuffer: 10 * 1024 * 1024 }).catch(() => ({ stdout: '' })), + execAsync('git diff --numstat --staged 2>/dev/null', { cwd: projectPath, maxBuffer: 10 * 1024 * 1024 }).catch(() => ({ stdout: '' })), + ]); + + // Combine outputs, removing duplicates by tracking seen files + const seenFiles = new Set(); + const allLines: string[] = []; + + for (const output of [unstagedResult.stdout, stagedResult.stdout]) { + for (const line of output.trim().split('\n').filter(Boolean)) { + const parts = line.split('\t'); + if (parts.length >= 3) { + const filePath = parts.slice(2).join('\t'); + if (!seenFiles.has(filePath)) { + seenFiles.add(filePath); + allLines.push(line); + } + } + } + } + + const stdout = allLines.join('\n'); + + const files: FileChange[] = []; + let totalAdditions = 0; + let totalDeletions = 0; + + // Parse numstat output: additions\tdeletions\tfilepath + const lines = stdout.trim().split('\n').filter(Boolean); + + for (const line of lines) { + const parts = line.split('\t'); + if (parts.length >= 3) { + const [addStr, delStr, ...pathParts] = parts; + const filePath = pathParts.join('\t'); // Handle paths with tabs + + // Binary files show as '-' for additions/deletions + const additions = addStr === '-' ? 0 : parseInt(addStr, 10); + const deletions = delStr === '-' ? 0 : parseInt(delStr, 10); + + // Determine status based on additions/deletions + let status: FileChange['status'] = 'modified'; + if (deletions === 0 && additions > 0) { + // Check if file is new (doesn't exist in base) + try { + await execAsync(`git show ${baseBranch}:"${filePath}" 2>/dev/null`, { cwd: projectPath }); + } catch { + status = 'added'; + } + } else if (additions === 0 && deletions > 0) { + // Could be deleted, check if file exists + if (!existsSync(join(projectPath, filePath))) { + status = 'deleted'; + } + } + + // Handle renamed files (path contains ' => ') + if (filePath.includes(' => ')) { + status = 'renamed'; + } + + // Extract filename and directory + const lastSlash = filePath.lastIndexOf('/'); + const filename = lastSlash >= 0 ? filePath.slice(lastSlash + 1) : filePath; + const directory = lastSlash >= 0 ? filePath.slice(0, lastSlash) : ''; + + files.push({ + path: filePath, + filename, + directory, + additions, + deletions, + status, + }); + + totalAdditions += additions; + totalDeletions += deletions; + } + } + + // Sort by directory then filename for logical grouping + files.sort((a, b) => { + // Sort by directory first + if (a.directory !== b.directory) { + return a.directory.localeCompare(b.directory); + } + // Then by filename + return a.filename.localeCompare(b.filename); + }); + + const response: GitChangesResponse = { + files, + totalAdditions, + totalDeletions, + totalFiles: files.length, + }; + + return NextResponse.json(response); + } catch (error) { + console.error('Error getting git changes:', error); + return NextResponse.json({ error: 'Failed to get git changes' }, { status: 500 }); + } +} diff --git a/packages/dashboard/src/app/api/phases/[number]/route.ts b/packages/dashboard/src/app/api/phases/[number]/route.ts new file mode 100644 index 0000000..7903cd5 --- /dev/null +++ b/packages/dashboard/src/app/api/phases/[number]/route.ts @@ -0,0 +1,352 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { readFile, readdir } from 'node:fs/promises'; +import { join } from 'node:path'; +import { existsSync } from 'node:fs'; + +interface Artifact { + name: string; + path: string; + exists: boolean; +} + +interface PhaseDetail { + number: string; + name: string; + status: 'pending' | 'in_progress' | 'completed'; + source: 'history' | 'phase_file' | 'none'; + content: string; + completedAt?: string; + goal?: string; + dependencies?: string; + complexity?: string; + artifacts: Artifact[]; + artifactsLocation?: string; +} + +/** + * Standard SDD artifact filenames + */ +const STANDARD_ARTIFACTS = [ + 'spec.md', + 'plan.md', + 'tasks.md', + 'discovery.md', + 'requirements.md', + 'research.md', + 'data-model.md', +]; + +/** + * Find artifacts for a phase by checking multiple locations + */ +async function findArtifacts( + projectPath: string, + phaseNumber: string, + phaseName: string +): Promise<{ artifacts: Artifact[]; location: string | undefined }> { + const normalizedName = phaseName.toLowerCase().replace(/\s+/g, '-'); + const phaseDirName = `${phaseNumber}-${normalizedName}`; + + // Check locations in order of priority: + // 1. specs/ (in-progress phases) + // 2. .specify/archive/ (completed but not yet cleaned up) + + const locations = [ + { path: join(projectPath, 'specs', phaseDirName), name: 'specs' }, + { path: join(projectPath, '.specify', 'archive', phaseDirName), name: 'archive' }, + ]; + + for (const location of locations) { + if (existsSync(location.path)) { + try { + const files = await readdir(location.path); + const mdFiles = files.filter((f) => f.endsWith('.md')); + + if (mdFiles.length > 0) { + // Include standard artifacts that exist, plus any additional .md files + const artifacts: Artifact[] = []; + const addedFiles = new Set(); + + // First add standard artifacts in order + for (const stdArtifact of STANDARD_ARTIFACTS) { + if (mdFiles.includes(stdArtifact)) { + artifacts.push({ + name: stdArtifact, + path: join(location.path, stdArtifact), + exists: true, + }); + addedFiles.add(stdArtifact); + } + } + + // Then add any additional .md files + for (const file of mdFiles) { + if (!addedFiles.has(file)) { + artifacts.push({ + name: file, + path: join(location.path, file), + exists: true, + }); + } + } + + // Also check for checklists subdirectory + const checklistsPath = join(location.path, 'checklists'); + if (existsSync(checklistsPath)) { + try { + const checklistFiles = await readdir(checklistsPath); + for (const file of checklistFiles.filter((f) => f.endsWith('.md'))) { + artifacts.push({ + name: `checklists/${file}`, + path: join(checklistsPath, file), + exists: true, + }); + } + } catch { + // Ignore errors reading checklists + } + } + + return { artifacts, location: location.name }; + } + } catch { + // Continue to next location + } + } + } + + // No artifacts found + return { artifacts: [], location: undefined }; +} + +/** + * Extract a specific phase section from HISTORY.md + * + * HISTORY.md format: + * ## 0040 - Phase Name <- Section header (##) + * **Completed**: 2026-01-20 + * # Phase 0040: Phase Name <- Content subheading (#) - NOT a new section + * **Goal**: ... + * ... rest of content ... + * --- <- Section divider + * ## 0045 - Next Phase <- Next section + */ +function extractPhaseFromHistory(historyContent: string, phaseNumber: string): Omit | null { + const lines = historyContent.split('\n'); + let inPhaseSection = false; + let currentPhase: Omit | null = null; + const contentLines: string[] = []; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + + // Section headers are specifically ## (2 hashes) - e.g., "## 0040 - Obsidian Integration" + // Single # headers inside content (like "# Phase 0040: Name") are NOT section boundaries + const sectionHeaderMatch = line.match(/^##\s*(\d{4})\s*[-:]\s*(.+)/); + + if (sectionHeaderMatch) { + // Found a new section header + if (inPhaseSection && currentPhase) { + // We were in the target section and hit a new one - return what we have + currentPhase.content = contentLines.join('\n').trim(); + return currentPhase; + } + + const [, num, name] = sectionHeaderMatch; + if (num === phaseNumber) { + // Found the target phase section + inPhaseSection = true; + currentPhase = { + number: num, + name: name.trim(), + status: 'completed', + source: 'history', + content: '', + }; + contentLines.length = 0; + continue; + } + } + + // Check for horizontal rule which often separates phases + if (inPhaseSection && line.trim() === '---') { + // Check if this is followed by another phase section + const nextLine = lines[i + 1]; + if (nextLine && nextLine.match(/^##\s*\d{4}/)) { + // End of our section + currentPhase!.content = contentLines.join('\n').trim(); + return currentPhase; + } + // Otherwise it's just a divider within the section, include it + } + + if (inPhaseSection) { + // Extract metadata from content + const completedMatch = line.match(/\*\*Completed\*\*:\s*(.+)/); + if (completedMatch && currentPhase) { + currentPhase.completedAt = completedMatch[1].trim(); + } + + const goalMatch = line.match(/\*\*Goal\*\*:\s*(.+)/); + if (goalMatch && currentPhase) { + currentPhase.goal = goalMatch[1].trim(); + } + + const depsMatch = line.match(/\*\*Dependencies\*\*:\s*(.+)/); + if (depsMatch && currentPhase) { + currentPhase.dependencies = depsMatch[1].trim(); + } + + const complexityMatch = line.match(/\*\*(?:Estimated\s+)?Complexity\*\*:\s*(.+)/); + if (complexityMatch && currentPhase) { + currentPhase.complexity = complexityMatch[1].trim(); + } + + contentLines.push(line); + } + } + + if (inPhaseSection && currentPhase) { + currentPhase.content = contentLines.join('\n').trim(); + return currentPhase; + } + + return null; +} + +/** + * Find and read a phase file from .specify/phases/ + */ +async function readPhaseFile(projectPath: string, phaseNumber: string): Promise | null> { + const phasesDir = join(projectPath, '.specify', 'phases'); + + if (!existsSync(phasesDir)) { + return null; + } + + try { + const files = await readdir(phasesDir); + const phaseFile = files.find((f) => f.startsWith(phaseNumber) && f.endsWith('.md')); + + if (!phaseFile) { + return null; + } + + const filePath = join(phasesDir, phaseFile); + const content = await readFile(filePath, 'utf-8'); + + // Extract name from filename + const nameMatch = phaseFile.match(/^\d{4}-(.+)\.md$/); + const name = nameMatch + ? nameMatch[1] + .split('-') + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' ') + : `Phase ${phaseNumber}`; + + // Extract metadata + let goal: string | undefined; + let dependencies: string | undefined; + let complexity: string | undefined; + let status: 'pending' | 'in_progress' = 'pending'; + + const goalMatch = content.match(/\*\*Goal\*\*:\s*(.+)/); + if (goalMatch) goal = goalMatch[1].trim(); + + const depsMatch = content.match(/\*\*Dependencies\*\*:\s*(.+)/); + if (depsMatch) dependencies = depsMatch[1].trim(); + + const complexityMatch = content.match(/\*\*(?:Estimated\s+)?Complexity\*\*:\s*(.+)/); + if (complexityMatch) complexity = complexityMatch[1].trim(); + + // Check for status in frontmatter + const statusMatch = content.match(/status:\s*([\w_]+)/); + if (statusMatch) { + const s = statusMatch[1].toLowerCase(); + if (s === 'in_progress' || s === 'active') { + status = 'in_progress'; + } + } + + return { + number: phaseNumber, + name, + status, + source: 'phase_file', + content, + goal, + dependencies, + complexity, + }; + } catch { + return null; + } +} + +export async function GET( + request: NextRequest, + { params }: { params: Promise<{ number: string }> } +) { + const { number: phaseNumber } = await params; + const { searchParams } = new URL(request.url); + const projectPath = searchParams.get('projectPath'); + const phaseName = searchParams.get('phaseName') || ''; + + if (!projectPath) { + return NextResponse.json({ error: 'Missing projectPath parameter' }, { status: 400 }); + } + + let phaseDetail: PhaseDetail | null = null; + + // First try HISTORY.md for completed phases + const historyPath = join(projectPath, '.specify', 'history', 'HISTORY.md'); + if (existsSync(historyPath)) { + try { + const historyContent = await readFile(historyPath, 'utf-8'); + const historyPhase = extractPhaseFromHistory(historyContent, phaseNumber); + if (historyPhase) { + phaseDetail = { ...historyPhase, artifacts: [], artifactsLocation: undefined }; + } + } catch { + // Continue to phase file + } + } + + // If not in history, try phase file + if (!phaseDetail) { + const phaseFileDetail = await readPhaseFile(projectPath, phaseNumber); + if (phaseFileDetail) { + phaseDetail = { ...phaseFileDetail, artifacts: [], artifactsLocation: undefined }; + } + } + + // If still nothing, create minimal response + if (!phaseDetail) { + phaseDetail = { + number: phaseNumber, + name: phaseName || `Phase ${phaseNumber}`, + status: 'pending', + source: 'none', + content: '', + artifacts: [], + }; + } + + // Find available artifacts + const { artifacts, location } = await findArtifacts( + projectPath, + phaseNumber, + phaseDetail.name + ); + phaseDetail.artifacts = artifacts; + phaseDetail.artifactsLocation = location; + + // Update status based on artifact location + if (location === 'specs') { + phaseDetail.status = 'in_progress'; + } else if (location === 'archive' || phaseDetail.source === 'history') { + phaseDetail.status = 'completed'; + } + + return NextResponse.json({ phase: phaseDetail }); +} diff --git a/packages/dashboard/src/app/api/phases/route.ts b/packages/dashboard/src/app/api/phases/route.ts new file mode 100644 index 0000000..e726286 --- /dev/null +++ b/packages/dashboard/src/app/api/phases/route.ts @@ -0,0 +1,155 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { readFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import { existsSync } from 'node:fs'; + +/** + * Phase status from ROADMAP.md + */ +type PhaseStatus = 'not_started' | 'in_progress' | 'complete' | 'awaiting_user' | 'blocked'; + +/** + * Parsed phase from ROADMAP.md + */ +interface Phase { + number: string; + name: string; + status: PhaseStatus; + hasUserGate: boolean; + verificationGate?: string; +} + +/** + * Parse phase status from status cell in table + */ +function parsePhaseStatus(statusCell: string): PhaseStatus { + const lower = statusCell.toLowerCase().replace(/_/g, ' '); + + if (lower.includes('✅') || lower.includes('complete') || lower.includes('done')) { + return 'complete'; + } + if (lower.includes('🔄') || lower.includes('in progress') || lower.includes('active')) { + return 'in_progress'; + } + if (lower.includes('⏳') || lower.includes('awaiting') || lower.includes('waiting')) { + return 'awaiting_user'; + } + if (lower.includes('🚫') || lower.includes('blocked')) { + return 'blocked'; + } + + return 'not_started'; +} + +/** + * Check if phase has USER GATE marker + */ +function hasUserGate(text: string): boolean { + return text.toUpperCase().includes('USER GATE'); +} + +/** + * Parse a table row into phase data + */ +function parseTableRow(row: string): Phase | null { + const cells = row + .replace(/^\|/, '') + .replace(/\|$/, '') + .split('|') + .map((c) => c.trim()); + + if (cells.length < 3) return null; + + const [phaseCell, nameCell, statusCell, gateCell] = cells; + + const phaseMatch = phaseCell.match(/(\d{4})/); + if (!phaseMatch) return null; + + const number = phaseMatch[1]; + const name = nameCell || ''; + const status = parsePhaseStatus(statusCell || ''); + const hasGate = hasUserGate(gateCell || '') || hasUserGate(statusCell || ''); + + return { + number, + name, + status, + hasUserGate: hasGate, + verificationGate: gateCell || undefined, + }; +} + +/** + * Parse ROADMAP.md content + */ +function parseRoadmapContent(content: string): Phase[] { + const lines = content.split('\n'); + const phases: Phase[] = []; + + let inTable = false; + let tableHeaderSeen = false; + + for (const line of lines) { + // Detect table start + if (line.includes('|') && line.includes('Phase') && line.includes('Status')) { + inTable = true; + tableHeaderSeen = false; + continue; + } + + // Skip table separator row + if (inTable && line.match(/^\|[-:\s|]+\|$/)) { + tableHeaderSeen = true; + continue; + } + + // Parse table rows after header + if (inTable && tableHeaderSeen && line.startsWith('|')) { + const phase = parseTableRow(line); + if (phase) { + phases.push(phase); + } + continue; + } + + // End table if we see non-table content + if (inTable && tableHeaderSeen && !line.startsWith('|') && line.trim() !== '') { + inTable = false; + tableHeaderSeen = false; + } + } + + return phases; +} + +export async function GET(request: NextRequest) { + const { searchParams } = new URL(request.url); + const projectPath = searchParams.get('projectPath'); + + if (!projectPath) { + return NextResponse.json({ error: 'Missing projectPath parameter' }, { status: 400 }); + } + + const roadmapPath = join(projectPath, 'ROADMAP.md'); + + if (!existsSync(roadmapPath)) { + return NextResponse.json({ phases: [], error: 'ROADMAP.md not found' }); + } + + try { + const content = await readFile(roadmapPath, 'utf-8'); + const phases = parseRoadmapContent(content); + + return NextResponse.json({ + phases, + activePhase: phases.find((p) => p.status === 'in_progress') ?? null, + progress: { + total: phases.length, + completed: phases.filter((p) => p.status === 'complete').length, + }, + }); + } catch (error) { + const message = error instanceof Error ? error.message : 'Unknown error'; + return NextResponse.json({ error: message }, { status: 500 }); + } +} diff --git a/packages/dashboard/src/app/globals.css b/packages/dashboard/src/app/globals.css index f1023fa..034d631 100644 --- a/packages/dashboard/src/app/globals.css +++ b/packages/dashboard/src/app/globals.css @@ -8,7 +8,7 @@ } .dark { - --background: #0a0a0a; + --background: #09090b; --foreground: #ededed; } @@ -17,3 +17,70 @@ body { color: var(--foreground); font-family: var(--font-geist-sans), Arial, Helvetica, sans-serif; } + +/* Glass morphism effect */ +.glass { + background: rgba(24, 24, 27, 0.8); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border: 1px solid rgba(39, 39, 42, 0.5); +} + +/* Grid background pattern */ +.bg-grid { + background-image: + linear-gradient(rgba(99, 102, 241, 0.03) 1px, transparent 1px), + linear-gradient(90deg, rgba(99, 102, 241, 0.03) 1px, transparent 1px); + background-size: 32px 32px; +} + +/* Omni-box gradient glow on focus */ +.omni-glow { + box-shadow: + 0 0 0 1px rgba(99, 102, 241, 0.3), + 0 0 20px rgba(99, 102, 241, 0.15), + 0 0 40px rgba(99, 102, 241, 0.05); +} + +/* Cursor blink animation */ +.cursor-blink::after { + content: '▋'; + animation: blink 1s step-end infinite; +} + +@keyframes blink { + 0%, 100% { opacity: 1; } + 50% { opacity: 0; } +} + +/* Custom scrollbar styling */ +.custom-scrollbar::-webkit-scrollbar { + width: 6px; + height: 6px; +} + +.custom-scrollbar::-webkit-scrollbar-track { + background: transparent; +} + +.custom-scrollbar::-webkit-scrollbar-thumb { + background: rgba(82, 82, 91, 0.5); + border-radius: 3px; +} + +.custom-scrollbar::-webkit-scrollbar-thumb:hover { + background: rgba(82, 82, 91, 0.8); +} + +/* Status glow effects */ +.glow-success { + box-shadow: 0 0 12px rgba(16, 185, 129, 0.4); +} + +.glow-warning { + box-shadow: 0 0 12px rgba(245, 158, 11, 0.4); +} + +.glow-danger { + box-shadow: 0 0 12px rgba(239, 68, 68, 0.4); +} diff --git a/packages/dashboard/src/app/page.tsx b/packages/dashboard/src/app/page.tsx index d5cb62c..65382db 100644 --- a/packages/dashboard/src/app/page.tsx +++ b/packages/dashboard/src/app/page.tsx @@ -1,12 +1,41 @@ -import { MainLayout } from "@/components/layout/main-layout" -import { ProjectList } from "@/components/projects/project-list" +'use client' + +import { GridBackground, FloatingOrbs } from '@/components/design-system' +import { ProjectList } from '@/components/projects/project-list' +import { Plus } from 'lucide-react' export default function Home() { return ( - -
- -
-
+
+ {/* Background decorations */} + + + + {/* Header */} +
+
+
+ {/* Logo */} +
+ SF +
+

SpecFlow Dashboard

+
+ + {/* Actions */} + +
+
+ + {/* Main content */} +
+
+ +
+
+
) } diff --git a/packages/dashboard/src/app/projects/[id]/page.tsx b/packages/dashboard/src/app/projects/[id]/page.tsx index 6dca481..acf4110 100644 --- a/packages/dashboard/src/app/projects/[id]/page.tsx +++ b/packages/dashboard/src/app/projects/[id]/page.tsx @@ -2,28 +2,35 @@ import { useEffect, useMemo, useState, useCallback, useRef } from "react" import { useParams, useRouter } from "next/navigation" -import { MainLayout } from "@/components/layout/main-layout" -import { ProjectDetailHeader } from "@/components/projects/project-detail-header" -import { ViewTabs } from "@/components/projects/view-tabs" -import { StatusView } from "@/components/projects/status-view" -import { KanbanView } from "@/components/projects/kanban-view" -import { TimelineView } from "@/components/projects/timeline-view" +import { AppLayout } from "@/components/layout/app-layout" +import { ViewType } from "@/components/layout/icon-sidebar" +import { DashboardWelcome } from "@/components/views/dashboard-welcome" +import { SessionConsole } from "@/components/views/session-console" +import { TasksKanban } from "@/components/views/tasks-kanban" +import { HistoryTimeline } from "@/components/views/history-timeline" +import { ContextDrawer } from "@/components/layout/context-drawer" +import { OmniBox, OmniBoxHandle } from "@/components/input/omni-box" +import { DecisionToast } from "@/components/input/decision-toast" +import { FailedToast } from "@/components/input/failed-toast" +import { DetachedBanner } from "@/components/input/detached-banner" +import type { WorkflowStatus } from "@/components/design-system" import { useConnection } from "@/contexts/connection-context" import { useProjects } from "@/hooks/use-projects" -import { useViewPreference } from "@/hooks/use-view-preference" import { useWorkflowExecution } from "@/hooks/use-workflow-execution" import { AlertCircle } from "lucide-react" import { SessionViewerDrawer } from "@/components/projects/session-viewer-drawer" -import { SessionHistoryList } from "@/components/projects/session-history-list" import { useSessionHistory } from "@/hooks/use-session-history" +import { useSessionMessages } from "@/hooks/use-session-messages" +import { usePhaseHistory } from "@/hooks/use-phase-history" +import { useGitChanges } from "@/hooks/use-git-changes" +import { useGitActivity } from "@/hooks/use-git-activity" import type { WorkflowIndexEntry } from "@/lib/services/workflow-service" import { toastWorkflowCancelled, toastWorkflowError, - toastAnswersSubmitted, } from "@/lib/toast-helpers" import type { ProjectStatus } from "@/lib/action-definitions" -import type { OrchestrationState } from "@specflow/shared" +import type { OrchestrationState, Task } from "@specflow/shared" import type { WorkflowSkill } from "@/hooks/use-workflow-skills" /** @@ -38,6 +45,29 @@ function getProjectStatus(state: OrchestrationState | null | undefined): Project return "needs_setup" } +/** + * Convert workflow execution status to WorkflowStatus for UI + */ +function getWorkflowStatus(execution: { status?: string } | null): WorkflowStatus { + if (!execution?.status) return 'idle' + switch (execution.status) { + case 'running': return 'running' + case 'waiting_for_input': return 'waiting' + case 'failed': return 'failed' + case 'detached': return 'idle' // Detached is not an error state - show as idle with message + case 'completed': + case 'cancelled': + default: return 'idle' + } +} + +/** + * Check if workflow is in detached state (dashboard lost track but session may be running) + */ +function isWorkflowDetached(execution: { status?: string } | null): boolean { + return execution?.status === 'detached' +} + export default function ProjectDetailPage() { const params = useParams() const router = useRouter() @@ -45,7 +75,10 @@ export default function ProjectDetailPage() { const { states, tasks, setSelectedProject } = useConnection() const { projects, loading: projectsLoading } = useProjects() - const [activeView, setActiveView] = useViewPreference(projectId) + const [activeView, setActiveView] = useState('dashboard') + + // OmniBox ref for focus handling + const omniBoxRef = useRef(null) // Find project in list const project = projects.find((p) => p.id === projectId) @@ -60,8 +93,7 @@ export default function ProjectDetailPage() { const [isStartingWorkflow, setIsStartingWorkflow] = useState(false) const [isCancellingWorkflow, setIsCancellingWorkflow] = useState(false) - // Question drawer state - const [isQuestionDrawerOpen, setIsQuestionDrawerOpen] = useState(false) + // Question drawer state - removed in favor of toast const previousStatusRef = useRef(null) // Session viewer drawer state @@ -77,6 +109,38 @@ export default function ProjectDetailPage() { refresh: refreshSessionHistory, } = useSessionHistory(project?.path ?? null) + // Session messages for live console view + // Include detached sessions - they may still be receiving writes + const isWorkflowActive = workflowExecution?.status === 'running' || + workflowExecution?.status === 'waiting_for_input' || + workflowExecution?.status === 'detached' + const { + messages: sessionMessages, + isLoading: sessionMessagesLoading, + } = useSessionMessages( + project?.path ?? null, + workflowExecution?.sessionId ?? null, + isWorkflowActive + ) + + // Phase history from ROADMAP.md + const { + phases: phaseHistory, + isLoading: phaseHistoryLoading, + } = usePhaseHistory(project?.path ?? null) + + // Git changes (touched files) + const { + files: touchedFiles, + totalAdditions, + totalDeletions, + } = useGitChanges(project?.path ?? null) + + // Git activity (recent commits) + const { + activities: recentActivity, + } = useGitActivity(project?.path ?? null, 20) + // Set selected project for command palette context useEffect(() => { if (project) { @@ -121,25 +185,14 @@ export default function ProjectDetailPage() { handleWorkflowStart(skill.command) }, [handleWorkflowStart]) - // Auto-open question drawer when questions arrive + // Track status changes for toast display useEffect(() => { - const prevStatus = previousStatusRef.current - const currentStatus = workflowExecution?.status - - // Detect transition to waiting_for_input - if ( - currentStatus === 'waiting_for_input' && - prevStatus !== 'waiting_for_input' - ) { - setIsQuestionDrawerOpen(true) - } - - previousStatusRef.current = currentStatus ?? null + previousStatusRef.current = workflowExecution?.status ?? null }, [workflowExecution?.status]) - // Handle question badge click - const handleQuestionBadgeClick = useCallback(() => { - setIsQuestionDrawerOpen(true) + // Handle OmniBox focus + const handleFocusOmniBox = useCallback(() => { + omniBoxRef.current?.focus() }, []) // Handle session button click (from header - shows current workflow) @@ -173,145 +226,234 @@ export default function ProjectDetailPage() { } }, [startWorkflow]) - // Handle answer submission - const handleSubmitAnswers = useCallback(async (answers: Record) => { - try { - await submitAnswers(answers) - setIsQuestionDrawerOpen(false) - toastAnswersSubmitted() - } catch (error) { - const message = error instanceof Error ? error.message : 'Unknown error' - toastWorkflowError(message) - throw error // Re-throw so drawer stays open + // Get workflow status for UI (must be before early returns for hooks consistency) + const workflowStatus = getWorkflowStatus(workflowExecution) + + // Get current task from tasks data (in_progress) + const currentTask: Task | null = useMemo(() => + projectTasks?.tasks?.find((t) => t.status === 'in_progress') ?? null + , [projectTasks]) + + // Get next task (first todo task) - shown when no current task + const nextTask: Task | null = useMemo(() => + projectTasks?.tasks?.find((t) => t.status === 'todo') ?? null + , [projectTasks]) + + // Handle OmniBox submit + const handleOmniBoxSubmit = useCallback((message: string) => { + // If waiting for input, submit as answer + if (workflowStatus === 'waiting' && workflowExecution?.output?.questions?.length) { + // For simplicity, use the message as answer to first question + submitAnswers({ '0': message }) + } else { + // Otherwise start a new workflow with the message + handleWorkflowStart(message) } - }, [submitAnswers]) + }, [workflowStatus, workflowExecution, submitAnswers, handleWorkflowStart]) + + // Handle decision toast answer + const handleDecisionAnswer = useCallback((answer: string) => { + if (workflowExecution?.output?.questions?.length) { + submitAnswers({ '0': answer }) + } + }, [workflowExecution, submitAnswers]) + + // Handle failed toast retry + const handleRetry = useCallback(() => { + // Re-start the last workflow + if (workflowExecution?.skill) { + handleWorkflowStart(workflowExecution.skill) + } + }, [workflowExecution, handleWorkflowStart]) + + // Handle failed toast dismiss + const handleDismiss = useCallback(() => { + // Cancel the failed workflow to clear state + cancelWorkflow() + }, [cancelWorkflow]) + + // Build questions for decision toast + const decisionQuestions = useMemo(() => { + if (!workflowExecution?.output?.questions) return [] + return workflowExecution.output.questions.map((q) => ({ + question: q.question, + options: q.options?.map((opt) => ({ + label: opt.label, + description: opt.description, + })) ?? [], + })) + }, [workflowExecution?.output?.questions]) // Loading state if (projectsLoading) { return ( - -
- {/* Header skeleton */} -
-
-
-
-
-
- - {/* Tabs skeleton */} -
-
-
-
-
-
-
- - {/* Content skeleton */} -
-
-
-
-
-
-
+ +
+
+
+
+
+
+
- + ) } // Project not found if (!project) { return ( - -
-
- -

- Project Not Found -

-

- The project with ID "{projectId}" could not be found. -

- -
+ +
+ +

+ Project Not Found +

+

+ The project with ID "{projectId}" could not be found. +

+
- +
) } - return ( - -
- + // Map internal view names to match existing component expectations + const renderContent = () => { + switch (activeView) { + case 'dashboard': + return ( + + ) + case 'session': + return ( + handleWorkflowStart('implement')} + onViewDashboard={() => setActiveView('dashboard')} + /> + ) + case 'tasks': + return + case 'history': + // Transform phase history to HistoryTimeline format + const phases = phaseHistory.map((p) => ({ + number: p.number, + name: p.name, + status: p.status === 'complete' ? 'completed' as const + : p.status === 'in_progress' ? 'in_progress' as const + : p.status === 'blocked' ? 'failed' as const + : 'pending' as const, + artifacts: ['spec.md', 'plan.md', 'tasks.md'], + })) + return + default: + return null + } + } - - -
- {activeView === "status" && ( - - )} - {activeView === "kanban" && ( - - )} - {activeView === "timeline" && ( - - )} + // Extract branch name from state + const branchName = state?.orchestration?.phase?.branch ?? undefined + + // Context drawer content + const contextDrawerContent = ( + + ) + + return ( + + {/* Main content */} +
+
+ {renderContent()}
- {/* Session Viewer Drawer */} - { - setIsSessionViewerOpen(open) - if (!open) setSelectedHistoricalSession(null) // Clear selection on close - }} - projectPath={project.path} - sessionId={selectedHistoricalSession?.sessionId ?? workflowExecution?.sessionId ?? null} - isActive={ - selectedHistoricalSession - ? (selectedHistoricalSession.status === 'running' || selectedHistoricalSession.status === 'waiting_for_input') - : (workflowExecution?.status === 'running' || workflowExecution?.status === 'waiting_for_input') - } - onResumeSession={handleResumeSession} - isResuming={isResumingSession} + {/* OmniBox at bottom */} +
- + + {/* Decision Toast - shown when waiting for input */} + {workflowStatus === 'waiting' && decisionQuestions.length > 0 && ( + + )} + + {/* Failed Toast - shown when workflow failed (not detached) */} + {workflowStatus === 'failed' && !isWorkflowDetached(workflowExecution) && ( + + )} + + {/* Detached Banner - shown when dashboard lost track but session may still be running */} + {isWorkflowDetached(workflowExecution) && ( + { + setActiveView('session') + }} + /> + )} + + {/* Session Viewer Drawer */} + { + setIsSessionViewerOpen(open) + if (!open) setSelectedHistoricalSession(null) // Clear selection on close + }} + projectPath={project.path} + sessionId={selectedHistoricalSession?.sessionId ?? workflowExecution?.sessionId ?? null} + isActive={ + selectedHistoricalSession + ? (selectedHistoricalSession.status === 'running' || selectedHistoricalSession.status === 'waiting_for_input') + : (workflowExecution?.status === 'running' || workflowExecution?.status === 'waiting_for_input') + } + onResumeSession={handleResumeSession} + isResuming={isResumingSession} + /> +
) } diff --git a/packages/dashboard/src/components/design-system/floating-orbs.tsx b/packages/dashboard/src/components/design-system/floating-orbs.tsx new file mode 100644 index 0000000..b580b6e --- /dev/null +++ b/packages/dashboard/src/components/design-system/floating-orbs.tsx @@ -0,0 +1,27 @@ +'use client' + +import { cn } from '@/lib/utils' + +interface FloatingOrbsProps { + className?: string +} + +export function FloatingOrbs({ className }: FloatingOrbsProps) { + return ( +