[AGILE-176] Add multi select drop down for sprint and backlog buckets (params hardening, UI improvements)#23820
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates Backlogs sprint/bucket filtering to support a multi-select SelectPanel UX and switches filter serialization to a compact, bookmark-friendly comma-delimited query param format.
Changes:
- Parse
bucket_ids/sprint_idsfrom either legacy array params or compact comma-delimited strings (with inbox sentinel support) and serialize back to comma-delimited strings. - Replace SelectPanel form submission with an explicit Stimulus-driven Apply/Clear flow (including reverting selection on native close).
- Update/extend Ruby specs and add a new Stimulus controller spec for the new submission behavior.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| modules/backlogs/spec/support/pages/backlog.rb | Adjusts feature spec page object to use the new Apply/close behavior of the SelectPanel. |
| modules/backlogs/spec/helpers/backlogs/common_helper_spec.rb | Updates expectations for backlog_filters.to_h serialization (comma-delimited strings). |
| modules/backlogs/spec/controllers/backlogs/backlog_filters_spec.rb | Expands coverage for parsing/serialization, including trimming, deduplication, and tamper-resistance. |
| modules/backlogs/spec/components/backlogs/backlog_filter_select_panel_component_spec.rb | Updates component spec to assert new Stimulus wiring and button states. |
| modules/backlogs/app/controllers/backlogs/backlog_filters.rb | Implements robust parsing and compact query serialization for filter ids. |
| modules/backlogs/app/components/backlogs/backlog_filter_select_panel_component.rb | Removes old hidden-field plumbing; relies on URL-driven filter state. |
| modules/backlogs/app/components/backlogs/backlog_filter_select_panel_component.html.erb | Switches footer buttons to Stimulus Apply/Clear (no form submit). |
| frontend/src/stimulus/controllers/dynamic/backlogs/backlog-filter-select-panel.controller.ts | New Stimulus controller implementing explicit Apply/Clear and revert-on-close semantics. |
| frontend/src/stimulus/controllers/dynamic/backlogs/backlog-filter-select-panel.controller.spec.ts | Adds unit tests for navigation, button enablement, clear behavior, and revert-on-close. |
9126e2a to
f7aa855
Compare
|
Warning Flaky specs
🤖 Ask Copilot to investigateCopy 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. |
Tampered query strings such as `?bucket_ids[0]=5` arrive as a nested `ActionController::Parameters` and crashed `from_params` with an `undefined method 'to_i'` error. Parsing now tokenizes only strings and arrays and ignores nested structures, so malformed input is dropped instead of raising a 500. Serialization joins id lists into the compact comma form, so the generated URLs stay bookmarkable (`?bucket_ids=1,2` rather than the bracketed array form) and passthrough filters render as a single hidden field instead of duplicated `name[]` inputs. https://community.openproject.org/wp/AGILE-176
Replaces submit-on-close with explicit submission. Apply navigates the backlogs frame with the current selection; Clear deselects everything and navigates with an empty filter; the native close (X, Escape, click-away) reverts the selection to the applied filter without submitting, so the panel always mirrors what is applied. Apply and Clear are disabled when they would have no effect (selection unchanged, or nothing selected) and update live on itemActivated. The applied filter is read from the URL as the single source of truth for both the change check and the revert target. Covered by a Vitest spec. https://community.openproject.org/wp/AGILE-176
Pass an explicit, field-scoped `id:` to the filter `SelectPanel` so the panel element and its trigger button keep deterministic ids across Turbo frame replacements, instead of Primer's per-render random id. https://community.openproject.org/wp/AGILE-176
f7aa855 to
17eb79b
Compare
Primer `Button` has built-in `trailing_visual` and `trailing_action` slots, so render the count and dropdown caret through them instead of a standalone `Primer::Beta::Counter`.
|
Warning Flaky specs
🤖 Ask Copilot to investigateCopy 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. |
On split-view details routes (/backlog/details/:id) the page URL is the details route, so deriving the frame target from window.location made Apply hit the `details` action and render the split view instead of the backlog list. The component now passes the backlog show URL as a Stimulus value, and the controller uses it (with the live query string) for both navigation and applied-filter reading.
|
Warning Flaky specs
🤖 Ask Copilot to investigateCopy 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. |
Covers applying a backlog filter while a work package is open in the split-view details pane (the /backlog/details/:id route). This is scenario coverage rather than a tight guard for the navigation target: the backlogs_container frame is lazy and re-points at the list endpoint, so the list recovers regardless. The controller-level guard for the navigation URL lives in the Stimulus controller spec.
Ticket
What are you trying to accomplish?
Screenshots
What approach did you choose and why?
Merge checklist