From 56f2417fd7aa34409988fb57fb17e7a6f6b5eb16 Mon Sep 17 00:00:00 2001 From: Daniele Palombo Date: Mon, 7 Sep 2020 10:04:21 +0200 Subject: [PATCH 01/10] Add Modal logic This commit is going to add a standard way to load the modals in solidus. They can be load and store as global object Spree.Views.Modals. --- backend/app/assets/javascripts/spree/backend.js | 1 + .../spree/backend/components/modals.js | 12 ++++++++++++ .../javascripts/spree/backend/namespaces.js | 3 ++- .../javascripts/spree/backend/views/index.js | 1 + .../javascripts/spree/backend/views/modals.js | 15 +++++++++++++++ 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 backend/app/assets/javascripts/spree/backend/components/modals.js create mode 100644 backend/app/assets/javascripts/spree/backend/views/modals.js diff --git a/backend/app/assets/javascripts/spree/backend.js b/backend/app/assets/javascripts/spree/backend.js index 2b3a52922b0..f3e3a792958 100644 --- a/backend/app/assets/javascripts/spree/backend.js +++ b/backend/app/assets/javascripts/spree/backend.js @@ -25,6 +25,7 @@ //= require spree/backend/admin //= require spree/backend/calculator //= require spree/backend/checkouts/edit +//= require spree/backend/components/modals //= require spree/backend/components/number_with_currency //= require spree/backend/components/tabs //= require spree/backend/components/tooltips diff --git a/backend/app/assets/javascripts/spree/backend/components/modals.js b/backend/app/assets/javascripts/spree/backend/components/modals.js new file mode 100644 index 00000000000..14cdbf508c9 --- /dev/null +++ b/backend/app/assets/javascripts/spree/backend/components/modals.js @@ -0,0 +1,12 @@ +/** + * Use this file to retrieve and store the modal that should be global to the + * site + * + * e.g. + * Spree.ready(function() { + * $('#batch-preview').each(function() { + * Spree.Views.Modals.batchPreview($(this)) + * }); + * }); + * + */ diff --git a/backend/app/assets/javascripts/spree/backend/namespaces.js b/backend/app/assets/javascripts/spree/backend/namespaces.js index 61f449e4998..b33fb03d7fe 100644 --- a/backend/app/assets/javascripts/spree/backend/namespaces.js +++ b/backend/app/assets/javascripts/spree/backend/namespaces.js @@ -10,6 +10,7 @@ _.extend(window.Spree, { Payment: {}, Promotions: {}, Stock: {}, - Tables: {} + Tables: {}, + Modals: {} } }) diff --git a/backend/app/assets/javascripts/spree/backend/views/index.js b/backend/app/assets/javascripts/spree/backend/views/index.js index 670ce59032b..b8d56599006 100644 --- a/backend/app/assets/javascripts/spree/backend/views/index.js +++ b/backend/app/assets/javascripts/spree/backend/views/index.js @@ -28,3 +28,4 @@ //= require 'spree/backend/views/tables/selectable_table' //= require 'spree/backend/views/tables/selectable_table/summary' //= require 'spree/backend/views/tables/selectable_table/sum_return_item_amount' +//= require 'spree/backend/views/modals' diff --git a/backend/app/assets/javascripts/spree/backend/views/modals.js b/backend/app/assets/javascripts/spree/backend/views/modals.js new file mode 100644 index 00000000000..ae3c933a5f9 --- /dev/null +++ b/backend/app/assets/javascripts/spree/backend/views/modals.js @@ -0,0 +1,15 @@ +/** + * Use this file to store the global modal + * + * e.g. + * Spree.Views.Modals = { + * myModal: function($el = null) { + * if($el != null) { + * this.myGlobalModal = new Spree.Views.Modals.MyModal({el: $el}) + * } + * + * return this.myGlobalModal; + * }, + * } + * + */ From 312e7df4f3e1d53ac04bc9bc98c88b1ef59e26ba Mon Sep 17 00:00:00 2001 From: Daniele Palombo Date: Mon, 7 Sep 2020 13:58:50 +0200 Subject: [PATCH 02/10] Add Spree::BatchAction::Base Object This is the base object to create the batch actions. Any batch action object should inherit from it and overriding the `call` method. --- core/app/models/spree/batch_action/base.rb | 11 +++++++++++ core/spec/models/spree/batch_action/base_spec.rb | 11 +++++++++++ 2 files changed, 22 insertions(+) create mode 100644 core/app/models/spree/batch_action/base.rb create mode 100644 core/spec/models/spree/batch_action/base_spec.rb diff --git a/core/app/models/spree/batch_action/base.rb b/core/app/models/spree/batch_action/base.rb new file mode 100644 index 00000000000..48cd8761eba --- /dev/null +++ b/core/app/models/spree/batch_action/base.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Spree + module BatchAction + class Base + def call(*_args) + raise NotImplementedError, "Please implement '#call' in your action: #{self.class.name}" + end + end + end +end diff --git a/core/spec/models/spree/batch_action/base_spec.rb b/core/spec/models/spree/batch_action/base_spec.rb new file mode 100644 index 00000000000..c51ea7a2623 --- /dev/null +++ b/core/spec/models/spree/batch_action/base_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Spree::BatchAction::Base, type: :model do + subject(:call) { Spree::BatchAction::Base.new.call } + + it 'raises an error when call is not overridden' do + expect { call }.to raise_error(NotImplementedError) + end +end From 5181505a19b1824c3ed68a0efccaa64f84cd07e9 Mon Sep 17 00:00:00 2001 From: Daniele Palombo Date: Mon, 7 Sep 2020 17:21:23 +0200 Subject: [PATCH 03/10] Add Spree::Backend::Batch Include this concern into controller to manage a batch action list. e.g. ``` include Spree::Backend::Batch set_batch_actions [ { action: 'Spree::BatchAction::DestroyRecordAction', icon: :trash, label: :delete } ] ``` In this way the controller will be able to run the specified batch actions --- .../components/selectable_table/summary.js | 7 ++- .../spree/backend/templates/index.js | 1 + .../backend/templates/tables/actions.hbs | 5 ++ .../templates/tables/selectable_label.hbs | 6 ++- .../javascripts/spree/backend/views/index.js | 1 + .../views/tables/selectable_table/actions.js | 20 +++++++ .../views/tables/selectable_table/summary.js | 19 +++++++ .../backend/components/selectable_table.scss | 4 ++ .../spree/backend/spree_admin.scss | 1 + .../helpers/spree/admin/actionable_helper.rb | 24 +++++++++ backend/lib/spree/backend.rb | 1 + backend/lib/spree/backend/batch.rb | 42 +++++++++++++++ backend/spec/lib/spree/backend/batch_spec.rb | 53 +++++++++++++++++++ 13 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 backend/app/assets/javascripts/spree/backend/templates/tables/actions.hbs create mode 100644 backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/actions.js create mode 100644 backend/app/assets/stylesheets/spree/backend/components/selectable_table.scss create mode 100644 backend/app/helpers/spree/admin/actionable_helper.rb create mode 100644 backend/lib/spree/backend/batch.rb create mode 100644 backend/spec/lib/spree/backend/batch_spec.rb diff --git a/backend/app/assets/javascripts/spree/backend/components/selectable_table/summary.js b/backend/app/assets/javascripts/spree/backend/components/selectable_table/summary.js index 3f85777a5d5..daab8cf8527 100644 --- a/backend/app/assets/javascripts/spree/backend/components/selectable_table/summary.js +++ b/backend/app/assets/javascripts/spree/backend/components/selectable_table/summary.js @@ -1,7 +1,12 @@ Backbone.on('selectableTable:init', function(selectableTable){ if(selectableTable.$el.find('.selectable').length > 0) { var tr = document.createElement('tr') - new Spree.Views.Tables.SelectableTable.Summary({el: tr, model: selectableTable.model , columns: selectableTable.maxColumns()}); + new Spree.Views.Tables.SelectableTable.Summary({ + el: tr, + model: selectableTable.model, + columns: selectableTable.maxColumns(), + selectableTable: selectableTable + }); selectableTable.$el.find('thead').prepend(tr); } }) diff --git a/backend/app/assets/javascripts/spree/backend/templates/index.js b/backend/app/assets/javascripts/spree/backend/templates/index.js index 39d4a178d98..08e018e53aa 100644 --- a/backend/app/assets/javascripts/spree/backend/templates/index.js +++ b/backend/app/assets/javascripts/spree/backend/templates/index.js @@ -1,6 +1,7 @@ //= require spree/backend/templates/_image //= require spree/backend/templates/tables/selectable_label //= require spree/backend/templates/tables/return_item_sum_amount +//= require spree/backend/templates/tables/actions //= require spree/backend/templates/orders/customer_details/autocomplete //= require spree/backend/templates/orders/details_adjustment_row //= require spree/backend/templates/orders/line_item diff --git a/backend/app/assets/javascripts/spree/backend/templates/tables/actions.hbs b/backend/app/assets/javascripts/spree/backend/templates/tables/actions.hbs new file mode 100644 index 00000000000..86610eba337 --- /dev/null +++ b/backend/app/assets/javascripts/spree/backend/templates/tables/actions.hbs @@ -0,0 +1,5 @@ +{{#if itemSelected}} + {{#each actions}} + {{{this}}} + {{/each}} +{{/if}} diff --git a/backend/app/assets/javascripts/spree/backend/templates/tables/selectable_label.hbs b/backend/app/assets/javascripts/spree/backend/templates/tables/selectable_label.hbs index 83d5290f7d9..63d1e0b9fa1 100644 --- a/backend/app/assets/javascripts/spree/backend/templates/tables/selectable_label.hbs +++ b/backend/app/assets/javascripts/spree/backend/templates/tables/selectable_label.hbs @@ -1,6 +1,10 @@ - + {{item_selected_label}} +{{#if actionable}} + + +{{/if}} diff --git a/backend/app/assets/javascripts/spree/backend/views/index.js b/backend/app/assets/javascripts/spree/backend/views/index.js index b8d56599006..f476fbf797c 100644 --- a/backend/app/assets/javascripts/spree/backend/views/index.js +++ b/backend/app/assets/javascripts/spree/backend/views/index.js @@ -28,4 +28,5 @@ //= require 'spree/backend/views/tables/selectable_table' //= require 'spree/backend/views/tables/selectable_table/summary' //= require 'spree/backend/views/tables/selectable_table/sum_return_item_amount' +//= require 'spree/backend/views/tables/selectable_table/actions' //= require 'spree/backend/views/modals' diff --git a/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/actions.js b/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/actions.js new file mode 100644 index 00000000000..11f5d108fba --- /dev/null +++ b/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/actions.js @@ -0,0 +1,20 @@ +Spree.Views.Tables.SelectableTable.Actions = Backbone.View.extend({ + initialize: function(options) { + this.listenTo(this.model, 'change', this.render); + + this.selectableTable = options.selectableTable; + this.actions = this.selectableTable.$el.data('actions'); + this.searchForm = $(this.selectableTable.$el.data('searchFormSelector')).clone(); + + this.render(); + }, + + render: function() { + var html = HandlebarsTemplates['tables/actions']({ + itemSelected: this.model.get('selectedItems').length > 0 || this.model.get('allSelected'), + actions: this.actions + }); + + this.$el.html(html); + }, +}); diff --git a/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/summary.js b/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/summary.js index ec0d075ead0..4df2de12bc5 100644 --- a/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/summary.js +++ b/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/summary.js @@ -14,6 +14,15 @@ Spree.Views.Tables.SelectableTable.Summary = Backbone.View.extend({ this.listenTo(this.model, 'change', this.render) this.colspan = options.columns - 1; + this.actionableColspan = 0 + + this.selectableTable = options.selectableTable; + this.actionable = this.selectableTable.$el.hasClass('actionable') + + if(this.actionable) { + this.colspan = options.columns - 3 + this.actionableColspan = 3 + } this.render(); }, @@ -23,12 +32,22 @@ Spree.Views.Tables.SelectableTable.Summary = Backbone.View.extend({ var all_items_selected = this.model.get('allSelected'); var html = HandlebarsTemplates['tables/selectable_label']({ + actionable: this.actionable, + actionableColspan: this.actionableColspan, colspan: this.colspan, item_selected_label: this.selectedItemLabel(all_items_selected, selectedItemLength), all_items_selected: all_items_selected }); this.$el.html(html); + + if(this.actionable) { + new Spree.Views.Tables.SelectableTable.Actions({ + el: this.$el.find('th.actions'), + model: this.model, + selectableTable: this.selectableTable, + }); + } }, selectedItemLabel: function(all_selected, selected_item_length) { diff --git a/backend/app/assets/stylesheets/spree/backend/components/selectable_table.scss b/backend/app/assets/stylesheets/spree/backend/components/selectable_table.scss new file mode 100644 index 00000000000..00ce5fc219a --- /dev/null +++ b/backend/app/assets/stylesheets/spree/backend/components/selectable_table.scss @@ -0,0 +1,4 @@ +.selectable-table .action-buttons { + margin-right: 0px; + float: right; +} diff --git a/backend/app/assets/stylesheets/spree/backend/spree_admin.scss b/backend/app/assets/stylesheets/spree/backend/spree_admin.scss index 0711d85a822..b0a36a81286 100644 --- a/backend/app/assets/stylesheets/spree/backend/spree_admin.scss +++ b/backend/app/assets/stylesheets/spree/backend/spree_admin.scss @@ -33,6 +33,7 @@ @import 'spree/backend/components/navigation'; @import 'spree/backend/components/sidebar'; @import 'spree/backend/components/editable_table'; +@import 'spree/backend/components/selectable_table'; @import 'spree/backend/components/pills'; @import 'spree/backend/components/tabs'; diff --git a/backend/app/helpers/spree/admin/actionable_helper.rb b/backend/app/helpers/spree/admin/actionable_helper.rb new file mode 100644 index 00000000000..7fc4db7e993 --- /dev/null +++ b/backend/app/helpers/spree/admin/actionable_helper.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Spree + module Admin + module ActionableHelper + extend ActiveSupport::Concern + + def batch_action_buttons(batch_actions) + batch_actions.map do |batch_action| + link_to_batch_action(batch_action) + end + end + + def link_to_batch_action(icon:, label:, action:) + options = {} + options[:class] = "fa fa-#{icon} icon_link with-tip batch-action no-text" + options[:title] = label + options[:data] = { action: action } + options.delete(:no_text) + link_to('', '#', options) + end + end + end +end diff --git a/backend/lib/spree/backend.rb b/backend/lib/spree/backend.rb index 6c63a1e36be..db9c818d22a 100644 --- a/backend/lib/spree/backend.rb +++ b/backend/lib/spree/backend.rb @@ -15,4 +15,5 @@ require 'spree/backend/action_callbacks' require 'spree/backend/callbacks' +require 'spree/backend/batch' require 'spree/backend/engine' diff --git a/backend/lib/spree/backend/batch.rb b/backend/lib/spree/backend/batch.rb new file mode 100644 index 00000000000..566fa58c68d --- /dev/null +++ b/backend/lib/spree/backend/batch.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module Spree + module Backend + module Batch + extend ActiveSupport::Concern + + included do + helper_method :batch_actions + helper 'spree/admin/actionable' + end + + module ClassMethods + attr_writer :batch_actions + + def batch_actions + @batch_actions || [] + end + + protected + + def set_batch_actions(args) + @batch_actions = args + end + + def add_batch_action(batch_action) + @batch_actions = batch_actions << batch_action + end + + def add_batch_actions(other_batch_actions) + @batch_actions = batch_actions + other_batch_actions + end + end + + protected + + def batch_actions + self.class.batch_actions + end + end + end +end diff --git a/backend/spec/lib/spree/backend/batch_spec.rb b/backend/spec/lib/spree/backend/batch_spec.rb new file mode 100644 index 00000000000..b4826bcd652 --- /dev/null +++ b/backend/spec/lib/spree/backend/batch_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Spree::Backend::Batch do + let(:described_module) { Spree::Backend::Batch } + let(:controller_class) do + class FakesController < ApplicationController + include Spree::Backend::Batch + set_batch_actions [] + end + end + + before do + controller_class + end + + describe '.set_batch_actions' do + before do + FakesController.class_eval do + set_batch_actions [{ action: 'Spree::Action' }] + end + end + + it 'has set batch actions' do + expect(FakesController.batch_actions).to eq [{ action: 'Spree::Action' }] + end + end + + describe '.add_batch_actions' do + before do + FakesController.class_eval do + add_batch_actions [{ action: 'Spree::Action' }] + end + end + + it 'has set batch actions' do + expect(FakesController.batch_actions).to eq [{ action: 'Spree::Action' }] + end + end + + describe '.add_batch_action' do + before do + FakesController.class_eval do + add_batch_action({ action: 'Spree::Action' }) + end + end + + it 'has set batch actions' do + expect(FakesController.batch_actions).to eq [{ action: 'Spree::Action' }] + end + end +end From 672f7d89987040ca19525cbe2d1152f944b26b1e Mon Sep 17 00:00:00 2001 From: Daniele Palombo Date: Mon, 7 Sep 2020 17:46:04 +0200 Subject: [PATCH 04/10] Add modal Preview This modal will show when a batch action is clicked. When the modal is shown it will be possible to show to the user an action preview, in this way we can ask to the user other configuration or just show what the action will do --- .../spree/backend/components/modals.js | 5 +++++ .../javascripts/spree/backend/views/index.js | 2 ++ .../javascripts/spree/backend/views/modals.js | 10 ++++++++++ .../spree/backend/views/modals/batch.js | 1 + .../backend/views/modals/batch/preview.js | 7 +++++++ .../views/tables/selectable_table/actions.js | 7 +++++++ .../admin/batch_actions/_preview.html.erb | 19 +++++++++++++++++++ .../views/spree/admin/shared/_head.html.erb | 9 +++++++++ 8 files changed, 60 insertions(+) create mode 100644 backend/app/assets/javascripts/spree/backend/views/modals/batch.js create mode 100644 backend/app/assets/javascripts/spree/backend/views/modals/batch/preview.js create mode 100644 backend/app/views/spree/admin/batch_actions/_preview.html.erb diff --git a/backend/app/assets/javascripts/spree/backend/components/modals.js b/backend/app/assets/javascripts/spree/backend/components/modals.js index 14cdbf508c9..70ac67c5aeb 100644 --- a/backend/app/assets/javascripts/spree/backend/components/modals.js +++ b/backend/app/assets/javascripts/spree/backend/components/modals.js @@ -10,3 +10,8 @@ * }); * */ +Spree.ready(function() { + $('#batch-preview').each(function() { + Spree.Views.Modals.batchPreview($(this)) + }) +}); diff --git a/backend/app/assets/javascripts/spree/backend/views/index.js b/backend/app/assets/javascripts/spree/backend/views/index.js index f476fbf797c..30fd0cf8e2a 100644 --- a/backend/app/assets/javascripts/spree/backend/views/index.js +++ b/backend/app/assets/javascripts/spree/backend/views/index.js @@ -30,3 +30,5 @@ //= require 'spree/backend/views/tables/selectable_table/sum_return_item_amount' //= require 'spree/backend/views/tables/selectable_table/actions' //= require 'spree/backend/views/modals' +//= require 'spree/backend/views/modals/batch' +//= require 'spree/backend/views/modals/batch/preview' diff --git a/backend/app/assets/javascripts/spree/backend/views/modals.js b/backend/app/assets/javascripts/spree/backend/views/modals.js index ae3c933a5f9..d731067a878 100644 --- a/backend/app/assets/javascripts/spree/backend/views/modals.js +++ b/backend/app/assets/javascripts/spree/backend/views/modals.js @@ -13,3 +13,13 @@ * } * */ +Spree.Views.Modals = { + batchPreview: function($el = null) { + if($el != null) { + this.modalBatchPreview = new Spree.Views.Modals.Batch.Preview({el: $el}) + } + + return this.modalBatchPreview; + }, + +}; diff --git a/backend/app/assets/javascripts/spree/backend/views/modals/batch.js b/backend/app/assets/javascripts/spree/backend/views/modals/batch.js new file mode 100644 index 00000000000..85508e3e81e --- /dev/null +++ b/backend/app/assets/javascripts/spree/backend/views/modals/batch.js @@ -0,0 +1 @@ +Spree.Views.Modals.Batch = {} diff --git a/backend/app/assets/javascripts/spree/backend/views/modals/batch/preview.js b/backend/app/assets/javascripts/spree/backend/views/modals/batch/preview.js new file mode 100644 index 00000000000..1a1d4408019 --- /dev/null +++ b/backend/app/assets/javascripts/spree/backend/views/modals/batch/preview.js @@ -0,0 +1,7 @@ +Spree.Views.Modals.Batch.Preview = Backbone.View.extend({ + show: function(options) { + this.searchForm = options.searchForm; + this.action = options.action; + this.$el.modal('show'); + }, +}) diff --git a/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/actions.js b/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/actions.js index 11f5d108fba..ab18a1affb5 100644 --- a/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/actions.js +++ b/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/actions.js @@ -1,4 +1,8 @@ Spree.Views.Tables.SelectableTable.Actions = Backbone.View.extend({ + events: { + 'click a.batch-action': 'previewBatchAction' + }, + initialize: function(options) { this.listenTo(this.model, 'change', this.render); @@ -17,4 +21,7 @@ Spree.Views.Tables.SelectableTable.Actions = Backbone.View.extend({ this.$el.html(html); }, + + previewBatchAction: function(e) { + } }); diff --git a/backend/app/views/spree/admin/batch_actions/_preview.html.erb b/backend/app/views/spree/admin/batch_actions/_preview.html.erb new file mode 100644 index 00000000000..0a8c77e5bd8 --- /dev/null +++ b/backend/app/views/spree/admin/batch_actions/_preview.html.erb @@ -0,0 +1,19 @@ + diff --git a/backend/app/views/spree/admin/shared/_head.html.erb b/backend/app/views/spree/admin/shared/_head.html.erb index be396021d45..5be88b14470 100644 --- a/backend/app/views/spree/admin/shared/_head.html.erb +++ b/backend/app/views/spree/admin/shared/_head.html.erb @@ -46,3 +46,12 @@ <% end %> <%= yield :head %> + +<%= +render( + 'spree/admin/batch_actions/preview', + target: 'batch-preview', + title: 'Preview batch command', + content: '' + ) +%> \ No newline at end of file From 4a08ee3f14fd0bf7b6a9e6cf7625d8c7887bbb78 Mon Sep 17 00:00:00 2001 From: Daniele Palombo Date: Fri, 22 Jan 2021 12:09:52 +0100 Subject: [PATCH 05/10] Open Preview Modal This commit adds to the Spree::Backend::Batch concern the `preview_batch` action. It will render the related partial under `spree/admin/batch_actions/*BATCH_ACTION_NAME*/preview` template. In this way, any BatchAction would have been its template and ask to the user other fields required to process the collection. --- .../views/tables/selectable_table/actions.js | 38 +++++++++++++++++++ backend/config/routes.rb | 6 +++ backend/lib/spree/backend/batch.rb | 22 +++++++++++ 3 files changed, 66 insertions(+) diff --git a/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/actions.js b/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/actions.js index ab18a1affb5..ce7dd46e979 100644 --- a/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/actions.js +++ b/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/actions.js @@ -9,6 +9,7 @@ Spree.Views.Tables.SelectableTable.Actions = Backbone.View.extend({ this.selectableTable = options.selectableTable; this.actions = this.selectableTable.$el.data('actions'); this.searchForm = $(this.selectableTable.$el.data('searchFormSelector')).clone(); + this.previewBatchUrl = this.selectableTable.$el.data('previewBatchUrl'); this.render(); }, @@ -23,5 +24,42 @@ Spree.Views.Tables.SelectableTable.Actions = Backbone.View.extend({ }, previewBatchAction: function(e) { + var self = this; + + var action = $(e.currentTarget).data('action'); + var inputAction = document.createElement('input'); + inputAction.name = 'batch_action_type'; + inputAction.value = action; + + if(this.selectableTable.$el.find('.selectAll:checked').length == 0) { + this.selectableTable.$el.find('.selectable:checked').each(function(_i, item){ + self.searchForm.append($(item).clone()); + }) + } + + this.searchForm.append(inputAction); + + options = { + searchForm: this.searchForm, + action: action + } + + Spree.ajax({ + type: 'POST', + url: this.previewBatchUrl, + data: this.searchForm.serialize(), + success: function() { + Spree.Views.Modals.batchPreview().show(options); + }, + error: function(msg) { + if (msg.responseJSON["error"]) { + show_flash('error', msg.responseJSON["error"]); + } else { + show_flash('error', "There was a problem adding this coupon code."); + } + } + }); + + this.searchForm = $(this.selectableTable.$el.data('searchFormSelector')).clone(); } }); diff --git a/backend/config/routes.rb b/backend/config/routes.rb index d5e7952eadc..cc2bf02ed1c 100644 --- a/backend/config/routes.rb +++ b/backend/config/routes.rb @@ -2,6 +2,12 @@ Spree::Core::Engine.routes.draw do namespace :admin do + concern :actionable_routes do + collection do + post :preview_batch + end + end + get '/search/users', to: "search#users", as: :search_users get '/search/products', to: "search#products", as: :search_products diff --git a/backend/lib/spree/backend/batch.rb b/backend/lib/spree/backend/batch.rb index 566fa58c68d..12c2d60e63e 100644 --- a/backend/lib/spree/backend/batch.rb +++ b/backend/lib/spree/backend/batch.rb @@ -7,6 +7,7 @@ module Batch included do helper_method :batch_actions + before_action :batch_action_collection, only: [:preview_batch] helper 'spree/admin/actionable' end @@ -32,6 +33,27 @@ def add_batch_actions(other_batch_actions) end end + def collection_actions + super + [:preview_batch] + end + + def batch_action_collection + @batch_action_collection = @collection + end + + def preview_batch + session[:return_to] = request.url + + @batch_action_type = params[:batch_action_type] + @batch_action_name = @batch_action_type.constantize.new.class.name.demodulize.underscore + + respond_to do |format| + format.js do + render inline: "$('#batch-preview .modal-body').html('<%= escape_javascript( render(partial: \"spree/admin/batch_actions/#{@batch_action_name}/preview\") ) %>')" + end + end + end + protected def batch_actions From 162cfe2ea88fb34ad3eb2045e3565d5b3b06cbfd Mon Sep 17 00:00:00 2001 From: Daniele Palombo Date: Fri, 22 Jan 2021 15:14:19 +0100 Subject: [PATCH 06/10] Add Modal Batch Result This modal will render the batch action result. --- .../spree/backend/components/modals.js | 4 ++++ .../javascripts/spree/backend/views/index.js | 1 + .../backend/views/modals/batch/preview.js | 7 +++++++ .../spree/backend/views/modals/batch/result.js | 14 ++++++++++++++ .../admin/batch_actions/_process.html.erb | 18 ++++++++++++++++++ .../views/spree/admin/shared/_head.html.erb | 11 ++++++++++- 6 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 backend/app/assets/javascripts/spree/backend/views/modals/batch/result.js create mode 100644 backend/app/views/spree/admin/batch_actions/_process.html.erb diff --git a/backend/app/assets/javascripts/spree/backend/components/modals.js b/backend/app/assets/javascripts/spree/backend/components/modals.js index 70ac67c5aeb..0e6a819173f 100644 --- a/backend/app/assets/javascripts/spree/backend/components/modals.js +++ b/backend/app/assets/javascripts/spree/backend/components/modals.js @@ -14,4 +14,8 @@ Spree.ready(function() { $('#batch-preview').each(function() { Spree.Views.Modals.batchPreview($(this)) }) + + $('#batch-result').each(function() { + Spree.Views.Modals.batchResult($(this)) + }) }); diff --git a/backend/app/assets/javascripts/spree/backend/views/index.js b/backend/app/assets/javascripts/spree/backend/views/index.js index 30fd0cf8e2a..4e1f0440e39 100644 --- a/backend/app/assets/javascripts/spree/backend/views/index.js +++ b/backend/app/assets/javascripts/spree/backend/views/index.js @@ -32,3 +32,4 @@ //= require 'spree/backend/views/modals' //= require 'spree/backend/views/modals/batch' //= require 'spree/backend/views/modals/batch/preview' +//= require 'spree/backend/views/modals/batch/result' diff --git a/backend/app/assets/javascripts/spree/backend/views/modals/batch/preview.js b/backend/app/assets/javascripts/spree/backend/views/modals/batch/preview.js index 1a1d4408019..f9f7b030732 100644 --- a/backend/app/assets/javascripts/spree/backend/views/modals/batch/preview.js +++ b/backend/app/assets/javascripts/spree/backend/views/modals/batch/preview.js @@ -1,7 +1,14 @@ Spree.Views.Modals.Batch.Preview = Backbone.View.extend({ + events: { + 'click #btn-process': 'process' + }, + show: function(options) { this.searchForm = options.searchForm; this.action = options.action; this.$el.modal('show'); }, + + process: function() { + } }) diff --git a/backend/app/assets/javascripts/spree/backend/views/modals/batch/result.js b/backend/app/assets/javascripts/spree/backend/views/modals/batch/result.js new file mode 100644 index 00000000000..d6ec038a1e0 --- /dev/null +++ b/backend/app/assets/javascripts/spree/backend/views/modals/batch/result.js @@ -0,0 +1,14 @@ +Spree.Views.Modals.Batch.Result = Backbone.View.extend({ + events: { + 'click #btn-close': 'close' + }, + + show: function() { + this.$el.modal('show'); + }, + + close: function() { + this.$el.modal('hide'); + document.location.reload(); + } +}) diff --git a/backend/app/views/spree/admin/batch_actions/_process.html.erb b/backend/app/views/spree/admin/batch_actions/_process.html.erb new file mode 100644 index 00000000000..92406d8ff57 --- /dev/null +++ b/backend/app/views/spree/admin/batch_actions/_process.html.erb @@ -0,0 +1,18 @@ + diff --git a/backend/app/views/spree/admin/shared/_head.html.erb b/backend/app/views/spree/admin/shared/_head.html.erb index 5be88b14470..9e90e2dea5d 100644 --- a/backend/app/views/spree/admin/shared/_head.html.erb +++ b/backend/app/views/spree/admin/shared/_head.html.erb @@ -54,4 +54,13 @@ render( title: 'Preview batch command', content: '' ) -%> \ No newline at end of file +%> + +<%= +render( + 'spree/admin/batch_actions/process', + target: 'batch-result', + title: 'Process batch command', + content: '' + ) +%> From c7ff27f45513cde5df463e93e468f20f7ffdd1ca Mon Sep 17 00:00:00 2001 From: Daniele Palombo Date: Fri, 22 Jan 2021 18:00:23 +0100 Subject: [PATCH 07/10] Add controller action to process BatchAction process_batch action is used to execute the BatchAction and return the result as js. --- backend/config/routes.rb | 1 + backend/lib/spree/backend/batch.rb | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/backend/config/routes.rb b/backend/config/routes.rb index cc2bf02ed1c..713eaf19cd4 100644 --- a/backend/config/routes.rb +++ b/backend/config/routes.rb @@ -5,6 +5,7 @@ concern :actionable_routes do collection do post :preview_batch + post :process_batch end end diff --git a/backend/lib/spree/backend/batch.rb b/backend/lib/spree/backend/batch.rb index 12c2d60e63e..76a24a83b41 100644 --- a/backend/lib/spree/backend/batch.rb +++ b/backend/lib/spree/backend/batch.rb @@ -7,7 +7,7 @@ module Batch included do helper_method :batch_actions - before_action :batch_action_collection, only: [:preview_batch] + before_action :batch_action_collection, only: [:preview_batch, :process_batch] helper 'spree/admin/actionable' end @@ -34,7 +34,7 @@ def add_batch_actions(other_batch_actions) end def collection_actions - super + [:preview_batch] + super + [:preview_batch, :process_batch] end def batch_action_collection @@ -54,6 +54,20 @@ def preview_batch end end + def process_batch + session[:return_to] = request.url + + @batch_action = params[:batch_action_type].constantize.new + @batch_action_name = @batch_action.class.name.demodulize.underscore + @result = @batch_action.call(batch_action_collection) + + respond_to do |format| + format.js do + render inline: "$('#batch-result .modal-body').html('<%= escape_javascript( render(partial: \"spree/admin/batch_actions/#{@batch_action_name}/result\") ) %>')" + end + end + end + protected def batch_actions From 202dac6dbefe263df70aa0fa396679f8cacb12fa Mon Sep 17 00:00:00 2001 From: Daniele Palombo Date: Fri, 22 Jan 2021 18:01:28 +0100 Subject: [PATCH 08/10] Execute BatchAction Process Execute the batch action and return the result in a modal. --- .../javascripts/spree/backend/views/modals.js | 7 ++++++ .../backend/views/modals/batch/preview.js | 23 +++++++++++++++++++ .../views/tables/selectable_table/actions.js | 2 ++ 3 files changed, 32 insertions(+) diff --git a/backend/app/assets/javascripts/spree/backend/views/modals.js b/backend/app/assets/javascripts/spree/backend/views/modals.js index d731067a878..ddb1a5fe328 100644 --- a/backend/app/assets/javascripts/spree/backend/views/modals.js +++ b/backend/app/assets/javascripts/spree/backend/views/modals.js @@ -22,4 +22,11 @@ Spree.Views.Modals = { return this.modalBatchPreview; }, + batchResult: function($el = null) { + if($el != null) { + this.modalBatchResult = new Spree.Views.Modals.Batch.Result({el: $el}) + } + + return this.modalBatchResult; + } }; diff --git a/backend/app/assets/javascripts/spree/backend/views/modals/batch/preview.js b/backend/app/assets/javascripts/spree/backend/views/modals/batch/preview.js index f9f7b030732..4dc89fbd64a 100644 --- a/backend/app/assets/javascripts/spree/backend/views/modals/batch/preview.js +++ b/backend/app/assets/javascripts/spree/backend/views/modals/batch/preview.js @@ -4,11 +4,34 @@ Spree.Views.Modals.Batch.Preview = Backbone.View.extend({ }, show: function(options) { + this.processBatchUrl = options.processBatchUrl; this.searchForm = options.searchForm; this.action = options.action; this.$el.modal('show'); }, process: function() { + var inputAction = document.createElement('input'); + inputAction.name = 'batch_action_type'; + inputAction.value = this.action; + this.searchForm.append(inputAction); + + this.$el.modal('hide'); + + Spree.ajax({ + type: 'POST', + url: this.processBatchUrl, + data: this.searchForm.serialize(), + success: function() { + Spree.Views.Modals.batchResult().show() + }, + error: function(msg) { + if (msg.responseJSON["error"]) { + show_flash('error', msg.responseJSON["error"]); + } else { + show_flash('error', "There was a problem adding this coupon code."); + } + } + }); } }) diff --git a/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/actions.js b/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/actions.js index ce7dd46e979..8cf972837c0 100644 --- a/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/actions.js +++ b/backend/app/assets/javascripts/spree/backend/views/tables/selectable_table/actions.js @@ -10,6 +10,7 @@ Spree.Views.Tables.SelectableTable.Actions = Backbone.View.extend({ this.actions = this.selectableTable.$el.data('actions'); this.searchForm = $(this.selectableTable.$el.data('searchFormSelector')).clone(); this.previewBatchUrl = this.selectableTable.$el.data('previewBatchUrl'); + this.processBatchUrl = this.selectableTable.$el.data('processBatchUrl'); this.render(); }, @@ -40,6 +41,7 @@ Spree.Views.Tables.SelectableTable.Actions = Backbone.View.extend({ this.searchForm.append(inputAction); options = { + processBatchUrl: this.processBatchUrl, searchForm: this.searchForm, action: action } From 3b1a45f6b99d965169ca36c71636e3e27234a84f Mon Sep 17 00:00:00 2001 From: Daniele Palombo Date: Mon, 7 Sep 2020 14:46:03 +0200 Subject: [PATCH 09/10] Add DestroyRecordAction This is the first batch action. It will handle the delete of multiple records. The partials _preview.html.erb and _result.html.erb are required to support admin user during usage. --- .../destroy_record_action/_preview.html.erb | 1 + .../destroy_record_action/_result.html.erb | 1 + .../spree/batch_action/destroy_record_action.rb | 16 ++++++++++++++++ core/config/locales/en.yml | 5 +++++ 4 files changed, 23 insertions(+) create mode 100644 backend/app/views/spree/admin/batch_actions/destroy_record_action/_preview.html.erb create mode 100644 backend/app/views/spree/admin/batch_actions/destroy_record_action/_result.html.erb create mode 100644 core/app/models/spree/batch_action/destroy_record_action.rb diff --git a/backend/app/views/spree/admin/batch_actions/destroy_record_action/_preview.html.erb b/backend/app/views/spree/admin/batch_actions/destroy_record_action/_preview.html.erb new file mode 100644 index 00000000000..e0c92827fdc --- /dev/null +++ b/backend/app/views/spree/admin/batch_actions/destroy_record_action/_preview.html.erb @@ -0,0 +1 @@ +<%= t('spree.batch_actions.destroy_record_action.confirm', total_count: @batch_action_collection.total_count) %> diff --git a/backend/app/views/spree/admin/batch_actions/destroy_record_action/_result.html.erb b/backend/app/views/spree/admin/batch_actions/destroy_record_action/_result.html.erb new file mode 100644 index 00000000000..62294c4150b --- /dev/null +++ b/backend/app/views/spree/admin/batch_actions/destroy_record_action/_result.html.erb @@ -0,0 +1 @@ +<%= t('spree.batch_actions.destroy_record_action.result', total_count: @batch_action_collection.total_count) %> diff --git a/core/app/models/spree/batch_action/destroy_record_action.rb b/core/app/models/spree/batch_action/destroy_record_action.rb new file mode 100644 index 00000000000..0890e224a75 --- /dev/null +++ b/core/app/models/spree/batch_action/destroy_record_action.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Spree + module BatchAction + class DestroyRecordAction < Base + def call(collection) + collection.map do |record| + next if record.try(:discard) + next if record.try(:destroy) + + record.id + end + end + end + end +end diff --git a/core/config/locales/en.yml b/core/config/locales/en.yml index 3df2dd198a3..da967dec50d 100644 --- a/core/config/locales/en.yml +++ b/core/config/locales/en.yml @@ -1084,6 +1084,10 @@ en: balance_due: Balance Due base_amount: Base Amount base_percent: Base Percent + batch_actions: + destroy_record_action: + confirm: You are going to destroy %{total_count} items. Are you sure? + result: "%{total_count} items have been deleted." bill_address: Bill Address billing: Billing billing_address: Billing Address @@ -1823,6 +1827,7 @@ en: price_sack: Price Sack process: Process product: Product + product_batch: Product Batch product_details: Product Details product_has_no_description: This product has no description product_not_available_in_this_currency: This product is not available in the selected From df0d78604be94d0ef38f225e3fca6e27013151ca Mon Sep 17 00:00:00 2001 From: Daniele Palombo Date: Fri, 22 Jan 2021 18:02:16 +0100 Subject: [PATCH 10/10] Add DestroyAction to ProductController --- .../spree/admin/products_controller.rb | 5 ++++ .../views/spree/admin/products/index.html.erb | 28 ++++++++++++++----- backend/config/routes.rb | 2 +- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/backend/app/controllers/spree/admin/products_controller.rb b/backend/app/controllers/spree/admin/products_controller.rb index f01e00fd1e5..27f48f12009 100644 --- a/backend/app/controllers/spree/admin/products_controller.rb +++ b/backend/app/controllers/spree/admin/products_controller.rb @@ -5,6 +5,11 @@ module Admin class ProductsController < ResourceController helper 'spree/products' + include Spree::Backend::Batch + set_batch_actions [ + { action: 'Spree::BatchAction::DestroyRecordAction', icon: :trash, label: :delete } + ] + before_action :load_data, except: [:index] update.before :update_before helper_method :clone_object_url diff --git a/backend/app/views/spree/admin/products/index.html.erb b/backend/app/views/spree/admin/products/index.html.erb index 3cab1ef3d33..e8379e1ed72 100644 --- a/backend/app/views/spree/admin/products/index.html.erb +++ b/backend/app/views/spree/admin/products/index.html.erb @@ -53,16 +53,29 @@ <%= paginate @collection, theme: "solidus_admin" %> <% if @collection.any? %> - + <%= + content_tag( + :table, + class: "index selectable-table actionable", + id: 'listing_products', + data: { + actions: batch_action_buttons(batch_actions), + search_form_selector: 'form.spree\\/product_search', + preview_batch_url: preview_batch_admin_products_path, + process_batch_url: process_batch_admin_products_path + } + ) do %> - - - - - + + + + + + + @@ -73,6 +86,7 @@ <% @collection.each do |product| %> id="<%= spree_dom_id product %>" data-hook="admin_products_index_rows"> + <% end %> -
<%= Spree::Variant.human_attribute_name(:sku) %> <%= sort_link @search,:name, Spree::Product.human_attribute_name(:name), { default_order: "desc" }, {title: 'admin_products_listing_name_title'} %>
<%= check_box_tag 'q[id_in][]', product.id, false, class: 'selectable' %> <%= product.sku %> <%= render 'spree/admin/shared/image', image: product.gallery.images.first, size: :mini %> @@ -89,7 +103,7 @@
+ <% end %> <% else %>
<%= render 'spree/admin/shared/no_objects_found', diff --git a/backend/config/routes.rb b/backend/config/routes.rb index 713eaf19cd4..48051242c4e 100644 --- a/backend/config/routes.rb +++ b/backend/config/routes.rb @@ -35,7 +35,7 @@ resources :tax_categories - resources :products do + resources :products, concerns: :actionable_routes do resources :product_properties do collection do post :update_positions