Skip to content

[DREAM-801] Extend BorderBoxList header API - #24643

Merged
myabc merged 11 commits into
devfrom
implementation/DREAM-801-borderbox-header-api
Aug 12, 2026
Merged

[DREAM-801] Extend BorderBoxList header API#24643
myabc merged 11 commits into
devfrom
implementation/DREAM-801-borderbox-header-api

Conversation

@myabc

@myabc myabc commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Ticket

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

What are you trying to accomplish?

First slice of the DREAM-697 split (supersedes the monolithic draft PR #23812): extends the shared OpenProject::Common::BorderBoxListComponent API that the consumer migrations later in this stack need.

  • header.with_title for linked or composed title content inside the configured heading element.
  • header.with_action_icon_button for icon-only header actions.
  • Header and row menus reworked through BorderBoxListComponent::Menu: the default kebab trigger stays automatic; callers can restyle it with button_arguments: or provide their own menu.with_show_button. The Backlogs bucket/sprint callers adopt the new argument.
  • with_empty_state gains an optional call-to-action (action_label:, action_icon:, action_arguments:).
  • Empty states are governed by a single empty_state_behavior: option: :static (default) renders the declared or generic blankslate only while the list is empty; :none suppresses it (used by the grouped WP types and project-attributes sections, where a blankslate under every empty group is noise); :dynamic additionally parks a <template> prototype next to the list and a small border-box-list Stimulus controller shows it client-side whenever no visible row remains (Backlogs opts in). This reverts the always-rendered empty-state row and its CSS sibling selectors from Implementation/agile 309 improve the dragging experience with the frame reloading #23950 — the data-turbo-permanent fix from that PR is kept.
  • The header heading line reserves min-height: var(--control-medium-size), so headers no longer shrink when filtering hides their action buttons (review finding on [DREAM-803] Migrate wiki, OAuth and project settings lists to BorderBoxList #24645).
  • Lookbook docs, previews and specs cover the new public API.

The originally drafted label: header-action deprecation was dropped — superseded by DREAM-780 (PR #24560).

What approach did you choose and why?

PR #23812 stalled as a 55-file review; this stack splits it into the shared API change (this PR) followed by one consumer-migration batch per PR. The empty-state policy replaces boolean opt-outs so invalid combinations (hidden + persistent) cannot be expressed, and client-side visibility lives in one list-owned controller (useMutation) instead of :only-child/:has() CSS. As discussed in review, the option may be revisited once #24669 (DREAM-805) lands — e.g. inferring :dynamic and interactive: from the declarative sortable wiring.

Visual comparisons

Show baseline/candidate screenshots

Baseline is shown on the left; the candidate stack is shown on the right. (Screenshots predate the empty-state rework; regeneration pending.)

Lookbook: custom header content

Lookbook custom header content — baseline left, candidate right

Lookbook: header drag handle

Lookbook header drag handle — baseline left, candidate right

Lookbook: default empty state

Lookbook default empty state — baseline left, candidate right

Merge checklist

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

@myabc myabc changed the title implementation/DREAM 801 borderbox header api [DREAM-801] Extend BorderBoxList header API Aug 6, 2026
@myabc
myabc requested a balanced review from Copilot August 6, 2026 17:44
@myabc
myabc marked this pull request as ready for review August 6, 2026 17:47
Comment thread lookbook/docs/components/border-box-list.md.erb
@myabc myabc added maintenance styling ruby Pull requests that update Ruby code needs review labels Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

Warning

Flaky specs

  • rspec ./modules/backlogs/spec/features/inbox_column_spec.rb[1:7:1]
  • rspec ./modules/overviews/spec/features/managing_dashboard_page_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 #24643, linked for reference only):

- `rspec ./modules/backlogs/spec/features/inbox_column_spec.rb[1:7:1]`
- `rspec ./modules/overviews/spec/features/managing_dashboard_page_spec.rb[1:1:1]`

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@myabc
myabc force-pushed the implementation/DREAM-801-borderbox-header-api branch from dd3996c to eb88b90 Compare August 6, 2026 19:43
@myabc
myabc requested a balanced review from Copilot August 6, 2026 19:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

Suppressed comments (3)

lookbook/previews/open_project/common/border_box_list_component_preview.rb:157

  • The Lookbook preview uses html_safe inline, which can normalize unsafe patterns for consumers copying examples. Prefer building the link with Rails helpers (e.g., link_to/tag.a) so the example is safe-by-default while still demonstrating with_title.
            header.with_title do
              '<a href="#" class="Link--primary no-underline">Linked delivery plan</a>'.html_safe
            end

app/components/open_project/common/border_box_list_component/empty_state.rb:104

  • Using a truthy check for @action_label will render a primary action even when the label is an empty string, creating an unlabeled control. Consider checking presence (e.g., present?) before rendering the CTA; also consider duplicating @action_arguments defensively to avoid unexpected mutation if downstream code modifies the hash.
          if @action_label
            action = blankslate.with_primary_action(**@action_arguments)
            action.with_leading_visual_icon(icon: @action_icon) if @action_icon
            action.with_content(@action_label)
          end

lookbook/previews/open_project/common/border_box_list_component_preview/with_header_drag_handle.html.erb:7

  • This template starts at column 1 but the overall formatting/indentation is inconsistent (e.g., argument alignment and template body indentation). Consider normalizing indentation to match surrounding Lookbook templates to keep previews easy to read/maintain.
<%= render OpenProject::Common::BorderBoxListComponent.new(
      container: "border-box-list-header-drag-handle-preview",
      padding:,
      header_padding:,
      collapsible:
    ) do |list| %>
  <% list.with_header(title: "Reorderable section", count: true, show_drag_handle: true) %>

@myabc
myabc force-pushed the implementation/DREAM-801-borderbox-header-api branch from eb88b90 to f52cb1a Compare August 6, 2026 20:44
@myabc myabc added this to the 17.8.x milestone Aug 6, 2026
@myabc
myabc force-pushed the implementation/DREAM-801-borderbox-header-api branch from f52cb1a to 053e626 Compare August 6, 2026 21:38
@myabc
myabc force-pushed the implementation/DREAM-801-borderbox-header-api branch from 053e626 to 0d5d9e9 Compare August 7, 2026 07:17
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

Warning

Flaky specs

  • rspec ./modules/backlogs/spec/features/inbox_column_spec.rb[1:7:1]
  • rspec ./modules/boards/spec/features/action_boards/version_board_spec.rb[1:2:1]
  • rspec ./spec/features/notifications/split_panel_navigation_spec.rb[1:2]
🤖 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 #24643, linked for reference only):

- `rspec ./modules/backlogs/spec/features/inbox_column_spec.rb[1:7:1]`
- `rspec ./modules/boards/spec/features/action_boards/version_board_spec.rb[1:2:1]`
- `rspec ./spec/features/notifications/split_panel_navigation_spec.rb[1:2]`

Treat this as a standalone task, unrelated to PR #24643. Create a new branch from origin/dev and open a new pull request targeting dev — do not stack it on PR #24643 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 force-pushed the implementation/DREAM-801-borderbox-header-api branch 3 times, most recently from 98e1458 to c8b4051 Compare August 7, 2026 19:07
Comment thread app/components/open_project/common/border_box_list_component.rb
@myabc
myabc force-pushed the implementation/DREAM-801-borderbox-header-api branch 2 times, most recently from b795009 to 60af92a Compare August 12, 2026 09:39
@github-actions

Copy link
Copy Markdown

Warning

Flaky specs

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

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

Treat this as a standalone task, unrelated to PR #24643. Create a new branch from origin/dev and open a new pull request targeting dev — do not stack it on PR #24643 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 requested a review from bsatarnejad August 12, 2026 11:02
myabc added 11 commits August 12, 2026 12:04
Adds the title and action-icon-button header slots and reworks
header and row menus so callers can restyle the default trigger
or provide their own show button.

https://community.openproject.org/wp/DREAM-697
Renders a generic blankslate whenever an itemless list does not
configure the empty-state slot, so every consumer keeps a stable
drop target and screen-reader announcement without bespoke copy.

https://community.openproject.org/wp/DREAM-697
Documents the `show_drag_handle` header option of
`BorderBoxListComponent` in Lookbook, pairing the header handle with
per-row `DragHandle` columns as reorderable lists render it.

https://community.openproject.org/wp/DREAM-697
Reverts commit 64ae48d (AGILE-309): rendering the empty state
alongside populated rows and hiding it with CSS sibling selectors made
every consumer carry structural :has()/:only-child compensations. A
follow-up commit reintroduces the instant blankslate as an opt-in,
controller-owned behavior. The independent Turbo fix 6aa9ff1 from
the same PR is preserved.

https://community.openproject.org/wp/DREAM-801
Grouped per-type and per-section lists showed a generic blankslate
under every empty group once the default empty state landed. A single
policy replaces boolean opt-outs: :static keeps the generic default,
:none suppresses it for grouped outliers, :dynamic reserves the
client-side lifecycle for sortable and filtered lists.

https://community.openproject.org/wp/DREAM-801
Lists whose rows change client-side (drag and drop, filtering) need
the blankslate to appear without a server round-trip. A list-owned
Stimulus controller now inserts a placeholder row cloned from an inert
template whenever no visible row remains, replacing the reverted CSS
sibling selectors. Producers stay untouched: the controller observes
row mutations instead of being called.

https://community.openproject.org/wp/DREAM-801
A :dynamic list populated at render time with no declared empty
state left its parked template prototype contentless, because
configure_empty_state! only injected the generic default when the
list was truly empty. Draining such a list to zero rows client-side
then cloned a blank placeholder instead of a real blankslate.

Dynamic lists now get the generic default whenever no empty-state
slot is declared, regardless of item count; :static keeps its
existing default-only-when-empty behavior.
Restores the instant blankslate from AGILE-309 for the sprint,
bucket and inbox lists through the lifecycle controller instead of the
reverted CSS rules.

https://community.openproject.org/wp/DREAM-801
Headers whose action buttons are hidden while filtering shrank by
the button height. The heading line now reserves the medium control
height, replacing the caller-side title padding the migrations
dropped.

https://community.openproject.org/wp/DREAM-801
Replaces the two ERB captures with Primer::ConditionalWrapper and
direct slot emission. Slot content memoizes on first render, so the
template prototype and the live empty row can both emit the slot
without a shared capture. The wrapper gains Primer's inert
data-view-component attribute; the controller and target contract is
unchanged.

https://community.openproject.org/wp/DREAM-801
Replaces the hand-rolled MutationObserver lifecycle with stimulus-use's
useMutation, which owns observer creation and disconnect teardown.
Events stay off via dispatchEvent: false so the placeholder insertion
does not emit bubbling mutate events the manual observer never had.

https://community.openproject.org/wp/DREAM-801
@myabc
myabc force-pushed the implementation/DREAM-801-borderbox-header-api branch from 553e48d to 14184ed Compare August 12, 2026 11:04
@myabc

myabc commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

@bsatarnejad thanks for the feedback. By default empty states are always rendered, but this can be controlled via an empty_state_behavior option:

  • disabled via :none
  • or displayed dynamically via the dynamic: option.

These API changes are a bit more rushed than I would like, so we probably need to re-evaluate soon. We've discussed the interactive: option before (for adding aria-live), and I think we can probably infer this automatically once #24669 (DREAM-805) lands (next release).

@github-actions

Copy link
Copy Markdown

Warning

Flaky specs

  • rspec ./modules/backlogs/spec/features/inbox_column_spec.rb[1:7: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 #24643, linked for reference only):

- `rspec ./modules/backlogs/spec/features/inbox_column_spec.rb[1:7:1]`

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

@bsatarnejad bsatarnejad left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🚀

@myabc
myabc merged commit d8c93ed into dev Aug 12, 2026
19 checks passed
@myabc
myabc deleted the implementation/DREAM-801-borderbox-header-api branch August 12, 2026 12:25
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 12, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

maintenance needs review ruby Pull requests that update Ruby code styling

Development

Successfully merging this pull request may close these issues.

3 participants