Skip to content

Read sortable lists from one rendered-list snapshot - #25793

Draft
myabc wants to merge 5 commits into
code-maintenance/sortable-lists-drag-sessionfrom
code-maintenance/sortable-lists-rendered-list
Draft

myabc wants to merge 5 commits into
code-maintenance/sortable-lists-drag-sessionfrom
code-maintenance/sortable-lists-rendered-list

Conversation

@myabc

@myabc myabc commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Ticket

No work package yet; interim branch name, stacked on #25792 (merge that first).

What are you trying to accomplish?

Second slice of the sortable-lists deepening agreed in the architecture review. Six separate row walks answered "which item precedes this spot" (drop resolution, list-only drops, directional menu moves, the reorder anchor, Shift ranges, position announcements), list-dom.ts threaded (element, rowsContainer) through 23 functions and returned string|null|undefined with three meanings, and "which list owns this element" was decided twice: by DOM closest() in selection and by outlet containment in the root, with a comment to keep them in agreement.

This PR adds rendered-list.ts: one snapshot of a list's rows, built per gesture and never kept across a Turbo morph, with pure functions for placement, availability, position, ranges and keyboard navigation. The root controller becomes the single owner of list topology (owns, ownerList); selection, drop resolution and menu moves all read from it. Row mutations move to row-mutations.ts, leaving list-dom.ts with the DOM contract (attributes, selectors, item readers, mobility). Net: roughly 900 fewer lines in the three "bag" files, no DOM attribute, wire or consumer change.

What approach did you choose and why?

Snapshot plus pure functions rather than a class per helper: placement maths has no lifetime, so an object would only relocate the interface. The snapshot classifies each direct row of the rows container once (item, truncation marker with hidden id and omitted count, or gap), and the single predecessor walk reads from that classification. The cross-list check stays in the selection orchestrator, ahead of the pure range calculation, so a Shift gesture into another list still restarts there.

One latent fix rides along: outlet-connected callbacks now hand the root reference only to children whose nearest root is this root, and disconnects are caller-aware, which the README already promised for independently nested roots. Every current consumer scopes its outlet selectors inside its root, so nothing changes for them. The last commit renames orderable to movable, matching the mobility attribute and the vocabulary.

Two degenerate shapes behave differently from before and are pinned by specs: a row whose item element has no id is a gap rather than an item, and an item placed inside the list element but outside its rows container is not reachable with the arrow keys. No consumer renders either.

AI involvement

Merge checklist

  • Added/updated tests
  • Added/updated documentation in Lookbook (patterns, previews, etc) — not needed; the Lookbook API reference does not document these internals
  • Tested major browsers (Chrome, Firefox, Edge, ...)

myabc added 5 commits October 3, 2026 01:23
Reads one list's rows once per calculation and answers placement,
availability, position, range and navigation questions from that
snapshot with pure functions. Nothing uses it yet; the walks it
replaces in list-dom, drag-and-drop and selection go next.
Selection resolved an item's list by walking the DOM to the nearest
list element; the root resolved it by innermost outlet containment,
without checking that the outlet belonged to it. The root now answers
both through owns and ownerList, stopping at the nearest root, and
hands its reference only to children it owns, which the README already
promised for independently nested roots. The range list key uses the
same separator as item keys.
Optimistic reorder, placement capture and restore and the ownership
check a rollback relies on move to row-mutations.ts unchanged; the
reorder resolves its anchor through the rendered list. list-dom.ts is
left with the DOM contract: attribute names, selectors, item readers
and mobility policy.
Drop resolution, menu moves, move availability, position
announcements, keyboard navigation and Shift ranges now build one
rendered-list snapshot per gesture and ask it. Deletes the six row
walks they replaced in list-dom, drag-and-drop and selection together
with their specs, whose cases live in rendered-list.spec. The
cross-list check stays in the orchestrator, ahead of the range
calculation.
Mobility is the noun the attribute, README and vocabulary use, and
movable its predicate; orderable was the one name that did not fit.
No behaviour change.
@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown

Warning

Flaky specs

  • rspec ./modules/bim/spec/features/bim_filter_spec.rb[1:1:1]
🤖 Ask Copilot to investigate

Copy the prompt below into a new comment on this PR to delegate the investigation to GitHub Copilot. It will look into the flakiness and open a separate pull request with you as reviewer.

@copilot The following spec(s) are flaky in CI (first seen on PR #25793, linked for reference only):

- `rspec ./modules/bim/spec/features/bim_filter_spec.rb[1:1:1]`

Treat this as a standalone task, unrelated to PR #25793. Create a new branch from origin/dev and open a new pull request targeting dev — do not stack it on PR #25793 or reuse that branch.

Follow the playbook in docs/development/testing/handling-flaky-tests/README.md to find the root cause and fix the underlying race — do not skip, delete, or weaken the spec to make it pass; disabling is a last resort per the playbook, and only with a bug ticket. Verify the fix by running the spec(s) repeatedly (e.g. `script/bulk_run_rspec --run-count 10`).

If you cannot reproduce the flake or are not confident in a fix after reasonable investigation, do not fabricate a change or skip the spec to force CI green. Instead, leave the pull request in draft and document what you tried, the suspected cause, and any leads in its description, then assign @myabc to take over.

Once the fix is verified, title the PR after the spec(s) it fixes, and use the PR description to explain the root cause, how the change resolves it, and the before/after results. Label the PR `flaky-spec`, assign @myabc, and request a review from @myabc.
On every commit, set @myabc as the sole co-author with a `Co-authored-by:` trailer (use their GitHub no-reply email so it links to their account), so it is traceable who dispatched the fix.

@myabc
myabc added this pull request to stack #25797 October 3, 2026 20:39

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant