Tasks first paint: last-known projects, folders, and sidebar summary - #1677
Open
lnittman wants to merge 4 commits into
Open
Tasks first paint: last-known projects, folders, and sidebar summary#1677lnittman wants to merge 4 commits into
lnittman wants to merge 4 commits into
Conversation
…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.
…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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.isLoadingsemantics are untouched (the list view's scroll restoration depends on its flip-on-refetch behavior).