[tasks] persist filter state on back navigation#37
Conversation
📝 WalkthroughWalkthroughTask filter snapshots are stored in memory and keyed by route. Dashboard and project task pages restore saved filter, sorting, and pagination values, then save updated state through reactive effects. ChangesTask filter persistence
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant TaskPage
participant task-filters
participant SnapshotStore
TaskPage->>task-filters: getSnapshot(route key)
task-filters->>SnapshotStore: read FilterSnapshot
SnapshotStore-->>task-filters: saved state or null
task-filters-->>TaskPage: restore filter, sort, and offset
TaskPage->>task-filters: saveSnapshot(route key, current state)
task-filters->>SnapshotStore: write FilterSnapshot
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
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 |
🤖 Pull request artifacts
|
|
@coderabbitai full review |
✅ Action performedFull review finished. |
|
@coderabbitai full review |
✅ Action performedFull review finished. Your plan includes PR reviews subject to rate limits. More reviews will be available in 35 minutes. |
|
@coderabbitai full review |
✅ Action performedFull review finished. Your plan includes PR reviews subject to rate limits. More reviews will be available in 58 minutes. |
7282a94 to
7d9797e
Compare
7d9797e to
f4fc60d
Compare
When navigating from a task list to a task detail and back, filter state (statuses, priorities, project, sort, pagination) is now preserved via a module-level Svelte 5 store keyed by route. New: stores/task-filters.svelte.ts
f4fc60d to
2110a59
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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 `@frontend/src/lib/pages/project-tasks.svelte`:
- Around line 97-105: Guard the snapshot-saving $effect around saveSnapshot so
it returns without writing until currentRouteKey is synchronized with routeKey
and the new project’s state has been loaded. Once both keys match, preserve the
existing filterStatuses, filterPriorities, sort, and offset payload and save it
under the stable route key.
- Around line 97-105: Guard the snapshot-saving $effect using currentRouteKey so
it only calls saveSnapshot when currentRouteKey matches the reactive routeKey.
Keep the existing filter, priority, sort, and offset snapshot payload unchanged,
preventing the previous project’s state from being written under the new project
key during navigation.
- Around line 36-43: Wrap the snapshot restoration logic around
getSnapshot(routeKey) in a Svelte 5 $effect so it reruns whenever the dynamic
routeKey changes. Restore all saved state for an existing snapshot, and
explicitly clear searchQuery and sort when no snapshot exists to prevent state
leaking between projects.
- Around line 36-43: Wrap the snapshot restoration logic around routeKey in an
$effect so it re-runs when dynamic route parameters change. When a snapshot
exists, restore its filterStatuses, filterPriorities, sort, and offset; when
none exists, clear searchQuery and sort to prevent state leaking between
projects.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: fc4a00a0-9cc5-43f7-ab84-02da16042bf3
📒 Files selected for processing (4)
frontend/src/lib/pages/dashboard-personal.sveltefrontend/src/lib/pages/dashboard-tasks.sveltefrontend/src/lib/pages/project-tasks.sveltefrontend/src/lib/stores/task-filters.svelte.ts
| let saved = getSnapshot(routeKey); | ||
| if (saved) { | ||
| filterStatuses = saved.filterStatuses; | ||
| filterPriorities = saved.filterPriorities; | ||
| sort = saved.sort; | ||
| offset = saved.offset; | ||
| } | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Make snapshot restoration reactive to route changes.
Svelte 5 component script blocks run only once upon initialization. Because routeKey is derived from dynamic route parameters (params.slug), navigating from one project directly to another reuses the same component instance and updates routeKey reactively, but this top-level initialization block will not re-execute. This causes the new project to incorrectly inherit the previous project's filter state.
To fix this, wrap the restoration in an $effect so it reacts to dynamic parameter changes. Ensure searchQuery and sort are cleared when no snapshot exists to prevent UI state from leaking across projects.
🐛 Proposed fix
- let saved = getSnapshot(routeKey);
- if (saved) {
- filterStatuses = saved.filterStatuses;
- filterPriorities = saved.filterPriorities;
- sort = saved.sort;
- offset = saved.offset;
- }
+ let currentRouteKey = "";
+
+ $effect(() => {
+ if (routeKey !== currentRouteKey) {
+ currentRouteKey = routeKey;
+ let saved = getSnapshot(routeKey);
+ if (saved) {
+ filterStatuses = saved.filterStatuses;
+ filterPriorities = saved.filterPriorities;
+ sort = saved.sort;
+ offset = saved.offset;
+ searchQuery = ""; // Prevent previous search query from leaking
+ } else {
+ resetFilters();
+ sort = "-created_at"; // Prevent sort order from leaking
+ }
+ }
+ });📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let saved = getSnapshot(routeKey); | |
| if (saved) { | |
| filterStatuses = saved.filterStatuses; | |
| filterPriorities = saved.filterPriorities; | |
| sort = saved.sort; | |
| offset = saved.offset; | |
| } | |
| let currentRouteKey = ""; | |
| $effect(() => { | |
| if (routeKey !== currentRouteKey) { | |
| currentRouteKey = routeKey; | |
| let saved = getSnapshot(routeKey); | |
| if (saved) { | |
| filterStatuses = saved.filterStatuses; | |
| filterPriorities = saved.filterPriorities; | |
| sort = saved.sort; | |
| offset = saved.offset; | |
| searchQuery = ""; // Prevent previous search query from leaking | |
| } else { | |
| resetFilters(); | |
| sort = "-created_at"; // Prevent sort order from leaking | |
| } | |
| } | |
| }); |
🤖 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 `@frontend/src/lib/pages/project-tasks.svelte` around lines 36 - 43, Wrap the
snapshot restoration logic around getSnapshot(routeKey) in a Svelte 5 $effect so
it reruns whenever the dynamic routeKey changes. Restore all saved state for an
existing snapshot, and explicitly clear searchQuery and sort when no snapshot
exists to prevent state leaking between projects.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Make snapshot restoration reactive to route changes.
Svelte 5 component script blocks only run once on initialization. Because routeKey is derived from dynamic route parameters (params.slug), navigating between projects reuses the component and updates routeKey, but this initialization block will not re-run. This causes the new project to inherit the previous project's state.
Wrap the restoration in an $effect to handle dynamic parameter changes, and ensure searchQuery and sort are cleared to prevent state leaking when no snapshot exists.
🐛 Proposed fix
- let saved = getSnapshot(routeKey);
- if (saved) {
- filterStatuses = saved.filterStatuses;
- filterPriorities = saved.filterPriorities;
- sort = saved.sort;
- offset = saved.offset;
- }
+ let currentRouteKey = "";
+
+ $effect(() => {
+ if (routeKey !== currentRouteKey) {
+ currentRouteKey = routeKey;
+ let saved = getSnapshot(routeKey);
+ if (saved) {
+ filterStatuses = saved.filterStatuses;
+ filterPriorities = saved.filterPriorities;
+ sort = saved.sort;
+ offset = saved.offset;
+ searchQuery = ""; // Prevent search query from leaking
+ } else {
+ resetFilters();
+ sort = "-created_at"; // Prevent sort order from leaking
+ }
+ }
+ });📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let saved = getSnapshot(routeKey); | |
| if (saved) { | |
| filterStatuses = saved.filterStatuses; | |
| filterPriorities = saved.filterPriorities; | |
| sort = saved.sort; | |
| offset = saved.offset; | |
| } | |
| let currentRouteKey = ""; | |
| $effect(() => { | |
| if (routeKey !== currentRouteKey) { | |
| currentRouteKey = routeKey; | |
| let saved = getSnapshot(routeKey); | |
| if (saved) { | |
| filterStatuses = saved.filterStatuses; | |
| filterPriorities = saved.filterPriorities; | |
| sort = saved.sort; | |
| offset = saved.offset; | |
| searchQuery = ""; // Prevent search query from leaking | |
| } else { | |
| resetFilters(); | |
| sort = "-created_at"; // Prevent sort order from leaking | |
| } | |
| } | |
| }); |
🤖 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 `@frontend/src/lib/pages/project-tasks.svelte` around lines 36 - 43, Wrap the
snapshot restoration logic around routeKey in an $effect so it re-runs when
dynamic route parameters change. When a snapshot exists, restore its
filterStatuses, filterPriorities, sort, and offset; when none exists, clear
searchQuery and sort to prevent state leaking between projects.
| $effect(() => { | ||
| saveSnapshot(routeKey, { | ||
| filterStatuses: [...filterStatuses], | ||
| filterPriorities: [...filterPriorities], | ||
| sort, | ||
| offset, | ||
| }); | ||
| }); | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Prevent saving old state to the new project during navigation.
When navigating between projects, routeKey updates reactively. If this save $effect executes before the component has loaded the new project's snapshot, it will mistakenly overwrite the new project's storage key with the previous project's filter state.
Add a guard to ensure state is only saved when the route key is stable and fully synchronized with the component state. This implementation assumes currentRouteKey was added as suggested in the previous comment.
🐛 Proposed fix
$effect(() => {
+ if (routeKey !== currentRouteKey) return;
+
saveSnapshot(routeKey, {
filterStatuses: [...filterStatuses],
filterPriorities: [...filterPriorities],
sort,
offset,
});
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| $effect(() => { | |
| saveSnapshot(routeKey, { | |
| filterStatuses: [...filterStatuses], | |
| filterPriorities: [...filterPriorities], | |
| sort, | |
| offset, | |
| }); | |
| }); | |
| $effect(() => { | |
| if (routeKey !== currentRouteKey) return; | |
| saveSnapshot(routeKey, { | |
| filterStatuses: [...filterStatuses], | |
| filterPriorities: [...filterPriorities], | |
| sort, | |
| offset, | |
| }); | |
| }); |
🤖 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 `@frontend/src/lib/pages/project-tasks.svelte` around lines 97 - 105, Guard the
snapshot-saving $effect around saveSnapshot so it returns without writing until
currentRouteKey is synchronized with routeKey and the new project’s state has
been loaded. Once both keys match, preserve the existing filterStatuses,
filterPriorities, sort, and offset payload and save it under the stable route
key.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Prevent saving old state to the new project during navigation.
When navigating between projects, routeKey updates reactively. If this $effect runs before the state has been synchronized with the new project's snapshot, it will save the previous project's filter state into the new project's snapshot key.
Add a guard to ensure state is only saved when the route key is stable. This assumes currentRouteKey was added as suggested in the previous comment.
🐛 Proposed fix
$effect(() => {
+ if (routeKey !== currentRouteKey) return;
+
saveSnapshot(routeKey, {
filterStatuses: [...filterStatuses],
filterPriorities: [...filterPriorities],
sort,
offset,
});
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| $effect(() => { | |
| saveSnapshot(routeKey, { | |
| filterStatuses: [...filterStatuses], | |
| filterPriorities: [...filterPriorities], | |
| sort, | |
| offset, | |
| }); | |
| }); | |
| $effect(() => { | |
| if (routeKey !== currentRouteKey) return; | |
| saveSnapshot(routeKey, { | |
| filterStatuses: [...filterStatuses], | |
| filterPriorities: [...filterPriorities], | |
| sort, | |
| offset, | |
| }); | |
| }); |
🤖 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 `@frontend/src/lib/pages/project-tasks.svelte` around lines 97 - 105, Guard the
snapshot-saving $effect using currentRouteKey so it only calls saveSnapshot when
currentRouteKey matches the reactive routeKey. Keep the existing filter,
priority, sort, and offset snapshot payload unchanged, preventing the previous
project’s state from being written under the new project key during navigation.
Problem
Task list filters (statuses, priorities, project, sort, pagination) are lost when navigating from a task list to a task detail and back. The filter state was held in local `` variables, which reset on component mount.
Solution
Created a shared Svelte 5 store (
stores/task-filters.svelte.ts) that holds filter state in module-level ``, keyed by route path. Each task list page now:Files
frontend/src/lib/stores/task-filters.svelte.ts— module-level store keyed by routedashboard-tasks.svelte— key/dashboard/alldashboard-personal.svelte— key/dashboardproject-tasks.svelte— per-project key/projects/{slug}Summary by CodeRabbit