feat(ui): keep the cursor on its task when a background sync lands - #237
Merged
Merged
Conversation
A sync completing mid-navigation rebuilds the task list, and the cursor is a position among selectable rows, so a task arriving above it slides the cursor onto a different task under the user's hands. Carry why the load was scheduled alongside it. A background sync re-anchors the cursor to the task it was on; a load the user asked for leaves it on its row, so marking an overdue task 'due today' does not drag the cursor into the Today section behind it. The reason has to travel with the load rather than sit in a field, since the origins overlap: a sync landing while the user navigates would otherwise consume the other's value. LoadKind replaces spawn_data_load's is_initial_load bool, which was already the same idea with one bit, and the InitialDataLoaded variant folds back into DataLoaded as a third reason.
romaintb
force-pushed
the
feat/selection-follows-task
branch
from
September 5, 2026 15:51
295d1c8 to
029ab58
Compare
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.
PR #209 item 2, and the last of the family. Builds on #236, which made local UUIDs survive a sync so there is something stable to anchor to.
The bug
A sync completing mid-navigation rebuilds the task list.
selected_indexis a position among selectable rows, so a task arriving above the cursor slides it onto a different task while the user is looking at it.The change
Carry why a load was scheduled alongside the load:
LoadKind::Background(a completed sync) re-anchors the cursor to the task it was on.LoadKind::User(navigation, a task operation, the debug refresh) leaves the cursor on its row, so marking an overdue task "due today" doesn't drag it into the Today section behind the task.LoadKind::Initialresolvesdefault_project, as before.The reason has to travel with the load rather than sit in a field on
AppComponent: the origins overlap, and a sync landing while the user navigates would otherwise consume the other one's value.Net effect on the surface is a wash or better.
LoadKindreplacesspawn_data_load'sis_initial_loadbool, which was already this idea with one bit, andAction::InitialDataLoadedfolds back intoDataLoadedas a third reason instead of a near-duplicate variant.The anchor is read off
TaskListComponentbeforesync_component_datarebuilds it, so no separate copy of the selection needs plumbing. If the sidebar moved while the load was in flight, the task simply isn't in the new list andselect_taskleaves the cursor alone.Tests
test_select_task_re_anchors_the_cursor_after_a_reloadasserts both halves: the middle assertion pins the pre-fix behaviour (a rebuild alone leaves the cursor on a row number, now pointing at the wrong task), thenselect_taskputs it back on the right one.cargo fmt,cargo clippy --all-targets,cargo testall clean.Still open
SidebarSelection::Project(usize)is positional, so a project deleted from another client slides the sidebar selection onto a neighbour. Same disease, one level up, and now unblocked by #236. Not in this PR.