Skip to content

feat(tasks): All Tasks cross-project view + fix viewMode flash on project switch#423

Open
hudsonhrh wants to merge 1 commit into
mainfrom
hudsonhrh/tasks-all-view-and-flash-fix
Open

feat(tasks): All Tasks cross-project view + fix viewMode flash on project switch#423
hudsonhrh wants to merge 1 commit into
mainfrom
hudsonhrh/tasks-all-view-and-flash-fix

Conversation

@hudsonhrh
Copy link
Copy Markdown
Member

Summary

Two related fixes on the tasks page, bundled into one PR because they touch the same code path:

  1. Flash fix — viewMode (board/list/gantt) no longer resets to 'board' for a frame when you switch projects in List or Gantt view. The view state is now hoisted above the keyed TaskBoardProvider boundary instead of being reset on every project remount.

  2. All Tasks view — new top-of-sidebar entry that aggregates every project's tasks into one cross-project view. Distinct accent treatment so it doesn't blend into the project list. Read-only for now (Add Task hidden, mutations toast "Open a project to make changes" — clicking a task navigates into the project's detail modal where everything works normally).

Screenshot

All Tasks view on Test6

(See /tmp/poa-screenshots/all-tasks-final.png locally — header shows ""All Tasks 28 tasks across 3 projects"", sidebar shows the accent-tinted ""All Tasks · 28 tasks · 3 projects"" entry at the top, list view aggregates across projects with a project chip on each row.)

Flash fix

Root cause: MainLayout.js mounts <TaskBoardProvider key={selectedProject.id}> so each project gets a fresh TaskBoardContext (intentional — optimistic state must reset per project). TaskBoard lives inside that subtree and owned useViewMode. On every project switch, useViewMode's state reset to the 'board' default, then a useEffect read localStorage and switched to the user's stored mode → that's the visible flash.

Fix: views/useViewMode.js split into a TaskViewModeProvider (lives at the MainLayout level, sibling above the keyed boundary) and a thin useViewMode consumer. Same public API; viewMode now persists across project switches.

All Tasks view design

Sidebar entry — distinct but consistent:

Position Top of sidebar, above the existing ""Projects"" heading
Visual Rounded card with purple gradient accent, stacked-icon glyph, count subtitle (""N tasks · M projects"")
Selected state Saturates the gradient + purple ring/shadow, matches the project-row selection pattern
Route ?projectId=__all__ (ALL_PROJECTS_ID sentinel — cannot collide with real on-chain project ids which are 0x-prefixed)

Data layer:

  • AllTasksProvider (new) wraps the same TaskBoardContext that ListView / GanttView / TaskBoardDesktop already consume, so the existing views render unchanged
  • aggregateAllTasksColumns(projects) merges same-status columns across every project and decorates each task with projectId + projectName for the chip
  • All mutators (addTask, moveTask, editTask, deleteTask, applyForTask, approveApplication, assignTask, rejectTask) are no-op + toast; the All Tasks view is a browser, not an editor
  • TaskColumn reads isAllTasks from context and hides the Add Task button accordingly
  • TaskCard and TaskRow render a project chip when task.projectName is populated (only true in this aggregation)

Mobile project picker doesn't include All Tasks yet — desktop-only for v1.

Test plan

  • yarn build clean
  • Headless Chrome screenshot on Test6 confirms All Tasks entry + aggregation + project chips
  • Navigate between projects in list/gantt view → no flash to board
  • Switch to All Tasks → board, list, gantt all render aggregated tasks
  • Add Task button is hidden in All Tasks board view
  • Drag a card in All Tasks board → toast ""Open a project to move this task""
  • Click a card in All Tasks → opens task modal in the right project context
  • Switch from All Tasks back to a specific project → no regression on the per-project flow

🤖 Generated with Claude Code

Two related changes to the tasks page that landed together since they touch
the same code path.

1. Hoist viewMode state above TaskBoardProvider
   TaskBoardProvider is keyed on selectedProject.id (intentional — resets per-
   project optimistic state). TaskBoard owned useViewMode, so the view mode
   state unmounted/remounted on every project switch, snapping from the 'board'
   default back to the stored value a frame later. That's the board→list flash
   when navigating between projects in list view.

   Fix: TaskViewModeProvider sits at MainLayout level (sibling above the keyed
   boundary). useViewMode is now a consumer; same public API, no flash.

2. All Tasks cross-project view
   New top-of-sidebar entry — distinct from project rows: gradient accent,
   stacked icon, task/project count subtitle. Clicking it sets the
   ALL_PROJECTS_ID ('__all__') sentinel as the active selection.

   AllTasksProvider (new) wraps the same TaskBoardContext that consumers
   already use, so ListView/GanttView/TaskBoard render unchanged. It supplies:
     - synthetic taskColumns: aggregateAllTasksColumns(projects) merges every
       project's columns by status and decorates each task with projectId +
       projectName for the chip
     - isAllTasks: true (read in TaskColumn to hide Add Task)
     - all mutators no-op + toast "Open a project to <action>" — the All Tasks
       view is for browsing, not editing. Clicking a task card still navigates
       into the project's detail modal where mutations work normally.

   View-side adaptations are minimal: TaskCard + TaskRow render a project chip
   when task.projectName is populated (only true in All-Tasks aggregation).

Files touched:
  - new: views/allTasks.js  (sentinel + aggregateAllTasksColumns + countAllTasks)
  - new: AllTasksProvider.jsx
  - views/useViewMode.js  (split into provider + consumer)
  - MainLayout.js         (hoist provider, render AllTasksProvider on sentinel)
  - ProjectSidebar.js     (top-of-sidebar entry)
  - TaskColumn.js         (hide Add Task in all-tasks mode)
  - TaskCard.js, TaskRow.jsx  (project chip)
  - TaskBoardContext.js   (export the context for the alt provider)
  - dataBaseContext.js    (synthetic ALL_TASKS_PROJECT, preserve across refreshes)

Tested locally: yarn build clean; All Tasks renders aggregated tasks across
Test6's 3 projects; viewMode persists across project switches with no flash.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant