trk_datatables 0.2.8 → 0.2.13

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6bbcc94c87611e1aaa08588c6599df2c691192850905da3b981a69d908ffb981
4
- data.tar.gz: ac998b4e62500caf9be81419909a8c1d530f64c7737330c0fd4de22a40a082df
3
+ metadata.gz: dfebccd40ad802ae6e7e6beb1eebec9099f9ede5bf4ed4d2f6f9ed92a08a8f03
4
+ data.tar.gz: 0fcb0efd54b898d2d2aa68ff76c095293fa0b57abb48a37bd893aa59a676ff4e
5
5
  SHA512:
6
- metadata.gz: 2adca44aac667b274f31b374f2914a9499f2c37294ef3d308ac45fd0fd0da26e0545093d62c508d42b5c78638e181e10b1c1f3b252396c0ca8a5a952a54dd509
7
- data.tar.gz: c1b6ab154c81408296714795d68521135da81bb0ca5226b9407c600f824cc566333f1f022cbd088d71629be94d83494ab2c94d41d71c178a2034e94b697288fd
6
+ metadata.gz: fa204f488a45f055b602e9baf8504cd64e8a91404a69800588065fcabbfa5a85ce2ae9220751fdf7633facdfe1627a98bae33354eabfaf6c64e9053f20f6472a
7
+ data.tar.gz: ba2fbe421642ed72bff9e023b541c4321c56baa653f54f1ac372d3e7d43233691a7316040340ff20c94e1d4fab6ceb5ce314fe0efeadfa65240e2dee2042593e
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- trk_datatables (0.2.8)
4
+ trk_datatables (0.2.13)
5
5
  activesupport
6
6
 
7
7
  GEM
@@ -52,4 +52,4 @@ DEPENDENCIES
52
52
  trk_datatables!
53
53
 
54
54
  BUNDLED WITH
55
- 2.1.4
55
+ 2.2.15
data/README.md CHANGED
@@ -256,7 +256,7 @@ For specific columns you can use following keys
256
256
  * `order: false` disable ordering for this column
257
257
  * `select_options: Post.statuses` generate select box instead of text input
258
258
  * `predefined_ranges: {}` for datetime fiels add ranges to pick up from
259
- * `hide: true` hide column with display none
259
+ * `hide: true` hide column with display none, for example `{ hide: @view.params[:user_id].present? }`
260
260
  * `class_name: 'Admin::User'` use different class name than
261
261
  `table_name.classify` (in this case of `admin_users` will be `AdminUser`)
262
262
  * `column_type_in_db` one of the: `:string`, `:integer`, `:date`, `:datetime`,
@@ -332,7 +332,7 @@ def columns
332
332
  end
333
333
 
334
334
  # in view
335
- link_to 'Active', search_posts_path(PostsDatatable.param_set('posts.status':
335
+ link_to 'Active', search_posts_path(PostsDatatable.param_set('posts.status',
336
336
  Post.statues.values_at(:published, :promoted)))
337
337
  ```
338
338
 
@@ -531,6 +531,94 @@ class MostLikedPostsDatatable < TrkDatatables::ActiveRecord
531
531
  end
532
532
  ```
533
533
 
534
+ ### Table less models
535
+
536
+ You can use raw sql to fetch the data and use it as a model.
537
+ Here is an example when there is no relations to other models
538
+ ```
539
+ # app/models/table_less.rb
540
+ class TableLess < ApplicationRecord
541
+ self.abstract_class = true
542
+
543
+ def self.load_schema!
544
+ @columns_hash ||= {}
545
+
546
+ # From active_record/attributes.rb
547
+ attributes_to_define_after_schema_loads.each do |name, (type, options)|
548
+ type = ActiveRecord::Type.lookup(type, **options.except(:default)) if type.is_a?(Symbol)
549
+
550
+ define_attribute(name, type, **options.slice(:default))
551
+
552
+ # Improve Model#inspect output
553
+ @columns_hash[name.to_s] = ActiveRecord::ConnectionAdapters::Column.new(name.to_s, options[:default])
554
+ end
555
+ end
556
+ end
557
+ ```
558
+
559
+ ```
560
+ # app/models/translation.rb
561
+ class Translation < TableLess
562
+ self.table_name = :translations
563
+
564
+ attribute :translateable_type, :string, default: nil
565
+ attribute :translateable_id, :string, default: nil
566
+ attribute :column_name, :string, default: nil
567
+ attribute :column_value, :string, default: nil
568
+
569
+ belongs_to :translateable, polymorphic: true
570
+ end
571
+ ```
572
+
573
+ ```
574
+ # app/datatables/translations_datatable.rb
575
+ # rubocop:disable Layout/LineLength
576
+ class TranslationsDatatable < BaseDatatable
577
+ def columns
578
+ {
579
+ 'translations.translateable_id': {},
580
+ 'translations.translateable_type': {hide: true},
581
+ 'translations.column_name': {},
582
+ 'translations.column_value': {},
583
+ '': {},
584
+ }
585
+ end
586
+
587
+ def all_items
588
+ sql = <<~SQL.squish
589
+ (
590
+ (SELECT 'Activity' AS translateable_type, id AS translateable_id, 'name' AS column_name, name AS column_value FROM activities)
591
+ UNION
592
+ (SELECT 'Activity' AS translateable_type, id AS translateable_id, 'description' AS column_name, description AS column_value FROM activities)
593
+ ) as translations
594
+ SQL
595
+ Translation.from([Arel.sql(sql)])
596
+ end
597
+
598
+ def rows(filtered)
599
+ filtered.map do |translation|
600
+ edit_link = @view.button_tag_open_modal(
601
+ @view.edit_translation_path(translation.translateable_id, translateable_type: translation.translateable_type, column_name: translation.column_name), title: @view.t_crud('edit', Translation)
602
+ )
603
+ [
604
+ @view.link_to(translation.translateable, translation.translateable),
605
+ translation.translateable_type,
606
+ translation.column_name,
607
+ translation.column_value,
608
+ edit_link,
609
+ ]
610
+ end
611
+ end
612
+ end
613
+ # rubocop:enable Layout/LineLength
614
+ ```
615
+
616
+ For column title we use `table_class.human_attribute_name column_name`. When
617
+ calculated_ columns is used than it can not find translation so better is to:
618
+ ```
619
+ 'string_calculated_in_db.column_value_translated': {search: false, title: @view.t('activerecord.attributes.translation.column_value_translated')},
620
+ ```
621
+
534
622
  ### Default order and page length
535
623
 
536
624
  You can override default order (index and direction) and default page length so
@@ -552,12 +640,41 @@ class PostsDatatable
552
640
  end
553
641
  ```
554
642
 
643
+ ### Render html with additional css class and different DOM
644
+
645
+ To add additional styling to your datatable you can use `:class` option when you
646
+ are calling `@datatable.render_html url, options` for example
647
+
648
+ ```
649
+ <%= @datatable.render_html search_posts_path(format: :json), class: 'table-hover' %>
650
+ ```
651
+
652
+ Default [DOM](https://datatables.net/reference/option/dom) is
653
+ `<"trk-global-search-wrapper"f>rtp<"trk-move-up"il>` which includes global
654
+ **f**iltering, p**r**ocessing loader, **t**able search, **p**agination, table
655
+ **i**nformation and **l**ength changing control. To override you can use
656
+
657
+ ```
658
+ <%= @datatable.render_html search_posts_path(format: :json), 'data-datatable-dom': 'rt' %>
659
+ ```
660
+
555
661
  ### Params
556
662
 
557
663
  To set parameters that you can use for links to set column search value, use
558
664
  this `PostsDatatable.param_set 'users.email', 'my@email.com'`. For between
559
665
  search you can use range `Time.zone.today..(Time.zone.today + 1.year)` and for
560
- in multiple values use array `[Post.statuses[:draft]]`.
666
+ in multiple values use array `[Post.statuses[:draft]]`. Note that in Rails
667
+ `Time.zone.now.to_s` usually returns seconds ('23:59:59') but if you change
668
+ default format like in `config/initializers/time_formats.rb` with
669
+ `Time::DATE_FORMATS[:default] = '%d-%b-%Y %I:%M %p'` than range
670
+ `Time.zone.now.at_beginning_of_day..Time.zone.now.at_end_of_day` will not
671
+ include those at end of day since param will not include seconds ('23:59') so in
672
+ this case you can use range for strings
673
+ `Time.zone.now.at_beginning_of_day.to_s..Time.zone.now.at_end_of_day.to_s(:with_seconds)`
674
+ and config/initializers/time_formats.rb `Time::DATE_FORMATS[:with_seconds] = '%d-%b-%Y %I:%M:%S %p'`
675
+
676
+ (or use date `Time.zone.today..Time.zone.today` but that will not populate
677
+ datetime fields in dateRangePicker correctly)
561
678
 
562
679
  ```
563
680
  <%= link_to 'Active posts for my@email.com', \
@@ -573,6 +690,15 @@ in multiple values use array `[Post.statuses[:draft]]`.
573
690
  This will fill proper column search values so you do not need to do it manually
574
691
  (`post_path(:columns=>{"3"=>{:search=>{:value=>"my@email.com"}},
575
692
  "2"=>{:search=>{:value=>"1|2"}}}, :user_id=>1)`)
693
+ Please note that user_id is not inside datatable params so it will not be used
694
+ for next search params (all other search params are used with Datatables and
695
+ will remain on next search) so you need to manually add that param
696
+ ```
697
+ <%= @datatable.render_html search_posts_path(user_id: params[:user_id], format: :json) %>
698
+ ```
699
+
700
+ You can use generic name `params[:non_table_filter]` and split with colon
701
+ `user_id:123` but that is not needed.
576
702
 
577
703
  For form fields you can use similar helper that will return name which points to
578
704
  specific column, for example:
@@ -596,10 +722,39 @@ For global search you can use `[search][value]` for example
596
722
  <% end %>
597
723
  ```
598
724
 
599
- If you need, you can fetch params with this helper
725
+ If you need, you can fetch params with this helper and for example, show the
726
+ link for that record
600
727
 
601
728
  ```
602
- PostsDatatable.param_get('users.email', params)
729
+ if @datatable.param_get("locations.name").present? &&
730
+ (location = Location.find_by(name: @datatable.param_get("locations.name")))
731
+ page_description "For <a href='#{location_path(location)}'>#{location.name}</a>"
732
+ breadcrumb "Dashboard": dashboard_path, location.name => location_path(location), "Package Sales": nil
733
+ else
734
+ breadcrumb "Dashboard": dashboard_path, "Package Sales": nil
735
+ end
736
+ ```
737
+
738
+ For other filter params which are not in columns you can use non table params
739
+ ```
740
+ # on dashboard
741
+ <%= link_to 'Locations', isp_locations_path(non_table_filter: "reseller_operator_id:#{@reseller_operator.id}") %>
742
+
743
+ # on index
744
+ if params[:non_table_filter].present? &&
745
+ (reseller_operator = ResellerOperator.find(params[:non_table_filter].split(":").second))
746
+ page_description "For <a href='#{reseller_operator_path(reseller_operator)}'>#{reseller_operator.company_name}</a>"
747
+ breadcrumb 'Dashboard' => isp_dashboard_path, reseller_operator.company_name => reseller_operator_path(reseller_operator), 'Locations' => nil
748
+ else
749
+ breadcrumb 'Dashboard' => isp_dashboard_path, 'Locations' => nil
750
+ end
751
+
752
+ # in datatables
753
+ case @view.params[:non_table_filter].to_s.split(':').first
754
+ when 'reseller_operator_id'
755
+ reseller_operator = ResellerOperator.find @view.params[:non_table_filter].split(':').second
756
+ all_isp_locations = all_isp_locations.where(reseller_operator: reseller_operator)
757
+ end
603
758
  ```
604
759
 
605
760
  You can set filters on datatable even params are blank, for example
@@ -661,7 +816,9 @@ end
661
816
 
662
817
  You can use condition to provide different data, for example let's assume
663
818
  `@view.api_user?` returns true for json requests from mobile app. Here is
664
- example that provides different columns for normal and api_user:
819
+ example that provides different columns for normal and api_user.
820
+ Note that when you are using different columns for some reason in `@view` you
821
+ need to provide view in `param_set` so it can check the same conditionals.
665
822
 
666
823
  ```
667
824
  # app/datatables/posts_datatable.rb
@@ -671,8 +828,14 @@ class PostsDatatable < TrkDatatables::ActiveRecord
671
828
  end
672
829
 
673
830
  def columns_for_html
831
+ balance = @view.current_location
832
+ {}
833
+ else
834
+ { 'integer_calculated_in_db.balance_amount_in_cents': { search: false, title: 'Balance' } }
835
+ end
674
836
  {
675
837
  'subscribers.subscriberid': {},
838
+ **balance,
676
839
  'subscribers.name': {},
677
840
  }
678
841
  end
@@ -691,8 +854,14 @@ class PostsDatatable < TrkDatatables::ActiveRecord
691
854
 
692
855
  def rows_for_html(filtered)
693
856
  filtered.map do |subscriber|
857
+ balance = if Constant.STILL_WITH_OLD_CODE
858
+ []
859
+ else
860
+ [@view.humanized_money_with_symbol(Money.new(location.balance_amount_in_cents)) : 'NA']
861
+ end
694
862
  [
695
863
  @view.link_to(subscriber.subscriberid, subscriber),
864
+ *balance,
696
865
  subscriber.name,
697
866
  ]
698
867
  end
@@ -712,6 +881,10 @@ class PostsDatatable < TrkDatatables::ActiveRecord
712
881
  @view.api_user? ? columns_for_api : nil
713
882
  end
714
883
  end
884
+
885
+ # On some dashboard page provide @view using `self` to param_set
886
+ link_to 'Active', search_posts_path(PostsDatatable.param_set('posts.status',
887
+ :active, self))
715
888
  ```
716
889
 
717
890
  ## Test your datatables
@@ -87,12 +87,15 @@ module TrkDatatables
87
87
  # we do not need to cast from string since range will do automatically
88
88
  parsed_from = from
89
89
  parsed_to = to
90
- when :date, :datetime
90
+ when :date
91
+ parsed_from = _parse_in_zone(from).to_date
92
+ parsed_to = _parse_in_zone(to).to_date
93
+ when :datetime
91
94
  parsed_from = _parse_in_zone(from)
92
95
  parsed_to = _parse_in_zone(to)
93
- if parsed_to.present? && !to.match(/AM|PM/)
94
- # we need to add one day since it looks at begining of a day 2010-10-10 00:00:00
95
- parsed_to += 60 * 60 * 24 - 1
96
+ if parsed_to.present? && !to.match(/:/)
97
+ # Use end of a day if time is not defined, for example 2020-02-02
98
+ parsed_to = parsed_to.at_end_of_day
96
99
  end
97
100
  end
98
101
  [parsed_from, parsed_to]
@@ -241,10 +241,7 @@ module TrkDatatables
241
241
  'Last Month':
242
242
  Time.zone.today.prev_month.beginning_of_month.beginning_of_day...Time.zone.today.prev_month.end_of_month.end_of_day,
243
243
  'This Year': Time.zone.today.beginning_of_year.beginning_of_day...Time.zone.today.end_of_day,
244
- }.transform_values do |range|
245
- # datepicker expects format 2020-11-29 11:59:59
246
- range.first.strftime('%F %T')..range.last.strftime('%F %T')
247
- end
244
+ }
248
245
  end
249
246
  end
250
247
  end
@@ -13,8 +13,8 @@ module TrkDatatables
13
13
  # @example
14
14
  # link_to 'Published posts for user1',
15
15
  # posts_path(PostsDatatable.param_set('posts.status', :published).merge(user_id: user1.id))
16
- def param_set(column_key, value)
17
- datatable = new OpenStruct.new(params: {})
16
+ def param_set(column_key, value, view = nil)
17
+ datatable = new view || OpenStruct.new(params: {})
18
18
  value = value.join MULTIPLE_OPTION_SEPARATOR if value.is_a? Array
19
19
  value = [value.first, value.last].join BETWEEN_SEPARATOR if value.is_a? Range
20
20
  column_index = datatable.index_by_column_key column_key
@@ -172,7 +172,12 @@ module TrkDatatables
172
172
  # This is helper
173
173
  def _determine_string_type_cast # :nodoc:
174
174
  if defined?(::ActiveRecord::Base)
175
- DB_ADAPTER_STRING_TYPE_CAST[::ActiveRecord::Base.connection_config[:adapter].to_sym]
175
+ current_adapter = if ::ActiveRecord::Base.respond_to?(:connection_db_config)
176
+ ::ActiveRecord::Base.connection_db_config.configuration_hash[:adapter]
177
+ else
178
+ ::ActiveRecord::Base.connection_config[:adapter]
179
+ end
180
+ DB_ADAPTER_STRING_TYPE_CAST[current_adapter.to_sym]
176
181
  else
177
182
  'not_used'
178
183
  end
@@ -117,7 +117,7 @@ module TrkDatatables
117
117
  def param_get(column_index)
118
118
  @params.dig :columns, column_index.to_s, :search, :value
119
119
  rescue TypeError => e
120
- raise Error, e.message + '. Column search is in a format: { "columns": { "0": { "search": { "value": { "ABC" } } } } }'
120
+ raise Error, "#{e.message}. Column search is in a format: { \"columns\": { \"0\": { \"search\": { \"value\": { \"ABC\" } } } } }"
121
121
  end
122
122
 
123
123
  def self.sample_view_params(options = {})
@@ -4,7 +4,7 @@ module TrkDatatables
4
4
  def initialize(search_link, datatable, html_options = {})
5
5
  @search_link = search_link
6
6
  @datatable = datatable
7
- @html_options = html_options
7
+ @html_options = html_options.symbolize_keys
8
8
  self.class.indent = 0
9
9
  end
10
10
 
@@ -89,6 +89,7 @@ module TrkDatatables
89
89
  # for initial page load we do not have ability to show recordsTotal
90
90
  # https://github.com/trkin/trk_datatables_js/issues/1
91
91
  'data-datatable-total-length': @datatable.filtered_items_count,
92
+ 'data-datatable-dom': @html_options[:'data-datatable-dom'] || '<"trk-global-search-wrapper"f>rtp<"trk-move-up"il>',
92
93
  ) do
93
94
  thead << "\n".html_safe << tbody
94
95
  end +
@@ -1,3 +1,3 @@
1
1
  module TrkDatatables
2
- VERSION = '0.2.8'.freeze
2
+ VERSION = '0.2.13'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trk_datatables
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.8
4
+ version: 0.2.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dusan Orlovic
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-02-22 00:00:00.000000000 Z
11
+ date: 2021-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -220,7 +220,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
220
220
  - !ruby/object:Gem::Version
221
221
  version: '0'
222
222
  requirements: []
223
- rubygems_version: 3.0.8
223
+ rubygems_version: 3.2.15
224
224
  signing_key:
225
225
  specification_version: 4
226
226
  summary: Gem that simplify using datatables with Ruby on Rails and Sinatra.