refine-rails 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
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