LearnNewsExamplesServices
Frontmatter
id12707
titleMulti-body grid column drag broken: SortZone assumes a single body
stateClosed
labels
bugairegressiongrid
assigneesneo-opus-ada
createdAtJun 8, 2026, 1:54 AM
updatedAtJun 8, 2026, 2:26 AM
githubUrlhttps://github.com/neomjs/neo/issues/12707
authorneo-opus-ada
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 8, 2026, 2:26 AM

Multi-body grid column drag broken: SortZone assumes a single body

Closed v13.0.0/archive-v13-0-0-chunk-16 bugairegressiongrid
neo-opus-ada
neo-opus-ada commented on Jun 8, 2026, 1:54 AM

Context

Column drag-to-reorder in the grid header broke after the multi-body flattened-DOM refactor (#9633 flattened DOM architecture + #9634 remove redundant grid wrapper node). Neo.draggable.grid.header.toolbar.SortZone was written when the grid had a single contiguous header toolbar and a single grid.body; the multi-body split (locked-start / center / locked-end bodies, each paired with its own header toolbar under a headerWrapper) invalidated those assumptions.

This is the urgent, release-blocking regression half of #9491 (the full multi-body SortZone overhaul). Per grid-finish coordination with @neo-opus-grace (grid-lead, operator-directed), the within-region regression fix is split out here so #9491 stays open for the cross-toolbar enhancement (which depends on the View-owned SM + #9872 redistribution/render).

Live latest-open sweep: checked the latest 20 open issues on 2026-06-08; no equivalent regression ticket found.

The Problem

SortZone resolved its grid Container via me.owner.parent and its cells via grid.body (the center body):

  • After the split, the header toolbars are children of the headerWrapper, so me.owner.parent is the headerWrapper — not the grid Container. Grid / columns / getDomRect access broke even in the common (no-locked-columns) case.
  • grid.body is only the center body. Locked-column cells live in bodyStart / bodyEnd, so grid.body.getColumnCells(dataField) returned empty for locked columns → wrong / empty drag proxy and broken cell hide / move.

Root cause confirmed statically: aria-colindex is assigned per-toolbar (src/grid/header/Toolbar.mjs:194) and columnPositions is per-Body, so a per-toolbar index lines up with its region body — the break was purely the single-body / owner.parent assumption. Live break-confirm + fix-verify is routed to @tobiu (headless DevIndex bootstrap is flaky for the agents; grid e2e is not CI-gated).

The Architectural Reality

  • src/draggable/grid/header/toolbar/SortZone.mjscreateDragProxy, onDragStart, switchItems, onDragEnd, moveTo all read me.owner.parent (grid) and grid.body (center body).
  • src/grid/Container.mjs (~823-906) creates headerStart (layoutLock: 'start') ↔ bodyStart, headerToolbarbody, headerEnd (layoutLock: 'end') ↔ bodyEnd. Toolbars carry gridContainer + layoutLock configs (src/grid/header/Toolbar.mjs:29 / :43), and Toolbar.mjs:254-256 already resolves its region body via gridContainer + layoutLock.
  • The body handles (bodyStart / body / bodyEnd) stay on grid.Container as the durable contract (survives the #9872 Container→View ownership move; per @neo-opus-grace).

The Fix

In SortZone.mjs:

  • Add a gridBody getter resolving the region body via me.owner.gridContainer + me.owner.layoutLock ('start'bodyStart, 'end'bodyEnd, else→body), mirroring grid.header.Toolbar.
  • Replace me.owner.parentme.owner.gridContainer (Container access) and center-only grid.bodyme.gridBody across createDragProxy / onDragStart / switchItems / onDragEnd / moveTo.
  • Add a CI-gated unit test for the gridBody region resolution.

Acceptance Criteria

  • SortZone resolves the grid Container via gridContainer and the region body via layoutLock — no owner.parent / hardcoded center grid.body.
  • Unit test covers gridBody resolution for start / end / center regions and runs in the CI unit suite.
  • Within-region column drag-reorder works in the multi-body grid (common no-locked case + within a locked region) — live-verified by @tobiu in DevIndex (post-merge; grid e2e is not CI-gated).

Out of Scope

  • Cross-toolbar drag (center→start re-lock) and the redistribution / newly-locked-body render on drop-to-lock — owned by @neo-opus-grace's View-owned SM + #9872 (the #9491 enhancement).
  • Locked-region column-index remap (toolbar-local ↔ global columns index) in moveTo / onDragEnd — folds into the shared global↔region-local column-index map @neo-opus-grace is building for SM keynav (per grid-finish convergence); the no-locked common case is already correct.

Related

  • #9491 — full multi-body SortZone overhaul (stays open for cross-toolbar)
  • #9486 — Grid Multi-Body epic
  • #9633 / #9634 — the flattened-DOM refactor that introduced the regression

Origin Session ID: 31325e4f-0fdf-4627-96ed-7983dd1b1002 Retrieval Hint: "multi-body grid SortZone column drag regression gridBody layoutLock"

tobiu closed this issue on Jun 8, 2026, 2:26 AM
tobiu referenced in commit b3ee96c - "fix(grid): resolve SortZone column DnD against multi-body region bodies (#12707) (#12708) on Jun 8, 2026, 2:26 AM