custom_table 0.1.0 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +24 -3
- data/Rakefile +0 -0
- data/app/assets/config/custom_table_manifest.js +0 -0
- data/app/assets/stylesheets/custom_table/application.scss +0 -0
- data/app/assets/stylesheets/custom_table/table.scss +52 -1
- data/app/controllers/concerns/custom_table_concern.rb +0 -0
- data/app/controllers/custom_table/application_controller.rb +0 -0
- data/app/controllers/custom_table/settings_controller.rb +2 -0
- data/app/helpers/custom_table/application_helper.rb +71 -20
- data/app/helpers/custom_table/fieldset_helper.rb +5 -4
- data/app/helpers/custom_table/icons_helper.rb +5 -0
- data/app/inputs/date_picker_input.rb +0 -0
- data/app/javascript/controllers/batch_actions_controller.js +34 -10
- data/app/javascript/controllers/table_controller.js +0 -0
- data/app/jobs/custom_table/application_job.rb +0 -0
- data/app/mailers/custom_table/application_mailer.rb +0 -0
- data/app/models/concerns/custom_table_settings.rb +1 -1
- data/app/models/custom_table/application_record.rb +0 -0
- data/app/views/custom_table/_download.haml +0 -0
- data/app/views/custom_table/_field.haml +0 -0
- data/app/views/custom_table/_field_plain.haml +0 -0
- data/app/views/custom_table/_fieldset.haml +0 -0
- data/app/views/custom_table/_filter.html.haml +21 -11
- data/app/views/custom_table/_settings.html.haml +3 -3
- data/app/views/custom_table/_table.html.haml +52 -21
- data/app/views/custom_table/_table.xlsx.axlsx +0 -0
- data/app/views/custom_table/_table_fe.xlsx.fast_excel +0 -0
- data/app/views/custom_table/_table_row.html.haml +16 -4
- data/app/views/custom_table/_table_row_data.html.haml +0 -0
- data/app/views/custom_table/settings/destroy.html.haml +0 -0
- data/app/views/custom_table/settings/edit.html.haml +0 -0
- data/app/views/custom_table/settings/update.html.haml +0 -0
- data/app/views/kaminari/bootstrap-5/_first_page.html.haml +3 -0
- data/app/views/kaminari/bootstrap-5/_last_page.html.haml +3 -0
- data/app/views/kaminari/bootstrap-5/_next_page.html.haml +3 -0
- data/app/views/kaminari/bootstrap-5/_paginator.html.haml +14 -0
- data/app/views/kaminari/bootstrap-5/_prev_page.haml.haml +3 -0
- data/app/views/layouts/custom_table/application.html.erb +0 -0
- data/config/initializers/simple_form_bootstrap.rb +21 -317
- data/config/locales/en.yml +8 -0
- data/config/locales/ru.yml +9 -0
- data/config/routes.rb +0 -0
- data/lib/custom_table/configuration.rb +12 -0
- data/lib/custom_table/engine.rb +0 -0
- data/lib/custom_table/version.rb +1 -1
- data/lib/custom_table.rb +0 -0
- data/lib/generators/custom_table/USAGE +0 -0
- data/lib/generators/custom_table/custom_table_generator.rb +0 -0
- data/lib/generators/custom_table/templates/initializer.rb +0 -0
- data/lib/generators/custom_table/templates/migration.rb +0 -0
- data/lib/tasks/custom_table_tasks.rake +0 -0
- metadata +22 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95c22fd839bbfa0375d8da036487f9236268e4f7e7c0aaa51c899c2a51fc9613
|
4
|
+
data.tar.gz: 1249a1a9138db0f22238bbb432b7ec6fda81117d401115f52f372d8c28b3e39d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8b95da2d272f54281fb41a74a754334480402535955752bd1a589497e3ff43ad41a7e0a00ec791fb214cb53a9cf24ebbd1d66d76d120ff36c94cb973e4fe169
|
7
|
+
data.tar.gz: 91cd56375930099532fa781e1504535f3fbf4831a02493013cd15ddff998af49f5b3a942c676a313881ec0b02bd1f7c4edad8589f69def95e7c96e3803cd13ae
|
data/README.md
CHANGED
@@ -4,7 +4,9 @@ Provides powerful set of functionality for showing tables of data:
|
|
4
4
|
* Generated table and filter panel for any model
|
5
5
|
* Declare fields that should be displayed, filtered or sorted
|
6
6
|
* Customize visible fields for each user
|
7
|
-
* Exporting table to XLSX
|
7
|
+
* Exporting table to XLSX (helpers for CAXLSX, fast_excel and CSV)
|
8
|
+
|
9
|
+
Requires and works only with Ransack, Kaminari, Bootstrap CSS, Rails, simple_form and Turbo gems.
|
8
10
|
|
9
11
|
## Setup
|
10
12
|
|
@@ -42,6 +44,7 @@ Use attribute name as key if possbile. Table will try to get most of options aut
|
|
42
44
|
* ```search``` contains search parameters. Skip this if search is not available for this fields
|
43
45
|
* * ```q``` ransack's "q" search marcher which is used to search by the field. For range use array of two elements, e.g. ```[:created_at_gteq, :created_at_lteq]```
|
44
46
|
* * ```type``` type of search element to draw
|
47
|
+
* * ```sm_visible``` set to true to make this field search always be visible in small screens (by default all fields collapsed)
|
45
48
|
* ```appear``` controls visibility of the field. Default value is hidden if not specially selected
|
46
49
|
* * ```default``` will appear by default
|
47
50
|
* * ```always``` will always appear
|
@@ -99,6 +102,7 @@ Options available are:
|
|
99
102
|
* ```tree``` set to true if you have parent-child relation and you want to show records grouped by parent. Be sure to disable pagination as it will only group current page records
|
100
103
|
* ```group_by``` set to helper name to group records by result of it. Be sure to disable pagination as it will only group current page records
|
101
104
|
* ```expanded``` expand grouped or trees by default
|
105
|
+
* ```sortable``` set to true to allow to sort models. Model needs to have ```position``` attribute and use ```acts_as_list``` gem to be sorted. Gem uses ```stimulus-sortable``` JS package for sorting
|
102
106
|
|
103
107
|
## Rendering search panel
|
104
108
|
|
@@ -159,8 +163,20 @@ Then just pass variant to filter and data helpers.
|
|
159
163
|
|
160
164
|
## Table Stimulus helper
|
161
165
|
|
166
|
+
## Batch Actions
|
167
|
+
|
168
|
+
You can set ```batch``` option to field definition to enable batch editing
|
169
|
+
|
170
|
+
You need to set following options to ```custom_table_data```:
|
162
171
|
|
172
|
+
* ```batch_actions``` - shows batch actions. Set to helper name for custom actions
|
173
|
+
* ```batch_activator``` - shows more compact batch selecting view. Enabled by default
|
163
174
|
|
175
|
+
You have to declare the following routes for the resource:
|
176
|
+
|
177
|
+
* ```batch_edit``` - POST with ```plural model name``` array will be requested to show form for mass editing
|
178
|
+
* ```batch_update``` - POST with ```plural model name``` array will be requested to update records with params
|
179
|
+
* ```batch_destroy``` - DELETE with ```plural model name``` array will be requested to delete records
|
164
180
|
|
165
181
|
## Downloading data as XLSX table
|
166
182
|
|
@@ -200,11 +216,16 @@ You can declare how each field is displayed. Just add it as block within field:
|
|
200
216
|
= fs.field :name do
|
201
217
|
= @instance.name.upcase
|
202
218
|
|
203
|
-
## Testing
|
219
|
+
## Testing hints for your app
|
204
220
|
|
205
221
|
Use ```custom_table_use_all_fields``` GET param with any value to show all available fields in your feature tests
|
206
222
|
|
207
223
|
## Development
|
208
224
|
|
209
|
-
Running tests:
|
225
|
+
Running tests:
|
226
|
+
|
227
|
+
* `bundle install`
|
228
|
+
* `bundle exec rails db:migrate`
|
229
|
+
* `RAILS_ENV=test bundle exec rspec`
|
230
|
+
|
210
231
|
|
data/Rakefile
CHANGED
File without changes
|
File without changes
|
File without changes
|
@@ -10,7 +10,7 @@ table.custom-table {
|
|
10
10
|
white-space: nowrap;
|
11
11
|
}
|
12
12
|
td.selected {
|
13
|
-
|
13
|
+
outline: 2px solid rgb(26, 179, 26) !important;
|
14
14
|
}
|
15
15
|
|
16
16
|
tr {
|
@@ -34,6 +34,10 @@ table.custom-table {
|
|
34
34
|
}
|
35
35
|
}
|
36
36
|
|
37
|
+
.checkbox-col {
|
38
|
+
width: 20px;
|
39
|
+
}
|
40
|
+
|
37
41
|
}
|
38
42
|
|
39
43
|
|
@@ -82,8 +86,55 @@ table.custom-table {
|
|
82
86
|
|
83
87
|
}
|
84
88
|
|
89
|
+
.batch-hidden {
|
90
|
+
th.checkbox-col, td.checkbox-col {
|
91
|
+
display: none;
|
92
|
+
}
|
93
|
+
.batch-actions {
|
94
|
+
display: none;
|
95
|
+
}
|
96
|
+
}
|
85
97
|
|
86
98
|
.widget table.custom-table td {
|
87
99
|
max-width: 120px;
|
88
100
|
overflow: hidden;
|
89
101
|
}
|
102
|
+
|
103
|
+
@include media-breakpoint-down(md) {
|
104
|
+
.custom-table-filter {
|
105
|
+
> :not(.has-value, .btn-group, .sm-visible) {
|
106
|
+
display: none;
|
107
|
+
}
|
108
|
+
&.show-all {
|
109
|
+
> :not(.has-value, .btn-group, .sm-visible) {
|
110
|
+
display: block;
|
111
|
+
}
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
}
|
116
|
+
|
117
|
+
|
118
|
+
@include media-breakpoint-down(lg) {
|
119
|
+
.overflow-x-lg-scroll {
|
120
|
+
overflow-x: scroll;
|
121
|
+
}
|
122
|
+
|
123
|
+
}
|
124
|
+
|
125
|
+
@include media-breakpoint-up(sm) {
|
126
|
+
.custom-table-settings {
|
127
|
+
columns: 2
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
|
132
|
+
@include media-breakpoint-up(lg) {
|
133
|
+
.modal-lg, .modal-xl {
|
134
|
+
.custom-table-settings {
|
135
|
+
columns: 3
|
136
|
+
}
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
|
File without changes
|
File without changes
|
@@ -41,6 +41,7 @@ module CustomTable
|
|
41
41
|
if current_user.save_custom_table_settings(model, variant, fields: p[:fields])
|
42
42
|
flash[:notice] = t("custom_table.customization_saved")
|
43
43
|
respond_to do |format|
|
44
|
+
format.html { render nil, status: :ok }
|
44
45
|
format.turbo_stream {render turbo_stream: turbo_stream.action(:refresh, nil)}
|
45
46
|
end
|
46
47
|
else
|
@@ -66,6 +67,7 @@ module CustomTable
|
|
66
67
|
if current_user.destroy_custom_table_settings(model, variant)
|
67
68
|
flash[:notice] = t("custom_table.customization_saved")
|
68
69
|
respond_to do |format|
|
70
|
+
format.html { render nil, status: :ok }
|
69
71
|
format.turbo_stream {render turbo_stream: turbo_stream.action(:refresh, nil)}
|
70
72
|
end
|
71
73
|
else
|
@@ -14,15 +14,15 @@ module CustomTable
|
|
14
14
|
options[:method] = :get
|
15
15
|
|
16
16
|
options[:html] ||= {}
|
17
|
-
options[:html][:class] = "row row-cols-
|
18
|
-
options[:wrapper] = options[:wrapper] || :
|
17
|
+
options[:html][:class] = "row row-cols-sm-auto g-3 align-items-center custom-table-filter"
|
18
|
+
options[:wrapper] = options[:wrapper] || :ct_inline_form
|
19
19
|
|
20
20
|
options[:wrapper_mappings] = {
|
21
|
-
boolean: :
|
22
|
-
check_boxes: :
|
23
|
-
radio_buttons: :
|
24
|
-
date: :
|
25
|
-
select: :
|
21
|
+
boolean: :ct_inline_boolean,
|
22
|
+
check_boxes: :ct_vertical_collection,
|
23
|
+
radio_buttons: :ct_vertical_collection,
|
24
|
+
date: :ct_inline_element,
|
25
|
+
select: :ct_inline_select
|
26
26
|
}
|
27
27
|
|
28
28
|
simple_form_for(record, options, &block)
|
@@ -80,10 +80,13 @@ module CustomTable
|
|
80
80
|
end
|
81
81
|
|
82
82
|
if !defs.nil? && defs[:amount]
|
83
|
+
val = item.send(field) rescue nil
|
84
|
+
return not_set if val.nil?
|
83
85
|
if !item.class.columns_hash[field.to_s].nil? && item.class.columns_hash[field.to_s].type == :integer
|
84
|
-
|
86
|
+
# Integer only
|
87
|
+
return amount_value(val, 0) rescue ""
|
85
88
|
else
|
86
|
-
return amount(
|
89
|
+
return amount(val) rescue ""
|
87
90
|
end
|
88
91
|
else
|
89
92
|
if item.class.reflect_on_association(field)
|
@@ -93,13 +96,21 @@ module CustomTable
|
|
93
96
|
return boolean_icon(item.send(field)) rescue ""
|
94
97
|
elsif item.class.defined_enums.has_key?(field.to_s)
|
95
98
|
return (item.send("human_#{field}") rescue (item.send(field).presence || not_set)).to_s rescue ""
|
96
|
-
elsif item.class.columns_hash[field.to_s] && [:date
|
97
|
-
return (item.send(field).blank? ? not_set : l(item.send(field), format:
|
99
|
+
elsif item.class.columns_hash[field.to_s] && [:date].include?(item.class.columns_hash[field.to_s].type)
|
100
|
+
return (item.send(field).blank? ? not_set : l(item.send(field), format: CustomTable.configuration.date_format)) rescue ""
|
101
|
+
elsif item.class.columns_hash[field.to_s] && [:datetime].include?(item.class.columns_hash[field.to_s].type)
|
102
|
+
return (item.send(field).blank? ? not_set : l(item.send(field), format: CustomTable.configuration.datetime_format)) rescue ""
|
98
103
|
elsif item.class.columns_hash[field.to_s] && [:integer, :float, :decimal].include?(item.class.columns_hash[field.to_s].type)
|
99
104
|
return not_set if (item.send(field) rescue nil).nil?
|
105
|
+
return item.send(field) if !defs.nil? && defs[:amount] === false # Showing simple output if amount is false
|
100
106
|
return amount(item.send(field)) rescue ""
|
101
107
|
else
|
102
|
-
|
108
|
+
# Non-column attribute
|
109
|
+
v = (item.send(field).presence || not_set) rescue nil
|
110
|
+
if !defs.nil? && !defs[:type].nil?
|
111
|
+
return date_value(v) if [:date, :datetime].include?(defs[:type])
|
112
|
+
end
|
113
|
+
return v.to_s.presence || not_set
|
103
114
|
end
|
104
115
|
end
|
105
116
|
|
@@ -133,9 +144,9 @@ module CustomTable
|
|
133
144
|
# We can try to sum value from database
|
134
145
|
|
135
146
|
if fields[field][:total_scope].nil?
|
136
|
-
out[field] = collection.except(:limit, :offset, :order, :group).sum(field)
|
137
|
-
else
|
138
|
-
out[field] = collection.except(:limit, :offset, :order, :group).send(fields[field][:total_scope])
|
147
|
+
out[field] = collection.except(:limit, :offset, :order, :group).distinct(false).sum(field)
|
148
|
+
else
|
149
|
+
out[field] = collection.except(:limit, :offset, :order, :group).distinct(false).send(fields[field][:total_scope])
|
139
150
|
end
|
140
151
|
else
|
141
152
|
# Taking simple summed value because all data is shown
|
@@ -254,7 +265,7 @@ module CustomTable
|
|
254
265
|
|
255
266
|
# Returns list of fields for customization form
|
256
267
|
def custom_table_fields_settings_for(model, variant: nil)
|
257
|
-
|
268
|
+
|
258
269
|
model_fields = custom_table_fields_definition_for(model, variant)
|
259
270
|
model_fields = model_fields.reject {|k,v| [:export, :never].include?(v[:appear]) }
|
260
271
|
|
@@ -282,7 +293,6 @@ module CustomTable
|
|
282
293
|
return model_fields.each{|k,f| f[:selected] = [:always, :default].include?(f[:appear])}
|
283
294
|
end
|
284
295
|
|
285
|
-
|
286
296
|
end
|
287
297
|
|
288
298
|
# Prepares object of user fields customization
|
@@ -314,9 +324,15 @@ module CustomTable
|
|
314
324
|
|
315
325
|
# Base definition for model
|
316
326
|
def custom_table_fields_definition_for(model, variant = nil)
|
327
|
+
|
317
328
|
helper_name = "#{model.model_name.singular}_custom_table_fields"
|
318
329
|
if (! self.class.method_defined?(helper_name))
|
319
|
-
|
330
|
+
helper_name = "#{model.model_name.element}_custom_table_fields"
|
331
|
+
|
332
|
+
# Removing namespace from model
|
333
|
+
if (! self.class.method_defined?(helper_name))
|
334
|
+
raise "#{helper_name} helper is not defined so we do not know how to render custom_table for #{model}"
|
335
|
+
end
|
320
336
|
end
|
321
337
|
|
322
338
|
if variant.nil? || method(helper_name).parameters.empty?
|
@@ -330,7 +346,9 @@ module CustomTable
|
|
330
346
|
|
331
347
|
# Base definition for model
|
332
348
|
def custom_table_fields_definition_for_field(model, field, variant = nil)
|
349
|
+
|
333
350
|
helper_name = "#{model.model_name.singular}_custom_table_fields"
|
351
|
+
|
334
352
|
if (! self.class.method_defined?(helper_name))
|
335
353
|
raise "#{helper_name} helper is not defined so we do not know how to render custom_table for #{model}"
|
336
354
|
end
|
@@ -340,6 +358,7 @@ module CustomTable
|
|
340
358
|
defs = self.send("#{helper_name}", variant)
|
341
359
|
end
|
342
360
|
return nil if defs[field].nil?
|
361
|
+
defs = defs[field]
|
343
362
|
defs[:label] = model.human_attribute_name(field) if defs[:label].nil?
|
344
363
|
return defs
|
345
364
|
end
|
@@ -358,9 +377,10 @@ module CustomTable
|
|
358
377
|
params[:paginate] = true if params[:paginate]!=false
|
359
378
|
params[:last_page] = true if params[:last_page]!=false
|
360
379
|
params[:namespace] = (controller.class.module_parent == Object) ? nil : controller.class.module_parent.to_s.underscore.to_sym
|
361
|
-
params[:force_edit_button] = false if params[:force_edit_button].nil?
|
362
380
|
params[:modal_edit] = true if params[:modal_edit].nil?
|
363
|
-
|
381
|
+
params[:with_select] = true if params[:with_select].nil? && params[:batch_actions]
|
382
|
+
params[:batch_activator] = true if params[:batch_activator].nil? && params[:batch_actions] === true
|
383
|
+
|
364
384
|
render "custom_table/table", params do
|
365
385
|
yield
|
366
386
|
end
|
@@ -478,6 +498,37 @@ module CustomTable
|
|
478
498
|
return out
|
479
499
|
end
|
480
500
|
|
501
|
+
def custom_table_batch_ids items
|
502
|
+
return if items.nil? || items.length == 0
|
503
|
+
capture do
|
504
|
+
items.each do |item|
|
505
|
+
concat hidden_field_tag("#{item.model_name.plural}[]", item.id)
|
506
|
+
end
|
507
|
+
concat content_tag(:p, t("custom_table.batch_selected_items_count", count: items.length))
|
508
|
+
concat content_tag(:p, t("custom_table.batch_action_description"))
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
def custom_table_batch_fields model
|
513
|
+
custom_table_fields_definition_for(model).select{|f, d| d[:batch] == true}.keys
|
514
|
+
end
|
515
|
+
|
516
|
+
def custom_table_batch_actions model
|
517
|
+
|
518
|
+
item = model.new
|
519
|
+
forms = []
|
520
|
+
forms.push (form_for(item, url: [:batch_edit, item.model_name.plural.to_sym], params: "ids[]", html: {class: "d-inline me-1"}, method: :post, "target": "remote-modal", data: {"turbo-frame": "remote-modal", "batch-actions-target": "form", "action": "batch-actions#submit"}) do |f|
|
521
|
+
concat(f.submit t("custom_table.batch_update"), class: "btn btn-success btn-sm my-1")
|
522
|
+
end)
|
523
|
+
|
524
|
+
forms.push (form_for(item, url: [:batch_destroy, item.model_name.plural.to_sym], params: "ids[]", html: {class: "d-inline"}, method: :delete, data: {"turbo-confirm": t("are_you_sure"), "batch-actions-target": "form", "action": "batch-actions#submit"}) do |f|
|
525
|
+
concat(f.submit t("custom_table.batch_destroy"), class: "btn btn-danger btn-sm my-1")
|
526
|
+
end)
|
527
|
+
|
528
|
+
forms.join("").html_safe
|
529
|
+
|
530
|
+
end
|
531
|
+
|
481
532
|
end
|
482
533
|
|
483
534
|
end
|
@@ -16,7 +16,7 @@ module CustomTable
|
|
16
16
|
|
17
17
|
def field column, **params, &block
|
18
18
|
|
19
|
-
defs = custom_table_fields_definition_for_field(@object.class, column) rescue nil
|
19
|
+
defs = @template.custom_table_fields_definition_for_field(@object.class, column) rescue nil
|
20
20
|
|
21
21
|
params = {} if params.nil?
|
22
22
|
params = params.deep_merge(@params)
|
@@ -25,12 +25,13 @@ module CustomTable
|
|
25
25
|
|
26
26
|
if params[:label].nil?
|
27
27
|
if !defs.nil? && !defs[:label].blank?
|
28
|
-
params[:label] = defs[:label]
|
28
|
+
params[:label] = defs[:label]
|
29
29
|
else
|
30
30
|
params[:label] = @object.class.human_attribute_name(column)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
+
|
34
35
|
params[:template] = "field" if params[:template].nil?
|
35
36
|
params[:column] = column
|
36
37
|
params[:object] = @object
|
@@ -48,14 +49,14 @@ module CustomTable
|
|
48
49
|
if block_given?
|
49
50
|
yield
|
50
51
|
else
|
51
|
-
@template.field_value_for(@object, column)
|
52
|
+
@template.field_value_for(@object, column, definitions: defs)
|
52
53
|
end
|
53
54
|
end
|
54
55
|
else
|
55
56
|
if block_given?
|
56
57
|
yield
|
57
58
|
else
|
58
|
-
@template.field_value_for(@object, column)
|
59
|
+
@template.field_value_for(@object, column, definitions: defs)
|
59
60
|
end
|
60
61
|
end
|
61
62
|
|
@@ -18,6 +18,11 @@ module CustomTable
|
|
18
18
|
return "bi bi-arrow-down-up" if CustomTable.configuration.icons_framework == :bi
|
19
19
|
end
|
20
20
|
|
21
|
+
def custom_table_search_icon_class
|
22
|
+
return "fa fa-search" if CustomTable.configuration.icons_framework == :fa
|
23
|
+
return "bi bi-search" if CustomTable.configuration.icons_framework == :bi
|
24
|
+
end
|
25
|
+
|
21
26
|
def custom_table_tree_child_icon_class
|
22
27
|
return "fa fa-arrow-right" if CustomTable.configuration.icons_framework == :fa
|
23
28
|
return "bi bi-arrow-return-right" if CustomTable.configuration.icons_framework == :bi
|
File without changes
|
@@ -2,15 +2,27 @@ import { Controller } from "@hotwired/stimulus"
|
|
2
2
|
|
3
3
|
export default class extends Controller {
|
4
4
|
|
5
|
-
static targets = [ "checkbox", "form" ]
|
5
|
+
static targets = [ "checkbox", "form", "activator" ]
|
6
6
|
|
7
7
|
connect() {
|
8
8
|
if (this.hasFormTarget && this.hasCheckboxTarget) {
|
9
9
|
console.log("Batch actions form", this.formTarget)
|
10
|
+
|
11
|
+
if (this.hasActivatorTarget) {
|
12
|
+
this.element.classList.add("batch-hidden")
|
13
|
+
this.activatorTarget.indeterminate = true
|
14
|
+
}
|
15
|
+
|
10
16
|
this.refresh();
|
11
17
|
}
|
12
18
|
}
|
13
19
|
|
20
|
+
activate() {
|
21
|
+
this.element.classList.remove("batch-hidden")
|
22
|
+
this.activatorTarget.classList.add("d-none")
|
23
|
+
|
24
|
+
}
|
25
|
+
|
14
26
|
submit(event) {
|
15
27
|
|
16
28
|
if (!this.hasCheckboxTarget) {
|
@@ -19,8 +31,11 @@ export default class extends Controller {
|
|
19
31
|
}
|
20
32
|
|
21
33
|
// Clearing any matching hidden fields from form
|
22
|
-
|
23
|
-
|
34
|
+
|
35
|
+
this.formTargets.forEach((form) => {
|
36
|
+
form.querySelectorAll('input[name="'+this.checkboxTargets[0].getAttribute("name")+'"]').forEach((cb) => {
|
37
|
+
cb.parentNode.removeChild(cb)
|
38
|
+
});
|
24
39
|
});
|
25
40
|
|
26
41
|
// Adding selected fields to form as hiddens
|
@@ -28,12 +43,14 @@ export default class extends Controller {
|
|
28
43
|
|
29
44
|
if (!cb.checked) return;
|
30
45
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
46
|
+
|
47
|
+
this.formTargets.forEach((form) => {
|
48
|
+
let input = document.createElement('input');
|
49
|
+
input.setAttribute('name', cb.getAttribute("name"));
|
50
|
+
input.setAttribute('value', cb.getAttribute("value"));
|
51
|
+
input.setAttribute('type', "hidden")
|
52
|
+
form.appendChild(input);//append the input to the form
|
53
|
+
});
|
37
54
|
|
38
55
|
})
|
39
56
|
|
@@ -43,11 +60,18 @@ export default class extends Controller {
|
|
43
60
|
}
|
44
61
|
|
45
62
|
refresh(){
|
63
|
+
|
64
|
+
if (!this.hasFormTarget) return;
|
65
|
+
|
46
66
|
let v = false
|
47
67
|
this.checkboxTargets.forEach((cb) => {
|
48
68
|
if (cb.checked) v = true;
|
49
69
|
});
|
50
|
-
|
70
|
+
|
71
|
+
this.formTargets.forEach((form) => {
|
72
|
+
form.querySelector('input[type="submit"]').disabled = !v
|
73
|
+
})
|
74
|
+
|
51
75
|
}
|
52
76
|
|
53
77
|
}
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,6 +1,6 @@
|
|
1
|
-
.
|
1
|
+
%div{class: CustomTable.configuration.filter_outer_wrapper_class}
|
2
2
|
|
3
|
-
.
|
3
|
+
%div{class: CustomTable.configuration.filter_inner_wrapper_class}
|
4
4
|
|
5
5
|
- url = local_assigns[:url].presence
|
6
6
|
- variant = local_assigns[:variant].presence
|
@@ -13,6 +13,10 @@
|
|
13
13
|
= f.input :s, as: :hidden, input_html: {value: params[:q].try(:[], :s)}
|
14
14
|
|
15
15
|
- fields = custom_table_fields_for(search_model, variant: variant, current_search: params[:q], predefined_fields: local_assigns[:fields]) if local_assigns[:fields].nil?
|
16
|
+
- has_unset_fields = false
|
17
|
+
|
18
|
+
- if CustomTable.configuration.show_search_icon
|
19
|
+
= custom_table_icon([custom_table_search_icon_class, "pe-0", "d-none", "d-md-inline"])
|
16
20
|
|
17
21
|
- fields.each do |key, defs|
|
18
22
|
|
@@ -29,20 +33,24 @@
|
|
29
33
|
- a[key].push field[:q]
|
30
34
|
- label = field[:label] || defs[:label]
|
31
35
|
|
36
|
+
- has_value = params[:q] && field[:q] && params[:q][field[:q].to_s].present?
|
37
|
+
- hvh = {wrapper_html: {class: (has_value ? "has-value" : (field[:sm_visible]==true ? "sm-visible" : ""))}}
|
38
|
+
- has_unset_fields = true if !has_value
|
39
|
+
|
32
40
|
- if field[:type] == :text
|
33
41
|
|
34
42
|
- ih = {class: "form-control-sm"}
|
35
43
|
- ih = ih.merge(defs[:input_html]) if !defs[:input_html].nil?
|
36
44
|
|
37
|
-
= f.input field[:q], input_html: ih, required: false, label: false, placeholder: label
|
45
|
+
= f.input field[:q], input_html: ih, required: false, label: false, placeholder: label, **hvh
|
38
46
|
|
39
47
|
- if field[:type] == :boolean
|
40
48
|
|
41
|
-
= f.input field[:q], as: :boolean, input_html: {}, required: false, label: label, unchecked_value: ""
|
49
|
+
= f.input field[:q], as: :boolean, input_html: {}, required: false, label: label, unchecked_value: "", **hvh
|
42
50
|
|
43
51
|
- if field[:type] == :switch
|
44
52
|
|
45
|
-
= f.input field[:q], as: :select, input_html: {:class => "form-select form-select-sm"}, required: false, label: false, :collection => [[t("yes")+" | #{label}", "true"], [t("no")+" | #{label}", "false"]], include_blank: label
|
53
|
+
= f.input field[:q], as: :select, input_html: {:class => "form-select form-select-sm"}, required: false, label: false, :collection => [[t("yes")+" | #{label}", "true"], [t("no")+" | #{label}", "false"]], include_blank: label, **hvh
|
46
54
|
|
47
55
|
- if field[:type] == :select
|
48
56
|
|
@@ -53,7 +61,7 @@
|
|
53
61
|
- collection = collection.accessible_by(current_ability)
|
54
62
|
- label_method = :to_s
|
55
63
|
|
56
|
-
= f.input field[:q], :as => :select, :input_html => {:class => "form-select form-select-sm"}, :required => false, :label => false, :collection => collection, label_method: label_method, include_blank: label, value_method: field[:value_method]
|
64
|
+
= f.input field[:q], :as => :select, :input_html => {:class => "form-select form-select-sm"}, :required => false, :label => false, :collection => collection, label_method: label_method, include_blank: label, value_method: field[:value_method], **hvh
|
57
65
|
|
58
66
|
- if field[:type] == :grouped_select
|
59
67
|
|
@@ -61,7 +69,7 @@
|
|
61
69
|
|
62
70
|
- collection = collection.accessible_by(current_ability) if collection.class.to_s =~ /ActiveRecord_Relation/i
|
63
71
|
|
64
|
-
= f.input field[:q], :as => :grouped_select, :input_html => {:class => "form-select form-select-sm"}, :required => false, :label => false, group_method: field[:group_method], :collection => collection, include_blank: label
|
72
|
+
= f.input field[:q], :as => :grouped_select, :input_html => {:class => "form-select form-select-sm"}, :required => false, :label => false, group_method: field[:group_method], value_method: field[:value_method], :collection => collection, include_blank: label, **hvh
|
65
73
|
|
66
74
|
- if field[:type] == :autocomplete
|
67
75
|
|
@@ -69,7 +77,7 @@
|
|
69
77
|
|
70
78
|
- collection = collection.accessible_by(current_ability) if collection.class.to_s =~ /ActiveRecord_Relation/i
|
71
79
|
|
72
|
-
= f.input field[:q], :as => :autocomplete, :input_html => {:class => "input-sm"}, :required => false, :label => false, :collection => collection, prompt: label
|
80
|
+
= f.input field[:q], :as => :autocomplete, :input_html => {:class => "input-sm"}, :required => false, :label => false, :collection => collection, url: field[:url], prompt: label, **hvh
|
73
81
|
|
74
82
|
- if field[:type] == :enum
|
75
83
|
|
@@ -77,15 +85,15 @@
|
|
77
85
|
- collection = [search_model, key.to_s.pluralize] if collection.nil?
|
78
86
|
- coll = collection[0].send(collection[1]).keys.map { |w| [(collection[0].method_defined?(:human_enum_name) ? collection[0].human_enum_name(collection[1].to_s.singularize, w) : w), w] }
|
79
87
|
|
80
|
-
= f.input field[:q], :as => :select, :input_html => {:class => "form-select form-select-sm"}, :required => false, :label => false, :collection => coll, include_blank: label
|
88
|
+
= f.input field[:q], :as => :select, :input_html => {:class => "form-select form-select-sm"}, :required => false, :label => false, :collection => coll, include_blank: label, **hvh
|
81
89
|
|
82
90
|
- if field[:type] == :dates
|
83
|
-
.col-
|
91
|
+
.col-6{class: (has_value ? "has-value" : "")}
|
84
92
|
.input-group.input-group-sm{"data-controller": "dates"}
|
85
93
|
= f.input_field field[:q][0], :as => :date_picker, :label => false, :class => "form-control", data: {"dates-target": "dateFrom"}, :placeholder => label+" ("+t("custom_table.date_from")+")"
|
86
94
|
= f.input_field field[:q][1], :as => :date_picker, :label => false, :class => "form-control", data: {"dates-target": "dateTo"}, :placeholder => label+" ("+t("custom_table.date_to")+")"
|
87
95
|
%button.btn.btn-outline-secondary.dropdown-toggle(type="button" data-bs-toggle="dropdown" aria-expanded="false")
|
88
|
-
%ul.dropdown-menu.dropdown-menu-end
|
96
|
+
%ul.dropdown-menu.dropdown-menu-end{style: "z-index: 1080"}
|
89
97
|
%button.dropdown-item{type: "button", "data-action": "dates#prevWeek"}= t("analytics.previos_week")
|
90
98
|
%button.dropdown-item{type: "button", "data-action": "dates#prevMonth"}= t("analytics.previos_month")
|
91
99
|
%button.dropdown-item{type: "button", "data-action": "dates#prevYear"}= t("analytics.previos_year")
|
@@ -94,6 +102,8 @@
|
|
94
102
|
|
95
103
|
.btn-group
|
96
104
|
= f.button :submit, t("search"), name: "", :class => "btn-sm btn-primary"
|
105
|
+
- if has_unset_fields
|
106
|
+
%button.d-md-none.btn.btn-sm.btn-outline-primary{onclick: "closest('form').classList.add('show-all'); return false"}= t("custom_table.show_all_filters")
|
97
107
|
- if user_signed_in? && current_user_has_customizable_fields_for?(search_model, variant) && !local_assigns[:hide_customization] && !local_assigns[:fields]# && !(profile_path rescue nil).nil?
|
98
108
|
= custom_table_settings_button search_model, variant
|
99
109
|
- if params[:q].present? && !params[:q].except(:s).empty?
|
@@ -19,7 +19,7 @@
|
|
19
19
|
- if !variant.nil?
|
20
20
|
%small= "(#{variant})"
|
21
21
|
|
22
|
-
%button.btn-close(type="button" data-
|
22
|
+
%button.btn-close(type="button" data-action="remote-modal#close" aria-label="close")
|
23
23
|
.modal-body
|
24
24
|
|
25
25
|
= turbo_frame_tag "custom-table-settings" do
|
@@ -32,11 +32,11 @@
|
|
32
32
|
= f.hidden_field "variant", value: variant
|
33
33
|
|
34
34
|
= f.simple_fields_for :fields do |sfi|
|
35
|
-
%div{data: {controller: "sortable", "
|
35
|
+
%div.custom-table-settings{data: {controller: "sortable", "sortable-handle-value": ".handle"}}
|
36
36
|
|
37
37
|
- items.each do |field, item|
|
38
38
|
-# = abort item.inspect
|
39
|
-
%div
|
39
|
+
%div.text-nowrap.overflow-x-hidden
|
40
40
|
%i.handle{style: "cursor: move", class: custom_table_move_icon_class}
|
41
41
|
.form-check.form-switch.d-inline-block
|
42
42
|
-# - if item[:appear] == :always
|