Skip to content

Commit be9a75e

Browse files
committed
Add ability to limit filter operators
Useful for tables with a large amount of records.
1 parent fdb9abb commit be9a75e

File tree

15 files changed

+263
-254
lines changed

15 files changed

+263
-254
lines changed

app/helpers/rails_admin/main_helper.rb

+5-15
Original file line numberDiff line numberDiff line change
@@ -42,28 +42,18 @@ def ordered_filters
4242
def ordered_filter_options
4343
if ordered_filters
4444
@ordered_filter_options ||= ordered_filters.map do |duplet|
45-
options = {index: duplet[0]}
4645
filter_for_field = duplet[1]
4746
filter_name = filter_for_field.keys.first
4847
filter_hash = filter_for_field.values.first
4948
unless (field = filterable_fields.find { |f| f.name == filter_name.to_sym })
5049
raise "#{filter_name} is not currently filterable; filterable fields are #{filterable_fields.map(&:name).join(', ')}"
5150
end
5251

53-
case field.type
54-
when :enum
55-
options[:select_options] = options_for_select(field.with(object: @abstract_model.model.new).enum, filter_hash['v'])
56-
when :date, :datetime, :time
57-
options[:datetimepicker_options] = field.datepicker_options
58-
end
59-
options[:label] = field.label
60-
options[:name] = field.name
61-
options[:type] = field.type
62-
options[:value] = filter_hash['v']
63-
options[:label] = field.label
64-
options[:operator] = filter_hash['o'] || field.default_filter_operator
65-
options[:required] = field.required
66-
options
52+
field.filter_options.merge(
53+
index: duplet[0],
54+
operator: filter_hash['o'] || field.default_filter_operator,
55+
value: filter_hash['v'],
56+
)
6757
end
6858
end
6959
end

app/views/rails_admin/main/index.html.erb

+1-16
Original file line numberDiff line numberDiff line change
@@ -26,26 +26,11 @@
2626
</a>
2727
<ul class="dropdown-menu dropdown-menu-end" id="filters">
2828
<% filterable_fields.each do |field| %>
29-
<%
30-
field_options = case field.type
31-
when :enum
32-
options_for_select(field.with(object: @abstract_model.model.new).enum)
33-
else
34-
''
35-
end
36-
%>
3729
<li>
3830
<a
3931
href="#"
4032
class="dropdown-item"
41-
data-field-label="<%= field.label %>"
42-
data-field-name="<%= field.name %>"
43-
data-field-operator="<%= field.default_filter_operator %>"
44-
data-field-options="<%= "#{field_options}" %>"
45-
data-field-required="<%= field.required.to_s %>"
46-
data-field-type="<%= field.type %>"
47-
data-field-value=""
48-
data-field-datetimepicker-options="<%= field.try(:datepicker_options).try(:to_json) %>"
33+
data-options="<%= field.with(view: self).filter_options.to_json %>"
4934
>
5035
<%= field.label %>
5136
</a>

config/locales/rails_admin.en.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
en:
22
admin:
33
js:
4-
true: True
5-
false: False
4+
true: "True"
5+
false: "False"
66
is_present: Is present
77
is_blank: Is blank
88
date: Date ...

lib/rails_admin/config/fields/base.rb

+20-6
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ def sort_column
7878
!virtual? || children_fields.first || false
7979
end
8080

81+
register_instance_option :search_operator do
82+
RailsAdmin::Config.default_search_operator
83+
end
84+
8185
register_instance_option :queryable? do
8286
!virtual?
8387
end
@@ -86,8 +90,22 @@ def sort_column
8690
!!searchable
8791
end
8892

89-
register_instance_option :search_operator do
90-
@search_operator ||= RailsAdmin::Config.default_search_operator
93+
register_instance_option :filter_operators do
94+
[]
95+
end
96+
97+
register_instance_option :default_filter_operator do
98+
nil
99+
end
100+
101+
def filter_options
102+
{
103+
label: label,
104+
name: name,
105+
operator: default_filter_operator,
106+
operators: filter_operators,
107+
type: type,
108+
}
91109
end
92110

93111
# serials and dates are reversed in list, which is more natural (last modified items first).
@@ -242,10 +260,6 @@ def sort_column
242260
[]
243261
end
244262

245-
register_instance_option :default_filter_operator do
246-
nil
247-
end
248-
249263
register_instance_option :eager_load do
250264
false
251265
end

lib/rails_admin/config/fields/types/belongs_to_association.rb

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ module Types
99
class BelongsToAssociation < RailsAdmin::Config::Fields::Association
1010
RailsAdmin::Config::Fields::Types.register(self)
1111

12+
register_instance_option :filter_operators do
13+
%w[_discard like not_like is starts_with ends_with] + (required? ? [] : %w[_separator _present _blank])
14+
end
15+
1216
register_instance_option :formatted_value do
1317
(o = value) && o.send(associated_model_config.object_label_method)
1418
end

lib/rails_admin/config/fields/types/boolean.rb

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ class Boolean < RailsAdmin::Config::Fields::Base
2424
}
2525
end
2626

27+
register_instance_option :filter_operators do
28+
%w[_discard true false] + (required? ? [] : %w[_separator _present _blank])
29+
end
30+
2731
register_instance_option :nullable? do
2832
properties&.nullable?
2933
end

lib/rails_admin/config/fields/types/datetime.rb

+10
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ def parse_input(params)
1818
params[name] = parse_value(params[name]) if params[name]
1919
end
2020

21+
register_instance_option :filter_operators do
22+
%w[default between today yesterday this_week last_week] + (required? ? [] : %w[_separator _not_null _null])
23+
end
24+
25+
def filter_options
26+
super.merge(
27+
datetimepicker_options: datepicker_options,
28+
)
29+
end
30+
2131
register_instance_option :date_format do
2232
:long
2333
end

lib/rails_admin/config/fields/types/enum.rb

+13-2
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,27 @@ module Types
99
class Enum < RailsAdmin::Config::Fields::Base
1010
RailsAdmin::Config::Fields::Types.register(self)
1111

12+
register_instance_option :filter_operators do
13+
%w[_discard] +
14+
enum.map do |label, value|
15+
{label: label, value: value || label}
16+
end + (required? ? [] : %w[_separator _present _blank])
17+
end
18+
1219
register_instance_option :partial do
1320
:form_enumeration
1421
end
1522

1623
register_instance_option :enum_method do
17-
@enum_method ||= bindings[:object].class.respond_to?("#{name}_enum") || bindings[:object].respond_to?("#{name}_enum") ? "#{name}_enum" : name
24+
@enum_method ||= bindings[:object].class.respond_to?("#{name}_enum") || (bindings[:object] || abstract_model.model.new).respond_to?("#{name}_enum") ? "#{name}_enum" : name
1825
end
1926

2027
register_instance_option :enum do
21-
bindings[:object].class.respond_to?(enum_method) ? bindings[:object].class.send(enum_method) : bindings[:object].send(enum_method)
28+
if abstract_model.model.respond_to?(enum_method)
29+
abstract_model.model.send(enum_method)
30+
else
31+
(bindings[:object] || abstract_model.model.new).send(enum_method)
32+
end
2233
end
2334

2435
register_instance_option :pretty_value do

lib/rails_admin/config/fields/types/has_one_association.rb

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ class HasOneAssociation < RailsAdmin::Config::Fields::Association
1010
# Register field type for the type loader
1111
RailsAdmin::Config::Fields::Types.register(self)
1212

13+
register_instance_option :filter_operators do
14+
%w[_discard like not_like is starts_with ends_with] + (required? ? [] : %w[_separator _present _blank])
15+
end
16+
1317
register_instance_option :partial do
1418
nested_form ? :form_nested_one : :form_filtering_select
1519
end

lib/rails_admin/config/fields/types/numeric.rb

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ class Numeric < RailsAdmin::Config::Fields::Base
1010
# Register field type for the type loader
1111
RailsAdmin::Config::Fields::Types.register(self)
1212

13+
register_instance_option :filter_operators do
14+
%w[default between] + (required? ? [] : %w[_separator _not_null _null])
15+
end
16+
1317
register_instance_option :view_helper do
1418
:number_field
1519
end

lib/rails_admin/config/fields/types/string_like.rb

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ module Config
77
module Fields
88
module Types
99
class StringLike < RailsAdmin::Config::Fields::Base
10+
register_instance_option :filter_operators do
11+
%w[_discard like not_like is starts_with ends_with] + (required? ? [] : %w[_separator _present _blank])
12+
end
13+
1014
register_instance_option :treat_empty_as_nil? do
1115
properties.try(:nullable?)
1216
end

lib/rails_admin/config/fields/types/time.rb

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ def parse_value(value)
1313
abstract_model.model.type_for_attribute(name.to_s).serialize(super)&.change(year: 2000, month: 1, day: 1)
1414
end
1515

16+
register_instance_option :filter_operators do
17+
%w[default between] + (required? ? [] : %w[_separator _not_null _null])
18+
end
19+
1620
register_instance_option :datepicker_options do
1721
{
1822
allowInput: true,

spec/integration/actions/index_spec.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@
324324
type: 'string',
325325
value: '',
326326
operator: 'is',
327-
required: true,
327+
operators: %w[_discard like not_like is starts_with ends_with],
328328
},
329329
{
330330
index: 2,
@@ -333,7 +333,7 @@
333333
type: 'belongs_to_association',
334334
value: '',
335335
operator: nil,
336-
required: false,
336+
operators: %w[_discard like not_like is starts_with ends_with _separator _present _blank],
337337
},
338338
]
339339
end

spec/integration/widgets/filter_box_spec.rb

+22-2
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,25 @@
6767
end
6868
end
6969

70+
it 'supports limiting filter operators' do
71+
RailsAdmin.config Player do
72+
list do
73+
field :name do
74+
filter_operators %w[is starts_with _present]
75+
end
76+
end
77+
end
78+
79+
visit index_path(model_name: 'player')
80+
is_expected.to have_no_css('#filters_box .filter')
81+
click_link 'Add filter'
82+
click_link 'Name'
83+
84+
within(:select, name: /f\[name\]\[\d+\]\[o\]/) do
85+
expect(page.all('option').map(&:value)).to eq %w[is starts_with _present]
86+
end
87+
end
88+
7089
describe 'for boolean field' do
7190
before do
7291
RailsAdmin.config FieldTest do
@@ -133,9 +152,10 @@
133152
visit index_path(model_name: 'team')
134153
click_link 'Add filter'
135154
click_link 'Color'
136-
expect(all('.select-single option').map(&:text)).to include 'white', 'black', 'red', 'green', 'blu<e>é'
155+
expect(all('#filters_box option').map(&:text)).to include 'white', 'black', 'red', 'green', 'blu<e>é'
137156
find('.filter .switch-select .fa-plus').click
138-
expect(all('.select-multiple option').map(&:text)).to include 'white', 'black', 'red', 'green', 'blu<e>é'
157+
expect(find('#filters_box select')['multiple']).to be true
158+
expect(find('#filters_box select')['name']).to match(/\[\]$/)
139159
end
140160
end
141161

0 commit comments

Comments
 (0)