From eac89aa9659e22ae2d9645e4bc2f13939ace982b Mon Sep 17 00:00:00 2001 From: Chris Todorov Date: Thu, 7 Mar 2024 11:15:17 -0800 Subject: [PATCH 1/2] Add the ability to configure batch action confirmation This change introduces a new boolean configuration on the `BatchAction` struct that would allow users of the `UI::Table` component to specify if a batch action requires confirmation. This change enables this new behaviour on the products index batch actions as a proof of concept. Co-authored-by: Kendra Riga Co-authored-by: Cameron Day --- .../solidus_admin/products/index/component.rb | 3 +++ .../solidus_admin/ui/table/component.js | 17 ++++++++++++++++- .../solidus_admin/ui/table/component.rb | 17 ++++++++++++++--- .../solidus_admin/ui/table/component.yml | 1 + admin/spec/features/products_spec.rb | 15 ++++++++++++--- 5 files changed, 46 insertions(+), 7 deletions(-) diff --git a/admin/app/components/solidus_admin/products/index/component.rb b/admin/app/components/solidus_admin/products/index/component.rb index 27b7446c7a0..029b1c2be02 100644 --- a/admin/app/components/solidus_admin/products/index/component.rb +++ b/admin/app/components/solidus_admin/products/index/component.rb @@ -33,18 +33,21 @@ def batch_actions action: solidus_admin.products_path, method: :delete, icon: 'delete-bin-7-line', + require_confirmation: true, }, { label: t('.batch_actions.discontinue'), action: solidus_admin.discontinue_products_path, method: :put, icon: 'pause-circle-line', + require_confirmation: true, }, { label: t('.batch_actions.activate'), action: solidus_admin.activate_products_path, method: :put, icon: 'play-circle-line', + require_confirmation: true, }, ] end diff --git a/admin/app/components/solidus_admin/ui/table/component.js b/admin/app/components/solidus_admin/ui/table/component.js index faba92015de..0e5472fa8bf 100644 --- a/admin/app/components/solidus_admin/ui/table/component.js +++ b/admin/app/components/solidus_admin/ui/table/component.js @@ -125,8 +125,23 @@ export default class extends Controller { } } + selectedRows() { + return this.checkboxTargets.filter((checkbox) => checkbox.checked) + } + + confirmAction(event) { + const message = event.params.message.replace( + "${count}", + this.selectedRows().length + ) + + if (!confirm(message)) { + event.preventDefault() + } + } + render() { - const selectedRows = this.checkboxTargets.filter((checkbox) => checkbox.checked) + const selectedRows = this.selectedRows() if (this.hasSearchFieldTarget) { this.searchToolbarTarget.toggleAttribute("hidden", this.modeValue !== "search") diff --git a/admin/app/components/solidus_admin/ui/table/component.rb b/admin/app/components/solidus_admin/ui/table/component.rb index a77cdc37a8a..091bde08e0c 100644 --- a/admin/app/components/solidus_admin/ui/table/component.rb +++ b/admin/app/components/solidus_admin/ui/table/component.rb @@ -5,7 +5,7 @@ class SolidusAdmin::UI::Table::Component < SolidusAdmin::BaseComponent Sortable = Struct.new(:url, :param, :animation, :handle, keyword_init: true) Scope = Struct.new(:label, :name, :default, keyword_init: true) Filter = Struct.new(:label, :combinator, :attribute, :predicate, :options, keyword_init: true) - BatchAction = Struct.new(:label, :icon, :action, :method, keyword_init: true) # rubocop:disable Lint/StructNewOverride + BatchAction = Struct.new(:label, :icon, :action, :require_confirmation, :method, keyword_init: true) # rubocop:disable Lint/StructNewOverride private_constant :BatchAction, :Column, :Filter, :Scope, :Sortable class Data < Struct.new(:rows, :class, :url, :prev, :next, :columns, :fade, :batch_actions, keyword_init: true) # rubocop:disable Lint/StructNewOverride,Style/StructInheritance @@ -97,7 +97,7 @@ def search_form_id end def render_batch_action_button(batch_action) - render component("ui/button").new( + params = { name: request_forgery_protection_token, value: form_authenticity_token(form_options: { action: batch_action.action, @@ -110,7 +110,18 @@ def render_batch_action_button(batch_action) icon: batch_action.icon, text: batch_action.label, scheme: :secondary, - ) + } + + if batch_action.require_confirmation + params["data-action"] = "click->#{stimulus_id}#confirmAction" + params["data-#{stimulus_id}-message-param"] = t( + ".action_confirmation", + action: batch_action.label.downcase, + resource: @data.plural_name.downcase + ) + end + + render component("ui/button").new(**params) end def render_ransack_filter_dropdown(filter, index) diff --git a/admin/app/components/solidus_admin/ui/table/component.yml b/admin/app/components/solidus_admin/ui/table/component.yml index 6014596942a..8f1c086e3db 100644 --- a/admin/app/components/solidus_admin/ui/table/component.yml +++ b/admin/app/components/solidus_admin/ui/table/component.yml @@ -5,6 +5,7 @@ en: select_row: 'Select row' filter: 'Filter' search_placeholder: 'Search all %{resources}' + action_confirmation: 'Are you sure you want to %{action} ${count} %{resource}?' refine_search: 'Refine Search' batch_actions: Batch actions cancel: Cancel diff --git a/admin/spec/features/products_spec.rb b/admin/spec/features/products_spec.rb index 860780f7427..0181dc9e130 100644 --- a/admin/spec/features/products_spec.rb +++ b/admin/spec/features/products_spec.rb @@ -29,7 +29,10 @@ visit "/admin/products" select_row("Just a product") - click_button "Delete" + + accept_confirm("Are you sure you want to delete 1 products?") do + click_button "Delete" + end expect(page).to have_content("Products were successfully removed.", wait: 5) expect(page).not_to have_content("Just a product") @@ -44,7 +47,10 @@ visit "/admin/products" find('main tbody tr:nth-child(2)').find('input').check - click_button "Discontinue" + + accept_confirm("Are you sure you want to discontinue 1 products?") do + click_button "Discontinue" + end expect(page).to have_content("Products were successfully discontinued.", wait: 5) within('main tbody tr:nth-child(2)') { @@ -59,7 +65,10 @@ } find('main tbody tr:nth-child(2)').find('input').check - click_button "Activate" + + accept_confirm("Are you sure you want to activate 1 products?") do + click_button "Activate" + end expect(page).to have_content("Products were successfully activated.", wait: 5) within('tbody') do From 2e70faf61aeff21fcf702ec6a18c5e9d64489284 Mon Sep 17 00:00:00 2001 From: Chris Todorov Date: Mon, 1 Apr 2024 21:15:13 -0700 Subject: [PATCH 2/2] Improve resource name pluralization in confirm dialog This change adds proper pluralization in the confirm dialog for the resource being modified. Previously the dialog always used the plural version of the resource. --- .../components/solidus_admin/ui/table/component.js | 14 ++++++++++---- .../components/solidus_admin/ui/table/component.rb | 9 +++++++-- .../solidus_admin/ui/table/component.yml | 2 +- admin/spec/features/products_spec.rb | 6 +++--- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/admin/app/components/solidus_admin/ui/table/component.js b/admin/app/components/solidus_admin/ui/table/component.js index 0e5472fa8bf..66837d4ce75 100644 --- a/admin/app/components/solidus_admin/ui/table/component.js +++ b/admin/app/components/solidus_admin/ui/table/component.js @@ -130,10 +130,16 @@ export default class extends Controller { } confirmAction(event) { - const message = event.params.message.replace( - "${count}", - this.selectedRows().length - ) + const message = event.params.message + .replace( + "${count}", + this.selectedRows().length + ).replace( + "${resource}", + this.selectedRows().length > 1 ? + event.params.resourcePlural : + event.params.resourceSingular + ) if (!confirm(message)) { event.preventDefault() diff --git a/admin/app/components/solidus_admin/ui/table/component.rb b/admin/app/components/solidus_admin/ui/table/component.rb index 091bde08e0c..c398b521d74 100644 --- a/admin/app/components/solidus_admin/ui/table/component.rb +++ b/admin/app/components/solidus_admin/ui/table/component.rb @@ -18,6 +18,10 @@ def initialize(**args) self.batch_actions = batch_actions.to_a.map { |action| BatchAction.new(**action) } end + def singular_name + self[:class].model_name.human if self[:class] + end + def plural_name self[:class].model_name.human.pluralize if self[:class] end @@ -116,9 +120,10 @@ def render_batch_action_button(batch_action) params["data-action"] = "click->#{stimulus_id}#confirmAction" params["data-#{stimulus_id}-message-param"] = t( ".action_confirmation", - action: batch_action.label.downcase, - resource: @data.plural_name.downcase + action: batch_action.label.downcase ) + params["data-#{stimulus_id}-resource-singular-param"] = @data.singular_name.downcase + params["data-#{stimulus_id}-resource-plural-param"] = @data.plural_name.downcase end render component("ui/button").new(**params) diff --git a/admin/app/components/solidus_admin/ui/table/component.yml b/admin/app/components/solidus_admin/ui/table/component.yml index 8f1c086e3db..0b43b9cf759 100644 --- a/admin/app/components/solidus_admin/ui/table/component.yml +++ b/admin/app/components/solidus_admin/ui/table/component.yml @@ -5,7 +5,7 @@ en: select_row: 'Select row' filter: 'Filter' search_placeholder: 'Search all %{resources}' - action_confirmation: 'Are you sure you want to %{action} ${count} %{resource}?' + action_confirmation: 'Are you sure you want to %{action} ${count} ${resource}?' refine_search: 'Refine Search' batch_actions: Batch actions cancel: Cancel diff --git a/admin/spec/features/products_spec.rb b/admin/spec/features/products_spec.rb index 0181dc9e130..9014543741d 100644 --- a/admin/spec/features/products_spec.rb +++ b/admin/spec/features/products_spec.rb @@ -30,7 +30,7 @@ visit "/admin/products" select_row("Just a product") - accept_confirm("Are you sure you want to delete 1 products?") do + accept_confirm("Are you sure you want to delete 1 product?") do click_button "Delete" end @@ -48,7 +48,7 @@ visit "/admin/products" find('main tbody tr:nth-child(2)').find('input').check - accept_confirm("Are you sure you want to discontinue 1 products?") do + accept_confirm("Are you sure you want to discontinue 1 product?") do click_button "Discontinue" end @@ -66,7 +66,7 @@ find('main tbody tr:nth-child(2)').find('input').check - accept_confirm("Are you sure you want to activate 1 products?") do + accept_confirm("Are you sure you want to activate 1 product?") do click_button "Activate" end