Repository navigation
feat(imago): tasks data layer and pure task model (IMG-9.1) - #2780
Conversation
Ports myimago's task-tree and task-edit onto the real GET /tasks shape: multiple assignees from task_assignees (legacy fields as fallback), per-list statuses with todo/in_progress/done groups, five-level nesting, and the server's completion guard (any move into a done status is refused while a direct subtask has no completedAt, in the server's own words). Default statuses are held to DEFAULT_TASK_STATUSES by a parity test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UxyeCYTQzNU9fkbDQHb1Yn
Lists a drive's TASK_LIST pages, loads a list's whole tree (paged, gated on subTaskCount so leaves never trigger GET /tasks' lazy writes) with each sub-list's statuses, and reads /tasks/statuses. Create, update, status, assignees, delete and reorder go through the IMG-1.5 client with CSRF, apply optimistically via the pure model, roll back on refusal and revalidate. The SWR provider now exposes its client to hooks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UxyeCYTQzNU9fkbDQHb1Yn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UxyeCYTQzNU9fkbDQHb1Yn
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
PageSpace records for IMG-9.1:
|
Independent review: IMG-9.1 @
|
Summary
Tasks data layer for imago in
apps/imago/src/ui/tasks/— data and a pure model, no views (those are IMG-9.2+)./api/pages/[pageId]/tasks{,/[taskId],/reorder,/statuses}and the drive pages route inlsmode), and the mapping into imago's model: multiple assignees fromtask_assignees(legacy single-assignee fields as a fallback), per-list statuses ordered by position, default statuses that a parity test holds toDEFAULT_TASK_STATUSES.locate, status groups, open/done/seed status picks (the same picks the server makes), five-level nesting, and edits (status, toggle, fields, assignees, add, remove, move) that validate and stamp the way the server does. Completing a parent is refused exactly as the server's completion guard does: any move into a done-group status, even from another done status, is refused while a direct untrashed subtask has nocompletedAt, in the server's own words (Complete all sub-tasks first (n of m remaining)).ApiClient(session cookie,X-CSRF-Tokenon writes).loadTaskTreepages through GET /tasks (200 per page, capped at the 5000 that reorder accepts) and loads sub-lists only for tasks the server counts subtasks for, because GET /tasks lazily writes a task list for any page it hasn't seen (the same gate classic'suseTaskSubTasksuses).useDriveTaskLists,useTaskStatuses,useTaskList(whole tree plus actions). Each write runs the pure edit first, so it can refuse without a request, then applies it optimistically, sends it, rolls back if the server refuses (e.g. a 422 SUBTASKS_INCOMPLETE race), and always revalidates from the server.api/swr-provider.tsxnow also exposes its client throughuseApiClient(), so the hooks that write use the same client SWR reads through.No new dependencies. Classic
apps/webis untouched.PageSpace
Builder: ag-lfkk4w4e
Criteria
apps/imago/src/ui/tasks/task-model/from-api.ts:92,apps/imago/src/ui/tasks/task-api/task-api.ts:42,:67,:78,apps/imago/src/ui/tasks/use-tasks/use-tasks.ts:177apps/imago/src/ui/tasks/task-model/from-api.test.ts:211,apps/imago/src/ui/tasks/task-api/task-api.test.ts:44,:131,apps/imago/src/ui/tasks/use-tasks/use-tasks.test.tsxapps/imago/src/ui/tasks/task-model/from-api.ts:38,apps/imago/src/ui/tasks/task-tree/task-tree.ts:86,:123,apps/imago/src/ui/tasks/task-edit/task-edit.ts:90apps/imago/src/ui/tasks/task-model/from-api.test.ts:58,apps/imago/src/ui/tasks/task-tree/task-tree.test.ts:217,apps/imago/src/ui/tasks/task-edit/task-edit.test.ts:23,:349apps/imago/src/ui/tasks/task-api/task-api.ts:100-135,apps/imago/src/ui/tasks/use-tasks/use-tasks.ts:89apps/imago/src/ui/tasks/task-api/task-api.test.ts:175,apps/imago/src/ui/tasks/use-tasks/use-tasks.test.tsx:179,:224,:297Verification (head 836bf39)
bun run typecheckturbo run lint --filter=@pagespace/imagobun run knip:check.pu/worktreesfalse positives (packages/lib env-bridge/drive-envs); none from this changeapps/imago: bun run test:coverageturbo run build --filter=@pagespace/imagobun run test:securityClient calls are tested against a fake fetch behind the real
createApiClient(CSRF minting included), as the scope asks; the routes themselves are not exercised here.Limitations
isTaskLinked; a TASK_LIST page dropped inside a list counts as a list until GET /tasks backfills its task row.No agent merges this PR; the owner may merge before the independent review lands.
🤖 Generated with Claude Code
https://claude.ai/code/session_01UxyeCYTQzNU9fkbDQHb1Yn