Skip to content

[DREAM-941] Publish row positions in hierarchy mode - #26293

Open
myabc wants to merge 6 commits into
feature/dream-938-row-positionsfrom
feature/dream-941-row-position-metadata
Open

myabc wants to merge 6 commits into
feature/dream-938-row-positionsfrom
feature/dream-941-row-position-metadata

Conversation

@myabc

@myabc myabc commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Note

This PR is stacked on #26291 (DREAM-938, global row positions). Please review/merge that PR first.

Ticket

https://community.openproject.org/wp/DREAM-941

What are you trying to accomplish?

tl;dr for humans: The default views show work packages as a tree, where only the server knows how many rows come before a page; this has the API send those positions so screen readers can announce "row X of Y" there too.

DREAM-938 withdraws positions in hierarchy mode because pages insert ancestors the results do not describe. The API now returns rowCount and rowPositions for hierarchy collections, every hierarchy table renders in the canonical order, and the list view publishes positions in hierarchy mode, across pages and after a drop.

What approach did you choose and why?

  • Server numbers the whole query. WorkPackage::HierarchyRowPositions orders results and visible ancestors depth first; sibling subtrees follow the earliest rank they contain ([Child, Other, Parent] → Parent, Child, Other). Pages keep their membership, so positions can have gaps.
  • Map keyed by work package id ({ position, parent }), since ancestors are not in _embedded.elements and a work package has one place in the tree. The frontend withdraws positions when its rendered tree disagrees.
  • One order everywhere. List, Gantt and embedded tables all use the canonical order, so a query never renders two ways.
  • After a drop, a saved ungrouped query refetches its page and recaptures positions in place when the rows match.

For discussion:

  • Cost: about +60–150 ms per hierarchy request on 30,000 open work packages; metadata is omitted above 10,000 results. Raise, drop or keep the cap?
  • Gantt and embedded reorder too. Gating on the list view would split it from its Gantt.

Not covered: expanded relation and children columns (DREAM-942); drops in grouped or unsaved manually sorted queries (DREAM-943).

AI involvement

Collaborative – AI generated a substantial part of the code; I reviewed and understand every line.

Merge checklist

  • Added/updated tests
  • Added/updated documentation in Lookbook (patterns, previews, etc)
  • Tested major browsers (Chrome, Firefox, Edge, ...)

@myabc
myabc added this pull request to stack #25836 October 24, 2026 20:10
@myabc
myabc force-pushed the feature/dream-941-row-position-metadata branch from ae661e2 to 2d9cb9e Compare October 24, 2026 20:14
@github-actions github-actions Bot added the ai: Collaborative 💻 AI generated a substantial part of the code; A human reviewed and understands every line. label Oct 24, 2026
@myabc myabc added this to the 18.0.x milestone Oct 24, 2026
@myabc myabc added feature javascript Pull requests that update Javascript code labels Oct 24, 2026
@myabc
myabc force-pushed the feature/dream-941-row-position-metadata branch from 2d9cb9e to e915a11 Compare October 24, 2026 20:40
Comment thread lib/api/v3/work_packages/work_package_collection_representer.rb
Comment thread spec/features/work_packages/table/treegrid_semantics_spec.rb Outdated
Comment thread spec/models/work_package/hierarchy_row_positions_spec.rb Outdated
@myabc
myabc force-pushed the feature/dream-941-row-position-metadata branch from e915a11 to cc4fc80 Compare October 24, 2026 21:52
@myabc myabc added ruby Pull requests that update Ruby code needs review and removed DO NOT MERGE labels Oct 24, 2026
@myabc
myabc force-pushed the feature/dream-941-row-position-metadata branch from cc4fc80 to 0643b94 Compare October 24, 2026 21:59
@myabc
myabc marked this pull request as ready for review October 24, 2026 21:59
@myabc
myabc force-pushed the feature/dream-941-row-position-metadata branch from 0643b94 to 32fd953 Compare October 24, 2026 22:51
@myabc
myabc requested a review from ulferts October 25, 2026 22:12
myabc added 6 commits October 26, 2026 03:46
Adds WorkPackage::HierarchyRowPositions, which numbers every result of
a hierarchy query and every visible contextual ancestor in depth-first
order. Sibling subtrees follow the earliest query rank of any matching
work package they contain, so a child ranked before its parent pulls
the parent's subtree forward. Each row's parent is its nearest visible
ancestor, matching the ancestor chain the frontend renders. A result
the user can no longer see, as a historic query may return, is
numbered as a root, so the numbering discloses no current parent of a
work package the collection itself redacts. Asking for a row the
numbering does not know returns nothing, so a work package that
stopped matching between paging and numbering cannot fail the request.

https://community.openproject.org/wp/DREAM-941
Adds rowCount and rowPositions to work package collections in
hierarchy mode. rowCount covers every result and every visible
contextual ancestor of the whole query; rowPositions gives each row
on the page, and each ancestor it renders under, its global position
and nearest visible parent. Both are computed from the scoped result
set and omitted above 10,000 results, where numbering the whole query
costs too much per request, or when the page holds a row the numbering
does not know.

https://community.openproject.org/wp/DREAM-941
Renders each hierarchy page depth first, with sibling subtrees ordered
by the earliest rank of any result they contain, so a child ranked
before its parent no longer defers until the parent appears. When the
collection carries row positions whose parents agree with the rendered
ancestors, the page follows those positions instead, which keeps it in
the query-wide order when a subtree spans pages. The same order
applies to every hierarchy table, Gantt and embedded tables included.

https://community.openproject.org/wp/DREAM-941
Lets TableRowPositions publish aria-rowindex and aria-rowcount in
hierarchy mode from the collection's rowCount and rowPositions. The
collection must still list the rendered results in order, every
rendered row must have an entry, every edge of a result's visible
ancestor chain must match the collection's parents, and positions must
rise in rendered order; anything else withdraws the whole family. The
renderer only orders a page by the positions under the same condition,
so a reorder rendered before its collection arrives keeps its new
order. Rows read their ancestry from the work package cache they
re-render from, so a cache that is newer than the collection never
mislabels rows, whether a row refreshes or the positions are
recaptured later. Expanded relation columns still withdraw positions.

https://community.openproject.org/wp/DREAM-941
Refetches the current page of a saved, ungrouped query once a drop has
been persisted. When the refetched collection lists the rows in the
order already on screen, it replaces the results and the positions are
recaptured in place, so they come back without a reload and without a
second render that would replace rows, focus or selection. Recapture
reads each row's ancestry from the work package cache, so a row that
moved while the refetch was in flight keeps the positions withdrawn.
A render that was still pending when the results changed recaptures
at commit. A failed refetch, a different order, a grouped query or an
unsaved query leaves the positions withdrawn as before.

https://community.openproject.org/wp/DREAM-941
Asserts positions in hierarchy mode instead of their absence, keeps the
collapsed descendants' slots, numbers a contextual ancestor once across
two pages, and expects positions to return after a drop without
revisiting the query.

https://community.openproject.org/wp/DREAM-941
@myabc
myabc force-pushed the feature/dream-941-row-position-metadata branch from 32fd953 to edc685b Compare October 26, 2026 03:52

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

Accessibility ai: Collaborative 💻 AI generated a substantial part of the code; A human reviewed and understands every line. feature javascript Pull requests that update Javascript code needs review ruby Pull requests that update Ruby code

Development

Successfully merging this pull request may close these issues.

1 participant