custom_table 0.1.0 → 1.0.10

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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -3
  3. data/Rakefile +0 -0
  4. data/app/assets/config/custom_table_manifest.js +0 -0
  5. data/app/assets/stylesheets/custom_table/application.scss +0 -0
  6. data/app/assets/stylesheets/custom_table/table.scss +52 -1
  7. data/app/controllers/concerns/custom_table_concern.rb +0 -0
  8. data/app/controllers/custom_table/application_controller.rb +0 -0
  9. data/app/controllers/custom_table/settings_controller.rb +2 -0
  10. data/app/helpers/custom_table/application_helper.rb +71 -20
  11. data/app/helpers/custom_table/fieldset_helper.rb +5 -4
  12. data/app/helpers/custom_table/icons_helper.rb +5 -0
  13. data/app/inputs/date_picker_input.rb +0 -0
  14. data/app/javascript/controllers/batch_actions_controller.js +34 -10
  15. data/app/javascript/controllers/table_controller.js +0 -0
  16. data/app/jobs/custom_table/application_job.rb +0 -0
  17. data/app/mailers/custom_table/application_mailer.rb +0 -0
  18. data/app/models/concerns/custom_table_settings.rb +1 -1
  19. data/app/models/custom_table/application_record.rb +0 -0
  20. data/app/views/custom_table/_download.haml +0 -0
  21. data/app/views/custom_table/_field.haml +0 -0
  22. data/app/views/custom_table/_field_plain.haml +0 -0
  23. data/app/views/custom_table/_fieldset.haml +0 -0
  24. data/app/views/custom_table/_filter.html.haml +21 -11
  25. data/app/views/custom_table/_settings.html.haml +3 -3
  26. data/app/views/custom_table/_table.html.haml +52 -21
  27. data/app/views/custom_table/_table.xlsx.axlsx +0 -0
  28. data/app/views/custom_table/_table_fe.xlsx.fast_excel +0 -0
  29. data/app/views/custom_table/_table_row.html.haml +16 -4
  30. data/app/views/custom_table/_table_row_data.html.haml +0 -0
  31. data/app/views/custom_table/settings/destroy.html.haml +0 -0
  32. data/app/views/custom_table/settings/edit.html.haml +0 -0
  33. data/app/views/custom_table/settings/update.html.haml +0 -0
  34. data/app/views/kaminari/bootstrap-5/_first_page.html.haml +3 -0
  35. data/app/views/kaminari/bootstrap-5/_last_page.html.haml +3 -0
  36. data/app/views/kaminari/bootstrap-5/_next_page.html.haml +3 -0
  37. data/app/views/kaminari/bootstrap-5/_paginator.html.haml +14 -0
  38. data/app/views/kaminari/bootstrap-5/_prev_page.haml.haml +3 -0
  39. data/app/views/layouts/custom_table/application.html.erb +0 -0
  40. data/config/initializers/simple_form_bootstrap.rb +21 -317
  41. data/config/locales/en.yml +8 -0
  42. data/config/locales/ru.yml +9 -0
  43. data/config/routes.rb +0 -0
  44. data/lib/custom_table/configuration.rb +12 -0
  45. data/lib/custom_table/engine.rb +0 -0
  46. data/lib/custom_table/version.rb +1 -1
  47. data/lib/custom_table.rb +0 -0
  48. data/lib/generators/custom_table/USAGE +0 -0
  49. data/lib/generators/custom_table/custom_table_generator.rb +0 -0
  50. data/lib/generators/custom_table/templates/initializer.rb +0 -0
  51. data/lib/generators/custom_table/templates/migration.rb +0 -0
  52. data/lib/tasks/custom_table_tasks.rake +0 -0
  53. metadata +25 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56a21b7978279adb93168f5879fbf85c9953cd90561b3eaffe12fb834039311c
4
- data.tar.gz: 5ea82cf638892d34ed8c5dab7dd30c9b4c9d6ea5eacaf954acaa874131dd62dd
3
+ metadata.gz: 1c8f1b7e32b3824da237f2ece73cbbcfcc8c68ddad60f85be8181a3b8f94b10f
4
+ data.tar.gz: 8908567c65f9dd6bc0fff9ff5a7a49178027169a6102d0f1fa7199c9912947b2
5
5
  SHA512:
6
- metadata.gz: f0bbd84de0dcd118e79935abf955dc93ddd3161a4871321945644bdf0ce04b14f5705f93e81e68f97f73d602f4ca0fad55dbabcacc06fa10c76501200d619d22
7
- data.tar.gz: d3ce8670c0d36f426f129a44a541932210986438657c1eeaaf76c7fe2ebca5f389c2ae958d4b6eb9b5d1d3bfb8d3b75fd2dde19a4413006265ae40136292ca7a
6
+ metadata.gz: b02a3f91be2c8ce188f0a2fb761e86e8ac0d71491858ce2e80aec9677d79a4da0296dd8b9ac9aaaa241b66edcd2da337d3670e952a490764dad28f5f52c9b712
7
+ data.tar.gz: af112016401e8f59038bc3a20e684f96c94d4fd97d260a4c7726ad1c1aa5ed5319188c867bae62310de162bc1f1cc1c00291d8dfd010f01cc8ce50f3fc9065a9
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: rspec
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
- border: 2px solid rgb(26, 179, 26) !important;
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
@@ -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-md-auto g-3 align-items-center custom-table-filter"
18
- options[:wrapper] = options[:wrapper] || :inline_form
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: :inline_boolean,
22
- check_boxes: :vertical_collection,
23
- radio_buttons: :vertical_collection,
24
- date: :inline_element,
25
- select: :inline_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
- return amount_value(item.send(field), 0) rescue ""
86
+ # Integer only
87
+ return amount_value(val, 0) rescue ""
85
88
  else
86
- return amount(item.send(field)) rescue ""
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, :datetime].include?(item.class.columns_hash[field.to_s].type)
97
- return (item.send(field).blank? ? not_set : l(item.send(field), format: :short)) rescue ""
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
- return (item.send(field).presence || not_set).to_s rescue ""
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
- raise "#{helper_name} helper is not defined so we do not know how to render custom_table for #{model}"
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].nil?
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
- this.formTarget.querySelectorAll('input[name="'+this.checkboxTargets[0].getAttribute("name")+'"]').forEach((cb) => {
23
- cb.parentNode.removeChild(cb)
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
- let input = document.createElement('input');
32
- input.setAttribute('name', cb.getAttribute("name"));
33
- input.setAttribute('value', cb.getAttribute("value"));
34
- input.setAttribute('type', "hidden")
35
-
36
- this.formTarget.appendChild(input);//append the input to the form
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
- this.formTarget.querySelector('input[type="submit"]').disabled = !v
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
@@ -3,7 +3,7 @@ module CustomTableSettings
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- serialize :custom_table
6
+ serialize :custom_table, coder: YAML
7
7
  end
8
8
 
9
9
  def save_custom_table_settings model_class, variant = nil, fields: nil, sorts: nil, per_page: nil
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,6 +1,6 @@
1
- .card
1
+ %div{class: CustomTable.configuration.filter_outer_wrapper_class}
2
2
 
3
- .card-body.bg-light
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-12
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-bs-dismiss="modal" aria-label="close")
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", "data-sortable-handle-value": ".handle"}, style: "columns: #{columns}"}
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