Skip to content

feat(todo): add dedicated TodoApp component with checklist UI, reorder, due dates#1946

Open
hognek wants to merge 4 commits into
jaylfc:devfrom
hognek:feat/1923-todo-app
Open

feat(todo): add dedicated TodoApp component with checklist UI, reorder, due dates#1946
hognek wants to merge 4 commits into
jaylfc:devfrom
hognek:feat/1923-todo-app

Conversation

@hognek

@hognek hognek commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Task: C2 of #1923 (Notes/Todo split). Builds on C1 backend (TodoStore + /api/todo routes).

Changes

New: desktop/src/apps/TodoApp.tsx (845 lines)

  • Checklist UI with Square/CheckSquare checkboxes
  • Optimistic toggle complete (revert on failure)
  • Move-up/Move-down reorder buttons → PUT /api/todo/{id}/items/reorder
  • Due date display with overdue highlighting (red border + "Overdue" label)
  • Inline add task input (Enter to submit)
  • Inline edit task with Save/Cancel
  • Incomplete/complete items split into separate sections
  • Back-navigation for mobile responsiveness
  • Defensive against missing items array in API responses

Modified: desktop/src/registry/app-registry.ts

  • Todo app now lazy-loads from @/apps/TodoApp instead of @/apps/NotesApp

Refactored: desktop/src/apps/NotesApp.tsx

  • Removed TODO_CONFIG and TodoApp export
  • Removed unused ListChecks import
  • Notes-only configuration (no behavior change)

Tests

  • New TodoApp.test.tsx: 12 tests (list CRUD, items, toggle, delete, add, reorder, due dates, overdue, inline edit)
  • Updated NotesApp.test.tsx: removed TodoApp import and Todo-specific tests (now 5 Notes-only tests)
  • Updated __tests__/NotesApp.test.tsx: removed TodoApp section (now 5 Notes-only tests)

Test results

TSC: clean (0 errors)
Tests: 22 passed (12 TodoApp + 10 NotesApp)
Full desktop suite: all passing (no regressions)

Bot-fix (commit 3d2625d)

  • Guard addItem/create against duplicate Enter submissions while request pending
  • Serialize toggleDone PATCH per itemId with pendingToggles Set to prevent overlapping updates
  • Show load error instead of "No lists yet" when list fetch fails
  • Keep mobile back-navigation available during detail load errors
  • Fix test: assert actual completed fixture ("Already done", not "Pick up laundry")

Depends on: C1 backend (#1923 todo-store branch — feat/1923-todo-store)

…r, due dates

- New TodoApp.tsx: checklist UI with checkboxes, optimistic toggle,
  move-up/down reorder buttons, due date display with overdue
  highlighting, inline add/edit, Pico CSS responsive layout
- Hits /api/todo endpoints (C1 backend) instead of shared /api/notes
- Splits incomplete/complete items into separate sections
- Move-up/down reorder sends PUT /api/todo/{id}/items/reorder
- Optimistic toggle for complete with revert on failure
- Defensive against missing items array in API responses

- Update app-registry: todo now lazy-loads from TodoApp.tsx directly
- Refactor NotesApp.tsx: remove TODO_CONFIG and TodoApp export,
  keep Notes-only config
- Update NotesApp tests: remove TodoApp import and Todo-specific tests
- Add TodoApp.test.tsx: 12 Vitest tests covering lists, items,
  toggle, delete, reorder, due dates, overdue, inline edit

Part of jaylfc#1923 (C2 — frontend split)
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Todo application extraction

Layer / File(s) Summary
Standalone Todo UI and behavior
desktop/src/apps/TodoApp.tsx, desktop/src/apps/TodoApp.test.tsx
Adds Todo list and item management, editing, completion, deletion, due-date display, reordering, list creation, and comprehensive request/UI tests.
Application wiring and Notes cleanup
desktop/src/registry/app-registry.ts, desktop/src/apps/NotesApp.tsx, desktop/src/apps/NotesApp.test.tsx, desktop/src/apps/__tests__/NotesApp.test.tsx
Registers the standalone TodoApp and removes the Todo configuration, export, and tests from NotesApp.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant TodoApp
  participant TodoDetailPane
  participant TodoAPI
  User->>TodoApp: Select or create todo list
  TodoApp->>TodoAPI: Load or create list
  TodoApp->>TodoDetailPane: Render selected list
  TodoDetailPane->>TodoAPI: Load list items
  User->>TodoDetailPane: Modify item
  TodoDetailPane->>TodoAPI: Persist item change
Loading

Possibly related PRs

Suggested reviewers: jaylfc

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding a dedicated TodoApp with checklist, reorder, and due-date support.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@hognek
hognek marked this pull request as ready for review July 17, 2026 20:48
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@gitar-bot

gitar-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown

Gitar is working

Gitar

Comment thread desktop/src/apps/TodoApp.tsx Outdated
);
}

if (error || !doc) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: A transient action error (failed toggle/delete/edit/reorder) sets the shared error state, which this early-return then uses to replace the ENTIRE detail pane with just the error text. The user loses the whole task list after a single failed toggle.

Use a separate, non-fatal actionError/banner state for transient action failures (like the banner already rendered at line 493) instead of the load-error error that controls this guard. This error should only represent "list could not be loaded".


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

Comment thread desktop/src/apps/TodoApp.tsx Outdated
<button
type="button"
onClick={() => onMove(item.id, 1)}
disabled={item.position >= itemCount - 1}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Move up/down uses item.position against the FULL list (itemCount = items.length), but incomplete and complete items are rendered in two separate <ul> sections. If the adjacent item by position is in the other section, moveItem swaps it within the full array (line 424) yet the UI recomputes the two sections, so the moved task appears to NOT move. Likewise the disabled check (position >= itemCount - 1) can wrongly enable/disable move buttons across the incomplete/complete boundary.

Recompute reorder indices within the visible section only, or operate on a single flat list in the UI rather than splitting by done.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

body: JSON.stringify({ title: title.trim() }),
});
if (!r.ok) throw new Error("Could not create list.");
const doc: TodoList = await r.json();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: On success you call onCreated(doc) and hide the form via setShowCreate(false), but creating is never reset to false. It only resets in the catch. If the component is ever reused/re-opened while mounted, it would stay in the creating state.

Suggested change
const doc: TodoList = await r.json();
const doc: TodoList = await r.json();
onCreated(doc);
setCreating(false);

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

Comment thread desktop/src/apps/TodoApp.tsx Outdated
try {
const r = await fetch(`/api/todo/${listId}`);
if (!r.ok) throw new Error("Could not load list.");
const data: TodoDetail = await r.json();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: The PR claims to be "defensive against missing items array," but r.json() is cast straight to TodoDetail and doc.items is only guarded later at line 468. If the response omits items or returns a non-array shape, incomplete/complete filters (line 469-470) run on undefined and throw. Validate items here before setDoc, e.g. coerce items: Array.isArray(data.items) ? data.items : [] when building the typed value.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No New Issues Found | Recommendation: Merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 0
Incremental Changes (commit f704cc8..3d2625d)
  • desktop/src/apps/TodoApp.tsx - bot-fix commit reviewed, no new issues
  • desktop/src/apps/TodoApp.test.tsx - test updated to assert actual completed fixture, no new issues
Prior Findings Resolved (verified this run)
  • desktop/src/apps/TodoApp.tsx:664 (SUGGESTION) - creating now reset on both success (L678) and error (L682) paths: CONFIRMED FIXED.
  • desktop/src/apps/TodoApp.tsx (WARNING) - transient action error blanking the task list pane: previously fixed, unchanged in this increment.
  • desktop/src/apps/TodoApp.tsx (WARNING) - move up/down reorder within separate sections: previously fixed, unchanged in this increment.
  • desktop/src/apps/TodoApp.tsx (SUGGESTION) - defensive against missing items array in API responses: previously added, unchanged in this increment.
Files Reviewed (incremental: 2 changed)
  • desktop/src/apps/TodoApp.tsx - incremental changes reviewed, no new issues
  • desktop/src/apps/TodoApp.test.tsx - incremental changes reviewed, no new issues

Files unchanged since previous review (NotesApp.tsx, app-registry.ts, tests/NotesApp.test.tsx) were not re-analyzed.

Previous Review Summaries (3 snapshots, latest commit f704cc8)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit f704cc8)

Status: No New Issues Found | Recommendation: Merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 0
Prior Findings Resolved (incremental)
  • desktop/src/apps/TodoApp.tsx:457 (WARNING) — Transient action error blanking the task list pane: FIXED (prior run). Condition changed from if (error || !doc) to if (!doc).
  • desktop/src/apps/TodoApp.tsx:651 (SUGGESTION) — creating never reset on success path: FIXED (prior run).
  • desktop/src/apps/TodoApp.tsx:235,248,419 (WARNING) — Move up/down used item.position against the full list, breaking reorder within separate incomplete/complete sections: FIXED. Buttons now use sectionIdx within the passed sectionItems (incomplete/complete), and moveItem swaps by id within the full array and rebases position for all items.
  • desktop/src/apps/TodoApp.tsx:307 (SUGGESTION) — Defensive against missing items array in API responses: ADDED. raw.items is coerced to [] when not an array.
Files Reviewed (incremental: 1 changed)
  • desktop/src/apps/TodoApp.tsx - incremental changes reviewed, no new issues

Files unchanged since previous review (NotesApp.tsx, app-registry.ts, tests) were not re-analyzed.

Previous review (commit 5659267)

Status: No New Issues Found | Recommendation: Merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 0
Prior Findings Resolved (incremental)
  • desktop/src/apps/TodoApp.tsx:457 (WARNING) — Transient action error blanking the task list pane: FIXED. Condition changed from if (error || !doc) to if (!doc), so a transient toggle/delete/reorder error no longer unmounts the list pane; the error still renders via {error ?? "List not found."} inside the !doc branch.
  • desktop/src/apps/TodoApp.tsx:651 (SUGGESTION) — creating never reset on success path: FIXED. setCreating(false) now called before onCreated(doc) on the success path.
Files Reviewed (incremental: 1 changed)
  • desktop/src/apps/TodoApp.tsx - 2 line change (both resolve prior findings)

Files unchanged since previous review (NotesApp.tsx, app-registry.ts, tests) were not re-analyzed.

Previous review (commit 3c31cb6)

Status: 4 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 2
Issue Details (click to expand)

WARNING

File Line Issue
desktop/src/apps/TodoApp.tsx 457 Transient action error sets shared error state; early-return blanks the entire task list pane after a single failed toggle/delete/reorder
desktop/src/apps/TodoApp.tsx 247 Move up/down uses full-list position while UI splits incomplete/complete into two sections; moves across the boundary appear to do nothing and disabled logic is wrong

SUGGESTION

File Line Issue
desktop/src/apps/TodoApp.tsx 651 creating never reset to false on success path (only in catch)
desktop/src/apps/TodoApp.tsx 305 r.json() cast to TodoDetail without validating items; a response missing items throws in filters at lines 469-470
Files Reviewed (6 files)
  • desktop/src/apps/TodoApp.tsx - 4 issues
  • desktop/src/apps/NotesApp.tsx - 0 issues (refactor only)
  • desktop/src/registry/app-registry.ts - 0 issues (1-line path swap)
  • desktop/src/apps/TodoApp.test.tsx - 0 issues
  • desktop/src/apps/NotesApp.test.tsx - 0 issues
  • desktop/src/apps/__tests__/NotesApp.test.tsx - 0 issues

Fix these issues in Kilo Cloud


Reviewed by hy3:free · Input: 36.8K · Output: 1.7K · Cached: 100K

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (2)
desktop/src/apps/TodoApp.test.tsx (2)

299-325: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Exercise both optimistic rendering and failure rollback.

The PATCH resolves immediately and the test only inspects its payload, so it does not verify that completion appears before the response or that a failed request restores the original state. Add deferred-success and failure cases.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@desktop/src/apps/TodoApp.test.tsx` around lines 299 - 325, The TodoApp PATCH
test only checks the request payload and must cover UI state transitions. Update
the test around the existing toggle flow to use a deferred PATCH response,
assert the task appears completed before resolving it, then add a failed-PATCH
case that rejects the request and verifies the task returns to its original
incomplete state.

404-431: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the exact reordered sequence.

These assertions pass for any array, including unchanged or invalid positions. Verify the expected item IDs and positions—and ideally the resulting visible order—to cover the reordering contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@desktop/src/apps/TodoApp.test.tsx` around lines 404 - 431, Strengthen the
reorder test around the “Move task down” interaction by asserting the PUT
request’s items contain the expected task IDs in the reordered sequence with
their correct positions, rather than only checking that items is an array. Also
verify the rendered task order after the move so the test covers both the API
payload and visible reordering behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@desktop/src/apps/TodoApp.test.tsx`:
- Around line 280-295: Update the test “splits incomplete and completed items
into sections” to assert the actual completed fixture, “Already done,” within
the completed section, and verify that the incomplete fixture remains within the
incomplete section. Remove the incorrect “Pick up laundry” assertion while
preserving the existing section-label checks.

In `@desktop/src/apps/TodoApp.tsx`:
- Around line 322-330: Guard the submission handlers addItem and the
corresponding list-creation handlers near the referenced sections against
in-flight requests by returning early when their existing loading flags are
active. Keep the current input validation and POST behavior unchanged, and
ensure repeated Enter presses cannot submit duplicate tasks or lists while a
request is pending.
- Around line 378-410: Update toggleDone to serialize PATCH requests per itemId,
preventing overlapping completion updates when the checkbox is toggled rapidly.
Disable the affected item’s checkbox while its request is pending or queue
subsequent desired states, and ensure rollback restores the correct prior state
for the serialized update rather than blindly using !done.
- Around line 716-727: Update loadLists to throw when the fetch response is not
OK, and track the resulting load failure separately from the lists data. Render
the load error state instead of “No lists yet” when loading fails, while
preserving the existing successfully loaded lists behavior.
- Around line 449-501: Restructure the TodoApp detail render around the existing
header and mobile Back button so they remain available whenever a document is
loaded, including mutation-error states. Reserve the fatal early-return state
for !doc, keep loading and error content within the loaded layout as
appropriate, and preserve the existing inline error banner so mutation errors do
not replace the document content.
- Around line 348-351: Update the TodoApp item deletion and reorder logic around
the setDoc updater and movement handlers to operate within the currently
rendered incomplete or completed section, using rendered indices rather than the
combined items array or global position values. Prevent moves across section
boundaries, derive button enabled states from section-local boundaries, and
normalize remaining positions after deletion so no gaps can make controls no-op.

---

Nitpick comments:
In `@desktop/src/apps/TodoApp.test.tsx`:
- Around line 299-325: The TodoApp PATCH test only checks the request payload
and must cover UI state transitions. Update the test around the existing toggle
flow to use a deferred PATCH response, assert the task appears completed before
resolving it, then add a failed-PATCH case that rejects the request and verifies
the task returns to its original incomplete state.
- Around line 404-431: Strengthen the reorder test around the “Move task down”
interaction by asserting the PUT request’s items contain the expected task IDs
in the reordered sequence with their correct positions, rather than only
checking that items is an array. Also verify the rendered task order after the
move so the test covers both the API payload and visible reordering behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ff5a78f-647a-4345-b6d2-5ca09fd69132

📥 Commits

Reviewing files that changed from the base of the PR and between 5e47856 and 3c31cb6.

📒 Files selected for processing (6)
  • desktop/src/apps/NotesApp.test.tsx
  • desktop/src/apps/NotesApp.tsx
  • desktop/src/apps/TodoApp.test.tsx
  • desktop/src/apps/TodoApp.tsx
  • desktop/src/apps/__tests__/NotesApp.test.tsx
  • desktop/src/registry/app-registry.ts
💤 Files with no reviewable changes (1)
  • desktop/src/apps/NotesApp.tsx

Comment thread desktop/src/apps/TodoApp.test.tsx
Comment thread desktop/src/apps/TodoApp.tsx
Comment thread desktop/src/apps/TodoApp.tsx
Comment on lines +378 to +410
async function toggleDone(itemId: string, done: boolean) {
if (!doc) return;
// Optimistic update
setDoc((prev) =>
prev
? {
...prev,
items: prev.items.map((i) =>
i.id === itemId ? { ...i, done } : i,
),
}
: prev,
);
try {
const r = await fetch(`/api/todo/${doc.id}/items/${itemId}`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ done }),
});
if (!r.ok) throw new Error("Could not update task.");
} catch (e) {
// Revert on failure
setDoc((prev) =>
prev
? {
...prev,
items: prev.items.map((i) =>
i.id === itemId ? { ...i, done: !done } : i,
),
}
: prev,
);
setError(e instanceof Error ? e.message : "Could not update task.");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Serialize completion updates per item.

The checkbox remains enabled while PATCH is pending. Rapid toggles can resolve out of order, leaving the server value different from the UI; the !done rollback also becomes incorrect with overlapping requests. Disable or queue updates per item.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@desktop/src/apps/TodoApp.tsx` around lines 378 - 410, Update toggleDone to
serialize PATCH requests per itemId, preventing overlapping completion updates
when the checkbox is toggled rapidly. Disable the affected item’s checkbox while
its request is pending or queue subsequent desired states, and ensure rollback
restores the correct prior state for the serialized update rather than blindly
using !done.

Comment thread desktop/src/apps/TodoApp.tsx
Comment thread desktop/src/apps/TodoApp.tsx
hognek added 3 commits July 17, 2026 22:55
- Change error guard from (error || !doc) to (!doc) so transient
  action errors show inline banner instead of blanking the pane
- Reset creating=false on success in CreateTodoForm
- Move-up/down uses full-list positions correctly; items share
  a single position space regardless of visual section split
- Kilo WARNING: reorder items within their visible section (incomplete/complete)
  instead of the full list, fixing cross-boundary swap bug and incorrect
  move-up/move-down disabled checks
- Kilo SUGGESTION: validate doc.items as array before setDoc in loadDoc
  to guard against missing/non-array items from the API

Desktop tests: 12/12 pass. TypeScript: clean.
…ror handling

- Guard addItem/create against duplicate Enter submissions while request pending
- Serialize toggleDone PATCH per itemId to prevent overlapping completion updates
- Show load error instead of 'No lists yet' when list fetch fails
- Keep mobile back-navigation available during detail load errors
- Fix test: assert actual completed fixture (Already done, not Pick up laundry)
@jaylfc

jaylfc commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Code is clean and every bot finding is folded (only 2 trivial test nitpicks left), nice. Held purely on merge order: the new TodoApp targets /api/todo + /items + /reorder, which do not exist on dev (dev only has /api/notes). Merging this alone ships a Todo app that 404s on every request. #1944 (the TodoStore + /api/todo backend) must land first or concurrently. #1944 is currently CONFLICTING; once you rebase and it merges, this is good to go.

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.

2 participants