Skip to content

[DREAM-885] Treegrid semantics (ARIA roles, states and row model) for the work package table - #26288

Open
myabc wants to merge 10 commits into
implementation/dream-886-focus-modelfrom
feature/dream-885-treegrid-semantics
Open

myabc wants to merge 10 commits into
implementation/dream-886-focus-modelfrom
feature/dream-885-treegrid-semantics

Conversation

@myabc

@myabc myabc commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Note

This PR is stacked on #26259 (DREAM-886, focus model). Please review/merge that PR first.

Ticket

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

What are you trying to accomplish?

tl;dr for humans: Screen readers hear the table as a plain table that wrongly claims most cells are buttons; this tells them it is a tree of rows and which rows are selected, nested, expanded or collapsed.

On keyboard-enabled tables (DREAM-886):

  • The table becomes role="treegrid" named "Work packages", aria-multiselectable, described by the current sort.
  • Rows get aria-level; work package rows aria-selected; group headers and hierarchy parents aria-expanded; collapsed rows aria-hidden; the sorted column aria-sort.
  • Relation expanders become native buttons ("Relations in for ") with aria-expanded.
  • Baseline status, hierarchy level and sum labels are readable from the row; empty sections stay hidden until they have rows.

What approach did you choose and why?

Keeps the native <table> and adds a small idempotent writer that projects committed state onto rows at the existing seams (commit, collapse, row refresh, selection painting). Expansion reuses DREAM-886's resolver, so aria-expanded always matches what Arrow Left/Right do. Header, colgroup, row and sums spans now come from one column calculation, so native spans and the accessible structure agree. Drag and baseline columns stay in the accessible column set, avoiding a second column mapping.

Out of scope: row positions (DREAM-938, #26291), selection gestures and announcements (DREAM-894, #26294), operating relation buttons and editors (DREAM-895), embedded tables (DREAM-896), screen-reader verification (DREAM-897).

Known gaps

  • A collapse landing while a redraw waits for its animation frame is undone on dev today. Enabled tables now rebuild the pending render; the general fix is OP-20570 ([OP-20570] Rebuild a pending render on collapse #26290).
  • Hierarchy parents expose no aria-expanded while the Subject column is hidden, matching the arrow keys.
  • With neither actions nor the column menu, the inline-create row spans one cell more than the header; the main list always has the trailing column (check in DREAM-896).

AI involvement

Directed – I specified the requirements and AI implemented most of it; I validated via testing rather than a full line-by-line review.

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 01:21

@LazyInject() workPackageViewCollapsedGroupsService:WorkPackageViewCollapsedGroupsService;

public readonly domId = uniqueId('wp-table-');

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra hyphen

@myabc myabc changed the title Feature/dream 885 treegrid semantics [DREAM-885] Treegrid semantics (ARIA roles, states and row model) for the work package table Oct 24, 2026
@myabc myabc added DO NOT MERGE javascript Pull requests that update Javascript code Accessibility feature labels Oct 24, 2026
@myabc
myabc force-pushed the feature/dream-885-treegrid-semantics branch 6 times, most recently from 5b229bf to 1e3e07d Compare October 24, 2026 04:17
@github-actions github-actions Bot added the ai: Directed 🪄 A human specified the requirements and AI implemented most of it; They validated via testing. label Oct 24, 2026
@myabc
myabc marked this pull request as ready for review October 24, 2026 17:49
@myabc
myabc requested a review from HDinger October 24, 2026 17:49
@myabc myabc added this to the 18.0.x milestone Oct 24, 2026
@myabc
myabc force-pushed the feature/dream-885-treegrid-semantics branch from 1e3e07d to bbe3e84 Compare October 26, 2026 03:52
myabc added 5 commits October 26, 2026 14:32
Adds a `baseline` harness option that activates the baseline view
service stub, and a per-fixture `baseline` field that builds the
timestamp attributes `getBaselineState` reads. Adds `translations`
with `%{name}` interpolation, leaving the default translator
returning keys, and a `formattedId` fixture field defaulting to the
hash-prefixed id.

https://community.openproject.org/wp/DREAM-885
Adds a required semantic `level` to every rendered occurrence: plain
rows and the placeholder are level 1, grouped members and sums rows
are 2 beneath their level 1 group header, hierarchy rows take their
ancestor count plus one, and relation rows sit one level below their
owner.

Moves `rowKindOf` and `expandedOf` from the keyboard folder into
`helpers/row-expansion.ts` without behavior change, so later tasks can
project `aria-level` and `aria-expanded` from the same sources.

https://community.openproject.org/wp/DREAM-885
Adds renderedColumns, the single calculation of the physical column
set (query columns, drag, baseline and one trailing actions or
configuration column). Keyboard-enabled tables derive their column
count, colgroup and augmented row columns from it, so header, rows,
sums, totals and full-width rows span the same columns. This fixes
the missing drag column when drag and drop is enabled outside manual
sort mode, and the phantom trailing column when neither actions nor
the column menu are enabled. The inline-create row still builds its
Cancel cell in that case, one cell beyond the span.

Capability-off tables keep their current column arithmetic.

https://community.openproject.org/wp/DREAM-885
Adds TreegridSemantics, a small idempotent writer that keyboard-enabled
tables construct. It projects the committed ledger onto the results
body: row and gridcell roles on each row's own cells, aria-level,
aria-selected on work package occurrences, aria-expanded from the
shared expansion resolver, aria-hidden for hidden occurrences and the
drag placeholder, and rowgroup exposure of the results section.

publishRendered paints before publication, which covers full renders,
setHidden and the empty visibility map of setGroupsCollapseState.
refreshRows repaints every occurrence of the refreshed work package
before notifying, and SelectionTransformer repaints selection after its
CSS painting. Exports paintRowRole and paintSectionExposure for the
template-owned and asynchronous producers. Capability-off tables keep
a null writer and their previous markup.

On enabled tables, setHidden rebuilds a pending render, so a group or
hierarchy collapse that lands before the frame commit cannot restore
the draft's stale visibility beside the live aria-expanded value.
Capability-off tables keep the existing race.

https://community.openproject.org/wp/DREAM-885
Adds screen-reader text for the baseline status next to the decorative
icon on keyboard-enabled tables, and rebuilds the baseline cell on row
refresh there so icon and text follow the same resource.

Gives every table a unique domId. Group sums and totals labels take an
ID derived from it, and non-empty navigable sum value cells are
described by their label.

The totals row directive reconciles its row role, cell roles and
aria-hidden, plus its section's exposure, when a table arrives and
after every clear or render, before notifying the refresh. A schema
that resolves after sums were disabled no longer renders the row.
Replacement drag handles keep the gridcell role.

https://community.openproject.org/wp/DREAM-885
myabc added 5 commits October 26, 2026 14:32
Passes a separate label level to the hierarchy indicator text. On
keyboard-enabled tables it reads the 1-based level that aria-level
exposes, on initial build and refresh alike; indentation keeps the
zero-based depth, and capability-off tables keep their text.

https://community.openproject.org/wp/DREAM-885
Gives keyboard-enabled work package tables the treegrid role, the
"Work packages" name and a per-table sort description that lists every
current criterion in order, including manual sorting and a primary
criterion on a hidden column. Exposes the header as a level 1 row of
named column headers and marks only the primary sorted header with
aria-sort, sharing the decision with SortHeaderDirective through
primarySortDirection.

Adds the translations for these names, plus the relations button name
used next. Capability-off tables keep their caption and native markup.

https://community.openproject.org/wp/DREAM-885
Exposes the no-results message, the Create/reference rows and the
active inline-create row on keyboard-enabled tables as level 1
structural rows of gridcells, without selection or expansion state.
The inline-create builder paints the active row when building and
refreshing it, and the inline-create section reconciles its rowgroup
exposure after every row or template change, so it stays hidden while
permissions render nothing and during the reset gap. Opening the
reference row now runs change detection so the row exists before
reconciliation.

Capability-off tables keep their native rows.

https://community.openproject.org/wp/DREAM-885
Renders the relation indicator as a named native button with
aria-expanded when keyboard navigation is enabled, reading the
expansion state from the relation columns service so repeated
occurrences agree. The button is excluded from the legacy keydown
handling, so Enter activates through its synthesized click exactly
once. The span indicator stays for tables without the capability.
Resets button chrome so the visual stays identical.

https://community.openproject.org/wp/DREAM-885
Adds a Cuprite feature spec for the keyboard-enabled work package
table in flat (with an expanded relation column), grouped and
hierarchy modes. Each example asserts computed roles, names and
descriptions through Capybara Accessible Selectors, explicit
aria-level, aria-selected and aria-expanded states, and runs axe
against the table after every state change with no rule disabled.

Collapsed rows are checked in Chrome's accessibility tree through
Ferrum, since display:none makes DOM absence assertions trivial. An
empty-results example covers the header row as Tab entry, recovery
after the last row disappears and leaving the grid by Tab.

https://community.openproject.org/wp/DREAM-885
@myabc
myabc force-pushed the feature/dream-885-treegrid-semantics branch from bbe3e84 to bd53f50 Compare October 26, 2026 14:32
@github-actions

Copy link
Copy Markdown

Warning

Flaky specs

  • rspec ./spec/features/work_packages/table/queries/id_filter_spec.rb[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 #26288, linked for reference only):

- `rspec ./spec/features/work_packages/table/queries/id_filter_spec.rb[1:1]`

Treat this as a standalone task, unrelated to PR #26288. Create a new branch from origin/dev and open a new pull request targeting dev — do not stack it on PR #26288 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.

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: Directed 🪄 A human specified the requirements and AI implemented most of it; They validated via testing. feature javascript Pull requests that update Javascript code needs review

Development

Successfully merging this pull request may close these issues.

1 participant