refine-rails 2.9.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 (141) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +413 -0
  3. data/Rakefile +8 -0
  4. data/app/assets/config/refine_rails_manifest.js +0 -0
  5. data/app/assets/javascripts/refine-stimulus.esm.js +2 -0
  6. data/app/assets/javascripts/refine-stimulus.esm.js.map +1 -0
  7. data/app/assets/javascripts/refine-stimulus.js +2 -0
  8. data/app/assets/javascripts/refine-stimulus.js.map +1 -0
  9. data/app/assets/javascripts/refine-stimulus.modern.js +2 -0
  10. data/app/assets/javascripts/refine-stimulus.modern.js.map +1 -0
  11. data/app/assets/javascripts/refine-stimulus.umd.js +2 -0
  12. data/app/assets/javascripts/refine-stimulus.umd.js.map +1 -0
  13. data/app/assets/stylesheets/index.css +1873 -0
  14. data/app/assets/stylesheets/index.tailwind.css +1035 -0
  15. data/app/controllers/refine/blueprints_controller.rb +80 -0
  16. data/app/controllers/refine/filter_application_controller.rb +29 -0
  17. data/app/controllers/refine/inline/criteria_controller.rb +161 -0
  18. data/app/controllers/refine/inline/stored_filters_controller.rb +84 -0
  19. data/app/controllers/refine/stored_filters_controller.rb +69 -0
  20. data/app/javascript/controllers/index.js +66 -0
  21. data/app/javascript/controllers/refine/add-controller.js +42 -0
  22. data/app/javascript/controllers/refine/criterion-form-controller.js +31 -0
  23. data/app/javascript/controllers/refine/date-controller.js +113 -0
  24. data/app/javascript/controllers/refine/defaults-controller.js +32 -0
  25. data/app/javascript/controllers/refine/delete-controller.js +13 -0
  26. data/app/javascript/controllers/refine/filter-pills-controller.js +63 -0
  27. data/app/javascript/controllers/refine/form-controller.js +51 -0
  28. data/app/javascript/controllers/refine/inline-conditions-controller.js +33 -0
  29. data/app/javascript/controllers/refine/popup-controller.js +46 -0
  30. data/app/javascript/controllers/refine/search-filter-controller.js +50 -0
  31. data/app/javascript/controllers/refine/server-refresh-controller.js +43 -0
  32. data/app/javascript/controllers/refine/state-controller.js +220 -0
  33. data/app/javascript/controllers/refine/stored-filter-controller.js +23 -0
  34. data/app/javascript/controllers/refine/submit-form-controller.js +8 -0
  35. data/app/javascript/controllers/refine/toggle-controller.js +12 -0
  36. data/app/javascript/controllers/refine/turbo-stream-form-controller.js +24 -0
  37. data/app/javascript/controllers/refine/turbo-stream-link-controller.js +24 -0
  38. data/app/javascript/controllers/refine/update-controller.js +86 -0
  39. data/app/javascript/index.js +1 -0
  40. data/app/javascript/refine/helpers/index.js +77 -0
  41. data/app/models/refine/blueprints/blueprint.rb +58 -0
  42. data/app/models/refine/blueprints/blueprint_example.json +25 -0
  43. data/app/models/refine/conditions/boolean_condition.rb +112 -0
  44. data/app/models/refine/conditions/clause.rb +38 -0
  45. data/app/models/refine/conditions/clauses.rb +38 -0
  46. data/app/models/refine/conditions/condition.rb +285 -0
  47. data/app/models/refine/conditions/condition_error.rb +1 -0
  48. data/app/models/refine/conditions/date_condition.rb +464 -0
  49. data/app/models/refine/conditions/date_with_time_condition.rb +8 -0
  50. data/app/models/refine/conditions/errors/condition_clause_error.rb +7 -0
  51. data/app/models/refine/conditions/errors/criteria_limit_exceeded_error.rb +2 -0
  52. data/app/models/refine/conditions/errors/option_error.rb +2 -0
  53. data/app/models/refine/conditions/errors/relationship_error.rb +1 -0
  54. data/app/models/refine/conditions/filter_condition.rb +93 -0
  55. data/app/models/refine/conditions/has_clauses.rb +117 -0
  56. data/app/models/refine/conditions/has_meta.rb +10 -0
  57. data/app/models/refine/conditions/has_refinements.rb +156 -0
  58. data/app/models/refine/conditions/numeric_condition.rb +224 -0
  59. data/app/models/refine/conditions/option_condition.rb +260 -0
  60. data/app/models/refine/conditions/text_condition.rb +152 -0
  61. data/app/models/refine/conditions/uses_attributes.rb +168 -0
  62. data/app/models/refine/filter.rb +302 -0
  63. data/app/models/refine/filters/blueprint_editor.rb +102 -0
  64. data/app/models/refine/filters/builder.rb +59 -0
  65. data/app/models/refine/filters/criterion.rb +87 -0
  66. data/app/models/refine/filters/query.rb +82 -0
  67. data/app/models/refine/inline/criteria/input.rb +50 -0
  68. data/app/models/refine/inline/criteria/numeric_refinement.rb +13 -0
  69. data/app/models/refine/inline/criteria/option.rb +2 -0
  70. data/app/models/refine/inline/criterion.rb +141 -0
  71. data/app/models/refine/invalid_filter_error.rb +8 -0
  72. data/app/models/refine/stabilize.rb +29 -0
  73. data/app/models/refine/stabilizers/database_stabilizer.rb +21 -0
  74. data/app/models/refine/stabilizers/errors/url_stabilizer_error.rb +2 -0
  75. data/app/models/refine/stabilizers/url_encoded_stabilizer.rb +21 -0
  76. data/app/models/refine/stored_filter.rb +14 -0
  77. data/app/models/refine/tracks_pending_relationship_subqueries.rb +196 -0
  78. data/app/views/_filter_builder_dropdown.html.erb +63 -0
  79. data/app/views/_filter_pills.html.erb +40 -0
  80. data/app/views/_loading.html.erb +32 -0
  81. data/app/views/refine/blueprints/_add_and.html.erb +25 -0
  82. data/app/views/refine/blueprints/_add_group.html.erb +24 -0
  83. data/app/views/refine/blueprints/_clause_select.html.erb +24 -0
  84. data/app/views/refine/blueprints/_condition_select.html.erb +53 -0
  85. data/app/views/refine/blueprints/_criterion.html.erb +41 -0
  86. data/app/views/refine/blueprints/_criterion_errors.html.erb +7 -0
  87. data/app/views/refine/blueprints/_delete_criterion.html.erb +11 -0
  88. data/app/views/refine/blueprints/_group.html.erb +13 -0
  89. data/app/views/refine/blueprints/_query.html.erb +34 -0
  90. data/app/views/refine/blueprints/_stored_filters.html.erb +23 -0
  91. data/app/views/refine/blueprints/clauses/_date_condition.html.erb +80 -0
  92. data/app/views/refine/blueprints/clauses/_date_picker.html.erb +26 -0
  93. data/app/views/refine/blueprints/clauses/_filter_condition.html.erb +36 -0
  94. data/app/views/refine/blueprints/clauses/_numeric_condition.html.erb +35 -0
  95. data/app/views/refine/blueprints/clauses/_option_condition.html.erb +37 -0
  96. data/app/views/refine/blueprints/clauses/_text_condition.html.erb +13 -0
  97. data/app/views/refine/blueprints/create.turbo_stream.erb +22 -0
  98. data/app/views/refine/blueprints/new.html.erb +7 -0
  99. data/app/views/refine/blueprints/show.html.erb +4 -0
  100. data/app/views/refine/blueprints/show.turbo_stream.erb +22 -0
  101. data/app/views/refine/inline/criteria/_form_fields.html.erb +62 -0
  102. data/app/views/refine/inline/criteria/create.turbo_stream.erb +19 -0
  103. data/app/views/refine/inline/criteria/edit.turbo_stream.erb +26 -0
  104. data/app/views/refine/inline/criteria/index.html.erb +64 -0
  105. data/app/views/refine/inline/criteria/new.turbo_stream.erb +24 -0
  106. data/app/views/refine/inline/filters/_add_first_condition_button.html.erb +19 -0
  107. data/app/views/refine/inline/filters/_and_button.html.erb +26 -0
  108. data/app/views/refine/inline/filters/_criterion.html.erb +23 -0
  109. data/app/views/refine/inline/filters/_group.html.erb +13 -0
  110. data/app/views/refine/inline/filters/_load_button.html.erb +15 -0
  111. data/app/views/refine/inline/filters/_or_button.html.erb +26 -0
  112. data/app/views/refine/inline/filters/_popup.html.erb +26 -0
  113. data/app/views/refine/inline/filters/_save_button.html.erb +15 -0
  114. data/app/views/refine/inline/filters/_show.html.erb +40 -0
  115. data/app/views/refine/inline/inputs/_date_condition.html.erb +7 -0
  116. data/app/views/refine/inline/inputs/_date_condition_days.html.erb +18 -0
  117. data/app/views/refine/inline/inputs/_date_condition_range.html.erb +22 -0
  118. data/app/views/refine/inline/inputs/_date_condition_single.html.erb +9 -0
  119. data/app/views/refine/inline/inputs/_date_picker.html.erb +20 -0
  120. data/app/views/refine/inline/inputs/_numeric_condition.html.erb +23 -0
  121. data/app/views/refine/inline/inputs/_option_condition.html.erb +14 -0
  122. data/app/views/refine/inline/inputs/_text_condition.html.erb +8 -0
  123. data/app/views/refine/inline/stored_filters/find.turbo_stream.erb +19 -0
  124. data/app/views/refine/inline/stored_filters/index.html.erb +28 -0
  125. data/app/views/refine/inline/stored_filters/new.turbo_stream.erb +47 -0
  126. data/app/views/refine/stored_filters/create.turbo_stream.erb +2 -0
  127. data/app/views/refine/stored_filters/find.turbo_stream.erb +5 -0
  128. data/app/views/refine/stored_filters/index.html.erb +39 -0
  129. data/app/views/refine/stored_filters/new.html.erb +29 -0
  130. data/app/views/refine/stored_filters/show.html.erb +1 -0
  131. data/config/locales/en/dates.en.yml +29 -0
  132. data/config/locales/en/en.yml +20 -0
  133. data/config/locales/en/refine.en.yml +187 -0
  134. data/config/routes.rb +17 -0
  135. data/lib/generators/filter/filter_generator.rb +27 -0
  136. data/lib/generators/filter/templates/filter.rb.erb +20 -0
  137. data/lib/refine/rails/engine.rb +15 -0
  138. data/lib/refine/rails/version.rb +5 -0
  139. data/lib/refine/rails.rb +38 -0
  140. data/lib/tasks/refine/rails_tasks.rake +13 -0
  141. metadata +202 -0
@@ -0,0 +1,15 @@
1
+ <%
2
+ criterion = Refine::Inline::Criterion.new(
3
+ stable_id: @refine_filter.to_stable_id,
4
+ client_id: @refine_client_id,
5
+ )
6
+ %>
7
+
8
+ <%= turbo_frame_tag dom_id(criterion, :save) do %>
9
+ <%= link_to new_refine_inline_stored_filter_path(criterion.to_params),
10
+ class: "refine--save-filter-link", data: {turbo_stream: true} do %>
11
+ <span class="material-icons-outlined refine--icon-sm">save</span>
12
+ <span class="refine--save-filter-link-label"><%= t('refine.inline.filters.save_filter') %></span>
13
+ <% end %>
14
+ <% end %>
15
+
@@ -0,0 +1,40 @@
1
+ <%
2
+ groups = Refine::Inline::Criterion.groups_from_filter(@refine_filter, client_id: @refine_client_id, stable_id: @refine_stable_id)
3
+
4
+ main_row_class = class_names "refine--filter-row" => true,
5
+ "refine--has-many-groups" => groups.many?
6
+ %>
7
+
8
+ <%= tag.div class: "refine--filter-wrapper", id: "refine-inline-filter-#{@refine_client_id}" do %>
9
+ <div class="refine--filter-row">
10
+ <%= render "refine/inline/filters/save_button" %>
11
+ </div>
12
+
13
+ <%= tag.div class: main_row_class do %>
14
+ <% if @refine_filter.blueprint.empty? %>
15
+ <%= render "refine/inline/filters/add_first_condition_button", position: 0, btn_class: "
16
+ refine--add-first-condition-btn" %>
17
+ <% else %>
18
+ <div class="refine--filter-label"><%= t('refine.inline.filters.filter') %>:</div>
19
+ <div class="refine--groups-wrapper">
20
+ <% groups.each.with_index do |group, i| %>
21
+ <% unless i == 0 %>
22
+ <div class="refine--group-join"><%= t("refine.inline.filters.or") %></div>
23
+ <% end %>
24
+
25
+ <%= render "refine/inline/filters/group", group: group %>
26
+ <% end %>
27
+
28
+ <div class="refine--group">
29
+ <div class="refine--group-conditions-wrapper">
30
+ <%= render "refine/inline/filters/or_button", position: @refine_filter.blueprint.length %>
31
+ </div>
32
+ </div>
33
+ </div>
34
+ <% end %>
35
+ <% end %>
36
+ <% end %>
37
+
38
+
39
+
40
+
@@ -0,0 +1,7 @@
1
+ <% if criterion.input.clause.in? ["exct", "gt", "lt"] %>
2
+ <%= render "refine/inline/inputs/date_condition_days", input_fields: input_fields, criterion: criterion, form_id: form_id %>
3
+ <% elsif criterion.input.clause == "btwn" %>
4
+ <%= render "refine/inline/inputs/date_condition_range", input_fields: input_fields, criterion: criterion, form_id: form_id %>
5
+ <% else %>
6
+ <%= render "refine/inline/inputs/date_condition_single", input_fields: input_fields, criterion: criterion, form_id: form_id %>
7
+ <% end %>
@@ -0,0 +1,18 @@
1
+ <div class="refine--date-condition-days-container">
2
+ <%= input_fields.label :days, t(".number_of_days"), class: "sr-only" %>
3
+ <%= input_fields.text_field :days,
4
+ class: "refine--input",
5
+ placeholder: criterion.condition.display.downcase,
6
+ form: form_id
7
+ %>
8
+ </div>
9
+ <div class="refine--date-condition-days-modifier-container">
10
+ <%= input_fields.collection_select :modifier,
11
+ Refine::Inline::Criteria::Input::MODIFIERS,
12
+ :first,
13
+ :last,
14
+ {},
15
+ class: "refine--select",
16
+ form: form_id
17
+ %>
18
+ </div>
@@ -0,0 +1,22 @@
1
+ <%= tag.div class: "refine--date-condition-first-date-container-btwn" do %>
2
+ <%= render "refine/inline/inputs/date_picker",
3
+ input_fields: input_fields,
4
+ attribute: :date1,
5
+ value: criterion.input.date1,
6
+ label: "#{criterion.condition.display.downcase} (#{t('.min')})",
7
+ form_id: form_id
8
+ %>
9
+
10
+ <div class="refine--date-condition-and"><%= t(".and") %></div>
11
+
12
+ <div class="refine--date-condition-second-date-container">
13
+ <%= render "refine/inline/inputs/date_picker",
14
+ input_fields: input_fields,
15
+ attribute: :date2,
16
+ value: criterion.input.date2,
17
+ label: "#{criterion.condition.display.downcase} (#{t('.max')})",
18
+ form_id: form_id
19
+ %>
20
+ </div>
21
+ <% end %>
22
+
@@ -0,0 +1,9 @@
1
+ <%= tag.div class: "refine--date-condition-first-date-container" do %>
2
+ <%= render "refine/inline/inputs/date_picker",
3
+ input_fields: input_fields,
4
+ attribute: :date1,
5
+ value: criterion.input.date1,
6
+ label: criterion.condition.display.downcase,
7
+ form_id: form_id
8
+ %>
9
+ <% end %>
@@ -0,0 +1,20 @@
1
+ <div
2
+ data-controller="refine--date"
3
+ class="refine-date-picker-container"
4
+ data-refine--date-locale-value="<%= I18n.locale %>"
5
+ data-refine--date-date-format-value="<%= I18n.t("refine.date.formats.moment") %>"
6
+ data-refine--date-datetime-format-value="<%= I18n.t("refine.time.formats.moment") %>"
7
+ >
8
+ <input
9
+ class="refine--input"
10
+ type="text"
11
+ value="<%= value&.to_date && I18n.l(value&.to_date, format: I18n.t("refine.date.formats.ruby")) %>"
12
+ data-refine--date-target="field"
13
+ placeholder="<%= label %>"
14
+ />
15
+ <%= input_fields.hidden_field attribute,
16
+ value: value&.to_date&.strftime('%Y-%m-%d'),
17
+ data: { refine__date_target: "hiddenField" },
18
+ form: form_id
19
+ %>
20
+ </div>
@@ -0,0 +1,23 @@
1
+ <%
2
+ is_range = ['btwn', 'nbtwn'].include? input_fields.object.clause
3
+ value1_placeholder = criterion.condition.display.downcase
4
+ value1_placeholder += " (#{t('.min')})" if is_range
5
+ value2_placeholder = "#{criterion.condition.display.downcase} (#{t('.max')})"
6
+ %>
7
+
8
+ <%= tag.div class: ('btwn' ? 'refine--numeric-condition-container' : 'refine-numeric-condition-container-btwn') do %>
9
+
10
+ <%= input_fields.text_field :value1,
11
+ class: "refine--input refine--numeric-input",
12
+ placeholder: value1_placeholder,
13
+ form: form_id
14
+ %>
15
+
16
+ <% if is_range %>
17
+ <div class="refine--numeric-condition-and"><%= t(".and") %></div>
18
+ <div class="refine--numeric-condition-second-container">
19
+ <%= input_fields.text_field :value2, class: "refine--input refine--numeric-input", placeholder: value2_placeholder,
20
+ form: form_id %>
21
+ </div>
22
+ <% end %>
23
+ <% end %>
@@ -0,0 +1,14 @@
1
+ <div class="refine-option--condition-container">
2
+ <%= input_fields.collection_select :selected,
3
+ criterion.options,
4
+ :id,
5
+ ->(o) {o.display.truncate(64)},
6
+ {},
7
+ class: "refine--select refine--option-select",
8
+ multiple: criterion.multiple?,
9
+ form: form_id
10
+ %>
11
+ <% if criterion.condition.meta[:postfix] %>
12
+ <span class="refine-option--condition-postfix"><%= meta[:postfix] %></span>
13
+ <% end %>
14
+ </div>
@@ -0,0 +1,8 @@
1
+ <div class="refine--text-condition-container">
2
+ <%= form.label :condition_id, criterion.condition.display, class: "sr-only" %>
3
+ <%= input_fields.text_field :value,
4
+ class: "refine--input refine--text-input #{"has-error" if criterion.errors.any?}",
5
+ placeholder: criterion.condition.display.downcase,
6
+ form: form_id
7
+ %>
8
+ </div>
@@ -0,0 +1,19 @@
1
+ <%= turbo_stream.append_all "body" do %>
2
+ <script>
3
+ (function() {
4
+ const event = new CustomEvent("filter-submit-success", {
5
+ bubbles: true,
6
+ detail: {
7
+ stableId: <%= @refine_stable_id.to_json.html_safe %>,
8
+ url: <%= @url_for_redirect.to_json.html_safe %>,
9
+ formId: <%= @refine_client_id.to_json.html_safe %>
10
+ }
11
+ })
12
+ document
13
+ .getElementById(<%= "refine-inline-filter-#{@refine_client_id}".to_json.html_safe %>)
14
+ .dispatchEvent(event)
15
+ })()
16
+ </script>
17
+ <% end %>
18
+
19
+ <%= turbo_stream.replace "refine-inline-filter-#{@refine_client_id}", partial: "refine/inline/filters/show" %>
@@ -0,0 +1,28 @@
1
+ <%= turbo_frame_tag dom_id(@criterion, :load), class: "refine--stored-filter-list-popup" do %>
2
+ <div class="refine--stored-filter-list">
3
+ <% if @stored_filters.empty? %>
4
+ <a><%= t('.no_stored_filters') %></a>
5
+ <% end %>
6
+
7
+
8
+ <% @stored_filters.each do |filter| %>
9
+ <%= form_with(
10
+ model: @criterion,
11
+ url: find_refine_inline_stored_filters_path,
12
+ method: :post,
13
+ class: "refine--stored-filter-search-form",
14
+ data: {
15
+ turbo_frame: "_top",
16
+ controller: "refine--submit-form"
17
+ }) do |form| %>
18
+ <!-- Saved filter selector -->
19
+ <%= form.hidden_field :stable_id %>
20
+ <%= form.hidden_field :client_id %>
21
+ <%= hidden_field_tag :id, filter.id %>
22
+ <a href="#" class="refine--stored-filter-list-item" data-action="refine--submit-form#submit">
23
+ <%= filter.name %>
24
+ </a>
25
+ <% end %>
26
+ <% end %>
27
+ </div>
28
+ <% end %>
@@ -0,0 +1,47 @@
1
+ <% form_id = dom_id(@criterion, :save_form) %>
2
+
3
+ <%= turbo_stream.update dom_id(@criterion, :save) do %>
4
+ <% if false && @stored_filter.errors.any? # TODO place in tooltip%>
5
+ <% @stored_filter.errors.full_messages.each do |message|%>
6
+ <p class="refine-stored-filter-error"><%= message %></p>
7
+ <% end %>
8
+ <% end %>
9
+
10
+ <%= tag.div class: "refine--save-filter-form" do %>
11
+
12
+ <%= fields model: @criterion do |criteria_fields| %>
13
+ <%= criteria_fields.hidden_field :client_id, form: form_id %>
14
+ <%= criteria_fields.hidden_field :stable_id, form: form_id %>
15
+ <% end %>
16
+
17
+ <%= fields model: @stored_filter do |stored_filter_fields| %>
18
+ <%= stored_filter_fields.label :name, "#{t('.save_filter_label')}" %>
19
+
20
+ <%# TODO replace with content-editable that writes to hidden input %>
21
+ <div class="refine--save-filter-input-wrapper">
22
+ <div class="refine--tooltip"><%= sanitize t('.tooltip') %></div>
23
+
24
+ <%= stored_filter_fields.text_field :name,
25
+ class: "refine--save-filter-input",
26
+ placeholder: t('.save_filter_placeholder'),
27
+ autofocus: true,
28
+ form: form_id
29
+ %>
30
+ </div>
31
+ <% end %>
32
+
33
+ <% end %>
34
+ <% end %>
35
+
36
+
37
+ <%# The actual form tag is appended to the end of the body html. Inputs are attached using the `form` attribute. This allows the query builder to be placed inside an outer form on the page. %>
38
+ <%= turbo_stream.append_all "body" do %>
39
+ <%= form_with(
40
+ url: refine_inline_stored_filters_path,
41
+ method: :post,
42
+ class: "refine--save-filter-form",
43
+ id: form_id,
44
+ data: {
45
+ turbo_frame: dom_id(@criterion, :save)
46
+ }) %>
47
+ <% end %>
@@ -0,0 +1,2 @@
1
+ <%= turbo_stream.replace dom_id(@refine_filter_builder, "stored_filters"), template: "refine/stored_filters/new" %>
2
+ <%= turbo_stream.replace(dom_id(@refine_filter_builder, "query"), partial: "refine/blueprints/query") %>
@@ -0,0 +1,5 @@
1
+ <%= turbo_stream.replace "stored_filters",
2
+ partial: "refine/blueprints/stored_filters" %>
3
+
4
+ <%= turbo_stream.replace dom_id(@refine_filter_builder, :query),
5
+ partial: "refine/blueprints/query" %>
@@ -0,0 +1,39 @@
1
+ <%= turbo_frame_tag "stored_filters" do %>
2
+ <% if flash.alert %>
3
+ <p class="refine-criterion-error">
4
+ <%= flash.alert %>
5
+ </p>
6
+ <% end %>
7
+
8
+ <%= content_tag :div, class: "refine-stored-filter-search-container" do %>
9
+ <%= form_with(
10
+ model: @refine_filter_builder,
11
+ url: find_refine_stored_filters_path,
12
+ method: :post,
13
+ class: "refine-stored-filter-search-form") do |form| %>
14
+ <!-- Saved filter selector -->
15
+ <%= form.hidden_field :filter_class %>
16
+ <%= form.hidden_field :client_id %>
17
+ <%= tag.div class: 'refine-stored-filter-search-selector-container', data: {
18
+ controller: 'fields--super-select',
19
+ fields__super_select_enable_search_value: 'true'
20
+ } do %>
21
+ <select
22
+ data-fields--super-select-target="select"
23
+ name="id"
24
+ >
25
+ <option disabled selected value>&mdash; <%= t("refine.stored_filters.select_saved_filter") %> &mdash;</option>
26
+ <% @stored_filters.each do |filter| %>
27
+ <option
28
+ value="<%= filter.id %>"
29
+ >
30
+ <%= filter.name %>
31
+ </option>
32
+ <% end %>
33
+ </select>
34
+ <% end %>
35
+ <%= link_to t('global.buttons.back'), stored_filters_refine_blueprint_path(@refine_filter_builder.to_params), class: "refine-stored-filter-search-button-cancel"%>
36
+ <%= button_tag t('global.buttons.choose_filter'), type: "submit", class: "refine-stored-filter-search-button-submit" %>
37
+ <% end %>
38
+ <% end %>
39
+ <% end%>
@@ -0,0 +1,29 @@
1
+ <%= turbo_frame_tag "stored_filters" do %>
2
+ <%= content_tag :div, class: "refine-stored-filter-container", data: {
3
+ controller: 'refine--stored-filter',
4
+ refine__stored_filter_id_value: @stored_filter&.id,
5
+ refine__stored_query_id_value: @refine_filter_builder.client_id,
6
+ refine__stored_filter_state_dom_id_value: dom_id(@refine_filter_builder, "query"),
7
+ action: 'blueprint-updated@window->refine--stored-filter#updateBlueprintField'
8
+ } do %>
9
+ <% if @stored_filter.errors.any? %>
10
+ <% @stored_filter.errors.full_messages.each do |message|%>
11
+ <p class="refine-stored-filter-error"><%= message %></p>
12
+ <% end %>
13
+ <% end %>
14
+ <%= form_with(model: @refine_filter_builder, url: refine_stored_filters_path, method: :post,
15
+ class: "refine-stored-filter-form", data: {
16
+ turbo_frame: :stored_filters
17
+ }) do |form| %>
18
+ <%= form.hidden_field :client_id %>
19
+ <%= form.hidden_field :filter_class %>
20
+ <%= form.hidden_field :blueprint_json, data: {refine__stored_filter_target: "blueprintField"} %>
21
+ <input type="text" name="name" placeholder="<%= t('global.filter_name_placeholder')%>"
22
+ class="refine-stored-filter-input"
23
+ value="<%= @stored_filter.name %>"
24
+ />
25
+ <%= link_to t('global.buttons.back'), stored_filters_refine_blueprint_path(@refine_filter_builder.to_params), class: "refine-stored-filter-search-button-cancel"%>
26
+ <%= button_tag t('global.buttons.save'), type: "submit", class: "refine-stored-filter-button-submit" %>
27
+ <% end %>
28
+ <% end %>
29
+ <% end%>
@@ -0,0 +1 @@
1
+ <%= render partial: "editor" %>
@@ -0,0 +1,29 @@
1
+ en:
2
+ time:
3
+ formats:
4
+ z: "%Z"
5
+ date:
6
+ order:
7
+ - :year
8
+ - :month
9
+ - :day
10
+ formats:
11
+ default: "%Y-%m-%d"
12
+ long: "%B %d, %Y"
13
+ short: "%b %d"
14
+ dmy: "%m/%d/%y"
15
+ z: "%Z"
16
+ stamp: "%Y%m%d" # YYYYMMDD
17
+ # formats shared with datetimes
18
+ month_and_year: "%B %Y" # results like: June 2018
19
+ month_day_year: "%B %e, %Y" # results like: June 6, 2018
20
+ abrv_month_day: "%b %-d" # results like: Jan 30
21
+ abrv_month_day_year: "%b %e, %Y" # results like: June 6, 2018
22
+ pretty: "%a, %b %e at %l:%M%p %Z" # results like: Wed, Jun 6 at 7:19AM UTC
23
+ pretty_time: "%l:%M%p %Z" # results like: 7:19AM UTC
24
+ pretty_time_simple: "%l:%M%p" # results like: 7:19AM
25
+ display_time: "%l:%M %p" # results like 4:22 PM
26
+ pretty_date_time_zone: "%a, %b %d, %Y at %l:%M %p %Z" # results like: Thu, Apr 19, 2018 at 2:32 PM UTC
27
+ pretty_day: "%A, %B %e"
28
+ date_range_field: "%m/%d/%y" # results like: 05/26/2022
29
+ date_plus_time_with_zone: "%m/%d/%y %l:%M%p %Z" # results like: 05/26/22 7:19AM UTC
@@ -0,0 +1,20 @@
1
+ en:
2
+ global:
3
+ filter_name_placeholder: Name your filter
4
+ buttons:
5
+ apply: Apply
6
+ cancel: Cancel
7
+ find_filter: Find a saved filter
8
+ save_filter: Save this filter
9
+ choose_filter: Load filter
10
+ filter: Filter
11
+ back: Back
12
+ save: Save
13
+ save_filter: Save this filter
14
+ refine:
15
+ refine_blueprints:
16
+ add_group:
17
+ create_filter: "Create a Filter"
18
+ add_or: "OR"
19
+ add_and:
20
+ add_and: "AND"
@@ -0,0 +1,187 @@
1
+ en:
2
+ refine:
3
+ date:
4
+ formats:
5
+ ruby: "%m/%d/%y"
6
+ moment: "MM/DD/YYYY"
7
+ time:
8
+ formats:
9
+ ruby: "%m/%d/%Y %l:%M %p"
10
+ moment: "MM/DD/YYYY h:mm A"
11
+ daterangepicker:
12
+ firstDay: 1
13
+ separator: " - "
14
+ applyLabel: "Apply"
15
+ cancelLabel: "Cancel"
16
+ fromLabel: "From"
17
+ toLabel: "To"
18
+ customRangeLabel: "Custom"
19
+ weekLabel: "W"
20
+ daysOfWeek:
21
+ - "Su"
22
+ - "Mo"
23
+ - "Tu"
24
+ - "We"
25
+ - "Th"
26
+ - "Fr"
27
+ - "Sa"
28
+ monthNames:
29
+ - "January"
30
+ - "February"
31
+ - "March"
32
+ - "April"
33
+ - "May"
34
+ - "June"
35
+ - "July"
36
+ - "August"
37
+ - "September"
38
+ - "October"
39
+ - "November"
40
+ - "December"
41
+ firstDay: 0
42
+ date_range_controller:
43
+ today: Today
44
+ yesterday: yesterday
45
+ last7Days: Last 7 Days
46
+ last30Days: Last 30 Days
47
+ thisMonth: This Month
48
+ lastMonth: Last Month
49
+ filter_pills:
50
+ pill_and:
51
+ and: and
52
+ or: or
53
+ stored_filters:
54
+ select_saved_filter: "Select a saved filter"
55
+ inline:
56
+ filters:
57
+ load_button: "Load Filter"
58
+ or_button: "+ Add OR Group"
59
+ filter: "Filter"
60
+ criteria_limit: "You can only create up to %{criteria_limit} filter conditions"
61
+ save_filter: "Save Filter"
62
+ or: "or"
63
+ inputs:
64
+ date_number_of_placeholder: "Number of"
65
+ days: "days"
66
+ and: "and"
67
+
68
+ refine_blueprints:
69
+ add_and:
70
+ add_and: "AND"
71
+ add_group:
72
+ add_or: "Add OR"
73
+ create_filter: "Create a filter"
74
+ group:
75
+ buttons:
76
+ add_and: "And"
77
+
78
+ query:
79
+ loading: "Loading..."
80
+ buttons:
81
+ add_or: "Add an 'OR'"
82
+ create_filter: "Create a filter"
83
+ remove_filter: "Remove filter"
84
+ query_or: "or"
85
+
86
+ boolean_condition:
87
+ is_true: is true
88
+ is_false: is false
89
+ is_set: is set
90
+ is_not_set: is not set
91
+ clause:
92
+ required: required
93
+ clauses:
94
+ date_condition:
95
+ number_of: "Number of"
96
+ days: days
97
+ ago: ago
98
+ from_now: from now
99
+ and: and
100
+ first_date: First Date
101
+ second_date: Second Date
102
+ date_number_of_placeholder: "Number of"
103
+ condition:
104
+ attribute_required: An attribute is required.
105
+ condition_must_have_id: Every condition must have an ID
106
+ clause_not_found: "The clause with id %{clause} was not found"
107
+ a_is_required: "A %{k} is required"
108
+ date_condition:
109
+ date1_error: date1 is not a real date
110
+ date2_error: date2 is not a real date
111
+ date1_greater_date2_error: Start date must be an earlier date than end date
112
+ timezone_error: "%{zone} timezone does not exist in ActiveSupport::TimeZone"
113
+ and: and
114
+ days: days
115
+ ago: ago
116
+ from_now: from now
117
+ not_supported: not supported
118
+ is_on: "on"
119
+ not_on: not on
120
+ is_on_or_before: is on or before
121
+ is_on_or_after: is on or after
122
+ is_between: is between
123
+ is_not_between: is not between
124
+ is_more_than: is more than
125
+ is: is
126
+ is_less_than: is less than
127
+ is_set: is set
128
+ is_not_set: is not set
129
+ filter_condition:
130
+ must_be_array: Select must be an array
131
+ options_not_determined: "No options could be determined"
132
+ must_have_id_and_display: An option must have an id and a display attribute.
133
+ must_be_unique: "Options must have unique IDs. Duplicate %{duplicates} found."
134
+ not_found: Filter not found
135
+ in: "Includes"
136
+ not_in: "Does Not Include"
137
+ has_clauses:
138
+ not_determined: "No clause could be determined?"
139
+ must_be_instance_of: "Every clause must be an instance of %{instance}"
140
+ must_have_id_and_display: "A clause must have both id and display keys"
141
+ not_found: "Clause with id: %{id} not found"
142
+ has_refinements:
143
+ not_allowed: "Refinements are not allowed"
144
+ numeric_condition:
145
+ and: and
146
+ not_supported: not supported
147
+ is: is
148
+ is_not: is not
149
+ is_gt: is greater than
150
+ is_gtteq: is greater than or equal to
151
+ is_lt: is less than
152
+ is_lteq: is less than or equal to
153
+ is_between: is between
154
+ is_not_between: is not between
155
+ is_set: is set
156
+ is_not_set: is not set
157
+ option_condition:
158
+ not_supported: not supported
159
+ must_be_array: "Select must be an array"
160
+ not_approved: "Selected %{select} is not configured in options list"
161
+ not_determined: "No options could be determined"
162
+ must_have_id_and_display: "An option must have an id and a display attribute."
163
+ must_be_unique: "Options must have unique IDs. Duplicate %{duplicates} found."
164
+ is: is
165
+ is_not: is not
166
+ is_one_of: is one of
167
+ is_not_one_of: is not one of
168
+ is_set: is set
169
+ is_not_set: is not set
170
+ text_condition:
171
+ is: "is"
172
+ is_not: "is not"
173
+ starts_with: "starts with"
174
+ ends_with: "ends with"
175
+ does_not_start_with: "does not start with"
176
+ does_not_end_with: "does not end with"
177
+ contains: "contains"
178
+ does_not_contain: "does not contain"
179
+ is_set: "is set"
180
+ is_not_set: "is not set"
181
+
182
+ inline:
183
+ filters:
184
+ add_first_condition_button:
185
+ filter: "Filter"
186
+ load_button:
187
+ load_filter: "Load Filter"
data/config/routes.rb ADDED
@@ -0,0 +1,17 @@
1
+ Rails.application.routes.draw do
2
+ namespace :refine do
3
+ resource :blueprint, only: [:show, :new, :create] do
4
+ get "stored_filters", on: :collection
5
+ get "validate", on: :collection
6
+ end
7
+ resources :stored_filters, only: [:index, :new, :create] do
8
+ post "find", on: :collection
9
+ end
10
+ namespace :inline do
11
+ resources :criteria, except: [:show]
12
+ resources :stored_filters, only: [:index, :new, :create] do
13
+ post "find", on: :collection
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Generates a filter for a given model.
4
+ class FilterGenerator < Rails::Generators::NamedBase
5
+ CONDITIONS = %w[text date numeric].freeze
6
+ source_root File.expand_path('templates', __dir__)
7
+
8
+ def create_filter
9
+ @conditions = extract_conditions(args)
10
+ template 'filter.rb.erb', "app/filters/#{plural_name}_filter.rb"
11
+ end
12
+
13
+ private
14
+
15
+ def extract_conditions(args)
16
+ conditions = []
17
+ args.each do |arg|
18
+ field, condition = arg.split(':')
19
+
20
+ throw "#{condition} is an invalid condition" unless CONDITIONS.include? condition
21
+
22
+ conditions << { field: field, condition: condition.capitalize }
23
+ end
24
+
25
+ conditions
26
+ end
27
+ end