Skip to content

Tasks first paint: last-known projects, folders, and sidebar summary - #1677

Open
lnittman wants to merge 4 commits into
get-bb:mainfrom
lnittman:bb/tasks-first-paint
Open

Tasks first paint: last-known projects, folders, and sidebar summary#1677
lnittman wants to merge 4 commits into
get-bb:mainfrom
lnittman:bb/tasks-first-paint

Conversation

@lnittman

Copy link
Copy Markdown
Contributor

Part of #1676 (item 1).

Tasks keeps an opt-in last-known snapshot for folders, projects, and the sidebar summary in useTasksQuery (localStorage, versioned key, validated against the query's own RPC output schema on read, written only after a successful fetch) and seeds the query state from it on mount, so a repeat visit paints the last resolved state immediately; the sidebar skeleton shows only while that data is absent. The empty state still waits for a resolved empty list. Snapshots from older storage versions are pruned once per load; the shared vitest setup clears storage per test.

Plugin code only (plugins/tasks); no SDK or host changes. isLoading semantics are untouched (the list view's scroll restoration depends on its flip-on-refetch behavior).

AGENT GENERATED: by Claude Fable 5

…y state

The shell collapsed 'projects unknown' and 'no projects' into one boolean, so
every mount rendered the list chrome and skeleton, then swapped to the empty
state once listProjects resolved. And useTasksQuery kept nothing between
mounts, so each visit started from a blank slate.

- useTasksQuery gains an opt-in persisted snapshot (localStorage, versioned
  key, validated against the query's own RPC output schema on read; written
  only after a successful fetch). folders, projects, and sidebar summary opt in.
- The sidebar skeleton and the empty state now gate on data presence, not the
  in-flight flag: a hydrated mount paints last-known truth immediately, a
  refetch keeps rows on screen, and emptiness only paints once it is known.
- manage.test clears localStorage between tests like shell.test already did.
…in tests

The snapshot key carries a version so a shape change is never read as trusted
data, but entries written under an older version would sit in the profile
forever; drop them once per page load on first snapshot access.

Mounting the shell now persists last-known sidebar data, so every test starts
from a cold profile via the shared vitest setup instead of per-file clears.
@lnittman lnittman changed the title Paint the Tasks page from its last-known projects and sidebar summary Tasks first paint: last-known projects, folders, and sidebar summary Aug 16, 2026
…pe change loads

Switching between All tasks, Active, and a project reuses the same ListView
instance, and its query keeps the previous scope's result while the new
scope fetches, so returning from an empty Active to All flashed "No tasks
yet" (Active's emptiness presented as All's truth) for the length of the
fetch. The existing settled-scope signal only fed scroll restoration, and
it was a ref, so settling could not rerender anything anyway.

The scope-settled signal is now state and gates the body: while a changed
scope is in flight the list reads as loading, and only a settled result may
claim the scope is empty or broken (a held error is the previous scope's
too). Settling also skips the commit that changes the scope: the query's
own effect flips isLoading in that same commit, but sibling effects still
read the previous render's value, so that commit must never settle the new
scope with the old scope's data. Covered by an All-to-Active-to-All test
with the return fetch deferred, which fails against the old gate.
…dy have

The scope gate landed too wide: it keyed on the scroll scope, which includes
filters and sort, so toggling a filter or reordering flashed loading rows
over data the view already held (sort is client-side and never even
refetches). The body now gates on the route scope alone, the fetch identity
across All, Active, and a project, which is the boundary where held data
belongs to another view; the scroll-restoration signal returns to its
original full-scope form.
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