headmin 0.4.0 → 0.5.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 (143) hide show
  1. checksums.yaml +4 -4
  2. data/.lock-487e157d270f3062a98b7b2a012753708-1272821827 +0 -0
  3. data/CHANGELOG.md +16 -2
  4. data/Gemfile.lock +77 -79
  5. data/app/assets/javascripts/headmin/controllers/autocomplete_controller.js +84 -21
  6. data/app/assets/javascripts/headmin/controllers/date_range_controller.js +12 -6
  7. data/app/assets/javascripts/headmin/controllers/filter_controller.js +61 -11
  8. data/app/assets/javascripts/headmin/controllers/filter_row_controller.js +50 -0
  9. data/app/assets/javascripts/headmin/controllers/flatpickr_controller.js +2 -6
  10. data/app/assets/javascripts/headmin/controllers/popup_controller.js +14 -5
  11. data/app/assets/javascripts/headmin/controllers/table_actions_controller.js +16 -21
  12. data/app/assets/javascripts/headmin/index.js +2 -0
  13. data/app/assets/javascripts/headmin.js +186 -56
  14. data/app/assets/stylesheets/headmin/filter.scss +74 -0
  15. data/app/assets/stylesheets/headmin/general.scss +8 -0
  16. data/app/assets/stylesheets/headmin/layout/body.scss +5 -0
  17. data/app/assets/stylesheets/headmin/popup.scss +0 -1
  18. data/app/assets/stylesheets/headmin.css +70 -1
  19. data/app/controllers/concerns/headmin/filterable.rb +27 -0
  20. data/app/models/concerns/headmin/field.rb +4 -2
  21. data/app/models/concerns/headmin/fieldable.rb +138 -44
  22. data/app/models/headmin/filter/base.rb +238 -0
  23. data/app/models/headmin/filter/base_view.rb +64 -0
  24. data/app/models/headmin/filter/boolean.rb +15 -0
  25. data/app/models/headmin/filter/boolean_view.rb +61 -0
  26. data/app/models/headmin/filter/button_view.rb +25 -0
  27. data/app/models/headmin/filter/conditional_view.rb +16 -0
  28. data/app/models/headmin/filter/date.rb +19 -0
  29. data/app/models/headmin/filter/date_view.rb +52 -0
  30. data/app/models/headmin/filter/flatpickr_view.rb +54 -0
  31. data/app/models/headmin/filter/menu_item_view.rb +6 -0
  32. data/app/models/headmin/filter/money.rb +13 -0
  33. data/app/models/headmin/filter/number.rb +27 -0
  34. data/app/models/headmin/filter/number_view.rb +54 -0
  35. data/app/models/headmin/filter/operator_view.rb +30 -0
  36. data/app/models/headmin/filter/options_view.rb +61 -0
  37. data/app/models/headmin/filter/row_view.rb +13 -0
  38. data/app/models/headmin/filter/search.rb +18 -0
  39. data/app/models/headmin/filter/search_view.rb +31 -0
  40. data/app/models/headmin/filter/text.rb +25 -0
  41. data/app/models/headmin/filter/text_view.rb +53 -0
  42. data/app/models/headmin/filters.rb +29 -0
  43. data/app/models/headmin/form/blocks_view.rb +1 -1
  44. data/app/models/headmin/form/checkbox_view.rb +3 -3
  45. data/app/models/headmin/form/date_range_view.rb +2 -2
  46. data/app/models/headmin/form/date_view.rb +5 -5
  47. data/app/models/headmin/form/datetime_range_view.rb +25 -0
  48. data/app/models/headmin/form/datetime_view.rb +45 -0
  49. data/app/models/headmin/form/email_view.rb +7 -7
  50. data/app/models/headmin/form/file_view.rb +6 -6
  51. data/app/models/headmin/form/flatpickr_range_view.rb +11 -22
  52. data/app/models/headmin/form/flatpickr_view.rb +4 -13
  53. data/app/models/headmin/form/input_group_view.rb +1 -1
  54. data/app/models/headmin/form/label_view.rb +1 -1
  55. data/app/models/headmin/form/number_view.rb +5 -5
  56. data/app/models/headmin/form/password_view.rb +5 -5
  57. data/app/models/headmin/form/redactorx_view.rb +2 -2
  58. data/app/models/headmin/form/search_view.rb +7 -7
  59. data/app/models/headmin/form/select_view.rb +6 -6
  60. data/app/models/headmin/form/switch_view.rb +1 -1
  61. data/app/models/headmin/form/text_view.rb +7 -7
  62. data/app/models/headmin/form/textarea_view.rb +5 -5
  63. data/app/models/headmin/form/url_view.rb +7 -7
  64. data/app/models/headmin/form/wrapper_view.rb +1 -1
  65. data/app/models/headmin/form/wysiwyg_view.rb +1 -1
  66. data/app/models/view_model.rb +1 -1
  67. data/app/views/examples/admin.html.erb +13 -13
  68. data/app/views/examples/auth.html.erb +1 -1
  69. data/app/views/headmin/_filters.html.erb +6 -6
  70. data/app/views/headmin/_form.html.erb +2 -2
  71. data/app/views/headmin/_index.html.erb +1 -1
  72. data/app/views/headmin/_pagination.html.erb +1 -1
  73. data/app/views/headmin/_popup.html.erb +2 -2
  74. data/app/views/headmin/_table.html.erb +1 -1
  75. data/app/views/headmin/dropdown/_devise.html.erb +8 -8
  76. data/app/views/headmin/dropdown/_locale.html.erb +4 -4
  77. data/app/views/headmin/filters/_base.html.erb +95 -0
  78. data/app/views/headmin/filters/_boolean.html.erb +23 -0
  79. data/app/views/headmin/filters/_date.html.erb +14 -38
  80. data/app/views/headmin/filters/_flatpickr.html.erb +15 -48
  81. data/app/views/headmin/filters/_number.html.erb +23 -0
  82. data/app/views/headmin/filters/_options.html.erb +24 -0
  83. data/app/views/headmin/filters/_search.html.erb +14 -12
  84. data/app/views/headmin/filters/_text.html.erb +23 -0
  85. data/app/views/headmin/filters/filter/_button.html.erb +9 -10
  86. data/app/views/headmin/filters/filter/_conditional.html.erb +18 -0
  87. data/app/views/headmin/filters/filter/_menu_item.html.erb +5 -2
  88. data/app/views/headmin/filters/filter/_null_select.html.erb +8 -0
  89. data/app/views/headmin/filters/filter/_operator.html.erb +16 -0
  90. data/app/views/headmin/filters/filter/_row.html.erb +11 -0
  91. data/app/views/headmin/forms/_blocks.html.erb +1 -1
  92. data/app/views/headmin/forms/_date_range.html.erb +3 -3
  93. data/app/views/headmin/forms/_datetime.html.erb +41 -0
  94. data/app/views/headmin/forms/_datetime_range.html.erb +40 -0
  95. data/app/views/headmin/forms/_file.html.erb +3 -3
  96. data/app/views/headmin/forms/_flatpickr.html.erb +1 -1
  97. data/app/views/headmin/forms/_flatpickr_range.html.erb +3 -4
  98. data/app/views/headmin/forms/_label.html.erb +1 -1
  99. data/app/views/headmin/forms/_repeater.html.erb +12 -12
  100. data/app/views/headmin/forms/fields/_base.html.erb +1 -1
  101. data/app/views/headmin/forms/fields/_file.html.erb +3 -3
  102. data/app/views/headmin/forms/fields/_files.html.erb +17 -0
  103. data/app/views/headmin/forms/fields/_group.html.erb +10 -5
  104. data/app/views/headmin/forms/fields/_list.html.erb +4 -4
  105. data/app/views/headmin/forms/fields/_text.html.erb +2 -2
  106. data/app/views/headmin/layout/_footer.html.erb +1 -1
  107. data/app/views/headmin/layout/_main.html.erb +1 -1
  108. data/app/views/headmin/nav/_dropdown.html.erb +3 -3
  109. data/app/views/headmin/nav/_item.html.erb +2 -2
  110. data/app/views/headmin/nav/item/_devise.html.erb +8 -8
  111. data/app/views/headmin/nav/item/_locale.html.erb +4 -4
  112. data/app/views/headmin/table/_actions.html.erb +3 -6
  113. data/app/views/headmin/table/actions/_export.html.erb +1 -1
  114. data/app/views/headmin/table/body/_row.html.erb +3 -3
  115. data/app/views/headmin/table/foot/_id.html.erb +1 -1
  116. data/app/views/headmin/views/devise/confirmations/_new.html.erb +1 -1
  117. data/app/views/headmin/views/devise/passwords/_edit.html.erb +2 -2
  118. data/app/views/headmin/views/devise/passwords/_new.html.erb +1 -1
  119. data/app/views/headmin/views/devise/registrations/_edit.html.erb +4 -4
  120. data/app/views/headmin/views/devise/registrations/_new.html.erb +3 -3
  121. data/app/views/headmin/views/devise/sessions/_new.html.erb +3 -3
  122. data/app/views/headmin/views/devise/unlocks/_new.html.erb +1 -1
  123. data/config/locales/en.yml +4 -0
  124. data/config/locales/headmin/dropdown/en.yml +6 -0
  125. data/config/locales/headmin/dropdown/nl.yml +6 -0
  126. data/config/locales/headmin/filters/en.yml +26 -1
  127. data/config/locales/headmin/filters/nl.yml +26 -1
  128. data/config/locales/headmin/forms/en.yml +1 -1
  129. data/config/locales/headmin/forms/nl.yml +1 -1
  130. data/config/locales/headmin/layout/en.yml +0 -9
  131. data/config/locales/headmin/layout/nl.yml +0 -9
  132. data/config/locales/headmin/nav/en.yml +7 -0
  133. data/config/locales/headmin/nav/nl.yml +7 -0
  134. data/config/locales/nl.yml +4 -0
  135. data/lib/generators/templates/views/layouts/auth.html.erb +1 -1
  136. data/lib/headmin/version.rb +1 -1
  137. data/package.json +1 -1
  138. metadata +44 -7
  139. data/app/controllers/concerns/headmin/filter.rb +0 -5
  140. data/app/controllers/concerns/headmin/searchable.rb +0 -15
  141. data/app/views/headmin/filters/_select.html.erb +0 -45
  142. data/app/views/headmin/filters/filter/_template.html.erb +0 -13
  143. data/app/views/headmin/forms/fields/_image.html.erb +0 -17
@@ -0,0 +1,61 @@
1
+ module Headmin
2
+ module Filter
3
+ class BooleanView < ViewModel
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 value
19
+ # If the value is nil we want to display the first option (which is true)
20
+ @value.nil? ? @value = true : ""
21
+ end
22
+
23
+ def id
24
+ "#{name}_value"
25
+ end
26
+
27
+ def name
28
+ @name || attribute
29
+ end
30
+
31
+ def label
32
+ @label || I18n.t("attributes.#{attribute}", default: name.to_s)
33
+ end
34
+
35
+ def default_base_options
36
+ {
37
+ label: label,
38
+ name: attribute,
39
+ filter: Headmin::Filter::Boolean.new(name, @params),
40
+ display_values: [[I18n.t("headmin.filters.values.true"), true], [I18n.t("headmin.filters.values.false"), false]],
41
+ allowed_operators: Headmin::Filter::Boolean::OPERATORS
42
+ }
43
+ end
44
+
45
+ def default_input_options
46
+ {
47
+ label: false,
48
+ wrapper: false,
49
+ id: id,
50
+ collection: [[I18n.t("headmin.filters.values.true"), 1], [I18n.t("headmin.filters.values.false"), 0]],
51
+ selected: value ? 1 : 0,
52
+ data: {
53
+ action: "change->filter#updateHiddenValue",
54
+ filter_target: "value",
55
+ filter_row_target: "original"
56
+ }
57
+ }
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,25 @@
1
+ module Headmin
2
+ module Filter
3
+ class ButtonView < ViewModel
4
+ def id
5
+ @id || SecureRandom.hex
6
+ end
7
+
8
+ def name
9
+ @name.to_sym
10
+ end
11
+
12
+ def label
13
+ @label || name.to_s.humanize
14
+ end
15
+
16
+ def display_values
17
+ @display_values || []
18
+ end
19
+
20
+ def filter
21
+ @filter || nil
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ module Headmin
2
+ module Filter
3
+ class ConditionalView < ViewModel
4
+ def selected
5
+ @selected ? "+#{@selected.to_s.upcase}+" : nil
6
+ end
7
+
8
+ def values
9
+ {
10
+ "+AND+": I18n.t("headmin.filters.filter.conditional.and"),
11
+ "+OR+": I18n.t("headmin.filters.filter.conditional.or")
12
+ }
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ module Headmin
2
+ module Filter
3
+ class Date < Headmin::Filter::Base
4
+ OPERATORS = %w[eq not_eq gt gteq lt lteq between not_between in not_in is_null is_not_null]
5
+
6
+ def cast_value(value)
7
+ value.present? ? value.to_date : ::Date.current
8
+ rescue
9
+ raise TypeError, "The value that was passed to this filter is not a date"
10
+ end
11
+
12
+ def display_value(value)
13
+ # This uses the default date format of headmin.
14
+ # Can be overwritten by setting default date format of the application.
15
+ I18n.l(value)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,52 @@
1
+ module Headmin
2
+ module Filter
3
+ class DateView < ViewModel
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
+ @name || attribute
24
+ end
25
+
26
+ def label
27
+ @label || I18n.t("attributes.#{attribute}", default: name.to_s)
28
+ end
29
+
30
+ def default_base_options
31
+ {
32
+ label: label,
33
+ name: attribute,
34
+ filter: Headmin::Filter::Date.new(name, @params),
35
+ allowed_operators: Headmin::Filter::Date::OPERATORS - %w[in not_in between not_between]
36
+ }
37
+ end
38
+
39
+ def default_input_options
40
+ {
41
+ label: false,
42
+ wrapper: false,
43
+ id: id,
44
+ data: {action: "change->filter#updateHiddenValue",
45
+ filter_target: "value",
46
+ filter_row_target: "original"},
47
+ class: "form-control"
48
+ }
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,54 @@
1
+ module Headmin
2
+ module Filter
3
+ class FlatpickrView < ViewModel
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
+ @name || attribute
24
+ end
25
+
26
+ def label
27
+ @label || I18n.t("attributes.#{attribute}", default: name.to_s)
28
+ end
29
+
30
+ def default_base_options
31
+ {
32
+ label: label,
33
+ name: attribute,
34
+ filter: Headmin::Filter::Date.new(name, @params),
35
+ allowed_operators: Headmin::Filter::Date::OPERATORS - %w[in not_in between not_between]
36
+ }
37
+ end
38
+
39
+ def default_input_options
40
+ {
41
+ label: false,
42
+ wrapper: false,
43
+ id: id,
44
+ data: {
45
+ action: "change->filter#updateHiddenValue",
46
+ filter_target: "value",
47
+ filter_row_target: "original"
48
+ },
49
+ class: "form-control"
50
+ }
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,6 @@
1
+ module Headmin
2
+ module Filter
3
+ class MenuItemView < ViewModel
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,13 @@
1
+ module Headmin
2
+ module Filter
3
+ class Money < Headmin::Filter::Number
4
+ def cast_value(value)
5
+ super(value) * 100
6
+ end
7
+
8
+ def attribute
9
+ "#{@attribute}_cents"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ module Headmin
2
+ module Filter
3
+ class Number < Headmin::Filter::Base
4
+ OPERATORS = %w[eq not_eq gt gteq lt lteq between not_between in not_in is_null is_not_null]
5
+
6
+ def cast_value(value)
7
+ is_i?(value) ? value.to_i : 0
8
+ end
9
+
10
+ def to_s
11
+ string
12
+ end
13
+
14
+ private
15
+
16
+ def is_i?(value)
17
+ # Regex: this selects signed digits (\d) only, it is then checked to the value, e.g.:
18
+ # is_i?("3") = true
19
+ # is_i?("-3") = true
20
+ # is_i?("3a") = false
21
+ # is_i?("3.2") = false
22
+
23
+ /\A[-+]?\d+\z/.match(value)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,54 @@
1
+ module Headmin
2
+ module Filter
3
+ class NumberView < ViewModel
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
+ @name || attribute
24
+ end
25
+
26
+ def label
27
+ @label || I18n.t("attributes.#{attribute}", default: name.to_s)
28
+ end
29
+
30
+ def default_base_options
31
+ {
32
+ label: label,
33
+ name: attribute,
34
+ filter: Headmin::Filter::Number.new(name, @params),
35
+ allowed_operators: Headmin::Filter::Number::OPERATORS - %w[in not_in between not_between]
36
+ }
37
+ end
38
+
39
+ def default_input_options
40
+ {
41
+ label: false,
42
+ wrapper: false,
43
+ id: id,
44
+ data: {
45
+ action: "change->filter#updateHiddenValue",
46
+ filter_target: "value",
47
+ filter_row_target: "original"
48
+ },
49
+ class: "form-control"
50
+ }
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,30 @@
1
+ module Headmin
2
+ module Filter
3
+ class OperatorView < ViewModel
4
+ def allowed_operators
5
+ @allowed_operators || []
6
+ end
7
+
8
+ def selected
9
+ @selected || nil
10
+ end
11
+
12
+ def operator_symbol
13
+ {
14
+ eq: "&equals; #{I18n.t("headmin.filters.operators.eq")}",
15
+ not_eq: "&ne; #{I18n.t("headmin.filters.operators.not_eq")}",
16
+ gt: "&gt; #{I18n.t("headmin.filters.operators.gt")}",
17
+ gteq: "&ge; #{I18n.t("headmin.filters.operators.gteq")}",
18
+ lt: "&lt; #{I18n.t("headmin.filters.operators.lt")}",
19
+ lteq: "&le; #{I18n.t("headmin.filters.operators.lteq")}",
20
+ starts_with: "&sqsub; #{I18n.t("headmin.filters.operators.starts_with")}",
21
+ ends_with: "&sqsup; #{I18n.t("headmin.filters.operators.ends_with")}",
22
+ matches: "&approx; #{I18n.t("headmin.filters.operators.matches")}",
23
+ does_not_match: "&napprox; #{I18n.t("headmin.filters.operators.does_not_match")}",
24
+ is_null: "&#9675; #{I18n.t("headmin.filters.operators.is_null")}",
25
+ is_not_null: "&#9679; #{I18n.t("headmin.filters.operators.is_not_null")}"
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,61 @@
1
+ module Headmin
2
+ module Filter
3
+ class OptionsView < ViewModel
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
+ def collection
17
+ @collection || []
18
+ end
19
+
20
+ private
21
+
22
+ def id
23
+ "#{name}_value"
24
+ end
25
+
26
+ def name
27
+ @name || attribute
28
+ end
29
+
30
+ def label
31
+ @label || I18n.t("attributes.#{attribute}", default: name.to_s)
32
+ end
33
+
34
+ def default_base_options
35
+ {
36
+ label: label,
37
+ name: attribute,
38
+ display_values: collection,
39
+ filter: Headmin::Filter::Text.new(name, @params),
40
+ allowed_operators: Headmin::Filter::Text::OPERATORS - %w[starts_with ends_with in not_in]
41
+ }
42
+ end
43
+
44
+ def default_input_options
45
+ {
46
+ label: false,
47
+ wrapper: false,
48
+ id: id,
49
+ data: {
50
+ action: "change->filter#updateHiddenValue",
51
+ filter_target: "value",
52
+ filter_row_target: "original"
53
+ },
54
+ collection: collection,
55
+ selected: selected,
56
+ class: "form-select"
57
+ }
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,13 @@
1
+ module Headmin
2
+ module Filter
3
+ class RowView < ViewModel
4
+ def operator
5
+ @operator || nil
6
+ end
7
+
8
+ def value
9
+ @value || nil
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ module Headmin
2
+ module Filter
3
+ class Search < Headmin::Filter::Base
4
+ def query(collection)
5
+ return collection unless @instructions.any?
6
+ collection.search(raw_value)
7
+ end
8
+
9
+ def cast_value(value)
10
+ value
11
+ end
12
+
13
+ def display_value(value)
14
+ value.downcase
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ module Headmin
2
+ module Filter
3
+ class SearchView < ViewModel
4
+ def input_options
5
+ keys = attributes - %i[params]
6
+ options = to_h.slice(*keys)
7
+ options = default_input_options.merge(options)
8
+ options.merge(label: false)
9
+ end
10
+
11
+ private
12
+
13
+ def default_input_options
14
+ {
15
+ name: name,
16
+ value: params[name],
17
+ wrapper: false,
18
+ placeholder: placeholder
19
+ }
20
+ end
21
+
22
+ def name
23
+ @name || attribute || :search
24
+ end
25
+
26
+ def placeholder
27
+ @placeholder || I18n.t("headmin.filters.search.placeholder", resource: label)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ module Headmin
2
+ module Filter
3
+ class Text < Headmin::Filter::Base
4
+ OPERATORS = %w[eq not_eq in not_in matches does_not_match starts_with ends_with is_null is_not_null starts_with ends_with]
5
+
6
+ def cast_value(value)
7
+ value
8
+ end
9
+
10
+ def display_value(value)
11
+ value.downcase
12
+ end
13
+
14
+ private
15
+
16
+ def convert_to_ends(value)
17
+ "%#{value}"
18
+ end
19
+
20
+ def convert_to_starts(value)
21
+ "#{value}%"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,53 @@
1
+ module Headmin
2
+ module Filter
3
+ class TextView < ViewModel
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
+ @name || attribute
24
+ end
25
+
26
+ def label
27
+ @label || I18n.t("attributes.#{attribute}", default: name.to_s)
28
+ end
29
+
30
+ def default_base_options
31
+ {
32
+ label: label,
33
+ name: attribute,
34
+ filter: Headmin::Filter::Text.new(name, @params),
35
+ allowed_operators: Headmin::Filter::Text::OPERATORS - %w[in not_in]
36
+ }
37
+ end
38
+
39
+ def default_input_options
40
+ {
41
+ label: false,
42
+ wrapper: false,
43
+ id: id,
44
+ data: {
45
+ action: "change->filter#updateHiddenValue",
46
+ filter_target: "value",
47
+ filter_row_target: "original"
48
+ }
49
+ }
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,29 @@
1
+ module Headmin
2
+ class Filters
3
+ # Example:
4
+ #
5
+ # @orders = Headmin::Filters.new(params, {
6
+ # status: :text,
7
+ # price: :number,
8
+ # in_stock: :boolean
9
+ # }).query(Order)
10
+
11
+ def initialize(params, param_types)
12
+ @params = params
13
+ @param_types = param_types
14
+ end
15
+
16
+ def parse(attribute, type)
17
+ class_name = "Headmin::Filter::#{type.to_s.classify}".constantize
18
+ class_name.new(attribute, @params)
19
+ end
20
+
21
+ def query(collection)
22
+ @param_types.each do |attribute, type|
23
+ filter = parse(attribute, type)
24
+ collection = filter.query(collection)
25
+ end
26
+ collection
27
+ end
28
+ end
29
+ end
@@ -4,7 +4,7 @@ module Headmin
4
4
  def repeater_options
5
5
  keys = %i[form attribute names label]
6
6
  options = to_h.slice(*keys)
7
- default_repeater_options.merge(options)
7
+ default_repeater_options.deep_merge(options)
8
8
  end
9
9
 
10
10
  def paths
@@ -17,7 +17,7 @@ module Headmin
17
17
  def input_options
18
18
  keys = attributes - %i[attribute form label validate wrapper checked_value unchecked_value]
19
19
  options = to_h.slice(*keys)
20
- default_input_options.merge(options)
20
+ default_input_options.deep_merge(options)
21
21
  end
22
22
 
23
23
  def label_options
@@ -31,11 +31,11 @@ module Headmin
31
31
  end
32
32
 
33
33
  def wrapper_options
34
- default_wrapper_options.merge(
34
+ default_wrapper_options.deep_merge(
35
35
  {
36
36
  class: %w[form-check mb-3]
37
37
  }
38
- ).merge(@wrapper || {})
38
+ ).deep_merge(@wrapper || {})
39
39
  end
40
40
 
41
41
  private
@@ -2,11 +2,11 @@ module Headmin
2
2
  module Form
3
3
  class DateRangeView < ViewModel
4
4
  def start_options
5
- default_start_options.merge(@start || {})
5
+ default_start_options.deep_merge(@start || {})
6
6
  end
7
7
 
8
8
  def end_options
9
- default_end_options.merge(@end || {})
9
+ default_end_options.deep_merge(@end || {})
10
10
  end
11
11
 
12
12
  private
@@ -12,19 +12,19 @@ module Headmin
12
12
  def input_options
13
13
  keys = attributes - %i[append attribute float form input_group input_group label prepend validate wrapper]
14
14
  options = to_h.slice(*keys)
15
- default_input_options.merge(options)
15
+ default_input_options.deep_merge(options)
16
16
  end
17
17
 
18
18
  def input_group_options
19
19
  default_input_group_options
20
- .merge(label_input_group_options)
21
- .merge(@input_group || {})
20
+ .deep_merge(label_input_group_options)
21
+ .deep_merge(@input_group || {})
22
22
  end
23
23
 
24
24
  def wrapper_options
25
- default_wrapper_options.merge({
25
+ default_wrapper_options.deep_merge({
26
26
  class: ["mb-3", ("form-floating" if float)]
27
- }).merge(@wrapper || {})
27
+ }).deep_merge(@wrapper || {})
28
28
  end
29
29
 
30
30
  private