mirror of
https://github.com/opf/openproject.git
synced 2026-06-13 19:20:00 +00:00
[#73968] Add card menu slot
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
This commit is contained in:
@@ -39,13 +39,17 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<% end %>
|
||||
|
||||
<% grid.with_area(:menu) do %>
|
||||
<%= render(
|
||||
OpenProject::Common::WorkPackageCardComponent::Menu.new(
|
||||
work_package:,
|
||||
src: menu_src,
|
||||
button_aria_label: t(".menu.label_actions")
|
||||
)
|
||||
) %>
|
||||
<% if menu? %>
|
||||
<%= menu %>
|
||||
<% else %>
|
||||
<%= render(
|
||||
OpenProject::Common::WorkPackageCardComponent::Menu.new(
|
||||
work_package:,
|
||||
src: menu_src,
|
||||
button_aria_label: t(".menu.label_actions")
|
||||
)
|
||||
) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% grid.with_area(:subject) do %>
|
||||
|
||||
@@ -35,11 +35,20 @@ module OpenProject
|
||||
include OpPrimer::ComponentHelpers
|
||||
|
||||
renders_one :metric, Primer::Content
|
||||
renders_one :menu, ->(src: nil, button_aria_label: nil, **system_arguments) {
|
||||
Menu.new(
|
||||
work_package:,
|
||||
src:,
|
||||
button_aria_label:,
|
||||
**system_arguments
|
||||
)
|
||||
}
|
||||
|
||||
attr_reader :work_package, :menu_src
|
||||
|
||||
# @param work_package [WorkPackage] the work package this card represents.
|
||||
# @param menu_src [String, NilClass] optional lazy menu source.
|
||||
# @param menu_src [String, NilClass] optional lazy menu source. Prefer the
|
||||
# `with_menu(src:)` slot for new call sites.
|
||||
def initialize(work_package:, menu_src: nil)
|
||||
super()
|
||||
|
||||
|
||||
@@ -54,6 +54,19 @@ module OpenProject
|
||||
end
|
||||
end
|
||||
|
||||
def with_menu
|
||||
work_package = WorkPackage.first
|
||||
return preview_message("No work packages in the database.") unless work_package
|
||||
|
||||
render OpenProject::Common::WorkPackageCardComponent.new(
|
||||
work_package:
|
||||
) do |card|
|
||||
card.with_menu do |menu|
|
||||
menu.with_item(label: "Open", href: "/work_packages/#{work_package.id}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def preview_message(text)
|
||||
|
||||
@@ -32,6 +32,8 @@ module Backlogs
|
||||
class WorkPackageCardComponent < ApplicationComponent
|
||||
attr_reader :work_package, :menu_src
|
||||
|
||||
delegate :with_menu, to: :card
|
||||
|
||||
def initialize(work_package:, menu_src: nil)
|
||||
super()
|
||||
|
||||
@@ -40,11 +42,21 @@ module Backlogs
|
||||
end
|
||||
|
||||
def call
|
||||
render(OpenProject::Common::WorkPackageCardComponent.new(work_package:, menu_src:)) do |card|
|
||||
card.with_metric do
|
||||
render(card) do |common_card|
|
||||
common_card.with_metric do
|
||||
render(Backlogs::StoryPointsComponent.new(work_package:))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def card
|
||||
@card ||= OpenProject::Common::WorkPackageCardComponent.new(work_package:, menu_src:)
|
||||
end
|
||||
|
||||
def before_render
|
||||
content
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -60,4 +60,20 @@ RSpec.describe Backlogs::WorkPackageCardComponent, type: :component do
|
||||
expect(rendered_component).to have_element "include-fragment",
|
||||
src: menu_src
|
||||
end
|
||||
|
||||
it "supports inline menu items through the menu slot" do
|
||||
rendered = render_inline(described_class.new(work_package:, menu_src:)) do |card|
|
||||
card.with_menu(button_aria_label: "Backlogs card actions") do |menu|
|
||||
menu.with_item(label: "Open", href: "/work_packages/#{work_package.id}")
|
||||
end
|
||||
end
|
||||
|
||||
expect(rendered).to have_link "Open", href: "/work_packages/#{work_package.id}"
|
||||
expect(rendered).to have_button(
|
||||
"work_package_#{work_package.id}_menu-button",
|
||||
accessible_name: "Backlogs card actions"
|
||||
)
|
||||
expect(rendered).to have_no_element "include-fragment"
|
||||
expect(rendered).to have_text("5 points", normalize_ws: true)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -96,5 +96,34 @@ RSpec.describe OpenProject::Common::WorkPackageCardComponent, type: :component d
|
||||
it "uses the provided menu src" do
|
||||
expect(rendered_component).to have_element "include-fragment", src: menu_src
|
||||
end
|
||||
|
||||
it "supports inline menu items through the menu slot" do
|
||||
rendered = render_inline(component) do |card|
|
||||
card.with_menu(button_aria_label: "Card actions") do |menu|
|
||||
menu.with_item(label: "Open", href: "/work_packages/#{work_package.id}")
|
||||
end
|
||||
end
|
||||
|
||||
expect(rendered).to have_link "Open", href: "/work_packages/#{work_package.id}"
|
||||
expect(rendered).to have_button(menu_button_id, accessible_name: "Card actions")
|
||||
expect(rendered).to have_no_element "include-fragment"
|
||||
end
|
||||
|
||||
it "supports deferred menu loading through the menu slot" do
|
||||
rendered = render_inline(described_class.new(work_package:)) do |card|
|
||||
card.with_menu(src: menu_src)
|
||||
end
|
||||
|
||||
expect(rendered).to have_element "include-fragment", src: menu_src
|
||||
end
|
||||
|
||||
it "uses the menu slot before the initializer menu source" do
|
||||
rendered = render_inline(component) do |card|
|
||||
card.with_menu(src: "/slot-menu")
|
||||
end
|
||||
|
||||
expect(rendered).to have_element "include-fragment", src: "/slot-menu"
|
||||
expect(rendered).to have_no_element "include-fragment", src: menu_src
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user