[#74088] Extract shared WorkPackageCardComponent and rename Backlogs components#22936
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces new Backlogs ViewComponents intended to standardize rendering of work package “cards” and their kebab action menus in the Backlogs UI.
Changes:
- Add
Backlogs::WorkPackageCardComponentplus component spec coverage for URL/drag/drop/menu derivation. - Extract a reusable
Backlogs::CardMenuComponent(ActionMenu show button + deferred fragment loading) with spec coverage. - Add an English i18n key for the new
card_menu_componentlabel.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| modules/backlogs/app/components/backlogs/work_package_card_component.rb | New component providing row args (DnD + stimulus data) and URL derivation based on parent (sprint/bucket/inbox). |
| modules/backlogs/app/components/backlogs/work_package_card_component.html.erb | New card layout template rendering info line, points, subject, and extracted card menu. |
| modules/backlogs/app/components/backlogs/card_menu_component.rb | New extracted component wrapping Primer ActionMenu setup (menu_id/src/classes). |
| modules/backlogs/app/components/backlogs/card_menu_component.html.erb | New extracted template rendering the kebab show button with accessible label. |
| modules/backlogs/spec/components/backlogs/work_package_card_component_spec.rb | Component specs for card content, row args, draggability, URL derivation, and all=1 param propagation. |
| modules/backlogs/spec/components/backlogs/card_menu_component_spec.rb | Component specs asserting ActionMenu markup, stable ids, deferred fragment src, and label. |
| modules/backlogs/config/locales/en.yml | Adds backlogs.card_menu_component.label_actions. |
2be6744 to
afba3c2
Compare
d0f5493 to
27e93f2
Compare
938af2e to
3441a3e
Compare
Add readers for the sprint form component state and use them from the template and helper methods instead of reading instance variables directly. Cover the reader and rendering behavior with a focused component spec.
Treat card box containers as Rails dom_target sources so shared card boxes can accept symbols, strings, model classes, and model instances without Backlogs-specific ID branching. Move Backlogs drag-and-drop target IDs into explicit caller-provided configuration, keeping the existing controller protocol while omitting generic DnD data for consumers that do not opt in. https://community.openproject.org/wp/73968
Extracts the BorderBox row arguments into a row-bridge object (`WorkPackageCardBoxComponent::Item`) so the box can build rows without forcing the visual card to render row-level concerns. The visual `WorkPackageCardComponent` constructor narrows to `(work_package:, menu_src:)`; in-repo callers updated. Adds a polymorphic slot API (`with_work_package_item`, `with_empty_item`) modeled on `Primer::Alpha::FileTreeView`, plus a public `#build_item` for off-box callers. Renames the URL pass-through to a generic `params:` kwarg, leaving Backlogs all-state handling at the call sites. https://community.openproject.org/wp/73968
Remove the story-points display from the shared work package card and expose a generic metric slot instead. Backlogs now opts into that slot with a small story-points component when rendering sprint, bucket, and inbox cards. https://community.openproject.org/wp/73968
…ent-renaming # Conflicts: # modules/backlogs/app/components/backlogs/backlog_bucket_item_component.rb # modules/backlogs/app/components/backlogs/inbox_item_component.rb # modules/backlogs/app/components/backlogs/sprint_component.rb # modules/backlogs/spec/components/backlogs/backlog_bucket_item_component_spec.rb # modules/backlogs/spec/components/backlogs/inbox_item_component_spec.rb # modules/backlogs/spec/components/backlogs/sprint_component_spec.rb
Move Backlogs-specific item/card concerns behind Backlogs components while keeping the common card box API focused on generic item rendering. The common item keeps generic draggability hooks, while Backlogs owns story points, menu URLs, and story controller row data. https://community.openproject.org/wp/73968
Expose a top-level menu slot on the common work package card so card and card-box callers can configure action menus in the same style. Keep menu_src as a compatibility shortcut for existing deferred Backlogs menus while allowing inline non-deferred menu items through the slot. https://community.openproject.org/wp/73968
Forward metric slot calls from the Backlogs card wrapper to the wrapped common card so Backlogs card box items keep the same customization surface as generic items. Keep story points as the default metric when callers do not provide their own metric slot. https://community.openproject.org/wp/73968
Marks the hard-coded `InfoLineComponent.new(work_package:)` call in the common card template as the integration point for InfoLine variants and status presentation requested by WP 73089. Defers the actual argument forwarding so this PR keeps a narrow scope. https://community.openproject.org/wp/73968
The common card box now exposes a generic `item` slot via `with_item` for manually composed rows. Automatic rendering still only builds work package items from the `work_packages:` argument. The Backlogs inbox now owns the truncate-middle show-more row, its route, Turbo frame, and draggable marker. https://community.openproject.org/wp/73968
| def work_package_count | ||
| @work_package_count ||= work_packages.size | ||
| def before_render | ||
| content |
There was a problem hiding this comment.
Since the role of this method call is not trivial, I would place a comment regarding its function.
There was a problem hiding this comment.
We have this pattern in a few places. I agree it's non-obvious. Perhaps something for the lookbook?
| end | ||
|
|
||
| def cards | ||
| @cards ||= visible_work_packages.map do |work_package| |
There was a problem hiding this comment.
I can answer the following question:
- do we want to even keep this truncation pattern?
AFAIK, yes. In future iterations of the page, we will possibly use pagination, but it's not in our immediate priority.
| container:, | ||
| work_packages: [], | ||
| drag_and_drop: nil, | ||
| item_component_klass: Item, |
There was a problem hiding this comment.
I think we can default to the Backlogs::WorkPackageCardBoxItemComponent.
Reuse the generic content item bridge for empty card box rows and keep only the empty-row data override. https://community.openproject.org/wp/73968
Removes dependency on Backlogs-specific `StoryPointsComponent`.
Ticket
https://community.openproject.org/wp/74088
https://community.openproject.org/wp/73968 (foundations)
https://community.openproject.org/wp/71402 (foundations)
What are you trying to accomplish?
Reduce duplication in the Backlogs card-list components by extracting shared
WorkPackageCardBoxComponent(with nestedHeader) andWorkPackageCardComponent(with nestedMenu), then migrateSprintComponentandBucketComponentto compose them. Also tightens the component vocabulary: drops the redundantBacklogprefix on bucket components (already namespaced underBacklogs::), drops theNewprefix on forms/dialogs that handle both create and edit, and singularisesBacklogsComponent->BacklogComponent.Screenshots
WorkPackageCardBoxComponentWorkPackageCardComponentWhat approach did you choose and why?
Composition via slots, not inheritance. A single
container:argument (Sprint,BacklogBucket, ornilfor inbox) drives DOM ids, list ids, drop-target wiring, and per-card URLs. Slot lambdas enforce structure where it matters (empty_state,Header#menu); the header'sactionsslot is a typedrenders_manyso consumers callheader.with_action_button(...)and pick upPrimer::Beta::Buttonslot helpers directly.The wireframe attached to WP #74088 has some naming drift relative to the current code. This PR series does not introduce a separate
BucketsComponent; the futureBacklogComponentcontinues to own the backlog header, bucket-list composition, and inbox composition.Merge checklist
WorkPackageCardBoxComponentWorkPackageCardComponentSprintComponentto useWorkPackageCardBoxComponentBacklogBucket*ComponenttoBucket*Component(replaces [#73081] Rename bucket UI components #22886)New*Component/New*Formto*Component/*Form(per @toy's suggestion)BacklogsComponenttoBacklogComponentBucketComponentto useWorkPackageCardBoxComponentInboxComponentto useWorkPackageCardBoxComponentWorkPackageCardBoxComponentandWorkPackageCardComponentgeneric (OP 73968):container:to be customised.WorkPackageCardComponentsupports non-deferred menus withoutsrc; consider exposing a top-level menu slot.WorkPackageCardComponentto pass arguments through toWorkPackages::InfoLineComponent.OpenProject::Common::WorkPackageCardBoxComponent::Item, excluding drag and drop cleanup tracked separately.backlogs--storyStimulus controller can move out of the common item in this PR.show_all_backlog) and avoidingcapturein templates.show_morehandling: decide whether truncation/show-more belongs in a Backlogs-specific wrapper or an intermediate specialised component.sprint_list_spec.rb,drag_in_sprint_spec.rb,story_points_spec.rb