refine-rails 2.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +413 -0
- data/Rakefile +8 -0
- data/app/assets/config/refine_rails_manifest.js +0 -0
- data/app/assets/javascripts/refine-stimulus.esm.js +2 -0
- data/app/assets/javascripts/refine-stimulus.esm.js.map +1 -0
- data/app/assets/javascripts/refine-stimulus.js +2 -0
- data/app/assets/javascripts/refine-stimulus.js.map +1 -0
- data/app/assets/javascripts/refine-stimulus.modern.js +2 -0
- data/app/assets/javascripts/refine-stimulus.modern.js.map +1 -0
- data/app/assets/javascripts/refine-stimulus.umd.js +2 -0
- data/app/assets/javascripts/refine-stimulus.umd.js.map +1 -0
- data/app/assets/stylesheets/index.css +1873 -0
- data/app/assets/stylesheets/index.tailwind.css +1035 -0
- data/app/controllers/refine/blueprints_controller.rb +80 -0
- data/app/controllers/refine/filter_application_controller.rb +29 -0
- data/app/controllers/refine/inline/criteria_controller.rb +161 -0
- data/app/controllers/refine/inline/stored_filters_controller.rb +84 -0
- data/app/controllers/refine/stored_filters_controller.rb +69 -0
- data/app/javascript/controllers/index.js +66 -0
- data/app/javascript/controllers/refine/add-controller.js +42 -0
- data/app/javascript/controllers/refine/criterion-form-controller.js +31 -0
- data/app/javascript/controllers/refine/date-controller.js +113 -0
- data/app/javascript/controllers/refine/defaults-controller.js +32 -0
- data/app/javascript/controllers/refine/delete-controller.js +13 -0
- data/app/javascript/controllers/refine/filter-pills-controller.js +63 -0
- data/app/javascript/controllers/refine/form-controller.js +51 -0
- data/app/javascript/controllers/refine/inline-conditions-controller.js +33 -0
- data/app/javascript/controllers/refine/popup-controller.js +46 -0
- data/app/javascript/controllers/refine/search-filter-controller.js +50 -0
- data/app/javascript/controllers/refine/server-refresh-controller.js +43 -0
- data/app/javascript/controllers/refine/state-controller.js +220 -0
- data/app/javascript/controllers/refine/stored-filter-controller.js +23 -0
- data/app/javascript/controllers/refine/submit-form-controller.js +8 -0
- data/app/javascript/controllers/refine/toggle-controller.js +12 -0
- data/app/javascript/controllers/refine/turbo-stream-form-controller.js +24 -0
- data/app/javascript/controllers/refine/turbo-stream-link-controller.js +24 -0
- data/app/javascript/controllers/refine/update-controller.js +86 -0
- data/app/javascript/index.js +1 -0
- data/app/javascript/refine/helpers/index.js +77 -0
- data/app/models/refine/blueprints/blueprint.rb +58 -0
- data/app/models/refine/blueprints/blueprint_example.json +25 -0
- data/app/models/refine/conditions/boolean_condition.rb +112 -0
- data/app/models/refine/conditions/clause.rb +38 -0
- data/app/models/refine/conditions/clauses.rb +38 -0
- data/app/models/refine/conditions/condition.rb +285 -0
- data/app/models/refine/conditions/condition_error.rb +1 -0
- data/app/models/refine/conditions/date_condition.rb +464 -0
- data/app/models/refine/conditions/date_with_time_condition.rb +8 -0
- data/app/models/refine/conditions/errors/condition_clause_error.rb +7 -0
- data/app/models/refine/conditions/errors/criteria_limit_exceeded_error.rb +2 -0
- data/app/models/refine/conditions/errors/option_error.rb +2 -0
- data/app/models/refine/conditions/errors/relationship_error.rb +1 -0
- data/app/models/refine/conditions/filter_condition.rb +93 -0
- data/app/models/refine/conditions/has_clauses.rb +117 -0
- data/app/models/refine/conditions/has_meta.rb +10 -0
- data/app/models/refine/conditions/has_refinements.rb +156 -0
- data/app/models/refine/conditions/numeric_condition.rb +224 -0
- data/app/models/refine/conditions/option_condition.rb +260 -0
- data/app/models/refine/conditions/text_condition.rb +152 -0
- data/app/models/refine/conditions/uses_attributes.rb +168 -0
- data/app/models/refine/filter.rb +302 -0
- data/app/models/refine/filters/blueprint_editor.rb +102 -0
- data/app/models/refine/filters/builder.rb +59 -0
- data/app/models/refine/filters/criterion.rb +87 -0
- data/app/models/refine/filters/query.rb +82 -0
- data/app/models/refine/inline/criteria/input.rb +50 -0
- data/app/models/refine/inline/criteria/numeric_refinement.rb +13 -0
- data/app/models/refine/inline/criteria/option.rb +2 -0
- data/app/models/refine/inline/criterion.rb +141 -0
- data/app/models/refine/invalid_filter_error.rb +8 -0
- data/app/models/refine/stabilize.rb +29 -0
- data/app/models/refine/stabilizers/database_stabilizer.rb +21 -0
- data/app/models/refine/stabilizers/errors/url_stabilizer_error.rb +2 -0
- data/app/models/refine/stabilizers/url_encoded_stabilizer.rb +21 -0
- data/app/models/refine/stored_filter.rb +14 -0
- data/app/models/refine/tracks_pending_relationship_subqueries.rb +196 -0
- data/app/views/_filter_builder_dropdown.html.erb +63 -0
- data/app/views/_filter_pills.html.erb +40 -0
- data/app/views/_loading.html.erb +32 -0
- data/app/views/refine/blueprints/_add_and.html.erb +25 -0
- data/app/views/refine/blueprints/_add_group.html.erb +24 -0
- data/app/views/refine/blueprints/_clause_select.html.erb +24 -0
- data/app/views/refine/blueprints/_condition_select.html.erb +53 -0
- data/app/views/refine/blueprints/_criterion.html.erb +41 -0
- data/app/views/refine/blueprints/_criterion_errors.html.erb +7 -0
- data/app/views/refine/blueprints/_delete_criterion.html.erb +11 -0
- data/app/views/refine/blueprints/_group.html.erb +13 -0
- data/app/views/refine/blueprints/_query.html.erb +34 -0
- data/app/views/refine/blueprints/_stored_filters.html.erb +23 -0
- data/app/views/refine/blueprints/clauses/_date_condition.html.erb +80 -0
- data/app/views/refine/blueprints/clauses/_date_picker.html.erb +26 -0
- data/app/views/refine/blueprints/clauses/_filter_condition.html.erb +36 -0
- data/app/views/refine/blueprints/clauses/_numeric_condition.html.erb +35 -0
- data/app/views/refine/blueprints/clauses/_option_condition.html.erb +37 -0
- data/app/views/refine/blueprints/clauses/_text_condition.html.erb +13 -0
- data/app/views/refine/blueprints/create.turbo_stream.erb +22 -0
- data/app/views/refine/blueprints/new.html.erb +7 -0
- data/app/views/refine/blueprints/show.html.erb +4 -0
- data/app/views/refine/blueprints/show.turbo_stream.erb +22 -0
- data/app/views/refine/inline/criteria/_form_fields.html.erb +62 -0
- data/app/views/refine/inline/criteria/create.turbo_stream.erb +19 -0
- data/app/views/refine/inline/criteria/edit.turbo_stream.erb +26 -0
- data/app/views/refine/inline/criteria/index.html.erb +64 -0
- data/app/views/refine/inline/criteria/new.turbo_stream.erb +24 -0
- data/app/views/refine/inline/filters/_add_first_condition_button.html.erb +19 -0
- data/app/views/refine/inline/filters/_and_button.html.erb +26 -0
- data/app/views/refine/inline/filters/_criterion.html.erb +23 -0
- data/app/views/refine/inline/filters/_group.html.erb +13 -0
- data/app/views/refine/inline/filters/_load_button.html.erb +15 -0
- data/app/views/refine/inline/filters/_or_button.html.erb +26 -0
- data/app/views/refine/inline/filters/_popup.html.erb +26 -0
- data/app/views/refine/inline/filters/_save_button.html.erb +15 -0
- data/app/views/refine/inline/filters/_show.html.erb +40 -0
- data/app/views/refine/inline/inputs/_date_condition.html.erb +7 -0
- data/app/views/refine/inline/inputs/_date_condition_days.html.erb +18 -0
- data/app/views/refine/inline/inputs/_date_condition_range.html.erb +22 -0
- data/app/views/refine/inline/inputs/_date_condition_single.html.erb +9 -0
- data/app/views/refine/inline/inputs/_date_picker.html.erb +20 -0
- data/app/views/refine/inline/inputs/_numeric_condition.html.erb +23 -0
- data/app/views/refine/inline/inputs/_option_condition.html.erb +14 -0
- data/app/views/refine/inline/inputs/_text_condition.html.erb +8 -0
- data/app/views/refine/inline/stored_filters/find.turbo_stream.erb +19 -0
- data/app/views/refine/inline/stored_filters/index.html.erb +28 -0
- data/app/views/refine/inline/stored_filters/new.turbo_stream.erb +47 -0
- data/app/views/refine/stored_filters/create.turbo_stream.erb +2 -0
- data/app/views/refine/stored_filters/find.turbo_stream.erb +5 -0
- data/app/views/refine/stored_filters/index.html.erb +39 -0
- data/app/views/refine/stored_filters/new.html.erb +29 -0
- data/app/views/refine/stored_filters/show.html.erb +1 -0
- data/config/locales/en/dates.en.yml +29 -0
- data/config/locales/en/en.yml +20 -0
- data/config/locales/en/refine.en.yml +187 -0
- data/config/routes.rb +17 -0
- data/lib/generators/filter/filter_generator.rb +27 -0
- data/lib/generators/filter/templates/filter.rb.erb +20 -0
- data/lib/refine/rails/engine.rb +15 -0
- data/lib/refine/rails/version.rb +5 -0
- data/lib/refine/rails.rb +38 -0
- data/lib/tasks/refine/rails_tasks.rake +13 -0
- 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,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>— <%= t("refine.stored_filters.select_saved_filter") %> —</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
|