Content
View differences
Updated by Alexander Coles 2 days ago
## Summary
Migrate list-shaped `Primer::Beta::BorderBox` / `border_box_container` usages to `OpenProject::Common::BorderBoxListComponent`, and extend the shared component API where the remaining migrations needed legitimate header flexibility.
Implementation is tracked in PR opf/openproject#23812.
## Implemented so far
### Shared component API
- Added `header.with_title` for linked or composed title content while still rendering inside the configured heading element.
- Added `header.with_action_icon_button` for icon-only header actions.
- Reworked header/row menus through `BorderBoxListComponent::Menu`, keeping the default kebab trigger automatic while allowing `button_arguments:` or a caller-provided `menu.with_show_button`.
- Added default empty-state rendering for itemless lists when callers do not provide a custom `with_empty_state` slot.
- Updated Lookbook docs, previews, preview specs, and component specs for the new public API.
### Migrated consumers
- `Wikis::CollapsiblePageLinksComponent`
- `Wikis::RelationPageLinksComponent`
- `Portfolios::IndexComponent`
- `OAuth::Applications::IndexComponent`
- `Settings::ProjectPhaseDefinitions::IndexComponent`
- `Projects::Settings::LifeCycle::IndexComponent`
- `Projects::Settings::ProjectCustomFieldSections::ShowComponent`
- `Projects::Settings::CreationWizard::ProjectCustomFieldSections::ShowComponent`
- `Workflows::TypeListComponent`, renamed from `Workflows::TableComponent`
- `WorkPackageTypes::ExportTemplateListComponent`
- `My::Notifications::ShowPageComponent`
- `WorkPackageMeetingsTab::MeetingComponent`
- `Admin::Departments::DetailComponent`
- `WorkPackageRelationsTab::IndexComponent`
Existing Backlogs bucket/sprint menu callers were also updated to the new `button_arguments:` API.
## Review and commit structure
The branch was regrouped for reviewability:
- the shared API change is now the first commit;
- each consumer migration is committed as a focused vertical slice;
- follow-up review fixes were folded into their owning commits rather than left as a trailing cleanup commit;
- every `[DREAM-697]` commit has a one-line detail and links back to this work package.
## Verification
- Component specs for the shared component and migrated consumers: 195 examples, 0 failures.
- Feature specs for workflow accessibility and export-template drag/toggle behavior: 4 examples, 0 failures.
- `bin/dirty-rubocop --against origin/dev`: 27 files, no offenses.
- `erb_lint` on changed ERB files: no errors.
- `git diff --check origin/dev..HEAD`: clean.
## Remaining migration candidates Deferred / out of scope
Ranked by fit (list-shaped BorderBox usages targeting BorderBoxListComponent).
| # | Component | Features | Notes |
|---|-----------|----------|-------|
| 1 | `Admin::Enumerations::IndexComponent` | header / drag / empty | Cherry-pick from `Documents::Admin::DocumentTypes::IndexComponent` remains intentionally excluded and should be handled with PR opf/openproject#23485 (DREAM-688, WP#74940). Shares a class hierarchy with #2. |
| 2 | `Documents::Admin::DocumentTypes::IndexComponent` | header / drag / empty | Coupled WP#74940 because it belongs to #1; also covered by PR opf/openproject#23485. |
| 3 | `Settings::ProjectCustomFieldSections::ShowComponent` | header / menu / drag / empty | Near-clone of the migrated `Projects::Settings::ProjectCustomFieldSections::ShowComponent`; high spec reuse. |
| 4 | `Storages::Admin::StorageListComponent` | header / empty | |
| 5 | `Wikis::Admin::WikiProviderListComponent` | header / empty | |
| 6 | `Meetings::Participants::ListComponent` | header / empty | |
| 7 | `Documents::ListComponent` | header / empty | Pagination row maps to a footer slot. |
| 8 | `MeetingSections::ShowComponent` | header / drag / empty | Nested drag targets (harder). |
| 9 | `WorkPackageTypes::FormConfiguration::GroupComponent` | header / drag / empty | |
| 10 | `Projects::Settings::CostTypes::IndexComponent` | toggle list / empty | Same shape as migrated life-cycle / export-template lists. |
| 11 | `ResourceAllocations::ListComponent` | headerless list | Same shape as migrated Portfolios. |
| 12 | `MeetingAgendaItems::ListComponent` | new-item form | No header; lowest fit. | same `Admin::Enumerations::IndexComponent` class hierarchy.
Note: PR opf/openproject#23485 also adds `spec/support/shared/components/border_box_list_component.rb`, which this branch already introduces -- expect a conflict on that file when integrating either way.
## Out More invasive or less direct BorderBox usages remain out of scope (not list-shaped)
Detail / single boxes: activities journal `ItemComponent` for this PR, including meeting section boxes, manage-shares rendering, form-configuration groups, and `RevisionComponent`. Wizards / accordions: SAML and OpenID Connect provider views, Storages `StorageViewComponent`, Wikis `WikiProviderViewComponent`, Jira import wizard. Other: date-picker dialog, creation-wizard blank slate, manage-shares (dynamic JS rows), custom-field hierarchy items (tree), filter form, health-reports dashboard. items.
Migrate list-shaped `Primer::Beta::BorderBox` / `border_box_container` usages to `OpenProject::Common::BorderBoxListComponent`, and extend the shared component API where the remaining migrations needed legitimate header flexibility.
Implementation is tracked in PR opf/openproject#23812.
## Implemented so far
### Shared component API
- Added `header.with_title` for linked or composed title content while still rendering inside the configured heading element.
- Added `header.with_action_icon_button` for icon-only header actions.
- Reworked header/row menus through `BorderBoxListComponent::Menu`, keeping the default kebab trigger automatic while allowing `button_arguments:` or a caller-provided `menu.with_show_button`.
- Added default empty-state rendering for itemless lists when callers do not provide a custom `with_empty_state` slot.
- Updated Lookbook docs, previews, preview specs, and component specs for the new public API.
### Migrated consumers
- `Wikis::CollapsiblePageLinksComponent`
- `Wikis::RelationPageLinksComponent`
- `Portfolios::IndexComponent`
- `OAuth::Applications::IndexComponent`
- `Settings::ProjectPhaseDefinitions::IndexComponent`
- `Projects::Settings::LifeCycle::IndexComponent`
- `Projects::Settings::ProjectCustomFieldSections::ShowComponent`
- `Projects::Settings::CreationWizard::ProjectCustomFieldSections::ShowComponent`
- `Workflows::TypeListComponent`, renamed from `Workflows::TableComponent`
- `WorkPackageTypes::ExportTemplateListComponent`
- `My::Notifications::ShowPageComponent`
- `WorkPackageMeetingsTab::MeetingComponent`
- `Admin::Departments::DetailComponent`
- `WorkPackageRelationsTab::IndexComponent`
Existing Backlogs bucket/sprint menu callers were also updated to the new `button_arguments:` API.
## Review and commit structure
The branch was regrouped for reviewability:
- the shared API change is now the first commit;
- each consumer migration is committed as a focused vertical slice;
- follow-up review fixes were folded into their owning commits rather than left as a trailing cleanup commit;
- every `[DREAM-697]` commit has a one-line detail and links back to this work package.
## Verification
- Component specs for the shared component and migrated consumers: 195 examples, 0 failures.
- Feature specs for workflow accessibility and export-template drag/toggle behavior: 4 examples, 0 failures.
- `bin/dirty-rubocop --against origin/dev`: 27 files, no offenses.
- `erb_lint` on changed ERB files: no errors.
- `git diff --check origin/dev..HEAD`: clean.
## Remaining migration candidates
Ranked by fit (list-shaped BorderBox usages targeting BorderBoxListComponent).
| # | Component | Features | Notes |
|---|-----------|----------|-------|
| 1 | `Admin::Enumerations::IndexComponent` | header / drag / empty | Cherry-pick from
| 2 | `Documents::Admin::DocumentTypes::IndexComponent` | header / drag / empty | Coupled
| 3 | `Settings::ProjectCustomFieldSections::ShowComponent` | header / menu / drag / empty | Near-clone of the migrated `Projects::Settings::ProjectCustomFieldSections::ShowComponent`; high spec reuse. |
| 4 | `Storages::Admin::StorageListComponent` | header / empty | |
| 5 | `Wikis::Admin::WikiProviderListComponent` | header / empty | |
| 6 | `Meetings::Participants::ListComponent` | header / empty | |
| 7 | `Documents::ListComponent` | header / empty | Pagination row maps to a footer slot. |
| 8 | `MeetingSections::ShowComponent` | header / drag / empty | Nested drag targets (harder). |
| 9 | `WorkPackageTypes::FormConfiguration::GroupComponent` | header / drag / empty | |
| 10 | `Projects::Settings::CostTypes::IndexComponent` | toggle list / empty | Same shape as migrated life-cycle / export-template lists. |
| 11 | `ResourceAllocations::ListComponent` | headerless list | Same shape as migrated Portfolios. |
| 12 | `MeetingAgendaItems::ListComponent` | new-item form | No header; lowest fit. |
Note: PR opf/openproject#23485 also adds `spec/support/shared/components/border_box_list_component.rb`, which this branch already introduces -- expect a conflict on that file when integrating either way.
## Out
Detail / single boxes: activities journal `ItemComponent`