From 6fb464fdd036955d9f6bc8070f50b5c4bacd93c0 Mon Sep 17 00:00:00 2001 From: Elia Schito Date: Fri, 4 Aug 2023 19:38:14 +0200 Subject: [PATCH] Use menu items for subitems too --- .../helpers/spree/admin/navigation_helper.rb | 32 ++-- .../admin/shared/_order_submenu.html.erb | 63 -------- .../admin/shared/_product_sub_menu.html.erb | 17 --- .../admin/shared/_promotion_sub_menu.html.erb | 8 - .../admin/shared/_settings_sub_menu.html.erb | 26 ---- .../views/spree/admin/shared/_tabs.html.erb | 32 ++-- backend/lib/spree/backend_configuration.rb | 143 +++++++++++++----- .../deprecated_tab_constants.rb | 30 ++++ .../spree/backend_configuration/menu_item.rb | 56 ++++++- .../templates/config/initializers/spree.rb.tt | 4 +- 10 files changed, 217 insertions(+), 194 deletions(-) delete mode 100644 backend/app/views/spree/admin/shared/_order_submenu.html.erb delete mode 100644 backend/app/views/spree/admin/shared/_product_sub_menu.html.erb delete mode 100644 backend/app/views/spree/admin/shared/_promotion_sub_menu.html.erb delete mode 100644 backend/app/views/spree/admin/shared/_settings_sub_menu.html.erb create mode 100644 backend/lib/spree/backend_configuration/deprecated_tab_constants.rb diff --git a/backend/app/helpers/spree/admin/navigation_helper.rb b/backend/app/helpers/spree/admin/navigation_helper.rb index 2145902dbb0..b50a08bf67d 100644 --- a/backend/app/helpers/spree/admin/navigation_helper.rb +++ b/backend/app/helpers/spree/admin/navigation_helper.rb @@ -42,18 +42,22 @@ def admin_page_title # Make an admin tab that covers one or more resources supplied by symbols # Option hash may follow. Valid options are # * :label to override link text, otherwise based on the first resource name (translated) - # * :route to override automatically determining the default route # * :match_path as an alternative way to control when the tab is active, /products would match /admin/products, /admin/products/5/variants etc. # * :match_path can also be a callable that takes a request and determines whether the menu item is selected for the request. - def tab(*args, &_block) - options = { label: args.first.to_s } + def tab(*args, &block) + block_content = capture(&block) if block_given? - if args.last.is_a?(Hash) - options = options.merge(args.pop) + options = args.pop if args.last.is_a?(Hash) + + if args.any? + warn "[DEPRECATION] Passing resources to #{self.class.name} is deprecated. Please pass a label instead." + end + + if options.key?(:route) + warn "[DEPRECATION] Passing a route to #{self.class.name} is deprecated. Please pass a url instead." end - options[:route] ||= "admin_#{args.first}" - destination_url = options[:url] || spree.send("#{options[:route]}_path") + destination_url = options[:url] || spree.send("admin_#{options[:label]}_path") label = t(options[:label], scope: [:spree, :admin, :tab]) css_classes = [] @@ -65,22 +69,12 @@ def tab(*args, &_block) link = link_to(label, destination_url) end - selected = if options[:match_path].is_a? Regexp - request.fullpath =~ options[:match_path] - elsif options[:match_path].respond_to?(:call) - options[:match_path].call(request) - elsif options[:match_path] - request.fullpath.starts_with?("#{spree.admin_path}#{options[:match_path]}") - else - request.fullpath.starts_with?(destination_url) || - args.include?(controller.controller_name.to_sym) - end - css_classes << 'selected' if selected + css_classes << 'selected' if options[:selected] if options[:css_class] css_classes << options[:css_class] end - content_tag('li', link + (yield if block_given?), class: css_classes.join(' ') ) + content_tag('li', link + block_content.to_s, class: css_classes.join(' ') ) end def link_to_clone(resource, options = {}) diff --git a/backend/app/views/spree/admin/shared/_order_submenu.html.erb b/backend/app/views/spree/admin/shared/_order_submenu.html.erb deleted file mode 100644 index 7f0741ad57c..00000000000 --- a/backend/app/views/spree/admin/shared/_order_submenu.html.erb +++ /dev/null @@ -1,63 +0,0 @@ - diff --git a/backend/app/views/spree/admin/shared/_product_sub_menu.html.erb b/backend/app/views/spree/admin/shared/_product_sub_menu.html.erb deleted file mode 100644 index dd44c97eeda..00000000000 --- a/backend/app/views/spree/admin/shared/_product_sub_menu.html.erb +++ /dev/null @@ -1,17 +0,0 @@ - diff --git a/backend/app/views/spree/admin/shared/_promotion_sub_menu.html.erb b/backend/app/views/spree/admin/shared/_promotion_sub_menu.html.erb deleted file mode 100644 index 1c45767fc35..00000000000 --- a/backend/app/views/spree/admin/shared/_promotion_sub_menu.html.erb +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/backend/app/views/spree/admin/shared/_settings_sub_menu.html.erb b/backend/app/views/spree/admin/shared/_settings_sub_menu.html.erb deleted file mode 100644 index b7180af6265..00000000000 --- a/backend/app/views/spree/admin/shared/_settings_sub_menu.html.erb +++ /dev/null @@ -1,26 +0,0 @@ - diff --git a/backend/app/views/spree/admin/shared/_tabs.html.erb b/backend/app/views/spree/admin/shared/_tabs.html.erb index 60e84498c7e..16f5afb9e06 100644 --- a/backend/app/views/spree/admin/shared/_tabs.html.erb +++ b/backend/app/views/spree/admin/shared/_tabs.html.erb @@ -1,15 +1,23 @@ -<% Spree::Backend::Config.menu_items.sort_by { |item| item.position || Float::INFINITY }.each do |menu_item| %> - <% if instance_exec(&menu_item.condition) %> - <%= - tab( - *menu_item.sections, - icon: menu_item.icon, - label: menu_item.label, - url: menu_item.url.is_a?(Symbol) ? spree.public_send(menu_item.url) : menu_item.url, - match_path: menu_item.match_path, - ) do - %> - <%- render partial: menu_item.partial if menu_item.partial %> +<% Spree::Backend::Config.menu_items.sort_by { |item| item.position || Float::INFINITY }.select { instance_exec(&_1.condition) }.each do |menu_item| %> + <%= tab( + icon: menu_item.icon, + label: menu_item.label, + url: menu_item.url, + selected: menu_item.selected?(request), + ) do %> + <% if menu_item.partial %> + <%- render partial: menu_item.partial %> + <% elsif menu_item.children.present? %> + <%- end %> <% end %> <% end %> diff --git a/backend/lib/spree/backend_configuration.rb b/backend/lib/spree/backend_configuration.rb index b9e14fcb26b..52291dd06e6 100644 --- a/backend/lib/spree/backend_configuration.rb +++ b/backend/lib/spree/backend_configuration.rb @@ -32,29 +32,19 @@ def theme_path(user_theme = nil) } } - ORDER_TABS ||= [:orders, :payments, :creditcard_payments, - :shipments, :credit_cards, :return_authorizations, - :customer_returns, :adjustments, :customer_details] - PRODUCT_TABS ||= [:products, :option_types, :properties, - :variants, :product_properties, :taxonomies, - :taxons] - CONFIGURATION_TABS ||= [:stores, :tax_categories, - :tax_rates, :zones, - :payment_methods, :shipping_methods, - :shipping_categories, :stock_locations, - :refund_reasons, :reimbursement_types, - :return_reasons, :adjustment_reasons, - :store_credit_reasons] - PROMOTION_TABS ||= [:promotions, :promotion_categories] - STOCK_TABS ||= [:stock_items] - USER_TABS ||= [:users, :store_credits] + autoload :ORDER_TABS, 'spree/backend_configuration/deprecated_tab_constants' + autoload :PRODUCT_TABS, 'spree/backend_configuration/deprecated_tab_constants' + autoload :CONFIGURATION_TABS, 'spree/backend_configuration/deprecated_tab_constants' + autoload :PROMOTION_TABS, 'spree/backend_configuration/deprecated_tab_constants' + autoload :STOCK_TABS, 'spree/backend_configuration/deprecated_tab_constants' + autoload :USER_TABS, 'spree/backend_configuration/deprecated_tab_constants' # Items can be added to the menu by using code like the following: # # Spree::Backend::Config.configure do |config| # config.menu_items << config.class::MenuItem.new( - # [:section], - # 'icon-name', + # label: :section, + # icon: 'icon-name', # url: 'https://solidus.io/' # ) # end @@ -75,45 +65,78 @@ def theme_path(user_theme = nil) def menu_items @menu_items ||= [ MenuItem.new( - ORDER_TABS, - 'shopping-cart', + label: :orders, + icon: admin_updated_navbar ? 'ri-inbox-line' : 'shopping-cart', condition: -> { can?(:admin, Spree::Order) }, position: 0 ), MenuItem.new( - PRODUCT_TABS, - 'th-large', + label: :products, + icon: admin_updated_navbar ? 'ri-price-tag-3-line' : 'th-large', condition: -> { can?(:admin, Spree::Product) }, - partial: 'spree/admin/shared/product_sub_menu', - position: 1 + position: 1, + children: [ + MenuItem.new( + label: :products, + condition: -> { can? :admin, Spree::Product }, + match_path: '/products', + ), + MenuItem.new( + label: :option_types, + condition: -> { can? :admin, Spree::OptionType }, + match_path: '/option_types', + ), + MenuItem.new( + label: :properties, + condition: -> { can? :admin, Spree::Property }, + ), + MenuItem.new( + label: :taxonomies, + condition: -> { can? :admin, Spree::Taxonomy }, + ), + MenuItem.new( + url: :admin_taxons_path, + condition: -> { can? :admin, Spree::Taxon }, + label: :display_order, + match_path: '/taxons', + ), + ], ), MenuItem.new( - PROMOTION_TABS, - 'bullhorn', - partial: 'spree/admin/shared/promotion_sub_menu', + label: :promotions, + icon: admin_updated_navbar ? 'ri-megaphone-line' : 'bullhorn', + children: [ + MenuItem.new( + label: :promotions, + condition: -> { can?(:admin, Spree::Promotion) }, + ), + MenuItem.new( + label: :promotion_categories, + condition: -> { can?(:admin, Spree::PromotionCategory) }, + ), + ], condition: -> { can?(:admin, Spree::Promotion) }, url: :admin_promotions_path, - position: 2 + position: 2, ), MenuItem.new( - STOCK_TABS, - 'cubes', - condition: -> { can?(:admin, Spree::StockItem) }, label: :stock, + icon: admin_updated_navbar ? 'ri-stack-line' : 'cubes', + condition: -> { can?(:admin, Spree::StockItem) }, url: :admin_stock_items_path, match_path: '/stock_items', - position: 3 + position: 3, ), MenuItem.new( - USER_TABS, - 'user', + label: :users, + icon: admin_updated_navbar ? 'ri-user-line' : 'user', condition: -> { Spree.user_class && can?(:admin, Spree.user_class) }, url: :admin_users_path, - position: 4 + position: 4, ), MenuItem.new( - CONFIGURATION_TABS, - 'wrench', + label: :settings, + icon: admin_updated_navbar ? 'ri-settings-line' : 'wrench', condition: -> { can?(:admin, Spree::Store) || can?(:admin, Spree::AdjustmentReason) || @@ -128,10 +151,50 @@ def menu_items can?(:admin, Spree::ReturnReason) || can?(:admin, Spree::Zone) }, - label: :settings, - partial: 'spree/admin/shared/settings_sub_menu', url: :admin_stores_path, - position: 5 + position: 5, + children: [ + MenuItem.new( + label: :stores, + condition: -> { can? :admin, Spree::Store }, + url: :admin_stores_path, + ), + MenuItem.new( + label: :payment_methods, + condition: -> { can? :admin, Spree::PaymentMethod }, + url: :admin_payment_methods_path, + ), + + MenuItem.new( + label: :taxes, + condition: -> { can?(:admin, Spree::TaxCategory) || can?(:admin, Spree::TaxRate) }, + url: :admin_tax_categories_path, + match_path: %r(tax_categories|tax_rates), + ), + MenuItem.new( + label: :checkout, + condition: -> { + can?(:admin, Spree::RefundReason) || + can?(:admin, Spree::ReimbursementType) || + can?(:show, Spree::ReturnReason) || + can?(:show, Spree::AdjustmentReason) + }, + url: :admin_refund_reasons_path, + match_path: %r(refund_reasons|reimbursement_types|return_reasons|adjustment_reasons|store_credit_reasons) + ), + MenuItem.new( + label: :shipping, + condition: -> { can?(:admin, Spree::ShippingMethod) || + can?(:admin, Spree::ShippingCategory) || can?(:admin, Spree::StockLocation) }, + url: :admin_shipping_methods_path, + match_path: %r(shipping_methods|shipping_categories|stock_locations), + ), + MenuItem.new( + label: :zones, + condition: -> { can?(:admin, Spree::Zone) }, + url: :admin_zones_path, + ), + ], ) ] end diff --git a/backend/lib/spree/backend_configuration/deprecated_tab_constants.rb b/backend/lib/spree/backend_configuration/deprecated_tab_constants.rb new file mode 100644 index 00000000000..5efbed17278 --- /dev/null +++ b/backend/lib/spree/backend_configuration/deprecated_tab_constants.rb @@ -0,0 +1,30 @@ +warn "DEPRECATION WARNING: Spree::BackendConfiguration::*_TABS is deprecated and will be removed in Spree 5.0. Please use Spree::BackendConfiguration::MenuItem(children:) instead." + +Spree::BackendConfiguration::ORDER_TABS ||= [ + :orders, :payments, :creditcard_payments, + :shipments, :credit_cards, :return_authorizations, + :customer_returns, :adjustments, :customer_details +] +Spree::BackendConfiguration::PRODUCT_TABS ||= [ + :products, :option_types, :properties, + :variants, :product_properties, :taxonomies, + :taxons +] +Spree::BackendConfiguration::CONFIGURATION_TABS ||= [ + :stores, :tax_categories, + :tax_rates, :zones, + :payment_methods, :shipping_methods, + :shipping_categories, :stock_locations, + :refund_reasons, :reimbursement_types, + :return_reasons, :adjustment_reasons, + :store_credit_reasons +] +Spree::BackendConfiguration::PROMOTION_TABS ||= [ + :promotions, :promotion_categories +] +Spree::BackendConfiguration::STOCK_TABS ||= [ + :stock_items +] +Spree::BackendConfiguration::USER_TABS ||= [ + :users, :store_credits +] diff --git a/backend/lib/spree/backend_configuration/menu_item.rb b/backend/lib/spree/backend_configuration/menu_item.rb index d257f43b8c1..8d0b850bb5f 100644 --- a/backend/lib/spree/backend_configuration/menu_item.rb +++ b/backend/lib/spree/backend_configuration/menu_item.rb @@ -4,12 +4,12 @@ module Spree class BackendConfiguration < Preferences::Configuration # An item which should be drawn in the admin menu class MenuItem - attr_reader :icon, :label, :partial, :condition, :sections, :match_path + attr_reader :icon, :label, :partial, :children, :condition, :sections, :match_path attr_accessor :position # @param sections [Array] The sections which are contained within - # this admin menu section. + # this admin menu section @deprecated. # @param icon [String] The icon to draw for this menu item # @param condition [Proc] A proc which returns true if this menu item # should be drawn. If nil, it will be replaced with a proc which always @@ -17,41 +17,83 @@ class MenuItem # @param label [Symbol] The translation key for a label to use for this # menu item. # @param partial [String] A partial to draw within this menu item for use - # in declaring a submenu - # @param url [String] A url where this link should send the user to + # in declaring a submenu @deprecated + # @param children [Array] An array + # @param url [String|Symbol] A url where this link should send the user to or a Symbol representing a route name # @param position [Integer] The position in which the menu item should render # nil will cause the item to render last # @param match_path [String, Regexp, callable] (nil) If the {url} to determine the active tab is ambigous # you can pass a String, Regexp or callable to identify this menu item. The callable # accepts a request object and returns a Boolean value. def initialize( - sections, - icon, + *args, + icon: nil, condition: nil, label: nil, partial: nil, + children: [], url: nil, position: nil, match_path: nil ) + if args.length == 2 + sections, icon = args + label ||= sections.first.to_s + warn "[DEPRECATION] Passing sections to #{self.class.name} is deprecated. Please pass a label instead." + warn "[DEPRECATION] Passing icon to #{self.class.name} is deprecated. Please use the keyword argument instead." + elsif args.any? + raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 0..2)" + end + + if partial + warn "[DEPRECATION] Passing a partial to #{self.class.name} is deprecated. Please use the children keyword argument instead." + raise ArgumentError, "cannot pass both partial and children to #{self.class.name}" if children.any? + end @condition = condition || -> { true } @sections = sections @icon = icon - @label = label || sections.first + @label = label @partial = partial + @children = children @url = url @position = position @match_path = match_path end + def selected?(request) + current_path?(request) || children.any? { |child| child.selected?(request) } + end + + def current_path?(request) + if match_path.is_a? Regexp + request.fullpath =~ match_path + elsif match_path.respond_to?(:call) + match_path.call(request) + elsif match_path + request.fullpath.starts_with?("#{spree.admin_path}#{match_path}") + else + request.fullpath.starts_with?(url) + end + end + def url if @url.respond_to?(:call) @url.call + elsif @url.is_a?(Symbol) + spree.public_send(@url) + elsif @url.nil? + spree.send("admin_#{@label}_path") else @url end end + + private + + def spree + Spree::Core::Engine.routes.url_helpers + end end end end diff --git a/core/lib/generators/solidus/install/templates/config/initializers/spree.rb.tt b/core/lib/generators/solidus/install/templates/config/initializers/spree.rb.tt index ae09e1d8ce1..b4ed5909e19 100644 --- a/core/lib/generators/solidus/install/templates/config/initializers/spree.rb.tt +++ b/core/lib/generators/solidus/install/templates/config/initializers/spree.rb.tt @@ -57,8 +57,8 @@ Spree::Backend::Config.configure do |config| # a new menu item: # # config.menu_items << config.class::MenuItem.new( - # [:section], - # 'icon-name', + # label: :section, + # icon: 'icon-name', # url: 'https://solidus.io/' # )