Skip to content

[DREAM-804] Migrate meetings, costs and work package tab lists to BorderBoxList - #24646

Merged
myabc merged 7 commits into
implementation/DREAM-803-project-core-list-migrationsfrom
implementation/DREAM-804-meetings-costs-list-migrations
Aug 12, 2026
Merged

[DREAM-804] Migrate meetings, costs and work package tab lists to BorderBoxList#24646
myabc merged 7 commits into
implementation/DREAM-803-project-core-list-migrationsfrom
implementation/DREAM-804-meetings-costs-list-migrations

Conversation

@myabc

@myabc myabc commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Ticket

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

What are you trying to accomplish?

Final slice of the DREAM-697 split: the remaining consumer migrations to OpenProject::Common::BorderBoxListComponent, one commit per surface.

  • WorkPackageMeetingsTab::MeetingComponent
  • Admin::Departments::DetailComponent — the hierarchy breadcrumbs render inside the list header through the new with_breadcrumbs header slot (the title remains as a visually hidden heading), the LDAP status becomes a header label, and the blank slates adopt the list empty-state mechanism (with the add-department call to action on the new primary-action API), retiring both bespoke blankslate components
  • WorkPackageRelationsTab::IndexComponent
  • Meetings::Participants::ListComponent — the heading decomposes into with_header(title:, count:) plus a mark-all-attended header action, retiring BoxHeaderComponent
  • Projects::Settings::CostTypes::IndexComponent
  • ResourceAllocations::ListComponent

After this lands, DREAM-697's remaining scope is bookkeeping: the multi-column tables reclassified for a future BorderBoxTable and the deferred rich-header surfaces stay out, as documented on the work package.

What approach did you choose and why?

Each migration is a focused vertical slice with its component spec. Stacked on #24645 only for linear review order; the surfaces are independent.

The departments surface needs a hierarchy trail in the box header, so the branch first extends the component with a with_breadcrumbs header slot: a thin wrapper around Primer::Beta::Breadcrumbs rendered in the title position, while the mandatory title turns into a visually hidden heading so the list keeps its accessible name and heading navigation. Collapsible headers reject the slot. Documented in Lookbook with a preview.

Visual comparisons

Show baseline/candidate screenshots

Baseline is shown on the left; the candidate stack is shown on the right.

Departments

Departments — baseline left, candidate right

Meeting participants

Meeting participants — baseline left, candidate right

Project cost types

Project cost types — baseline left, candidate right

Work package meetings tab

Work package meetings tab — baseline left, candidate right

Work package relations tab

Work package relations tab — baseline left, candidate right

Work package resource allocations

Work package resource allocations — 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 804 meetings costs list migrations [DREAM-804] Migrate meetings, costs and work package tab lists to BorderBoxList Aug 6, 2026
@myabc
myabc requested a lite review from Copilot August 6, 2026 17:46
Comment thread app/components/admin/departments/detail_component.html.erb Outdated

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-804-meetings-costs-list-migrations branch from a054b81 to 151356d Compare August 6, 2026 19:43
@myabc
myabc requested a lite review from Copilot August 6, 2026 19:49

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 16 out of 16 changed files in this pull request and generated no new comments.

Suppressed comments (6)

modules/meeting/app/components/meetings/participants/list_component.rb:49

  • This predicate re-queries/iterates over @meeting.participants even though @meeting_participants was already built in initialize. Using @meeting_participants here avoids duplicate association loads and keeps behavior consistent with the sorted participant list (e.g., !@meeting_participants.all?(&:attended?) && @meeting.in_progress?).
    def show_mark_all_attended?
      !@meeting.participants.all?(&:attended?) && @meeting.in_progress?
    end

modules/meeting/app/components/meetings/participants/list_component.html.erb:19

  • The header count uses @meeting.participants.count, which can trigger an extra COUNT query even though @meeting_participants has already been computed. Prefer using @meeting_participants.size (or @meeting_participants.length) so the count is derived from the already-loaded/sorted list and avoids extra DB work.
          list.with_header(
            title: t("meeting.participants.label.participants"),
            count: @meeting.participants.count,
            color: :muted
          ) do |header|

modules/meeting/app/components/meetings/participants/list_component.html.erb:43

  • list.with_empty_state is declared unconditionally. If BorderBoxListComponent does not automatically suppress the empty state when items exist, this will render both the empty-state and the participant rows simultaneously. If the component API expects callers to only declare empty-state when empty, wrap this in an if @meeting_participants.none?/if @meeting_participants.empty? guard (or switch to the component’s documented pattern for conditional empty-states).
          list.with_empty_state(
            title: I18n.t("meeting.participants.blankslate.heading"),
            description: I18n.t("meeting.participants.blankslate.description"),
            icon: :people
          )

          @meeting_participants.each do |participant|
            list.with_item do
              render(Meetings::Participants::BoxRowComponent.new(meeting: @meeting, participant:))
            end
          end

modules/costs/app/components/projects/settings/cost_types/index_component.html.erb:38

  • The empty-state is declared unconditionally after rendering items. If BorderBoxListComponent doesn’t internally hide the empty-state when items are present, this will display an empty-state alongside the populated list. If the API requires explicit conditional rendering, guard the empty-state with if cost_types.none? (or if empty?) so it only appears when there are no items.
  <% cost_types.each do |cost_type| %>
    <% list.with_item do %>

modules/costs/app/components/projects/settings/cost_types/index_component.html.erb:97

  • The empty-state is declared unconditionally after rendering items. If BorderBoxListComponent doesn’t internally hide the empty-state when items are present, this will display an empty-state alongside the populated list. If the API requires explicit conditional rendering, guard the empty-state with if cost_types.none? (or if empty?) so it only appears when there are no items.
  <% list.with_empty_state(
       title: I18n.t("cost_types.settings.cost_types.heading"),
       description: I18n.t("cost_types.admin.cost_type_projects.no_projects.description"),
       icon: :checklist
     ) %>

spec/components/work_package_relations_tab/index_component_spec.rb:61

  • The spec used to assert the presence of the group test selector (op-relation-group-parent) but that assertion was removed. The component still sets test_selector: \"op-relation-group-#{relation_group.type}\", so keeping an explicit expectation for the test selector helps prevent regressions in DOM hooks relied upon by system tests/JS. Consider reintroducing an assertion for the op-relation-group-parent selector in this example.
    it "renders the relations group with the parent work package in it" do
      expect(render_component).to have_list "Parent"

@myabc
myabc force-pushed the implementation/DREAM-804-meetings-costs-list-migrations branch from 151356d to f2f00a3 Compare August 6, 2026 20:44
@myabc
myabc force-pushed the implementation/DREAM-804-meetings-costs-list-migrations branch from f2f00a3 to 14df6ca Compare August 6, 2026 21:06
@myabc myabc added maintenance styling ruby Pull requests that update Ruby code labels Aug 6, 2026
@myabc myabc added this to the 17.8.x milestone Aug 6, 2026
@myabc
myabc force-pushed the implementation/DREAM-804-meetings-costs-list-migrations branch from 14df6ca to 37559d2 Compare August 6, 2026 21:38
@myabc
myabc force-pushed the implementation/DREAM-804-meetings-costs-list-migrations branch from 37559d2 to 2c4d40e Compare August 7, 2026 07:17
@myabc
myabc force-pushed the implementation/DREAM-804-meetings-costs-list-migrations branch 2 times, most recently from 77a4f41 to 4a329b4 Compare August 7, 2026 19:05
@myabc
myabc force-pushed the implementation/DREAM-804-meetings-costs-list-migrations branch 2 times, most recently from d245402 to 01612e5 Compare August 7, 2026 19:32
@myabc
myabc marked this pull request as ready for review August 7, 2026 19:33
<% end %>
<% end %>

<% list.with_empty_state(

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.

“Cost types” now appears both in the box header and again as the blankslate heading. Previously it appeared only in the blankslate. Is it intended?

h2 changed to h4, is it correct?

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.

h2 changed to h4, is it correct?

Yes. This should be level 4, I believe (the page heading is level 2)

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.

“Cost types” now appears both in the box header and again as the blankslate heading. Previously it appeared only in the blankslate. Is it intended?

I think that's ok for now. We will probably need to do some small design follow ups but need feedback from the UX team first.

Comment thread app/components/work_package_relations_tab/index_component.rb
@myabc
myabc force-pushed the implementation/DREAM-804-meetings-costs-list-migrations branch 2 times, most recently from c1e031d to 0d0a2e9 Compare August 12, 2026 08:37
@myabc
myabc force-pushed the implementation/DREAM-804-meetings-costs-list-migrations branch from 0d0a2e9 to 893effa Compare August 12, 2026 08:40
@myabc
myabc force-pushed the implementation/DREAM-804-meetings-costs-list-migrations branch from 893effa to 3207290 Compare August 12, 2026 09:39
@myabc
myabc force-pushed the implementation/DREAM-804-meetings-costs-list-migrations branch from 3207290 to 79ab90e Compare August 12, 2026 11:01
@myabc
myabc force-pushed the implementation/DREAM-804-meetings-costs-list-migrations branch 2 times, most recently from 62171fe to 69ec480 Compare August 12, 2026 11:16
@myabc
myabc force-pushed the implementation/DREAM-804-meetings-costs-list-migrations branch from 69ec480 to c00174e Compare August 12, 2026 11:23
@myabc
myabc requested a review from bsatarnejad August 12, 2026 11:47
myabc added 7 commits August 12, 2026 14:26
Uses the title slot for meeting links and shared rows for agendas.

https://community.openproject.org/wp/DREAM-697
Lets a list header show a hierarchy trail in the title position, as
the departments detail box needs. The title stays mandatory and turns
into a visually hidden heading, so the list keeps its accessible name
and heading navigation. Collapsible headers reject the slot because
the gem's CollapsibleHeader only accepts h1-h6 title tags.
Replaces the bespoke department box with a BorderBoxList. The
hierarchy breadcrumbs render in the list header through the new
breadcrumbs slot, the LDAP status becomes a header label, and both
bespoke blankslate components retire in favour of the list's
empty-state mechanism.

https://community.openproject.org/wp/DREAM-697
Moves relation groups and rows onto BorderBoxListComponent.

https://community.openproject.org/wp/DREAM-697
Renders the meeting participants box through the shared
`BorderBoxListComponent` instead of bespoke `border_box_container`
markup. The participants header keeps its title, count, and mark-all
action via the title slot, rows render the existing participant row
component, and the empty list uses the shared empty-state slot
(people icon) in place of the hand-rolled Blankslate branch. Adds a
component spec using the shared list examples.

https://community.openproject.org/wp/DREAM-697
Renders the project cost-types settings list through the shared
`BorderBoxListComponent` instead of a bespoke `Primer::Beta::BorderBox`.
The header title, per-row name and toggle switch, and toggle data
attributes are preserved; the separate itemless branch is folded into
the shared empty-state slot so the list owns its empty state. Adds a
component spec using the shared list examples.

https://community.openproject.org/wp/DREAM-697
Renders the resource allocations list through the shared
`BorderBoxListComponent` instead of a bespoke `Primer::Beta::BorderBox`,
keeping the list headerless and preserving the existing per-row list
item component and its arguments. The surrounding progress row and the
`allocations.any?` guard are kept, so an empty allocation set still
renders nothing. Adds a component spec.

https://community.openproject.org/wp/DREAM-697
@myabc
myabc force-pushed the implementation/DREAM-804-meetings-costs-list-migrations branch from c00174e to d36799b Compare August 12, 2026 12:26

@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.

Thanks for the clarifications. LGTM 👍🏼

@github-actions

Copy link
Copy Markdown

Warning

Flaky specs

  • rspec ./spec/features/roles/report_spec.rb[1:1]
  • rspec ./spec/features/roles/report_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 #24646, linked for reference only):

- `rspec ./spec/features/roles/report_spec.rb[1:1]`
- `rspec ./spec/features/roles/report_spec.rb[1:2]`

Treat this as a standalone task, unrelated to PR #24646. Create a new branch from origin/dev and open a new pull request targeting dev — do not stack it on PR #24646 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 merged commit 768b1b8 into dev Aug 12, 2026
27 of 28 checks passed
@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