headmin 0.5.4 → 0.5.5
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 +4 -4
- data/Gemfile.lock +1 -1
- data/app/assets/stylesheets/headmin.css +1 -1
- data/app/controllers/concerns/headmin/pagination.rb +5 -1
- data/app/models/headmin/filter/association_view.rb +1 -1
- data/app/models/headmin/filter/base.rb +34 -17
- data/app/models/headmin/filter/boolean_view.rb +1 -5
- data/app/models/headmin/filter/date_view.rb +1 -5
- data/app/models/headmin/filter/field.rb +55 -0
- data/app/models/headmin/filter/field_view.rb +50 -0
- data/app/models/headmin/filter/filter_view.rb +25 -0
- data/app/models/headmin/filter/number_view.rb +1 -5
- data/app/models/headmin/filter/options_view.rb +1 -5
- data/app/models/headmin/filter/text_view.rb +1 -5
- data/app/models/headmin/filters.rb +19 -4
- data/app/views/headmin/_filters.html.erb +1 -1
- data/app/views/headmin/filters/_field.html.erb +23 -0
- data/lib/headmin/version.rb +1 -1
- data/package.json +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3445263c38deb23953f15bd095f0ab4d35acdba03e57863990afc270b3b0ec2d
|
4
|
+
data.tar.gz: 7ff3cbb8b497e7abfec49ee1222f3980b08779627179d788cd332794076c3ec7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b6d3c45da2fc0d1e3d9d3f69daccfdb689eae2785cc46d19fdec80ffff497987193fcb251eb2576f95d2d7927179d2c0264fa0548c3363240193a0c51e7efcc
|
7
|
+
data.tar.gz: 1badf3f039045aaf9ddee10bcf1f2686bd3cd44f0e04db6f893c8e61c4cf8974b3464a427bcf6c66cbc7bfd03e2b502d48bd4edd8a4c26527484feefac74691b
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
@charset "UTF-8";
|
2
2
|
@import "https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css";
|
3
3
|
|
4
|
-
/* sass-plugin-0:/
|
4
|
+
/* sass-plugin-0:/usr/local/var/www/headmin/src/scss/headmin.scss */
|
5
5
|
:root {
|
6
6
|
--bs-blue: #0d6efd;
|
7
7
|
--bs-indigo: #6610f2;
|
@@ -2,7 +2,11 @@ module Headmin
|
|
2
2
|
module Pagination
|
3
3
|
def paginate(collection)
|
4
4
|
@records_filtered = collection.count
|
5
|
-
collection.
|
5
|
+
if collection.is_a?(Array)
|
6
|
+
Kaminari.paginate_array(collection).page(page).per(per_page)
|
7
|
+
else
|
8
|
+
collection.page(page).per(per_page)
|
9
|
+
end
|
6
10
|
end
|
7
11
|
|
8
12
|
def page
|
@@ -21,12 +21,13 @@ module Headmin
|
|
21
21
|
}
|
22
22
|
|
23
23
|
# Methods
|
24
|
-
def initialize(attribute, params)
|
25
|
-
@
|
26
|
-
@
|
24
|
+
def initialize(attribute, params, association: nil)
|
25
|
+
@attribute = association ? "#{association}_#{attribute}".to_sym : attribute
|
26
|
+
@raw_value = params[@attribute]
|
27
|
+
@association = association
|
27
28
|
@instructions = []
|
28
29
|
|
29
|
-
if params.key?(attribute)
|
30
|
+
if params.key?(@attribute)
|
30
31
|
parse(@raw_value)
|
31
32
|
end
|
32
33
|
end
|
@@ -61,7 +62,8 @@ module Headmin
|
|
61
62
|
query = build_query(query, collection, instruction)
|
62
63
|
end
|
63
64
|
|
64
|
-
collection.
|
65
|
+
collection = collection.joins(@association) if @association
|
66
|
+
collection.distinct.where(query)
|
65
67
|
end
|
66
68
|
|
67
69
|
def cast_value(value)
|
@@ -74,6 +76,30 @@ module Headmin
|
|
74
76
|
value
|
75
77
|
end
|
76
78
|
|
79
|
+
def build_query(query, collection, instruction)
|
80
|
+
query_operator = convert_to_query_operator(instruction[:operator])
|
81
|
+
query_value = convert_to_query_value(instruction[:value], instruction[:operator])
|
82
|
+
|
83
|
+
query_operator, query_value = process_null_operators(query_operator, query_value)
|
84
|
+
|
85
|
+
model = collection.is_a?(Class) ? collection : collection.model
|
86
|
+
|
87
|
+
if @association
|
88
|
+
# Association attributes are passed through as {association}_{attribute}, so we need to transform this into {attribute}
|
89
|
+
new_attribute = attribute.to_s.gsub("#{@association}_", "").to_sym
|
90
|
+
new_model = model.reflect_on_association(@association)
|
91
|
+
|
92
|
+
# In case the association cannot be found, raise a well defined error
|
93
|
+
raise UnknownAssociation if new_model.nil?
|
94
|
+
|
95
|
+
new_query = new_model.klass.arel_table[new_attribute].send(query_operator, query_value)
|
96
|
+
else
|
97
|
+
new_query = model.arel_table[attribute].send(query_operator, query_value)
|
98
|
+
end
|
99
|
+
|
100
|
+
query ? query.send(instruction[:conditional], new_query) : new_query
|
101
|
+
end
|
102
|
+
|
77
103
|
private
|
78
104
|
|
79
105
|
def parse(string)
|
@@ -139,18 +165,6 @@ module Headmin
|
|
139
165
|
process_value(string, operator)
|
140
166
|
end
|
141
167
|
|
142
|
-
def build_query(query, collection, instruction)
|
143
|
-
query_operator = convert_to_query_operator(instruction[:operator])
|
144
|
-
query_value = convert_to_query_value(instruction[:value], instruction[:operator])
|
145
|
-
|
146
|
-
query_operator, query_value = process_null_operators(query_operator, query_value)
|
147
|
-
|
148
|
-
model = collection.is_a?(Class) ? collection : collection.model
|
149
|
-
new_query = model.arel_table[attribute].send(query_operator, query_value)
|
150
|
-
|
151
|
-
query ? query.send(instruction[:conditional], new_query) : new_query
|
152
|
-
end
|
153
|
-
|
154
168
|
def process_null_operators(operator, value)
|
155
169
|
# In case of null operators (is_null and is_not_null), we have to intercept the operator and value values
|
156
170
|
# and transform them to the correct operator (eq or not_eq) and value (nil)
|
@@ -237,5 +251,8 @@ module Headmin
|
|
237
251
|
|
238
252
|
class NotImplementedMethodError < StandardError
|
239
253
|
end
|
254
|
+
|
255
|
+
class UnknownAssociation < StandardError
|
256
|
+
end
|
240
257
|
end
|
241
258
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Headmin
|
2
2
|
module Filter
|
3
|
-
class BooleanView <
|
3
|
+
class BooleanView < FilterView
|
4
4
|
def base_options
|
5
5
|
keys = %i[name label form]
|
6
6
|
options = to_h.slice(*keys)
|
@@ -28,10 +28,6 @@ module Headmin
|
|
28
28
|
@name || attribute
|
29
29
|
end
|
30
30
|
|
31
|
-
def label
|
32
|
-
@label || I18n.t("attributes.#{attribute}", default: name.to_s)
|
33
|
-
end
|
34
|
-
|
35
31
|
def default_base_options
|
36
32
|
{
|
37
33
|
label: label,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Headmin
|
2
2
|
module Filter
|
3
|
-
class DateView <
|
3
|
+
class DateView < FilterView
|
4
4
|
def base_options
|
5
5
|
keys = %i[name label form]
|
6
6
|
options = to_h.slice(*keys)
|
@@ -23,10 +23,6 @@ module Headmin
|
|
23
23
|
@name || attribute
|
24
24
|
end
|
25
25
|
|
26
|
-
def label
|
27
|
-
@label || I18n.t("attributes.#{attribute}", default: name.to_s)
|
28
|
-
end
|
29
|
-
|
30
26
|
def default_base_options
|
31
27
|
{
|
32
28
|
label: label,
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Headmin
|
2
|
+
module Filter
|
3
|
+
class Field < Headmin::Filter::Base
|
4
|
+
OPERATORS = %w[eq not_eq matches does_not_match]
|
5
|
+
|
6
|
+
def initialize(attribute, params, association: nil)
|
7
|
+
@attribute = association ? "#{association}_#{attribute}".to_sym : attribute
|
8
|
+
@attribute = "field_#{attribute}".to_sym
|
9
|
+
@raw_value = params[@attribute]
|
10
|
+
@association = association
|
11
|
+
@instructions = []
|
12
|
+
|
13
|
+
if params.key?(@attribute)
|
14
|
+
parse(@raw_value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def cast_value(value)
|
19
|
+
value
|
20
|
+
end
|
21
|
+
|
22
|
+
def display_value(value)
|
23
|
+
value.downcase
|
24
|
+
end
|
25
|
+
|
26
|
+
def query(collection)
|
27
|
+
return collection unless @instructions.any?
|
28
|
+
|
29
|
+
query = nil
|
30
|
+
|
31
|
+
@instructions.each do |instruction|
|
32
|
+
query = build_query(query, collection, instruction)
|
33
|
+
end
|
34
|
+
|
35
|
+
collection = collection.joins(:fields)
|
36
|
+
collection.where(query)
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_query(query, collection, instruction)
|
40
|
+
query_operator = convert_to_query_operator(instruction[:operator])
|
41
|
+
query_value = convert_to_query_value(instruction[:value], instruction[:operator])
|
42
|
+
|
43
|
+
query_operator, query_value = process_null_operators(query_operator, query_value)
|
44
|
+
|
45
|
+
model = collection.is_a?(Class) ? collection : collection.model
|
46
|
+
|
47
|
+
new_attribute = attribute.to_s.gsub("field_", "").to_sym
|
48
|
+
fields_model = model.reflect_on_association(:fields).klass
|
49
|
+
new_query = fields_model.arel_table[:name].matches(new_attribute).and(fields_model.arel_table[:value].send(query_operator, query_value))
|
50
|
+
|
51
|
+
query ? query.send(instruction[:conditional], new_query) : new_query
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Headmin
|
2
|
+
module Filter
|
3
|
+
class FieldView < FilterView
|
4
|
+
def base_options
|
5
|
+
keys = %i[name label form]
|
6
|
+
options = to_h.slice(*keys)
|
7
|
+
default_base_options.merge(options)
|
8
|
+
end
|
9
|
+
|
10
|
+
def input_options
|
11
|
+
keys = %i[form]
|
12
|
+
options = to_h.slice(*keys)
|
13
|
+
default_input_options.merge(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def id
|
19
|
+
"#{name}_value"
|
20
|
+
end
|
21
|
+
|
22
|
+
def name
|
23
|
+
"field_#{@name}".to_sym || attribute
|
24
|
+
end
|
25
|
+
|
26
|
+
def default_base_options
|
27
|
+
{
|
28
|
+
label: label,
|
29
|
+
name: "field_#{attribute}".to_sym,
|
30
|
+
filter: Headmin::Filter::Field.new("field_#{attribute}".to_sym, @params),
|
31
|
+
allowed_operators: Headmin::Filter::Field::OPERATORS - %w[in not_in]
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def default_input_options
|
36
|
+
{
|
37
|
+
label: false,
|
38
|
+
wrapper: false,
|
39
|
+
id: id,
|
40
|
+
name: nil,
|
41
|
+
data: {
|
42
|
+
action: "change->filter#updateHiddenValue",
|
43
|
+
filter_target: "value",
|
44
|
+
filter_row_target: "original"
|
45
|
+
}
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Headmin
|
2
|
+
module Filter
|
3
|
+
class FilterView < ViewModel
|
4
|
+
def attribute
|
5
|
+
@association ? "#{@association}_#{@attribute}".to_sym : @attribute
|
6
|
+
end
|
7
|
+
|
8
|
+
def label
|
9
|
+
@label || I18n.t("attributes.#{attribute}", default: @association ? "#{association_model.model_name.human(count: 1)} - #{association_model.human_attribute_name(@attribute)}" : name.to_s)
|
10
|
+
end
|
11
|
+
|
12
|
+
def reflection
|
13
|
+
if @association
|
14
|
+
form.object.class.reflect_on_association(@association)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def association_model
|
19
|
+
if @association
|
20
|
+
reflection.klass
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Headmin
|
2
2
|
module Filter
|
3
|
-
class NumberView <
|
3
|
+
class NumberView < FilterView
|
4
4
|
def base_options
|
5
5
|
keys = %i[name label form]
|
6
6
|
options = to_h.slice(*keys)
|
@@ -23,10 +23,6 @@ module Headmin
|
|
23
23
|
@name || attribute
|
24
24
|
end
|
25
25
|
|
26
|
-
def label
|
27
|
-
@label || I18n.t("attributes.#{attribute}", default: name.to_s)
|
28
|
-
end
|
29
|
-
|
30
26
|
def default_base_options
|
31
27
|
{
|
32
28
|
label: label,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Headmin
|
2
2
|
module Filter
|
3
|
-
class OptionsView <
|
3
|
+
class OptionsView < FilterView
|
4
4
|
def base_options
|
5
5
|
keys = %i[name label form]
|
6
6
|
options = to_h.slice(*keys)
|
@@ -27,10 +27,6 @@ module Headmin
|
|
27
27
|
@name || attribute
|
28
28
|
end
|
29
29
|
|
30
|
-
def label
|
31
|
-
@label || I18n.t("attributes.#{attribute}", default: name.to_s)
|
32
|
-
end
|
33
|
-
|
34
30
|
def default_base_options
|
35
31
|
{
|
36
32
|
label: label,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Headmin
|
2
2
|
module Filter
|
3
|
-
class TextView <
|
3
|
+
class TextView < FilterView
|
4
4
|
def base_options
|
5
5
|
keys = %i[name label form]
|
6
6
|
options = to_h.slice(*keys)
|
@@ -23,10 +23,6 @@ module Headmin
|
|
23
23
|
@name || attribute
|
24
24
|
end
|
25
25
|
|
26
|
-
def label
|
27
|
-
@label || I18n.t("attributes.#{attribute}", default: name.to_s)
|
28
|
-
end
|
29
|
-
|
30
26
|
def default_base_options
|
31
27
|
{
|
32
28
|
label: label,
|
@@ -13,15 +13,30 @@ module Headmin
|
|
13
13
|
@param_types = param_types
|
14
14
|
end
|
15
15
|
|
16
|
-
def parse(attribute, type)
|
16
|
+
def parse(attribute, type, association: nil)
|
17
17
|
class_name = "Headmin::Filter::#{type.to_s.classify}".constantize
|
18
|
-
class_name.new(attribute, @params)
|
18
|
+
class_name.new(attribute, @params, association: association)
|
19
19
|
end
|
20
20
|
|
21
21
|
def query(collection)
|
22
22
|
@param_types.each do |attribute, type|
|
23
|
-
|
24
|
-
|
23
|
+
if type.is_a? Hash
|
24
|
+
# We are given attribute filters of an association
|
25
|
+
association = attribute
|
26
|
+
|
27
|
+
# By default, we offer a filter of type association
|
28
|
+
association_filter = Headmin::Filter::Association.new(attribute, @params, association: nil)
|
29
|
+
collection = association_filter.query(collection)
|
30
|
+
|
31
|
+
# Query all the passed attribute filters for this association
|
32
|
+
type.each do |new_attribute, new_type|
|
33
|
+
filter = parse(new_attribute, new_type, association: association)
|
34
|
+
collection = filter.query(collection)
|
35
|
+
end
|
36
|
+
else
|
37
|
+
filter = parse(attribute, type)
|
38
|
+
collection = filter.query(collection)
|
39
|
+
end
|
25
40
|
end
|
26
41
|
collection
|
27
42
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<%
|
2
|
+
# headmin/filters/field
|
3
|
+
#
|
4
|
+
# ==== Required parameters
|
5
|
+
# * +form+ - Form object
|
6
|
+
# * +attribute+ - Name of the attribute to be filtered
|
7
|
+
#
|
8
|
+
# ==== Optional parameters
|
9
|
+
# * +label+ - Display label
|
10
|
+
# * +name+ - Name of the filter parameter
|
11
|
+
#
|
12
|
+
# ==== Examples
|
13
|
+
# Basic version
|
14
|
+
# <%= render "headmin/filters", url: admin_orders_path do |form| %#>
|
15
|
+
# <%= render "headmin/filters/field", form: form, attribute: :title %#>
|
16
|
+
# <% end %#>
|
17
|
+
|
18
|
+
text = Headmin::Filter::FieldView.new(local_assigns.merge(params: params))
|
19
|
+
%>
|
20
|
+
|
21
|
+
<%= render "headmin/filters/base", text.base_options do |value| %>
|
22
|
+
<%= render "headmin/forms/text", text.input_options.merge({value: value}) %>
|
23
|
+
<% end %>
|
data/lib/headmin/version.rb
CHANGED
data/package.json
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: headmin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jef Vlamings
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-09-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: closure_tree
|
@@ -268,6 +268,9 @@ files:
|
|
268
268
|
- app/models/headmin/filter/conditional_view.rb
|
269
269
|
- app/models/headmin/filter/date.rb
|
270
270
|
- app/models/headmin/filter/date_view.rb
|
271
|
+
- app/models/headmin/filter/field.rb
|
272
|
+
- app/models/headmin/filter/field_view.rb
|
273
|
+
- app/models/headmin/filter/filter_view.rb
|
271
274
|
- app/models/headmin/filter/flatpickr_view.rb
|
272
275
|
- app/models/headmin/filter/menu_item_view.rb
|
273
276
|
- app/models/headmin/filter/money.rb
|
@@ -336,6 +339,7 @@ files:
|
|
336
339
|
- app/views/headmin/filters/_base.html.erb
|
337
340
|
- app/views/headmin/filters/_boolean.html.erb
|
338
341
|
- app/views/headmin/filters/_date.html.erb
|
342
|
+
- app/views/headmin/filters/_field.html.erb
|
339
343
|
- app/views/headmin/filters/_flatpickr.html.erb
|
340
344
|
- app/views/headmin/filters/_number.html.erb
|
341
345
|
- app/views/headmin/filters/_options.html.erb
|