Repository navigation
fix: keep the Work items and Projects selection on the saved item after a reorder - #92
Conversation
Manage > Work items and Manage > Projects kept the selection as a row number. A priority or rank save re-sorted the list under it, so after Back the highlight, the scroll and Enter went to whichever item now held the old row. The selection now follows the item's identity (work item id, project slug) through the Work items reload and the Projects upsert and reload. When the item is no longer listed, the old position is kept within the list; an empty list selects nothing. Filter changes still start at the first row. The identity rule is dashboard_core::selection::reselect. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Load more disappears with the last page and takes the focus with it, so Tab had nothing to move from. Opening a row and going Back focuses the list the way the dialog does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@sfl review |
There was a problem hiding this comment.
✅ Verdict: PASS • Round 1
Confidence: 8/10
Review done by claude-opus-5-5 (same family: same-family: codex gated: codex Weekly 164% SUS 61 🔴 pause, defer)
The PR makes the Manage > Work items and Manage > Projects lists keep their selection on the item's identity (id or slug) through reloads and upserts. It does this with a new dashboard_core::selection::reselect helper and adds headless tests and capture tests. I found no Critical, High or Medium defect. The one Low finding is that a reorder save on an item past the first page still loses the selection, and it does not block approval.
🔨 Full-Spectrum Review Summary
Effort: high
Review time: 2m 10s
Token count: Unavailable
| Pass | 🔴 Critical | 🟠 High | 🟡 Medium | ⚪ Low |
|---|---|---|---|---|
| 🔒 Security | 0 | 0 | 0 | 0 |
| ✅ Accuracy | 0 | 0 | 0 | 1 |
| 🧰 Quality & Maintainability | 0 | 0 | 0 | 0 |
| Total | 0 | 0 | 0 | 1 |
Key Findings
- ⚪ LOW — Accuracy: A reorder save on an item that stays past page 1 still moves the selection to another item.
crates/dashboard-app/src/manage/work_items.rs:291: Trigger: the list has more than 50 matching items and Load more has been used. The user opens an item past the first page and saves a rank or priority change that leaves it past page 1. For example, with 62 items at P2 rank 0, row 55 is set to rank 5. A reorder save resets the list to the first page (load_work(id, true, ..)at line 504), soreselectdoes not find the savedidand clamps the selection to row 49. Impact: after Back, the highlight is on a different item and Enter opens that item. That is the #91 wrong-target symptom, now limited to deep-page items. The behaviour predates this PR, and the new page-2 test covers only an item that moves into page 1. The PR presents this case as the documented 'no longer listed' fallback, and it causes no wrong write. (non-blocking)
Coverage
- Files reviewed:
crates/dashboard-core/src/selection.rscrates/dashboard-core/src/lib.rscrates/dashboard-app/src/manage/work_items.rscrates/dashboard-app/src/manage/projects.rscrates/dashboard-app/src/work_items_tests.rscrates/dashboard-app/src/projects_tests.rscrates/dashboard-app/src/captures.rs
- Context read:
Issue #91 body (acceptance criteria)PR #92 body
- Verified:
- The compare's
base_commit.shaisba301aed65e9e3d29eab99510c4bf9e3de41fc53and its last commit isd1a076168012dc1968409822b1025d792129e7b2, matching the PR'sbase.shaandhead.sha; the head is ahead by 2 and behind by 0 reselectreturns the first index that matches the identity, otherwiseoldclamped tolen-1, and 0 for an empty list, which matches its doc comment and unit tests- In the Work items reload,
previousis taken only whenrows_filter == filterand only on the first-page (cursor.is_none()) branch; the Load more branch and thegenerationguard are unchanged set_work_filterand the Projects filter observer andtoggle_untrackedstill setselected = 0, so filter resets are kept- Projects
keep_selectionreads the previous slug fromvisible(cx)before the change and reselects among the visible rows after it; it is used inupsert(save and re-read paths) and in theload_projectssuccess path leave_project_editornow callsscroll_to_item(selected); the scroll container's children are exactly the visible rows, so the index matches, asmove_in_projectsalready assumedopen_work_itemandopen_project_editorsetselectedto the opened row, so after Back the selection identifies the edited item- The write paths, the
If-Matchprecondition and the single-write behaviour are not changed by the diff - Every
FakeWorkfixture setspriority, so theOption<u64>sort key inin_pmd_ordernever meetsNone - The new capture tests are
#[ignore]and needCAPTURE_DIR, so they stay out of default runs
- The compare's
- Not verified:
- Runtime and GUI behaviour, and the CI results the PR body reports: execution is forbidden
- Projects
load_projectsreselection during a re-sort: no test exercises it, and I checked it by reading only - Whether
reopen_created_project's filter clear, through the deferred observer, later resets the selection: this is existing code outside the diff - The screenshots and recording linked in the PR body were not opened
- Manage > Fleet positional selection: out of scope according to #91
- Tests run: None. Reviewer execution is disabled.
HemSoft full-spectrum review • 3 evidence-based passes • Reviewed head d1a076168012dc1968409822b1025d792129e7b2 • SFL v0
Risk level: 2/10 (project-dashboard)
Worked on by: claude-opus-5-5 on laptop, for Chief dispatch 358679b9
Summary
Manage > Work items and Manage > Projects stored the selection as a row number. A save that re-sorted the list left that number in place, so after Back the highlight, the scroll and Enter landed on whichever item now held the old row. The selection now follows the item's identity (work item
id, projectslug) among the rows returned by a reload or upsert. A Work item that remains beyond the first reloaded page still falls back to another row; that remaining criterion stays with issue #91.dashboard-core/src/selection.rs:reselect, the window-free rule with unit tests. The row that now has the selected identity stays selected. If no row has it, the old position is kept within the new list. An empty list gives row 0, which holds nothing.manage/work_items.rs: a first-page reload under the same filters reselects byid. Under new filters the existing behaviour stays: a filter chip has already reset the selection to row 0, and the clamped position is otherwise kept.manage/projects.rs:upsert(save and re-read) and the list reload reselect byslugamong the visible rows. Back now also scrolls to the selection, as Work items already did.Nothing changes in the write path: same path, same
If-Match, still exactly one write per save and no automatic retry. Late-save, generation and version guards, paging, read-only mode and the loading and error states are untouched.Acceptance Criteria
a_priority_save_that_moves_the_item_keeps_it_selected_after_back(row 2 → 0),a_rank_save_that_moves_the_item_down_keeps_it_selected_after_back(row 0 → 1),a_moved_item_stays_selected_when_the_reload_brings_back_only_the_first_page(row 55 on page 2 → 0 after the first-page reload). Back scrolls toselected, which now holds the new row. Also the capture below.a_priority_save_that_moves_the_project_keeps_it_selected_after_back, anda_priority_changed_elsewhere_keeps_the_project_selected_after_the_conflictfor the re-read path. Also the capture below.a_save_that_keeps_the_order_keeps_the_same_row_selectedanda_project_save_that_keeps_the_order_keeps_the_same_row_selected.an_item_that_leaves_the_status_filter_hands_the_selection_to_a_listed_rowandan_untracked_project_hidden_from_the_list_hands_the_selection_to_a_listed_row(onba301aedthis one left the selection past the last row, so Enter opened nothing). An empty list opens nothing and writes nothing:when_the_last_item_leaves_the_list_enter_opens_nothingandwhen_the_last_project_leaves_the_list_enter_opens_nothing.a_filter_change_selects_the_first_row_even_when_the_selected_item_is_still_listed(Work items chip, item still listed) anda_project_filter_change_selects_the_first_row. One note on the issue's "as they do now": the Work items project-slug text field never reset to row 0. It keeps the clamped position, and this PR leaves that as it was.Definition of Done
manage/work_items.rsandmanage/projects.rs; the identity logic is indashboard-core(selection.rs).work_items_tests.rs(7 new) andprojects_tests.rs(6 new) cover reorder, item-left-the-list, empty list and filter reset. The Work items fake gained an opt-inin_pmd_orderlisting (effective priority, rank, then newest, as pmd's read API documents), so the reorder really happens. Existing tests keep insertion order.ba301aedand pass with the fix. Six fail for the bug: Work items priority, rank and page-2 reorder; Projects priority save, conflict re-read and hidden untracked. The other seven are controls and contract checks (unchanged order, status-filter fallback, empty list, filter reset) and pass on both, as they should.cargo fmt,cargo clippy,cargo test --workspace,cargo denyand standalone core pass locally on Linux (below). Exact-head CI 42323265012 completed successfully: all five required jobs and every executed step pass atd1a076168012dc1968409822b1025d792129e7b2.Validation
Local runs, not CI. Linux runs were on Mini, from a
git archiveof the exact commit with every one of the 119 files checked against the commit's blob IDs, an isolatedCARGO_TARGET_DIR,--offlineandCARGO_BUILD_JOBS=4.$Dis the scratch folder there.RED: the new tests on
ba301aedproduction (blobs8eb9300formanage/work_items.rsanda7475a0for coreprojects.rs). The only additions were the test files and the#[cfg(test)]accessorProjectsDialog::selected():cd $D/baseline && cargo test -p dashboard-app --locked --offline work_items_tests: 25 passed, 3 failed (priority row 2 left at 2; rank left at 0; page 2 left at clamped 49 instead of 0).cargo test -p dashboard-app --locked --offline projects_tests: 18 passed, 3 failed (priority save left at row 3; conflict left at row 4; hidden untracked left at row 4, past the last of 4 rows).GREEN at
d1a0761, Linux:cargo fmt --all --check: pass.cargo clippy --workspace --all-targets --locked --offline -- -D warnings: pass.cargo test --workspace --locked --offline: pass (dashboard-app 197 passed, 16 ignored; every dashboard-core suite passed, 39 unit tests including 5 forselection).cargo deny --locked check advisories(0.20.2):advisories ok.cargo check -p dashboard-core --locked --offlineandcargo test -p dashboard-core --locked --offline: pass.I used one Cargo test filter per command. The issue's
-- work_items_tests projects_testsform passes both names to libtest; I ran each name as its own command instead.On Windows (this laptop), the same three Work items and three Projects tests fail on
ba301aedproduction. At729f965,work_items_testsgave 27 passed and 1 failed: the page-2 test's own focus step, whichd1a0761fixes and which then passed on Linux. The Windows Projects GREEN run didn't complete, because a reused scratch build cache failed inlibsqlite3-sys. The fresh-target local Windows run was stopped while compiling because its test file was stale; it supplies no final-head Windows result. Exact-head CI 42323265012 passed bothrust (windows-latest)andcore (windows-latest), which are the Windows evidence for this head.Screenshots (current head
d1a0761)Rendered offscreen on Linux (Mini, llvmpipe) by
CAPTURE_DIR=$D/captures-head cargo test -p dashboard-app --locked --offline selection_after_reorder -- --ignored --test-threads=1, with the newcaptures_work_selection_after_reorderandcaptures_projects_selection_after_reorder: 2 passed. Default 1100×760 window, default theme, fixtures only. Each flow is keyboard only: Down to the item, Enter, Tab to P0, Enter, Ctrl+Enter, Tab to Back to list, Enter, then Enter again. Each test asserts the order, the selected row and the single write right after saving each frame.Work items before the save: #202 is selected at row 5.
Work items after the P0 save and Back: #202 is first and still highlighted.
Enter reopens #202.
Projects before the save: gh-x (P3) is selected at row 4.
Projects after the P0 save and Back: gh-x is first and still highlighted.
Enter reopens gh-x.
Before the fix, from the same capture tests on
ba301aedproduction, which fail at the after-Back check: the highlight stays at the old row, on #201 and on hs-buddy.Recording: the eight current-head frames (Projects 1–4, then Work items 1–4, 1.5 s each). GPUI's headless renderer produces still frames, so this is a frame sequence, not a live screen recording.
selection-flow.mp4
Risks and deferred work
SFL Round 1 reports the remaining deep-page case: with more than 50 matching items, saving rank or priority on an item that stays beyond page 1 reloads only page 1, then clamps selection to its last row. The new page-2 test proves movement into page 1 only. This is a non-blocking Low review note, and it leaves the broader issue criterion incomplete. The initiating Chief parent retains the claim and implementation follow-through for that case.
The Projects list reload (
load_projects) now keeps the selection the same way. It runs on open and on Retry, and no test re-sorts the list during a reload; the upsert paths are tested.Manage > Fleet uses the same positional selection. It is out of scope here, as Keep the Work items and Projects selection on the saved item after a reorder #91 says.
Related to #91
🤖 Generated with Claude Code