custom_table 0.1.0

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 (48) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +210 -0
  3. data/Rakefile +8 -0
  4. data/app/assets/config/custom_table_manifest.js +1 -0
  5. data/app/assets/stylesheets/custom_table/application.scss +1 -0
  6. data/app/assets/stylesheets/custom_table/table.scss +89 -0
  7. data/app/controllers/concerns/custom_table_concern.rb +118 -0
  8. data/app/controllers/custom_table/application_controller.rb +4 -0
  9. data/app/controllers/custom_table/settings_controller.rb +86 -0
  10. data/app/helpers/custom_table/application_helper.rb +483 -0
  11. data/app/helpers/custom_table/fieldset_helper.rb +90 -0
  12. data/app/helpers/custom_table/icons_helper.rb +42 -0
  13. data/app/inputs/date_picker_input.rb +52 -0
  14. data/app/javascript/controllers/batch_actions_controller.js +53 -0
  15. data/app/javascript/controllers/table_controller.js +109 -0
  16. data/app/jobs/custom_table/application_job.rb +4 -0
  17. data/app/mailers/custom_table/application_mailer.rb +6 -0
  18. data/app/models/concerns/custom_table_settings.rb +42 -0
  19. data/app/models/custom_table/application_record.rb +5 -0
  20. data/app/views/custom_table/_download.haml +19 -0
  21. data/app/views/custom_table/_field.haml +8 -0
  22. data/app/views/custom_table/_field_plain.haml +1 -0
  23. data/app/views/custom_table/_fieldset.haml +2 -0
  24. data/app/views/custom_table/_filter.html.haml +104 -0
  25. data/app/views/custom_table/_settings.html.haml +57 -0
  26. data/app/views/custom_table/_table.html.haml +261 -0
  27. data/app/views/custom_table/_table.xlsx.axlsx +76 -0
  28. data/app/views/custom_table/_table_fe.xlsx.fast_excel +141 -0
  29. data/app/views/custom_table/_table_row.html.haml +72 -0
  30. data/app/views/custom_table/_table_row_data.html.haml +26 -0
  31. data/app/views/custom_table/settings/destroy.html.haml +4 -0
  32. data/app/views/custom_table/settings/edit.html.haml +2 -0
  33. data/app/views/custom_table/settings/update.html.haml +4 -0
  34. data/app/views/layouts/custom_table/application.html.erb +15 -0
  35. data/config/initializers/simple_form_bootstrap.rb +468 -0
  36. data/config/locales/en.yml +18 -0
  37. data/config/locales/ru.yml +18 -0
  38. data/config/routes.rb +5 -0
  39. data/lib/custom_table/configuration.rb +10 -0
  40. data/lib/custom_table/engine.rb +12 -0
  41. data/lib/custom_table/version.rb +3 -0
  42. data/lib/custom_table.rb +14 -0
  43. data/lib/generators/custom_table/USAGE +8 -0
  44. data/lib/generators/custom_table/custom_table_generator.rb +16 -0
  45. data/lib/generators/custom_table/templates/initializer.rb +3 -0
  46. data/lib/generators/custom_table/templates/migration.rb +5 -0
  47. data/lib/tasks/custom_table_tasks.rake +4 -0
  48. metadata +300 -0
@@ -0,0 +1,483 @@
1
+ module CustomTable
2
+ module ApplicationHelper
3
+
4
+ # MOVE TO GENERATED HELPER
5
+ # def boolean_icon(value, true_value = nil, false_value = nil)
6
+ # capture do
7
+ # concat content_tag(:i, "", class: (value ? "bi bi-check-lg text-success" : "bi bi-x-lg text-danger"), data: {raw: value})
8
+ # concat content_tag(:span, value ? true_value : false_value, class: "ms-1") unless true_value.nil?
9
+ # end
10
+ # end
11
+
12
+ def custom_table_form_for(record, options = {}, &block)
13
+ options[:url] = request.path if options[:url].nil?
14
+ options[:method] = :get
15
+
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
19
+
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
26
+ }
27
+
28
+ simple_form_for(record, options, &block)
29
+ end
30
+
31
+ def fields_table_for(collection, options = {}, &block); end
32
+
33
+ # Tries to fetch attribute value by all possible ways (by priority):
34
+ # Helper {singular_model_name}_{field}_field
35
+ # Helper {singular_model_name}_{field}
36
+ # Helper {singular_model_name}_{field}_raw
37
+ # Attribute of model
38
+ def field_value_for item, field, definitions: nil, variant: nil
39
+
40
+ defs = definitions
41
+
42
+ model_name = item.model_name.singular
43
+ global_model_name = item.class.model_name.singular # non-model
44
+
45
+ helpers = []
46
+ helpers += [defs[:helper]] if !defs.nil?
47
+
48
+ helpers += [
49
+ "#{model_name}_#{variant}_#{field}_field",
50
+ "#{model_name}_#{variant}_#{field}",
51
+ ] if !variant.nil?
52
+
53
+ helpers += [
54
+ "#{model_name}_#{field}_field",
55
+ "#{model_name}_#{field}",
56
+ "#{model_name}_#{field}_raw",
57
+ "#{global_model_name}_#{field}"
58
+ ]
59
+
60
+ if item.class.superclass.to_s != "ApplicationRecord"
61
+ super_model_name = item.class.superclass.model_name.singular
62
+ helpers += [
63
+ "#{super_model_name}_#{field}_field",
64
+ "#{super_model_name}_#{field}",
65
+ "#{super_model_name}_#{field}_raw",
66
+ ]
67
+ end
68
+
69
+ helpers = helpers.flatten.compact
70
+
71
+ helpers.each do |helper|
72
+ if self.class.method_defined?(helper)
73
+ if self.method(helper).arity == 1 || self.method(helper).arity == -2
74
+ return self.send(helper, item) || not_set
75
+ end
76
+ if self.method(helper).arity == 2
77
+ return self.send(helper, item, field) || not_set
78
+ end
79
+ end
80
+ end
81
+
82
+ if !defs.nil? && defs[:amount]
83
+ 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 ""
85
+ else
86
+ return amount(item.send(field)) rescue ""
87
+ end
88
+ else
89
+ if item.class.reflect_on_association(field)
90
+ return not_set if (item.send(field) rescue nil).nil?
91
+ return render(item.send(field)) rescue item.send(field).to_s rescue ""
92
+ elsif item.class.columns_hash[field.to_s] && item.class.columns_hash[field.to_s].type == :boolean
93
+ return boolean_icon(item.send(field)) rescue ""
94
+ elsif item.class.defined_enums.has_key?(field.to_s)
95
+ 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 ""
98
+ elsif item.class.columns_hash[field.to_s] && [:integer, :float, :decimal].include?(item.class.columns_hash[field.to_s].type)
99
+ return not_set if (item.send(field) rescue nil).nil?
100
+ return amount(item.send(field)) rescue ""
101
+ else
102
+ return (item.send(field).presence || not_set).to_s rescue ""
103
+ end
104
+ end
105
+
106
+ end
107
+
108
+ def custom_table_totals collection, fields, totals = {}, fields_totals = {}
109
+
110
+ out = {}
111
+ totals = {} if totals.nil?
112
+ fields_totals = {} if fields_totals.nil?
113
+
114
+ fields.keys.each do |field|
115
+
116
+ # We only work if field total is enabled explicitly with definition or totals
117
+ next if !fields[field][:total] && !totals.has_key?(field)
118
+
119
+ # Taking pre-defined value if available
120
+ if !totals[field].nil?
121
+ out[field] = totals[field]
122
+ else
123
+ model_class = collection.model
124
+ # Trying to find helper first
125
+ model_name = model_class.model_name.singular
126
+ helper = "#{model_name}_#{field}_total"
127
+
128
+ if self.class.method_defined?(helper)
129
+ # Better use helper!
130
+ out[field] = self.send(helper, collection.except(:limit, :offset, :order, :group))
131
+ else
132
+ if collection.respond_to?(:total_pages) && (!model_class.columns_hash[field.to_s].nil? || !fields[field][:total_scope].nil?)
133
+ # We can try to sum value from database
134
+
135
+ 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])
139
+ end
140
+ else
141
+ # Taking simple summed value because all data is shown
142
+ out[field] = fields_totals[field]
143
+ end
144
+
145
+ end
146
+
147
+ end
148
+ end
149
+
150
+ out
151
+
152
+ end
153
+
154
+ # Same as above but for Export only
155
+ def raw_field_value_for item, field, definitions: nil, variant: nil
156
+
157
+ defs = definitions
158
+
159
+ model_name = item.model_name.singular
160
+ global_model_name = item.class.model_name.singular
161
+
162
+ helpers = []
163
+
164
+ helpers += [
165
+ "#{model_name}_#{variant}_#{field}_field_raw",
166
+ "#{model_name}_#{variant}_#{field}_raw",
167
+ ] if !variant.nil?
168
+
169
+ helpers += [
170
+ "#{model_name}_#{field}_field_raw",
171
+ "#{model_name}_#{field}_raw",
172
+ "#{global_model_name}_#{field}_raw"
173
+ ]
174
+
175
+ if item.class.superclass.to_s != "ApplicationRecord"
176
+ super_model_name = item.class.superclass.model_name.singular
177
+ helpers += [
178
+ "#{super_model_name}_#{field}_field_raw",
179
+ "#{super_model_name}_#{field}_raw",
180
+ ]
181
+ end
182
+
183
+ helpers = helpers.flatten.compact
184
+
185
+ helpers.each do |helper|
186
+ return self.send(helper, item) if self.class.method_defined?(helper)
187
+ end
188
+
189
+ if !defs.nil? && defs[:amount]
190
+ return item.send(field) rescue nil
191
+ else
192
+ if item.class.reflect_on_association(field)
193
+ return item.send(field).to_s rescue nil
194
+ elsif item.class.columns_hash[field.to_s] && item.class.columns_hash[field.to_s].type == :boolean
195
+ return item.send(field) rescue nil
196
+ elsif item.class.defined_enums.has_key?(field.to_s)
197
+ return (item.send(field).presence) rescue nil
198
+ elsif item.class.columns_hash[field.to_s] && [:date, :datetime].include?(item.class.columns_hash[field.to_s].type)
199
+ return (item.send(field).presence) rescue nil
200
+ elsif item.class.columns_hash[field.to_s] && [:float, :decimal].include?(item.class.columns_hash[field.to_s].type)
201
+ return item.send(field).round(2) rescue nil
202
+ elsif item.class.columns_hash[field.to_s] && [:integer].include?(item.class.columns_hash[field.to_s].type)
203
+ return item.send(field) rescue nil
204
+ else
205
+ return (item.send(field).presence) rescue nil
206
+ end
207
+ end
208
+
209
+ end
210
+
211
+
212
+ # Returns list of fields to show in table according user settings
213
+ def custom_table_fields_for(model, variant: nil, current_search: {}, predefined_fields: nil, use_all_fields: false)
214
+
215
+ fields = []
216
+ current_search = {} if current_search.nil?
217
+
218
+ model_fields = custom_table_fields_definition_for(model, variant)
219
+
220
+ if (!predefined_fields.nil?)
221
+ out = {}
222
+ predefined_fields.each do |f|
223
+ out[f] = model_fields[f]
224
+ end
225
+ return out.compact
226
+ # return model_fields.select {|k,v| predefined_fields.include?(k) }
227
+ end
228
+
229
+ fields_key = model.model_name.to_s
230
+ fields_key += "-#{variant}" unless variant.nil?
231
+
232
+ s = custom_table_user_customized_fields_for(model, variant)
233
+
234
+ use_all_fields = true if params[:custom_table_use_all_fields]
235
+
236
+ if use_all_fields
237
+ selected_fields = model_fields.keys
238
+ else
239
+ if !s.nil?
240
+ # Use saved user settings for the model
241
+ always_selected_fields = model_fields.select { |x, y| [:always].include?(y[:appear]) || current_search.keys.include?(x.to_s) }.keys
242
+ always_selected_fields.each {|f| s = {"#{f.to_s}": true}.merge(s) if s[f].nil? }
243
+ selected_fields = s.select{|f,v| v }.keys
244
+ else
245
+ # Use default model settings
246
+ selected_fields = model_fields.select { |x, y| [:always, :default].include?(y[:appear]) || current_search.keys.include?(x.to_s) }.keys
247
+ end
248
+ end
249
+
250
+ # Filter selection again with model settings for sure
251
+ return selected_fields.collect{|f| [f, model_fields[f]]}.to_h
252
+
253
+ end
254
+
255
+ # Returns list of fields for customization form
256
+ def custom_table_fields_settings_for(model, variant: nil)
257
+
258
+ model_fields = custom_table_fields_definition_for(model, variant)
259
+ model_fields = model_fields.reject {|k,v| [:export, :never].include?(v[:appear]) }
260
+
261
+ fields_key = model.model_name.to_s
262
+ fields_key += "-#{variant}" unless variant.nil?
263
+
264
+ user_customization = custom_table_user_customized_fields_for(model, variant)
265
+
266
+ if !user_customization.nil?
267
+ # Add new fields at the top to user customization if not present
268
+ model_fields.each do |f, v|
269
+ next if !user_customization[f].nil?
270
+ selected = [:always, :default].include?(v[:appear])
271
+ new_field = {"#{f.to_s}": selected}
272
+ if selected
273
+ user_customization = new_field.merge(user_customization)
274
+ else
275
+ user_customization = user_customization.merge(new_field)
276
+ end
277
+ end
278
+ return user_customization.reject{|f,v| model_fields[f].nil?}.collect{|f,v| [f, {selected: v}.merge(model_fields[f])]}.to_h
279
+ else
280
+ # Use default model settings
281
+ # abort model_fields.transform_values!{|f| f[:selected] = true}.inspect
282
+ return model_fields.each{|k,f| f[:selected] = [:always, :default].include?(f[:appear])}
283
+ end
284
+
285
+
286
+ end
287
+
288
+ # Prepares object of user fields customization
289
+ def custom_table_user_customized_fields_for(model, variant = nil)
290
+ fields_key = custom_table_fields_key(model, variant)
291
+ defs = custom_table_fields_definition_for(model, variant)
292
+ return nil if current_user.nil? || current_user.custom_table.nil? || current_user.custom_table.dig(fields_key, :fields).nil?
293
+ return current_user.custom_table.dig(fields_key, :fields).symbolize_keys.reject{|k,v| defs[k.to_sym].nil?}
294
+
295
+ end
296
+
297
+ # Prepares object of user search customization
298
+ def custom_table_user_customization_for(model, variant = nil)
299
+ fields_key = custom_table_fields_key(model, variant)
300
+ return nil if current_user.nil? || current_user.custom_table.nil?
301
+ return current_user.custom_table[fields_key]&.symbolize_keys
302
+ end
303
+
304
+ def custom_table_fields_key(model, variant = nil)
305
+ fields_key = model.model_name.to_s
306
+ fields_key += "-#{variant}" unless variant.nil?
307
+ return fields_key
308
+ end
309
+
310
+ def custom_table_customizable_fields_for(model, variant = nil)
311
+ model_fields = custom_table_fields_definition_for(model, variant)
312
+ model_fields.reject {|k,v| [:always, :export, :never].include?(v[:appear]) }
313
+ end
314
+
315
+ # Base definition for model
316
+ def custom_table_fields_definition_for(model, variant = nil)
317
+ helper_name = "#{model.model_name.singular}_custom_table_fields"
318
+ 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}"
320
+ end
321
+
322
+ if variant.nil? || method(helper_name).parameters.empty?
323
+ defs = self.send("#{helper_name}")
324
+ else
325
+ defs = self.send("#{helper_name}", variant)
326
+ end
327
+
328
+ return defs.each{|x,y| y[:label] = model.human_attribute_name(x) if y[:label].nil? }
329
+ end
330
+
331
+ # Base definition for model
332
+ def custom_table_fields_definition_for_field(model, field, variant = nil)
333
+ helper_name = "#{model.model_name.singular}_custom_table_fields"
334
+ if (! self.class.method_defined?(helper_name))
335
+ raise "#{helper_name} helper is not defined so we do not know how to render custom_table for #{model}"
336
+ end
337
+ if variant.nil? || method(helper_name).parameters.empty?
338
+ defs = self.send("#{helper_name}")
339
+ else
340
+ defs = self.send("#{helper_name}", variant)
341
+ end
342
+ return nil if defs[field].nil?
343
+ defs[:label] = model.human_attribute_name(field) if defs[:label].nil?
344
+ return defs
345
+ end
346
+
347
+
348
+ # Returns true if model can be customized by current user at least by one field
349
+ def current_user_has_customizable_fields_for?(model, variant=nil)
350
+ return false if current_user.nil?
351
+ custom_table_customizable_fields_for(model, variant).count.positive?
352
+ end
353
+
354
+ def custom_table_data collection, variant=nil, **params
355
+
356
+ params[:collection] = collection
357
+ params[:variant] = variant
358
+ params[:paginate] = true if params[:paginate]!=false
359
+ params[:last_page] = true if params[:last_page]!=false
360
+ 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
+ params[:modal_edit] = true if params[:modal_edit].nil?
363
+
364
+ render "custom_table/table", params do
365
+ yield
366
+ end
367
+ end
368
+
369
+ # Data for updating values via turbo according object id and field name
370
+ def custom_table_row_data item, variant = nil, **params
371
+
372
+ params[:item] = item
373
+ params[:variant] = variant
374
+ params[:namespace] = (controller.class.module_parent == Object) ? nil : controller.class.module_parent.to_s.underscore.to_sym
375
+
376
+ render "custom_table/table_row_data", params do
377
+ yield
378
+ end
379
+ end
380
+
381
+ def custom_table_filter search_model, variant=nil, **params, &block
382
+
383
+ params[:search_model] = search_model
384
+ params[:variant] = variant
385
+ render "custom_table/filter", params do |f|
386
+ yield if !block.nil?
387
+ end
388
+ end
389
+
390
+ # Rounded
391
+ def amount_round(c)
392
+ content_tag(:span, amount_value(c, 0), "data-raw": (c.blank? ? nil : c.round))
393
+ end
394
+
395
+ # Base
396
+ def amount(c)
397
+ content_tag(:span, amount_value(c), "data-raw": (c.blank? ? nil : c.round(2)))
398
+ end
399
+
400
+ # Abstract
401
+ def amount_value(c, p = 2)
402
+ number_to_currency(c, precision: p, locale: :en, unit: "")
403
+ end
404
+
405
+ # Colored
406
+ def amount_color(c)
407
+ content_tag(:span, amount(c), class: ["amount", (c.to_f >= 0 ? "positive" : "negative")])
408
+ end
409
+
410
+ # Colored rounded
411
+ def amount_round_color(c)
412
+ content_tag(:span, amount_round(c), class: ["amount", (c.to_f >= 0 ? "positive" : "negative")])
413
+ end
414
+
415
+ def custom_table_download_button collection, **p
416
+ p[:collection] = collection
417
+ p[:downloads] ||= {}
418
+ p[:downloads].unshift({title: t("custom_table.download_as_csv"), href: params.permit!.merge({:format => :csv})}) if p[:csv]
419
+ render "custom_table/download", p
420
+ end
421
+
422
+ def custom_table_settings search_model, variant=nil, **params
423
+
424
+ params[:search_model] = search_model
425
+ params[:variant] = variant
426
+
427
+ render "custom_table/settings", params
428
+
429
+ end
430
+
431
+ def custom_table_settings_button search_model, variant=nil, size: "sm"
432
+ link_to custom_table.edit_setting_path(search_model.model_name, variant: variant), :class => "btn btn-outline-primary btn-#{size}", data: {"turbo-frame": "remote-modal"} do
433
+ custom_table_settings_icon
434
+ end
435
+ end
436
+
437
+ def custom_table_variants_for model
438
+ helper_name = "#{model.model_name.singular}_custom_table_variants"
439
+ return self.send(helper_name) if self.class.method_defined?(helper_name)
440
+ return []
441
+ end
442
+
443
+ def tree_opener item_id, has_children=false, expanded=false
444
+ content_tag :span, class: "tree-opener #{expanded ? 'opened' : ''}", data: {action: (has_children ? "click->table#toggle" : ""), "table-css-param": ".child-of-#{item_id}"} do
445
+ concat content_tag(:span, (has_children ? "▶" : "▷"), class: "closed")
446
+ concat content_tag(:span, "▼", class: "opened")
447
+ end
448
+ end
449
+
450
+ def custom_table_fields_totals fields:, totals:, item:, fields_totals:, variant:
451
+ fields.each do |field, defs|
452
+ if !totals.nil? && totals.has_key?(field) && totals[field].nil? # Auto-counting
453
+ fields_totals[field] = 0 if fields_totals[field].nil?
454
+ fields_totals[field] += raw_field_value_for(item, field, definitions: defs, variant: variant).to_f rescue 0
455
+ end
456
+ end
457
+ return fields_totals
458
+ end
459
+
460
+ def custom_table_batch_selector_check_box item, **params
461
+
462
+ # abort params.inspect
463
+
464
+ params[:param] = "#{item.model_name.plural}[]" if params[:param].nil?
465
+ params[:data] = {"toggle-target": "checkbox", "batch-actions-target": "checkbox", "action": "toggle#recalculateToggler batch-actions#refresh"}
466
+
467
+ check_box_tag params[:param], item.id, (!params[item.model_name.plural.to_sym].blank?) && (params[item.model_name.plural.to_sym].include?(item.id.to_s)), params
468
+ end
469
+
470
+ # Gets array of fields and results in object of available fields and definitions from fields from list
471
+ def custom_table_fields_list_to_definitions model, fields
472
+ d = custom_table_fields_definition_for(model)
473
+ out = {}
474
+ fields.each do |f|
475
+ found = d.find {|k, v| k == f }
476
+ out[f] = found[1] if !found.nil?
477
+ end
478
+ return out
479
+ end
480
+
481
+ end
482
+
483
+ end
@@ -0,0 +1,90 @@
1
+ module CustomTable
2
+
3
+ module FieldsetHelper
4
+
5
+ class FieldsetBuilder
6
+
7
+ def initialize(object, template, **params)
8
+ @object = object
9
+ @template = template
10
+ @params = params
11
+ end
12
+
13
+ def has_editable?
14
+ @template.respond_to?(:editable)
15
+ end
16
+
17
+ def field column, **params, &block
18
+
19
+ defs = custom_table_fields_definition_for_field(@object.class, column) rescue nil
20
+
21
+ params = {} if params.nil?
22
+ params = params.deep_merge(@params)
23
+ params[:editable] = true if params[:editable].nil?
24
+ params[:adaptive] = false if params[:adaptive].nil?
25
+
26
+ if params[:label].nil?
27
+ if !defs.nil? && !defs[:label].blank?
28
+ params[:label] = defs[:label].nil?
29
+ else
30
+ params[:label] = @object.class.human_attribute_name(column)
31
+ end
32
+ end
33
+
34
+ params[:template] = "field" if params[:template].nil?
35
+ params[:column] = column
36
+ params[:object] = @object
37
+
38
+ hint_key = "simple_form.hints.#{@object.model_name.singular}.#{column}"
39
+ if I18n.exists?(hint_key)
40
+ params[:hint] = I18n.t(hint_key)
41
+ end
42
+
43
+ @template.render "custom_table/#{params[:template]}", **params do
44
+ if params[:editable] && has_editable?
45
+ params[:editable_params] = {} if params[:editable_params].nil?
46
+ editable_field = params[:editable_params][:field] || column
47
+ @template.editable @object, editable_field, **params[:editable_params] do
48
+ if block_given?
49
+ yield
50
+ else
51
+ @template.field_value_for(@object, column)
52
+ end
53
+ end
54
+ else
55
+ if block_given?
56
+ yield
57
+ else
58
+ @template.field_value_for(@object, column)
59
+ end
60
+ end
61
+
62
+ end
63
+ end
64
+
65
+ end
66
+
67
+ def fieldset object=nil, **params, &block
68
+
69
+ builder = FieldsetBuilder.new(object, self, **params)
70
+ output = capture(builder, &block)
71
+
72
+ render "custom_table/fieldset" do
73
+ output
74
+ end
75
+
76
+ end
77
+
78
+ def field object, column, **params, &block
79
+
80
+ params[:template] = "field_plain"
81
+
82
+ builder = FieldsetBuilder.new(object, self, **params)
83
+
84
+ builder.field(column, **params, &block)
85
+
86
+ end
87
+
88
+ end
89
+
90
+ end
@@ -0,0 +1,42 @@
1
+ module CustomTable
2
+
3
+ module IconsHelper
4
+
5
+ def custom_table_download_icon
6
+ return custom_table_icon("fa fa-download") if CustomTable.configuration.icons_framework == :fa
7
+ return custom_table_icon("bi bi-download") if CustomTable.configuration.icons_framework == :bi
8
+ end
9
+
10
+ def custom_table_settings_icon
11
+ return custom_table_icon("fa fa-cog") if CustomTable.configuration.icons_framework == :fa
12
+ return custom_table_icon("bi bi-gear") if CustomTable.configuration.icons_framework == :bi
13
+
14
+ end
15
+
16
+ def custom_table_move_icon_class
17
+ return "fa fa-sort" if CustomTable.configuration.icons_framework == :fa
18
+ return "bi bi-arrow-down-up" if CustomTable.configuration.icons_framework == :bi
19
+ end
20
+
21
+ def custom_table_tree_child_icon_class
22
+ return "fa fa-arrow-right" if CustomTable.configuration.icons_framework == :fa
23
+ return "bi bi-arrow-return-right" if CustomTable.configuration.icons_framework == :bi
24
+ end
25
+
26
+ def custom_table_cancel_icon
27
+ return custom_table_icon("fa fa-ban") if CustomTable.configuration.icons_framework == :fa
28
+ return custom_table_icon("bi bi-slash-circle") if CustomTable.configuration.icons_framework == :bi
29
+ end
30
+
31
+ def custom_table_search_icon
32
+ return custom_table_icon("fa fa-search") if CustomTable.configuration.icons_framework == :fa
33
+ return custom_table_icon("bi bi-search") if CustomTable.configuration.icons_framework == :bi
34
+ end
35
+
36
+ def custom_table_icon c
37
+ return content_tag(:i, "", class: c)
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,52 @@
1
+ class DatePickerInput < SimpleForm::Inputs::StringInput
2
+ def input(wrapper_options)
3
+ set_html_options
4
+ set_value_html_option
5
+
6
+ classes = ["input-group"]
7
+
8
+ input_html_options[:data] ||= {}
9
+ input_html_options[:data]["controller"] = "flatpickr"
10
+
11
+ picker_options = (options[:picker] || {}).merge!(flatpickr_options)
12
+
13
+ picker_options.each do |k, v|
14
+ input_html_options[:data]["flatpickr-#{k}-value"] = v
15
+ end
16
+
17
+ input_html_options[:data]["flatpickr-locale-value"] = I18n.locale
18
+
19
+ classes.push("input-group-sm") if input_html_options[:class].include? "input-sm"
20
+
21
+ # template.content_tag :div, class: classes do
22
+ input = super(wrapper_options) # leave StringInput do the real rendering
23
+ # end
24
+ end
25
+
26
+ def input_html_classes
27
+ super.push '' # 'form-control'
28
+ end
29
+
30
+ private
31
+
32
+ def set_html_options
33
+ input_html_options[:type] = 'text'
34
+ input_html_options[:data] ||= {}
35
+ end
36
+
37
+ def set_value_html_option
38
+ # return unless value.present?
39
+ # input_html_options[:value] ||= I18n.localize(value, format: display_pattern)
40
+ end
41
+
42
+ def value
43
+ v = object.send(attribute_name) if object.respond_to?(attribute_name) || object.is_a?(Ransack::Search)
44
+ v = v.to_date if v.is_a?(String)
45
+ v
46
+ end
47
+
48
+ def flatpickr_options
49
+ {}
50
+ end
51
+
52
+ end