datagrid 2.0.7 → 2.0.9

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: 9d7cb9f6ca20bf850b830352d5acedd8b71c33cd344b27a2ad87ae6a9f78d58f
4
- data.tar.gz: a6261913da93d1c8e1a875ff1b98efb907e015af43f03603ba4c40d48bca8c30
3
+ metadata.gz: 7592d1dfa05d5c24e010e0e92ee7d5cf8851b374e2857ea3e26f081640fbaf3d
4
+ data.tar.gz: 13620861647c6fdc672666f323454b0af81070ad240554a2767d105125e7de16
5
5
  SHA512:
6
- metadata.gz: 4e20609d434f571ba4fcec92f821fd2bf6a9e4995629fd0a3702562d3b2dbd06f647dbac9104cdf45d37a11b622e7d64012f160348493e0f70ab5972900e9a9b
7
- data.tar.gz: e16a562a395b43cd36da74635ec61bc4b4c800f7b68d64e2e4dfd4713ac6c3bd9fe1b64d9ccb44ba03ae44dbb264c919a03c6e94f7e05f5fa9ae61ac4baa1bee
6
+ metadata.gz: 75f9d5b8a61c198427fdda8a4aa21dcb1da83a8c6e5f26b987b6f2d22d05ed0fdc63d3cd592659cec6ff7d9da1f0a5e48c834d6aab03aad56d21f33b186cd6a7
7
+ data.tar.gz: 37427086dc281ed3809c4b2e05cb047f60e4ca7069da6483c662c13b95528cf1a859e39226adfe8e06ede455ab559fead8a61cdd9dd64869cf0a892fa6177c05
data/CHANGELOG.md CHANGED
@@ -1,5 +1,51 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.0.9]
4
+
5
+ * Use new Rails 7.1 `locals` notation in ERB partials.
6
+ * The `FormBuilder#datagrid_filter_input` method now accepts `select_choices` and `select_options` options for the `select` tag.
7
+ * Rename the `Datagrid#select_options` method to `#select_choices`.
8
+ * Added a partial for the dynamic filter allowing to customize the UI [#347](https://github.com/bogdan/datagrid/pull/347).
9
+
10
+
11
+ ``` erb
12
+ <%# locals: (filter:, form:, field_options:, operation_options:, value_options:) -%>
13
+
14
+ <%= form.datagrid_filter_input(
15
+ filter,
16
+ **field_options,
17
+ class: [*field_options[:class], "datagrid-dynamic-field"]
18
+ ) %>
19
+
20
+ <%= form.datagrid_filter_input(
21
+ filter,
22
+ **operation_options,
23
+ class: [*operation_options[:class], "datagrid-dynamic-operation"]
24
+ ) %>
25
+
26
+ <%= form.datagrid_filter_input(
27
+ filter,
28
+ **value_options,
29
+ class: [*value_options[:class], "datagrid-dynamic-value"]
30
+ ) %>
31
+ ```
32
+
33
+ ## [2.0.8]
34
+
35
+ * Rescue StatementInvalid when guessing column type from a query
36
+ * Prevent typecasting of date into timestamp when `:date` filter has a block
37
+
38
+ ``` ruby
39
+ class MyGrid < Datagrid::Base
40
+ scope { User }
41
+
42
+ filter(:created_at, :date) do |scope, value|
43
+ value.is_a?(Date) # => true
44
+ scope.joins(:registration).where(registrations: { registration_date: value })
45
+ end
46
+ end
47
+ ```
48
+
3
49
  ## [2.0.7]
4
50
 
5
51
  * Raise `Datagrid::ConfigurationError` when column or filter name
@@ -0,0 +1,19 @@
1
+ <%# locals: (filter:, form:, field_options:, operation_options:, value_options:) -%>
2
+
3
+ <%= form.datagrid_filter_input(
4
+ filter,
5
+ **field_options,
6
+ class: [*field_options[:class], "datagrid-dynamic-field"]
7
+ ) %>
8
+
9
+ <%= form.datagrid_filter_input(
10
+ filter,
11
+ **operation_options,
12
+ class: [*operation_options[:class], "datagrid-dynamic-operation"]
13
+ ) %>
14
+
15
+ <%= form.datagrid_filter_input(
16
+ filter,
17
+ **value_options,
18
+ class: [*value_options[:class], "datagrid-dynamic-value"]
19
+ ) %>
@@ -1,3 +1,4 @@
1
+ <%# locals: (form:, elements:, choices:, filter:, options: {}) -%>
1
2
  <%#
2
3
  Indent in this file may cause extra space to appear.
3
4
  You can add indent if whitespace doesn't matter for you
@@ -1,3 +1,4 @@
1
+ <%# locals: (grid:, options: {}) -%>
1
2
  <%= form_with model: grid, html: {class: 'datagrid-form'}, scope: grid.param_name, method: :get, **options do |f| %>
2
3
  <% grid.filters.each do |filter| %>
3
4
  <div class="datagrid-filter" data-filter="<%= filter.name %>" data-type="<%= filter.type %>">
@@ -1,7 +1,8 @@
1
+ <%# locals: (grid:, options: {}) -%>
1
2
  <tr>
2
3
  <% grid.html_columns(*options[:columns]).each do |column| %>
3
4
  <%= tag.th(
4
- # Consider maintaining consistency with datagrid/rows partial
5
+ # Consider maintaining consistency with datagrid/row partial
5
6
  "data-column": column.name,
6
7
  **column.tag_options,
7
8
  class: [
@@ -1,3 +1,4 @@
1
+ <%# locals: (grid:, column:) -%>
1
2
  <div class="order">
2
3
  <%= link_to(
3
4
  I18n.t("datagrid.table.order.asc").html_safe,
@@ -1,3 +1,4 @@
1
+ <%# locals: (form:, filter:, from_options: {}, to_options: {}) -%>
1
2
  <%= form.datagrid_filter_input(filter, class: 'datagrid-range-from', **from_options) %>
2
3
  <span class="datagrid-range-separator"><%= I18n.t('datagrid.filters.range.separator') %></span>
3
4
  <%# Generating id only for "from" input to make sure -%>
@@ -1,8 +1,9 @@
1
+ <%# locals: (grid:, asset:, options: {}) -%>
1
2
  <tr>
2
3
  <% grid.html_columns(*options[:columns]).each do |column| %>
3
4
  <%= tag.td(
4
5
  datagrid_value(grid, column, asset),
5
- # Consider maintaining consistency with datagrid/rows partial
6
+ # Consider maintaining consistency with datagrid/head partial
6
7
  "data-column": column.name,
7
8
  **column.tag_options,
8
9
  class: [
@@ -1,9 +1,4 @@
1
- <%#
2
- Local variables:
3
- * grid - instance of Datagrid
4
- * assets - Array of database Entities
5
- * options - passed options Hash
6
- %>
1
+ <%# locals: (grid:, assets:, options: {}) -%>
7
2
  <% if grid.html_columns(*options[:columns]).any? %>
8
3
  <%= tag.table class: 'datagrid-table', **options.fetch(:html, {}) do %>
9
4
  <thead>
@@ -265,11 +265,13 @@ module Datagrid
265
265
  # @param block [Block] proc to calculate a column value
266
266
  # @option options [Boolean, String] html Determines if the column should be present
267
267
  # in the HTML table and how it is formatted.
268
- # @option options [String, Array<Symbol>] order Determines if the column can be sortable and
268
+ # @option options [String, Array<Symbol>, Proc] order Determines if the column can be sortable and
269
269
  # specifies the ORM ordering method.
270
270
  # Example: `"created_at, id"` for ActiveRecord, `[:created_at, :id]` for Mongoid.
271
- # @option options [String] order_desc Specifies a descending order for the column
272
- # (used when `:order` cannot be easily reversed by the ORM).
271
+ # Can be a Proc accepting a scope argument and returning a scope with applied order
272
+ # @option options [String, Array<Symbol>, Proc] order_desc Specifies a descending order for the column.
273
+ # See `order` option for context.
274
+ # Used when `:order` cannot be easily reversed by the ORM.
273
275
  # @option options [Boolean, Proc] order_by_value Enables Ruby-level ordering for the column.
274
276
  # Warning: Sorting large datasets in Ruby is not recommended.
275
277
  # If `true`, Datagrid orders by the column value.
@@ -277,8 +279,8 @@ module Datagrid
277
279
  # @option options [Boolean] mandatory If `true`, the column will never be hidden by the `#column_names` selection.
278
280
  # @option options [Symbol] before Places the column before the specified column when determining order.
279
281
  # @option options [Symbol] after Places the column after the specified column when determining order.
280
- # @option options [Boolean, Proc] if conditions when a column is available.
281
- # @option options [Boolean, Proc] unless conditions when a column is not available.
282
+ # @option options [Symbol, Proc] if conditions when a column is available, can be a method name or a proc with grid argument returning `Boolean`.
283
+ # @option options [Symbol, Proc] unless conditions when a column is not available, can be a method name or a proc with grid argument returning `Boolean`.
282
284
  # @option options [Symbol, Array<Symbol>] preload Specifies associations
283
285
  # to preload for the column within the scope.
284
286
  # @option options [Hash] tag_options Specifies HTML attributes for the `<td>` or `<th>` of the column.
@@ -86,22 +86,32 @@ module Datagrid
86
86
  scope.where("#{field} #{contains_predicate} ?", "%#{value}%")
87
87
  end
88
88
 
89
+ def builtin_type(scope, field)
90
+ if scope_has_column?(scope, field)
91
+ scope.columns_hash[field.to_s].type
92
+ else
93
+ begin
94
+ scope.connection.select_all(
95
+ scope.unscope(:select, :order).select(field => "custom_field").limit(0).arel
96
+ ).column_types['custom_field']&.type
97
+ rescue ActiveRecord::StatementInvalid
98
+ nil
99
+ end
100
+ end
101
+ end
102
+
89
103
  def normalized_column_type(scope, field)
90
- builtin_type = scope_has_column?(scope, field) ?
91
- scope.columns_hash[field.to_s].type :
92
- scope.connection.select_all(
93
- scope.unscope(:select, :order).select(field => "custom_field").limit(0).arel
94
- ).column_types['custom_field']&.type
95
-
96
- {
97
- %i[string text time binary] => :string,
98
- %i[integer primary_key] => :integer,
99
- %i[float decimal] => :float,
100
- [:date] => :date,
101
- %i[datetime timestamp timestamptz] => :timestamp,
102
- [:boolean] => :boolean,
103
- }.each do |keys, value|
104
- return value if keys.include?(builtin_type)
104
+ if builtin_type = builtin_type(scope, field)
105
+ {
106
+ %i[string text time binary] => :string,
107
+ %i[integer primary_key] => :integer,
108
+ %i[float decimal] => :float,
109
+ [:date] => :date,
110
+ %i[datetime timestamp timestamptz] => :timestamp,
111
+ [:boolean] => :boolean,
112
+ }.each do |keys, value|
113
+ return value if keys.include?(builtin_type)
114
+ end
105
115
  end
106
116
  nil
107
117
  end
@@ -23,7 +23,7 @@ module Datagrid
23
23
  end
24
24
 
25
25
  def parse(value)
26
- raise NotImplementedError, "#parse(value) suppose to be overwritten"
26
+ raise NotImplementedError, "#{self.class}#parse(value) suppose to be overwritten"
27
27
  end
28
28
 
29
29
  def default_input_options
@@ -12,7 +12,7 @@ module Datagrid
12
12
  end
13
13
 
14
14
  def apply(grid_object, scope, value)
15
- if !dummy? && grid_object.driver.timestamp_column?(scope, name)
15
+ if !dummy? && !block && grid_object.driver.timestamp_column?(scope, name)
16
16
  value = Datagrid::Utils.format_date_as_timestamp(value)
17
17
  end
18
18
  super
@@ -328,9 +328,15 @@ module Datagrid
328
328
  apply_filters(scope, filters.map { |f| filter_by_name(f) })
329
329
  end
330
330
 
331
+ # @!visibility private
332
+ def select_options(filter)
333
+ Datagrid::Utils.warn_once "#select_options is deprecated and renamed. Use #select_choices instead."
334
+ select_choices(filter)
335
+ end
336
+
331
337
  # @return [Array] the select options for the filter
332
338
  # @raise [ArgumentError] if the filter doesn't support select options
333
- def select_options(filter)
339
+ def select_choices(filter)
334
340
  find_select_filter(filter).select(self)
335
341
  end
336
342
 
@@ -47,7 +47,7 @@ module Datagrid
47
47
  # * `type` - special attribute the determines an input tag to be made.
48
48
  # Examples: `text`, `select`, `textarea`, `number`, `date` etc.
49
49
  # @return [String] an input tag for the corresponding filter name
50
- def datagrid_filter_input(attribute_or_filter, **options, &block)
50
+ def datagrid_filter_input(attribute_or_filter, select_choices: nil, select_options: {}, **options, &block)
51
51
  filter = datagrid_get_filter(attribute_or_filter)
52
52
  options = add_filter_options(filter, **options)
53
53
  type = options.delete(:type)&.to_sym
@@ -73,11 +73,12 @@ module Datagrid
73
73
  when :select
74
74
  select(
75
75
  filter.name,
76
- object.select_options(filter) || [],
76
+ select_choices || object.select_choices(filter) || [],
77
77
  {
78
78
  include_blank: filter.include_blank,
79
79
  prompt: filter.prompt,
80
80
  include_hidden: false,
81
+ **select_options,
81
82
  },
82
83
  multiple: filter.multiple?,
83
84
  **options,
@@ -97,7 +98,7 @@ module Datagrid
97
98
  protected
98
99
 
99
100
  def datagrid_enum_checkboxes_filter(filter, options = {})
100
- elements = object.select_options(filter).map do |element|
101
+ elements = object.select_choices(filter).map do |element|
101
102
  text, value = @template.send(:option_text_and_value, element)
102
103
  checked = enum_checkbox_checked?(filter, value)
103
104
  [value, text, checked]
@@ -137,50 +138,56 @@ module Datagrid
137
138
  end
138
139
 
139
140
  def datagrid_dynamic_filter(filter, options = {})
140
- field, operation, value = object.filter_value(filter)
141
141
  options = add_filter_options(filter, **options)
142
- field_input = dynamic_filter_select(
143
- filter.name,
144
- object.select_options(filter) || [],
142
+ field, operation, value = object.filter_value(filter)
143
+ field_options = datagrid_dynamic_field_options(options: options, field: field, filter: filter)
144
+ operation_options = datagrid_dynamic_operation_options(options: options, operation: operation, filter: filter)
145
+ value_options = datagrid_dynamic_value_options(options: options, value: value, filter: filter)
146
+ render_partial(
147
+ "dynamic_filter",
148
+ { filter: filter,
149
+ form: self,
150
+ field_options: field_options,
151
+ operation_options: operation_options,
152
+ value_options: value_options, },
153
+ )
154
+ end
155
+
156
+ def datagrid_dynamic_field_options(options:, field:, filter:)
157
+ options.merge(
145
158
  {
146
- include_blank: filter.include_blank,
147
- prompt: filter.prompt,
148
- include_hidden: false,
149
- selected: field,
159
+ type: :select,
160
+ select_choices: object.select_choices(filter),
161
+ select_options: {
162
+ selected: field,
163
+ },
164
+ name: @template.field_name(object_name, filter.name, "field"),
150
165
  },
151
- **add_html_classes(options, "datagrid-dynamic-field"),
152
- name: @template.field_name(object_name, filter.name, "field"),
153
166
  )
154
- operation_input = dynamic_filter_select(
155
- filter.name, filter.operations_select,
167
+ end
168
+
169
+ def datagrid_dynamic_operation_options(options:, operation:, filter:)
170
+ options.merge(
156
171
  {
157
- include_blank: false,
158
- include_hidden: false,
159
- prompt: false,
160
- selected: operation,
172
+ type: :select,
173
+ select_choices: filter.operations_select,
174
+ select_options: {
175
+ include_blank: false,
176
+ prompt: false,
177
+ selected: operation,
178
+ },
179
+ name: @template.field_name(object_name, filter.name, "operation"),
161
180
  },
162
- **add_html_classes(options, "datagrid-dynamic-operation"),
163
- name: @template.field_name(object_name, filter.name, "operation"),
164
- )
165
- value_input = datagrid_filter_input(
166
- filter.name,
167
- **add_html_classes(options, "datagrid-dynamic-value"),
168
- value: value,
169
- name: @template.field_name(object_name, filter.name, "value"),
170
181
  )
171
- [field_input, operation_input, value_input].join("\n").html_safe
172
182
  end
173
183
 
174
- def dynamic_filter_select(name, variants, select_options, html_options)
175
- if variants.size <= 1
176
- value = variants.first
177
- # select options format may vary
178
- value = value.last if value.is_a?(Array)
179
- # don't render any visible input when there is nothing to choose from
180
- hidden_field(name, **html_options, value: value)
181
- else
182
- select(name, variants, select_options, html_options)
183
- end
184
+ def datagrid_dynamic_value_options(options:, value:, filter:)
185
+ options.merge(
186
+ {
187
+ value: value,
188
+ name: @template.field_name(object_name, filter.name, "value"),
189
+ },
190
+ )
184
191
  end
185
192
 
186
193
  def datagrid_range_filter(filter, options = {})
@@ -205,10 +212,6 @@ module Datagrid
205
212
  raise(ArgumentError, "Datagrid filter #{attribute_or_filter} not found")
206
213
  end
207
214
 
208
- def add_html_classes(options, *classes)
209
- Datagrid::Utils.add_html_classes(options, *classes)
210
- end
211
-
212
215
  def partial_path(name)
213
216
  if (partials = options[:partials])
214
217
  partial_name = File.join(partials, name)
@@ -42,7 +42,7 @@ shared_examples_for "Datagrid" do
42
42
  when :integer
43
43
  1
44
44
  when :enum
45
- select = subject.select_options(filter)
45
+ select = subject.select_choices(filter)
46
46
  select.first&.last
47
47
  else
48
48
  raise "unknown filter type: #{filter.class}"
@@ -41,17 +41,6 @@ module Datagrid
41
41
  true
42
42
  end
43
43
 
44
- def add_html_classes(options, *classes)
45
- return options if classes.empty?
46
-
47
- options = options.clone
48
- options[:class] ||= []
49
- array = options[:class].is_a?(Array)
50
- value = [*options[:class], *classes]
51
- options[:class] = array ? value : value.join(" ")
52
- options
53
- end
54
-
55
44
  def string_like?(value)
56
45
  value.is_a?(Symbol) || value.is_a?(String)
57
46
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Datagrid
4
- VERSION = "2.0.7"
4
+ VERSION = "2.0.9"
5
5
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datagrid
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.7
4
+ version: 2.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bogdan Gusiev
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-11-18 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: railties
@@ -38,6 +37,7 @@ files:
38
37
  - LICENSE.txt
39
38
  - README.md
40
39
  - app/assets/stylesheets/datagrid.css
40
+ - app/views/datagrid/_dynamic_filter.html.erb
41
41
  - app/views/datagrid/_enum_checkboxes.html.erb
42
42
  - app/views/datagrid/_form.html.erb
43
43
  - app/views/datagrid/_head.html.erb
@@ -98,7 +98,6 @@ metadata:
98
98
  changelog_uri: https://github.com/bogdan/datagrid/blob/main/CHANGELOG.md
99
99
  source_code_uri: https://github.com/bogdan/datagrid
100
100
  rubygems_mfa_required: 'true'
101
- post_install_message:
102
101
  rdoc_options: []
103
102
  require_paths:
104
103
  - lib
@@ -113,8 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
112
  - !ruby/object:Gem::Version
114
113
  version: '0'
115
114
  requirements: []
116
- rubygems_version: 3.4.10
117
- signing_key:
115
+ rubygems_version: 3.6.7
118
116
  specification_version: 4
119
117
  summary: Library that provides DSL to present table like data
120
118
  test_files: []