active_admin_scoped_collection_actions 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a65b49d4828e78148e804d19a9b15bfaa9071027
4
+ data.tar.gz: ec99d5cd551fc53b4908a3fecdc0fcedce8446e0
5
+ SHA512:
6
+ metadata.gz: 83339dcb013111f69603215ee092e1e326b688ba6ecdc7daa1710719548a651777c70c7b4edc97ac037698b4e9bcfa17e1eb954322b0dc38682f4f6d1b02abf7
7
+ data.tar.gz: c06b050bc9577e7d6bb1e1831968926c246e73f64748d24b743531aa77fb118b22e4a706e8beeeea1e1c72f52c1c5e3187846d3628627e04b65351307478e4f6
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.idea
11
+ .DS_Store
12
+ /spec/rails
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ script: bundle exec rspec spec
2
+ rvm:
3
+ - 2.1.10
4
+ - 2.2.6
5
+ - 2.3.3
6
+ before_install:
7
+ - gem install bundler -v '= 1.9.3'
8
+ - gem update --system
9
+ - gem --version
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in activeadmin_scoped_collection_actions.gemspec
4
+ gemspec
5
+ group :test do
6
+ gem 'sprockets-rails', '2.3.3'
7
+ gem 'rails', '4.2.0'
8
+ gem 'rspec-rails'
9
+ gem 'activeadmin', github: 'activeadmin', ref: '64b5295571400c461376cf060dae9522731fe6d9'
10
+ gem 'sass-rails'
11
+ gem 'sqlite3'
12
+ gem 'launchy'
13
+ gem 'database_cleaner'
14
+ gem 'capybara'
15
+ gem 'selenium-webdriver'
16
+ gem 'poltergeist'
17
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Gena M.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,300 @@
1
+ [![Build Status](https://img.shields.io/travis/activeadmin-plugins/active_admin_scoped_collection_actions.svg)](https://travis-ci.org/activeadmin-plugins/active_admin_scoped_collection_actions)
2
+
3
+ # ActiveAdmin Scoped Collection Actions
4
+ Plugin for ActiveAdmin. Provides batch Update and Delete for scoped_collection (Filters + Scope) across all pages.
5
+
6
+ ![Step 1](/screenshots/sidebar.png)
7
+
8
+ ![Step 1](/screenshots/pupup.png)
9
+
10
+
11
+ # Description
12
+
13
+ This gem give you ability to perform various batch actions on any filtered (or scoped) resource. Action applies to all records across all pages. It is similar to ActiveAdmin batch action, but affects all filtered records. This is usefull if you want to delete or update a lot of records in one click.
14
+
15
+ # Install
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'active_admin_scoped_collection_actions', github: 'activeadmin-plugins/active_admin_scoped_collection_actions'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ ```
26
+ $ bundle
27
+ ```
28
+
29
+ Add the following line at the end of "app/assets/javascript/active_admin.js.coffee":
30
+
31
+ ```javascript
32
+ //= require active_admin_scoped_collection_actions
33
+ ```
34
+
35
+ Also include CSS in "app/assets/stylesheets/active_admin.css.scss"
36
+
37
+ ```css
38
+ @import "active_admin_scoped_collection_actions";
39
+ ```
40
+
41
+ # Usage
42
+
43
+ Usually you need two standard actions: Delete and Update.
44
+
45
+ For example, if you have resource Posts and you want to have a delete action, add:
46
+
47
+ ```ruby
48
+ scoped_collection_action :scoped_collection_destroy
49
+ ```
50
+
51
+ Example:
52
+
53
+ ```ruby
54
+ ActiveAdmin.register Post do
55
+ config.batch_actions = true
56
+
57
+ scoped_collection_action :scoped_collection_destroy
58
+
59
+ index do
60
+ # ...
61
+ end
62
+ end
63
+ ```
64
+
65
+ **Important**: Visit Posts page with your browser and you will see no changes. Now, perform any filter with the Filters sidebar. Only after you filter will you see a delete button. It will be in sidebar under Filters.
66
+
67
+ ### Update action
68
+
69
+ Update is second standard action and is more complex. It has "form" hash wrapped in Proc:
70
+
71
+ ```ruby
72
+ scoped_collection_action :scoped_collection_update, form: -> do
73
+ { name: 'text',
74
+ diagonal: 'text',
75
+ manufactured_at: 'datepicker',
76
+ vendor_id: Vendor.all.map { |region| [region.name, region.id] },
77
+ has_3g: [['Yes', 't'], ['No', 'f']]
78
+ }
79
+ end
80
+ ```
81
+
82
+ In this example Phone model has fields:
83
+ * name - varchar string
84
+ * diagonal - integer(of float)
85
+ * manufactured_at - datetime
86
+ * vendor_id - association "belongs_to :vendor, class_name: 'Vendor', foreign_key: :vendor_id"
87
+ * has_3g - boolean
88
+
89
+ Parameter "form" is a proc object which returns Hash. It defines what fields you want to be able to update. Hash keys are column names in database. Hash values are a types of HTML inputs. We support only "text", "datepicker" and "selectbox". If you want something more complex - you can build your own forms.
90
+
91
+ # Custom Actions
92
+
93
+ Example: We have Phone resource and it has column "manufactured_at". We need an action which will erase this date.
94
+
95
+ In ActiveAdmin resource:
96
+
97
+ ```ruby
98
+ ActiveAdmin.register Phone do
99
+ config.batch_actions = true
100
+
101
+ scoped_collection_action :erase_date do
102
+ scoped_collection_records.update_all(manufactured_at: nil)
103
+ end
104
+
105
+ index do
106
+ # ...
107
+ end
108
+ end
109
+ ```
110
+
111
+ This simple code will create a new button "Erase date" in sidebar. After clicking this button, the user will see confirm message "Are you sure?". After confirming, all filtered records will be updated.
112
+
113
+
114
+ # Details and Settings
115
+
116
+
117
+ ### Why I don't see Sidebar with Collection Actions.
118
+
119
+ Sidebar visibility by default depends on several things.
120
+
121
+ First you must set:
122
+
123
+ ```ruby
124
+ config.batch_actions = true
125
+ ```
126
+
127
+ Actually, inside of this Gem we use "batch_actions". So without them Collection Actions wouldn't work.
128
+
129
+ ```ruby
130
+ scoped_collection_action :something_here
131
+ ```
132
+
133
+ You resource should have some collection actions. If it doesn't have any, the sidebar will not appear.
134
+
135
+ By default we dont allow perform actions on **all** the records. We want protect you from accidental deleting.
136
+
137
+ Sidebar with buttons will appear only after you perform filtering or scopes on resource records.
138
+
139
+ And lastly you can manage sidebar visibility by resource config:
140
+
141
+ ```ruby
142
+ # Always
143
+ config.scoped_collection_actions_if = -> { true }
144
+ # Only for scopes
145
+ config.scoped_collection_actions_if = -> { params[:scope] }
146
+ # etc.
147
+ ```
148
+
149
+ ### Can I use my handler on update/delete action?
150
+
151
+ You can pass block to default actions update and delete.
152
+ And do custom redirect after it. Use `render` (location: 'something') instead of `redirect_to()`.
153
+
154
+ This example renders form which allows to change `name` field. And after it do redirect to dashboard page.
155
+
156
+ ```ruby
157
+ scoped_collection_action :scoped_collection_update,
158
+ form: -> {
159
+ {name: 'text'}
160
+ } do
161
+ scoped_collection_records.update_all(name: params[:changes][:name])
162
+ flash[:notice] = 'Name successfully changed.'
163
+ render nothing: true, status: :no_content, location: admin_dashboard_path
164
+ end
165
+ ```
166
+
167
+
168
+ ### How can I rename button?
169
+
170
+ Every scoped_collection_action has option `:title`.
171
+
172
+ Example:
173
+
174
+ ```ruby
175
+ scoped_collection_action :erase_date, title: 'Nullify' do
176
+ scoped_collection_records.update_all(manufactured_at: nil)
177
+ end
178
+ ```
179
+
180
+
181
+ ### How can I modify modal dialog title?
182
+
183
+ Similar to button title. Use option `:confirm`
184
+
185
+ ```ruby
186
+ scoped_collection_action :scoped_collection_destroy, confirm: 'Delete all phones?'
187
+ ```
188
+
189
+
190
+ ### Can I replace you pop-up form with my own?
191
+
192
+ Yes. But also you must take care of mandatory parameters passed to the server.
193
+
194
+
195
+ ```ruby
196
+ scoped_collection_action :my_pop_action, class: 'my_popup'
197
+ ```
198
+
199
+ Now in HTML page, you have button:
200
+
201
+ ```html
202
+ <button class="my_popup" data="{&quot;auth_token&quot;:&quot;2a+KLu5u9McQENspCiep0DGZI6D09fCVXAN9inrwRG0=&quot;,&quot;batch_action&quot;:&quot;my_pop_action&quot;,&quot;confirm&quot;:&quot;Are you sure?&quot;}">My pop action</button>
203
+ ```
204
+
205
+ Without handler, clicking on the button does nothing.
206
+
207
+ You can render the form in any way you want:
208
+ - It can be some popup(Fancybox, Simplemodal, etc.), or some inline collapsible form.
209
+ - It can even be a separate full-page.
210
+
211
+ One thing is important - how you will send data to server. Generally it should be:
212
+
213
+ POST request
214
+
215
+ URL: /admin/collection_path/batch_action
216
+
217
+ with GET params identical to current page
218
+
219
+ The easiest way to get them is:
220
+
221
+ ```javascript
222
+ url = window.location.pathname + '/batch_action' + window.location.search
223
+ ```
224
+
225
+ And Request body params should be like:
226
+
227
+ ```
228
+ changes[manufactured_at] = "2015-07-21 18:11"
229
+ changes[diagonal] = "7"
230
+ changes[some_filed_name]='new value'
231
+ authenticity_token = "2a+KLu5u9McQENspCiep0DGZI6D09fCVXAN9inrwRG0="
232
+ batch_action = "my_pop_action"
233
+ ```
234
+
235
+ ```authenticity_token``` and ```batch_action``` you can get from data-attribute of the Button.
236
+
237
+
238
+ Example in JavaScript:
239
+
240
+ ```javascript
241
+ url = window.location.pathname + '/batch_action' + window.location.search
242
+ form_data = {
243
+ changes: {"manufactured_at": "2015-07-21 18:11", "diagonal": "7"},
244
+ collection_selection: [],
245
+ authenticity_token: "2a+KLu5u9McQENspCiep0DGZI6D09fCVXAN9inrwRG0=",
246
+ batch_action: "my_pop_action"
247
+ }
248
+ $.post(url, form_data).always () ->
249
+ window.location.reload()
250
+ ```
251
+
252
+ ### How notify user about success and error operations?
253
+
254
+ We recommend using Rails Flash messages.
255
+
256
+ Example with updating phone diagonal attribute. In this case model Phone has validation:
257
+
258
+ ```ruby
259
+ class Phone < ActiveRecord::Base
260
+ validates :diagonal, numericality: { only_integer: true }
261
+ end
262
+ ```
263
+
264
+ ```ruby
265
+ scoped_collection_action :change_diagonal, form: { diagonal: 'text' } do
266
+ errors = []
267
+ scoped_collection_records.find_each do |record|
268
+ errors << "#{record.errors.full_messages.join('. ')}" unless record.update(diagonal: params[:changes][:diagonal])
269
+ end
270
+ if errors.empty?
271
+ flash[:notice] = 'Diagonal changed successfully'
272
+ else
273
+ flash[:error] = errors.join('. ')
274
+ end
275
+ render nothing: true, status: :no_content
276
+ end
277
+ ```
278
+
279
+ When you try to update diagonal with "5.6" you will see flash error:
280
+
281
+ ```
282
+ Diagonal must be an integer.
283
+ ```
284
+
285
+ But if you use your custom popup, you can show messages with JS.
286
+
287
+
288
+ ### Can I perform action only on selected items?
289
+
290
+ Standard index-page of a resource with batch_action enabled has selectable column.
291
+
292
+ If you checked some items and parform any Collection Action, the handler will take care of it. If you write custom actions, you should do like this:
293
+
294
+ ```ruby
295
+ scoped_collection_action :do_something do
296
+ scoped_collection_records.find_each do |record|
297
+ record.update(name: 'x')
298
+ end
299
+ end
300
+ ```
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler"
2
+ require 'rake'
3
+ Bundler.setup
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ # Import all our rake tasks
7
+ FileList['tasks/**/*.rake'].each { |task| import task }
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ require File.expand_path('../lib/active_admin_scoped_collection_actions/version', __FILE__)
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "active_admin_scoped_collection_actions"
6
+ spec.version = ActiveAdminScopedCollectionActions::VERSION
7
+ spec.authors = ["Gena M."]
8
+ spec.email = ["workgena@gmail.com"]
9
+
10
+ spec.summary = %q{scoped_collection actions extension for ActiveAdmin}
11
+ spec.description = %q{Plugin for ActiveAdmin. Provides batch Update and Delete for scoped_collection (Filters + Scope) across all pages.}
12
+ spec.homepage = "https://github.com/activeadmin-plugins/active_admin_scoped_collection_actions"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ spec.bindir = "exe"
17
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.8"
21
+ spec.add_development_dependency "rake", "~> 10.0"
22
+ end
@@ -0,0 +1,11 @@
1
+ require 'activeadmin'
2
+ require 'active_admin_scoped_collection_actions/engine'
3
+ require 'active_admin_scoped_collection_actions/version'
4
+ require 'active_admin_scoped_collection_actions/dsl'
5
+ require 'active_admin_scoped_collection_actions/resource_extension'
6
+ require 'active_admin_scoped_collection_actions/controller'
7
+ require 'active_admin_scoped_collection_actions/authorization'
8
+
9
+ ActiveAdmin::ResourceDSL.send :include, ActiveAdminScopedCollectionActions::DSL
10
+ ActiveAdmin::Resource.send :include, ActiveAdminScopedCollectionActions::ResourceExtension
11
+ ActiveAdmin::Authorization.send :include, ActiveAdminScopedCollectionActions::Authorization
@@ -0,0 +1,8 @@
1
+ module ActiveAdminScopedCollectionActions
2
+ module Authorization
3
+ BATCH_UPDATE = :batch_edit
4
+ BATCH_DESTROY = :batch_destroy
5
+ end
6
+
7
+ Auth = Authorization
8
+ end
@@ -0,0 +1,8 @@
1
+ module ActiveAdminScopedCollectionActions
2
+ module Controller
3
+ def scoped_collection_records
4
+ selection = params.fetch(:collection_selection, [])
5
+ selection.any? ? batch_action_collection.where(resource_class.primary_key => selection) : batch_action_collection
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,76 @@
1
+ module ActiveAdminScopedCollectionActions
2
+ module DSL
3
+
4
+ def scoped_collection_action(name, options = {}, &block)
5
+ if name == :scoped_collection_destroy
6
+ options[:title] = 'Delete batch' if options[:title].nil?
7
+ add_scoped_collection_action_default_destroy(options, &block)
8
+ elsif name == :scoped_collection_update
9
+ options[:title] = 'Update batch' if options[:title].nil?
10
+ add_scoped_collection_action_default_update(options, &block)
11
+ else
12
+ batch_action(name, if: proc { false }, &block)
13
+ end
14
+ # sidebar button
15
+ config.add_scoped_collection_action(name, options)
16
+ end
17
+
18
+
19
+ def add_scoped_collection_action_default_update(options, &block)
20
+ batch_action :scoped_collection_update, if: proc { false } do
21
+ unless authorized?(:batch_edit, resource_class)
22
+ flash[:error] = 'Access denied'
23
+ render nothing: true, status: :no_content and next
24
+ end
25
+ if !params.has_key?(:changes) || params[:changes].empty?
26
+ render nothing: true, status: :no_content and next
27
+ end
28
+ permitted_changes = params.require(:changes).permit(*(options[:form].call.keys))
29
+ if block_given?
30
+ instance_eval &block
31
+ else
32
+ errors = []
33
+ scoped_collection_records.find_each do |record|
34
+ unless update_resource(record, [permitted_changes])
35
+ errors << "#{record.attributes[resource_class.primary_key]} | #{record.errors.full_messages.join('. ')}"
36
+ end
37
+ end
38
+ if errors.empty?
39
+ flash[:notice] = 'Batch update done'
40
+ else
41
+ flash[:error] = errors.join(". ")
42
+ end
43
+ render nothing: true, status: :no_content
44
+ end
45
+ end
46
+ end
47
+
48
+
49
+ def add_scoped_collection_action_default_destroy(_, &block)
50
+ batch_action :scoped_collection_destroy, if: proc { false } do |_|
51
+ unless authorized?(:batch_destroy, resource_class)
52
+ flash[:error] = 'Access denied'
53
+ render nothing: true, status: :no_content and next
54
+ end
55
+ if block_given?
56
+ instance_eval &block
57
+ else
58
+ errors = []
59
+ scoped_collection_records.find_each do |record|
60
+ unless destroy_resource(record)
61
+ errors << "#{record.attributes[resource_class.primary_key]} | Cant be destroyed}"
62
+ end
63
+ end
64
+ if errors.empty?
65
+ flash[:notice] = 'Batch destroy done'
66
+ else
67
+ flash[:error] = errors.join(". ")
68
+ end
69
+ render nothing: true, status: :no_content
70
+ end
71
+ end
72
+ end
73
+
74
+
75
+ end
76
+ end
@@ -0,0 +1,9 @@
1
+ module ActiveAdminScopedCollectionActions
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ config.after_initialize do
5
+ ActiveAdmin::ResourceController.send :include, ActiveAdminScopedCollectionActions::Controller
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,75 @@
1
+ module ActiveAdminScopedCollectionActions
2
+ module ResourceExtension
3
+
4
+ def initialize(*)
5
+ super
6
+ add_scoped_collection_actions_sidebar_section
7
+ end
8
+
9
+ def scoped_collection_actions
10
+ @scoped_collection_actions || {}
11
+ end
12
+
13
+ def scoped_collection_actions_on_all=(bool)
14
+ @scoped_collection_actions_unconditionally = bool
15
+ end
16
+
17
+ def scoped_collection_actions_on_all
18
+ @scoped_collection_actions_unconditionally || false
19
+ end
20
+
21
+ def add_scoped_collection_action(name, options)
22
+ (@scoped_collection_actions ||= {})[name.to_sym] = options
23
+ end
24
+
25
+ def add_scoped_collection_actions_sidebar_section
26
+ self.sidebar_sections << scoped_collection_actions_sidebar_section
27
+ end
28
+
29
+ def scoped_collection_actions_if=(if_proc)
30
+ @if_proc = if_proc
31
+ end
32
+
33
+ def scoped_collection_actions_if
34
+ @if_proc
35
+ end
36
+
37
+ def scoped_collection_sidebar_condition
38
+ -> do
39
+ if active_admin_config.scoped_collection_actions_if.is_a?(Proc)
40
+ instance_exec &active_admin_config.scoped_collection_actions_if
41
+ else
42
+ filtered_scoped = (params[:q] || params[:scope])
43
+ on_all = active_admin_config.scoped_collection_actions_on_all
44
+ has_actions = active_admin_config.scoped_collection_actions.any?
45
+ batch_actions_enabled = active_admin_config.batch_actions_enabled?
46
+ ( batch_actions_enabled && has_actions && (filtered_scoped || on_all) )
47
+ end
48
+ end
49
+ end
50
+
51
+ def scoped_collection_actions_sidebar_section
52
+ ActiveAdmin::SidebarSection.new :collection_actions, only: :index, if: scoped_collection_sidebar_condition do
53
+
54
+ div 'This batch operations affect selected records. Or if none is selected, it will involve all records by current filters and scopes.'
55
+
56
+ active_admin_config.scoped_collection_actions.each do |key, options={}|
57
+ b_title = options.fetch(:title, ::ActiveSupport::Inflector.humanize(key))
58
+ b_options = {}
59
+ b_options[:class] = options[:class] if options[:class].present?
60
+ # Important: If user did not specify html_class, then use default
61
+ b_options[:class] = 'scoped_collection_action_button' unless b_options[:class]
62
+ b_data = { auth_token: form_authenticity_token.to_s }
63
+ b_data[:batch_action] = key.to_s
64
+ if options[:form].present?
65
+ b_data[:inputs] = options[:form].is_a?(Proc) ? options[:form].call : options[:form]
66
+ end
67
+ b_data[:confirm] = options.fetch(:confirm, 'Are you sure?')
68
+ b_options[:data] = b_data.to_json
69
+ button b_title, b_options
70
+ end
71
+ end
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,3 @@
1
+ module ActiveAdminScopedCollectionActions
2
+ VERSION = "0.2.1"
3
+ end
Binary file
Binary file
data/tasks/test.rake ADDED
@@ -0,0 +1,6 @@
1
+ desc "Creates a test rails app for the specs to run against"
2
+ task :setup do
3
+ require 'rails/version'
4
+ system("mkdir spec/rails") unless File.exists?("spec/rails")
5
+ system "bundle exec rails new spec/rails/rails-#{Rails::VERSION::STRING} -m spec/support/rails_template.rb --skip-spring"
6
+ end
@@ -0,0 +1,25 @@
1
+ #= require ./lib/dialog_mass_fields_update
2
+
3
+ $(document).ready ->
4
+
5
+ $('.scoped_collection_action_button').click (e) ->
6
+ e.preventDefault()
7
+ fields = JSON.parse( $(this).attr('data') )
8
+
9
+ ActiveAdmin.dialogMassFieldsUpdate fields['confirm'], fields['inputs'],
10
+ (inputs)=>
11
+ url = window.location.pathname + '/batch_action' + window.location.search
12
+ form_data = {
13
+ changes: inputs,
14
+ collection_selection: [],
15
+ authenticity_token: fields['auth_token'],
16
+ batch_action: fields['batch_action']
17
+ }
18
+ $('.paginated_collection').find('input.collection_selection:checked').each (i, el) ->
19
+ form_data["collection_selection"].push($(el).val())
20
+
21
+ $.post(url, form_data).always (data, textStatus, jqXHR) ->
22
+ if jqXHR.getResponseHeader('Location')
23
+ window.location.assign jqXHR.getResponseHeader('Location')
24
+ else
25
+ window.location.reload()
@@ -0,0 +1,54 @@
1
+ ActiveAdmin.dialogMassFieldsUpdate = (message, inputs, callback)->
2
+ html = """<form id="dialog_confirm" title="#{message}"><div stype="padding-right:4px;padding-left:1px;margin-right:2px"><ul>"""
3
+ for name, type of inputs
4
+ if /^(datepicker|checkbox|text)$/.test type
5
+ wrapper = 'input'
6
+ else if $.isArray type
7
+ [wrapper, elem, opts, type] = ['select', 'option', type, '']
8
+ else
9
+ throw new Error "Unsupported input type: {#{name}: #{type}}"
10
+
11
+ klass = if type is 'datepicker' then type else ''
12
+ html += """<li>
13
+ <input type='checkbox' class='mass_update_protect_fild_flag' value='Y' id="mass_update_dialog_#{name}" />
14
+ <label for="mass_update_dialog_#{name}"> #{name.charAt(0).toUpperCase() + name.slice(1)}</label>
15
+ <#{wrapper} name="#{name}" class="#{klass}" type="#{type}" disabled="disabled">""" +
16
+ (if opts then (
17
+ for v in opts
18
+ $elem = $("<#{elem}/>")
19
+ if $.isArray v
20
+ $elem.text(v[0]).val(v[1])
21
+ else
22
+ $elem.text(v)
23
+ $elem.wrap('<div>').parent().html()
24
+ ).join '' else '')
25
+ if wrapper == 'select'
26
+ html += "</#{wrapper}>"
27
+ html += "</li>"
28
+
29
+ [wrapper, elem, opts, type, klass] = [] # unset any temporary variables
30
+
31
+ html += "</ul></div></form>"
32
+
33
+ form = $(html).appendTo('body')
34
+
35
+ $('body').trigger 'mass_update_modal_dialog:before_open', [form]
36
+
37
+ form.dialog
38
+ modal: true
39
+ dialogClass: 'active_admin_dialog active_admin_dialog_mass_update_by_filter',
40
+ maxHeight: window.innerHeight - window.innerHeight * 0.1,
41
+ open: ->
42
+ $('body').trigger 'mass_update_modal_dialog:after_open', [form]
43
+ $('.mass_update_protect_fild_flag').on 'change', (e) ->
44
+ if this.checked
45
+ $(e.target).next().next().removeAttr('disabled').trigger("chosen:updated")
46
+ else
47
+ $(e.target).next().next().attr('disabled', 'disabled').trigger("chosen:updated")
48
+ buttons:
49
+ OK: (e)->
50
+ $(e.target).closest('.ui-dialog-buttonset').html('<span>Processing. Please wait...</span>')
51
+ callback $(@).serializeObject()
52
+ Cancel: ->
53
+ $('.mass_update_protect_fild_flag').off('change')
54
+ $(@).dialog('close').remove()
@@ -0,0 +1,34 @@
1
+ .active_admin_dialog_mass_update_by_filter {
2
+ form {
3
+ overflow-y: scroll;
4
+
5
+ li {
6
+ display: block;
7
+ margin: 10px 0 0 0;
8
+ }
9
+ input[type=text], input[type=datepicker], select {
10
+ margin-top: 3px;
11
+ display: block;
12
+ }
13
+ input[type=text], input[type=datepicker] {
14
+ width: calc(100% - 20px);
15
+ padding: 8px 10px 7px;
16
+ }
17
+ select {
18
+ width: 100%;
19
+ }
20
+ }
21
+ button {
22
+ cursor: pointer;
23
+ }
24
+ }
25
+
26
+ .sidebar_section.panel {
27
+ .scoped_collection_action_button {
28
+ cursor: pointer;
29
+ margin: 10px 5px 0 0;
30
+ &:last-child {
31
+ margin-right: 0;
32
+ }
33
+ }
34
+ }
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_admin_scoped_collection_actions
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Gena M.
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-04-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.8'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: Plugin for ActiveAdmin. Provides batch Update and Delete for scoped_collection
42
+ (Filters + Scope) across all pages.
43
+ email:
44
+ - workgena@gmail.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - ".travis.yml"
51
+ - CODE_OF_CONDUCT.md
52
+ - Gemfile
53
+ - LICENSE.txt
54
+ - README.md
55
+ - Rakefile
56
+ - active_admin_scoped_collection_actions.gemspec
57
+ - lib/active_admin_scoped_collection_actions.rb
58
+ - lib/active_admin_scoped_collection_actions/authorization.rb
59
+ - lib/active_admin_scoped_collection_actions/controller.rb
60
+ - lib/active_admin_scoped_collection_actions/dsl.rb
61
+ - lib/active_admin_scoped_collection_actions/engine.rb
62
+ - lib/active_admin_scoped_collection_actions/resource_extension.rb
63
+ - lib/active_admin_scoped_collection_actions/version.rb
64
+ - screenshots/pupup.png
65
+ - screenshots/sidebar.png
66
+ - tasks/test.rake
67
+ - vendor/assets/javascripts/active_admin_scoped_collection_actions.js.coffee
68
+ - vendor/assets/javascripts/lib/dialog_mass_fields_update.js.coffee
69
+ - vendor/assets/stylesheets/active_admin_scoped_collection_actions.scss
70
+ homepage: https://github.com/activeadmin-plugins/active_admin_scoped_collection_actions
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 2.6.10
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: scoped_collection actions extension for ActiveAdmin
94
+ test_files: []