avo 2.4.1 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of avo might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/app/components/avo/edit/field_wrapper_component.html.erb +2 -2
- data/app/components/avo/edit/field_wrapper_component.rb +6 -1
- data/app/components/avo/fields/belongs_to_field/autocomplete_component.html.erb +3 -0
- data/app/components/avo/fields/belongs_to_field/autocomplete_component.rb +4 -0
- data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +26 -27
- data/app/components/avo/filters_component.html.erb +3 -3
- data/app/components/avo/filters_component.rb +2 -1
- data/app/components/avo/paginator_component.html.erb +3 -3
- data/app/components/avo/paginator_component.rb +3 -3
- data/app/components/avo/views/resource_index_component.html.erb +3 -3
- data/app/components/avo/views/resource_index_component.rb +10 -3
- data/app/controllers/avo/associations_controller.rb +6 -1
- data/app/controllers/avo/base_controller.rb +24 -1
- data/app/controllers/avo/search_controller.rb +22 -1
- data/app/helpers/avo/url_helpers.rb +3 -3
- data/app/javascript/js/controllers/filter_controller.js +9 -0
- data/app/javascript/js/controllers/search_controller.js +9 -2
- data/app/views/avo/base/_boolean_filter.html.erb +23 -15
- data/app/views/avo/base/_multiple_select_filter.html.erb +5 -1
- data/app/views/avo/base/_select_filter.html.erb +5 -1
- data/app/views/avo/base/_text_filter.html.erb +5 -1
- data/app/views/avo/base/index.html.erb +1 -0
- data/app/views/avo/partials/_sidebar_extra.html.erb +2 -0
- data/db/factories.rb +5 -3
- data/lib/avo/base_resource.rb +1 -0
- data/lib/avo/fields/belongs_to_field.rb +11 -1
- data/lib/avo/fields/has_base_field.rb +2 -0
- data/lib/avo/filters/base_filter.rb +18 -0
- data/lib/avo/hosts/association_scope_host.rb +8 -0
- data/lib/avo/services/authorization_service.rb +8 -10
- data/lib/avo/version.rb +1 -1
- data/lib/generators/avo/eject_generator.rb +2 -3
- data/lib/generators/avo/templates/locales/avo.en.yml +2 -1
- data/lib/generators/avo/templates/locales/avo.nb-NO.yml +2 -1
- data/lib/generators/avo/templates/locales/avo.pt-BR.yml +2 -1
- data/lib/generators/avo/templates/locales/avo.ro.yml +2 -1
- data/public/avo-assets/avo.js +22 -22
- data/public/avo-assets/avo.js.map +2 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a1c24962e7af4aae8d474872c00149aac873f23dbbfad3ddf4c8de53cc4c1f75
|
4
|
+
data.tar.gz: e356866b46a51297a576a79d77cdc45f29c3482409390a95257a36797f4e759d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b946132563c3180eefa6eee7417fadb6d85658ffef574560c748ca75da3353c277b978884de218701fedf1e2db732fe129418ae26effad8e4d272223b5aeb25
|
7
|
+
data.tar.gz: 25e18c2e1de5509adfe6a051e64195d5522bfdccceecf9208458d0c0603f3452f818759056c2f24fdaedaa89788bcf00a7e17574bde09265b1c2773fece5e152
|
data/Gemfile.lock
CHANGED
@@ -4,8 +4,8 @@
|
|
4
4
|
<% if @model.present? and @model.errors.include? @field.id %>
|
5
5
|
<div class="text-red-600 mt-2 text-sm"><%= @model.errors.full_messages_for(@field.id).to_sentence %></div>
|
6
6
|
<% end %>
|
7
|
-
<% if
|
8
|
-
<div class="text-gray-600 mt-2 text-sm"><%==
|
7
|
+
<% if help.present? %>
|
8
|
+
<div class="text-gray-600 mt-2 text-sm"><%== help %></div>
|
9
9
|
<% end %>
|
10
10
|
</div>
|
11
11
|
<% end %>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Avo::Edit::FieldWrapperComponent < ViewComponent::Base
|
4
|
-
def initialize(field: nil, dash_if_blank: true, full_width: false, displayed_in_modal: false, form: nil, resource: {}, label: nil, **args)
|
4
|
+
def initialize(field: nil, dash_if_blank: true, full_width: false, displayed_in_modal: false, form: nil, resource: {}, label: nil, help: nil, **args)
|
5
5
|
@field = field
|
6
6
|
@dash_if_blank = dash_if_blank
|
7
7
|
@classes = args[:class].present? ? args[:class] : ""
|
@@ -12,5 +12,10 @@ class Avo::Edit::FieldWrapperComponent < ViewComponent::Base
|
|
12
12
|
@model = resource.present? ? resource.model : nil
|
13
13
|
@full_width = full_width
|
14
14
|
@label = label
|
15
|
+
@help = help
|
16
|
+
end
|
17
|
+
|
18
|
+
def help
|
19
|
+
@help || @field.help
|
15
20
|
end
|
16
21
|
end
|
@@ -4,6 +4,9 @@
|
|
4
4
|
data-search-resource="<%= @model_key %>"
|
5
5
|
data-translation-keys='{"no_item_found": "<%= I18n.translate 'avo.no_item_found' %>"}'
|
6
6
|
data-via-association="belongs_to"
|
7
|
+
data-via-association-id="<%= @field.id %>"
|
8
|
+
data-via-reflection-id="<%= @field.model.id %>"
|
9
|
+
data-via-reflection-class="<%= @field.model.class.to_s %>"
|
7
10
|
></div>
|
8
11
|
<div class="relative w-full" autocomplete="off">
|
9
12
|
<%= @form.text_field @foreign_key,
|
@@ -34,6 +34,10 @@ class Avo::Fields::BelongsToField::AutocompleteComponent < ViewComponent::Base
|
|
34
34
|
result
|
35
35
|
end
|
36
36
|
|
37
|
+
def reflection_class
|
38
|
+
has_polymorphic_association? ? polymorphic_class : @resource.model_class._reflections[@field.id.to_s].klass
|
39
|
+
end
|
40
|
+
|
37
41
|
private
|
38
42
|
|
39
43
|
def should_prefill?
|
@@ -1,20 +1,19 @@
|
|
1
|
-
<%
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
<div class="divide-y"
|
1
|
+
<% if is_polymorphic? %>
|
2
|
+
<%
|
3
|
+
# Set the model keys so we can pass them over
|
4
|
+
model_keys = @field.types.map do |type|
|
5
|
+
resource = Avo::App.get_resource_by_model_name(type.to_s)
|
6
|
+
[type.to_s, resource.model_key]
|
7
|
+
end.to_h
|
8
|
+
%>
|
9
|
+
<div class="divide-y"
|
11
10
|
data-controller="belongs-to-field"
|
12
11
|
data-searchable="<%= @field.searchable %>"
|
13
12
|
data-association="<%= @field.id %>"
|
14
13
|
data-association-class="<%= @field&.target_resource&.model_class || nil %>"
|
15
14
|
>
|
16
|
-
|
17
|
-
|
15
|
+
<%= edit_field_wrapper field: @field, index: @index, form: @form, resource: @resource, displayed_in_modal: @displayed_in_modal, help: @field.polymorphic_help || '' do %>
|
16
|
+
<%= @form.select @field.type_input_foreign_key, @field.types.map { |type| [type.to_s.underscore.humanize, type.to_s] },
|
18
17
|
{
|
19
18
|
value: @field.value,
|
20
19
|
include_blank: @field.placeholder,
|
@@ -26,21 +25,21 @@
|
|
26
25
|
'data-action': 'change->belongs-to-field#changeType'
|
27
26
|
}
|
28
27
|
%>
|
29
|
-
|
28
|
+
<%
|
30
29
|
# If the select field is disabled, no value will be sent. It's how HTML works.
|
31
30
|
# Thus the extra hidden field to actually send the related id to the server.
|
32
31
|
if disabled %>
|
33
|
-
|
32
|
+
<%= @form.hidden_field @field.type_input_foreign_key %>
|
33
|
+
<% end %>
|
34
34
|
<% end %>
|
35
|
-
|
36
|
-
|
37
|
-
<div class="hidden"
|
35
|
+
<% @field.types.each do |type| %>
|
36
|
+
<div class="hidden"
|
38
37
|
data-belongs-to-field-target="type"
|
39
38
|
data-type="<%= type %>"
|
40
39
|
>
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
<%= edit_field_wrapper field: @field, index: @index, form: @form, resource: @resource, displayed_in_modal: @displayed_in_modal, label: type.to_s.underscore.humanize do %>
|
41
|
+
<% if @field.searchable %>
|
42
|
+
<%= render Avo::Fields::BelongsToField::AutocompleteComponent.new form: @form,
|
44
43
|
field: @field,
|
45
44
|
type: type,
|
46
45
|
model_key: model_keys[type.to_s],
|
@@ -49,8 +48,8 @@
|
|
49
48
|
disabled: disabled,
|
50
49
|
polymorphic_record: polymorphic_record
|
51
50
|
%>
|
52
|
-
|
53
|
-
|
51
|
+
<% else %>
|
52
|
+
<%= @form.select @field.id_input_foreign_key,
|
54
53
|
options_for_select(@field.values_for_type(type), @resource.present? && @resource.model.present? ? @resource.model[@field.id_input_foreign_key] : nil),
|
55
54
|
{
|
56
55
|
value: @resource.model[@field.id_input_foreign_key].to_s,
|
@@ -61,17 +60,17 @@
|
|
61
60
|
disabled: disabled
|
62
61
|
}
|
63
62
|
%>
|
64
|
-
|
63
|
+
<%
|
65
64
|
# If the select field is disabled, no value will be sent. It's how HTML works.
|
66
65
|
# Thus the extra hidden field to actually send the related id to the server.
|
67
66
|
if disabled %>
|
68
67
|
<%= @form.hidden_field @field.id_input_foreign_key %>
|
69
68
|
<% end %>
|
69
|
+
<% end %>
|
70
70
|
<% end %>
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
</div>
|
71
|
+
</div>
|
72
|
+
<% end %>
|
73
|
+
</div>
|
75
74
|
<% else %>
|
76
75
|
<%= edit_field_wrapper field: @field, index: @index, form: @form, resource: @resource, displayed_in_modal: @displayed_in_modal do %>
|
77
76
|
<% if @field.searchable %>
|
@@ -9,12 +9,12 @@
|
|
9
9
|
'data-action': 'click->toggle-panel#togglePanel',
|
10
10
|
'data-tippy': 'tooltip' do %>
|
11
11
|
<%= t 'avo.filters' %>
|
12
|
-
<% if
|
13
|
-
<span class="ml-1">(<%=
|
12
|
+
<% if @applied_filters.present? %>
|
13
|
+
<span class="ml-1">(<%= @applied_filters.count %> applied)</span>
|
14
14
|
<% end %>
|
15
15
|
<% end %>
|
16
16
|
<div
|
17
|
-
class="absolute block inset-auto sm:right-0 top-full bg-white min-w-[300px] mt-2 z-20 shadow-modal rounded
|
17
|
+
class="absolute block inset-auto sm:right-0 top-full bg-white min-w-[300px] mt-2 z-20 shadow-modal rounded divide-y divide-gray-300 <%= 'hidden' unless params[:keep_filters_panel_open] %>"
|
18
18
|
data-toggle-panel-target="panel"
|
19
19
|
>
|
20
20
|
<% @filters.each do |filter| %>
|
@@ -3,9 +3,10 @@
|
|
3
3
|
class Avo::FiltersComponent < ViewComponent::Base
|
4
4
|
include Avo::ApplicationHelper
|
5
5
|
|
6
|
-
def initialize(filters: [], resource: nil)
|
6
|
+
def initialize(filters: [], resource: nil, applied_filters: [])
|
7
7
|
@filters = filters
|
8
8
|
@resource = resource
|
9
|
+
@applied_filters = applied_filters
|
9
10
|
end
|
10
11
|
|
11
12
|
def render?
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<%
|
2
2
|
per_page_options = [*Avo.configuration.per_page_steps, Avo.configuration.per_page.to_i, index_params[:per_page].to_i]
|
3
3
|
|
4
|
-
if
|
4
|
+
if parent_model.present?
|
5
5
|
per_page_options.prepend Avo.configuration.via_per_page
|
6
6
|
end
|
7
7
|
|
@@ -24,8 +24,8 @@
|
|
24
24
|
%> <%= t('avo.per_page').downcase %>
|
25
25
|
</div>
|
26
26
|
<% per_page_options.each do |option| %>
|
27
|
-
<% if
|
28
|
-
<%= link_to "Change to #{option} items per page", helpers.related_resources_path(
|
27
|
+
<% if parent_model.present? %>
|
28
|
+
<%= link_to "Change to #{option} items per page", helpers.related_resources_path(parent_model, parent_model, per_page: option, keep_query_params: true), class: 'hidden', 'data-per-page-option': option, 'data-turbo-frame': turbo_frame %>
|
29
29
|
<% else %>
|
30
30
|
<%= link_to "Change to #{option} items per page", helpers.resources_path(resource: resource, per_page: option, keep_query_params: true), class: 'hidden', 'data-per-page-option': option, 'data-turbo-frame': turbo_frame %>
|
31
31
|
<% end %>
|
@@ -5,13 +5,13 @@ class Avo::PaginatorComponent < ViewComponent::Base
|
|
5
5
|
attr_reader :turbo_frame
|
6
6
|
attr_reader :index_params
|
7
7
|
attr_reader :resource
|
8
|
-
attr_reader :
|
8
|
+
attr_reader :parent_model
|
9
9
|
|
10
|
-
def initialize(resource: nil,
|
10
|
+
def initialize(resource: nil, parent_model: nil, pagy: nil, turbo_frame: nil, index_params: nil)
|
11
11
|
@pagy = pagy
|
12
12
|
@turbo_frame = turbo_frame
|
13
13
|
@index_params = index_params
|
14
14
|
@resource = resource
|
15
|
-
@
|
15
|
+
@parent_model = parent_model
|
16
16
|
end
|
17
17
|
end
|
@@ -30,7 +30,7 @@
|
|
30
30
|
<% end %>
|
31
31
|
<% if @filters.present? || available_view_types.count > 1 %>
|
32
32
|
<div class="justify-self-end flex justify-start xs:justify-end items-center px-4 space-x-3">
|
33
|
-
<%= render Avo::FiltersComponent.new filters: @filters, resource: @resource %>
|
33
|
+
<%= render Avo::FiltersComponent.new filters: @filters, resource: @resource, applied_filters: @applied_filters %>
|
34
34
|
<%= render partial: 'avo/partials/view_toggle_button', locals: { available_view_types: available_view_types, view_type: view_type, turbo_frame: @turbo_frame } if available_view_types.count > 1 %>
|
35
35
|
</div>
|
36
36
|
<% end %>
|
@@ -51,7 +51,7 @@
|
|
51
51
|
<% if view_type.to_sym == :table %>
|
52
52
|
<% if @models.present? %>
|
53
53
|
<div class="mt-8">
|
54
|
-
<%= render Avo::PaginatorComponent.new pagy: @pagy, turbo_frame: @turbo_frame || 'none', index_params: @index_params, resource: @resource,
|
54
|
+
<%= render Avo::PaginatorComponent.new pagy: @pagy, turbo_frame: @turbo_frame || 'none', index_params: @index_params, resource: @resource, parent_model: @parent_model %>
|
55
55
|
</div>
|
56
56
|
<% end %>
|
57
57
|
<% end %>
|
@@ -59,7 +59,7 @@
|
|
59
59
|
<% if view_type.to_sym == :grid %>
|
60
60
|
<%= render Avo::Index::ResourceGridComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model) %>
|
61
61
|
<div class="mt-14">
|
62
|
-
<%= render Avo::PaginatorComponent.new pagy: @pagy, turbo_frame: @turbo_frame || 'none', index_params: @index_params, resource: @resource,
|
62
|
+
<%= render Avo::PaginatorComponent.new pagy: @pagy, turbo_frame: @turbo_frame || 'none', index_params: @index_params, resource: @resource, parent_model: @parent_model %>
|
63
63
|
</div>
|
64
64
|
<% end %>
|
65
65
|
<% end %>
|
@@ -14,7 +14,8 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
|
|
14
14
|
actions: [],
|
15
15
|
reflection: nil,
|
16
16
|
turbo_frame: "",
|
17
|
-
parent_model: nil
|
17
|
+
parent_model: nil,
|
18
|
+
applied_filters: []
|
18
19
|
)
|
19
20
|
@resource = resource
|
20
21
|
@resources = resources
|
@@ -26,6 +27,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
|
|
26
27
|
@reflection = reflection
|
27
28
|
@turbo_frame = turbo_frame
|
28
29
|
@parent_model = parent_model
|
30
|
+
@applied_filters = applied_filters
|
29
31
|
end
|
30
32
|
|
31
33
|
def title
|
@@ -90,7 +92,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
|
|
90
92
|
if @reflection.present?
|
91
93
|
args = {
|
92
94
|
via_relation_class: reflection_model_class,
|
93
|
-
via_resource_id: @parent_model.id
|
95
|
+
via_resource_id: @parent_model.id
|
94
96
|
}
|
95
97
|
|
96
98
|
if @reflection.is_a? ActiveRecord::Reflection::ThroughReflection
|
@@ -126,7 +128,12 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
|
|
126
128
|
end
|
127
129
|
|
128
130
|
def description
|
129
|
-
|
131
|
+
# If this is a has many association, the user can pass a description to be shown just for this association.
|
132
|
+
if @reflection.present?
|
133
|
+
return field.description if field.present? && field.description
|
134
|
+
|
135
|
+
return
|
136
|
+
end
|
130
137
|
|
131
138
|
@resource.resource_description
|
132
139
|
end
|
@@ -21,7 +21,7 @@ module Avo
|
|
21
21
|
@association_field = @parent_resource.get_field params[:related_name]
|
22
22
|
|
23
23
|
if @association_field.present? && @association_field.scope.present?
|
24
|
-
@query =
|
24
|
+
@query = Avo::Hosts::AssociationScopeHost.new(block: @association_field.scope, query: @query, parent: @parent_model).handle
|
25
25
|
end
|
26
26
|
|
27
27
|
super
|
@@ -45,6 +45,11 @@ module Avo
|
|
45
45
|
if @field.present? && !@field.searchable
|
46
46
|
query = @authorization.apply_policy @attachment_class
|
47
47
|
|
48
|
+
# Add the association scope to the query scope
|
49
|
+
if @field.scope.present?
|
50
|
+
query = Avo::Hosts::AssociationScopeHost.new(block: @field.scope, query: query, parent: @model).handle
|
51
|
+
end
|
52
|
+
|
48
53
|
@options = query.all.map do |model|
|
49
54
|
[model.send(@attachment_resource.class.title), model.id]
|
50
55
|
end
|
@@ -310,11 +310,34 @@ module Avo
|
|
310
310
|
end
|
311
311
|
|
312
312
|
def set_applied_filters
|
313
|
-
@applied_filters =
|
313
|
+
@applied_filters = Avo::Filters::BaseFilter.decode_filters(params[Avo::Filters::BaseFilter::PARAM_KEY])
|
314
|
+
|
315
|
+
# Some filters react to others and will have to be merged into this
|
316
|
+
@applied_filters = @applied_filters.merge reactive_filters
|
314
317
|
rescue
|
315
318
|
@applied_filters = {}
|
316
319
|
end
|
317
320
|
|
321
|
+
def reactive_filters
|
322
|
+
filter_reactions = {}
|
323
|
+
|
324
|
+
# Go through all filters
|
325
|
+
@resource.get_filters
|
326
|
+
.select do |filter_class|
|
327
|
+
filter_class.instance_methods(false).include? :react
|
328
|
+
end
|
329
|
+
.each do |filter_class|
|
330
|
+
# Run the react method if it's present
|
331
|
+
reaction = filter_class.new.react
|
332
|
+
|
333
|
+
next if reaction.nil?
|
334
|
+
|
335
|
+
filter_reactions[filter_class.to_s] = filter_class.new.react
|
336
|
+
end
|
337
|
+
|
338
|
+
filter_reactions
|
339
|
+
end
|
340
|
+
|
318
341
|
# Get the default state of the filters and override with the user applied filters
|
319
342
|
def filters_to_be_applied
|
320
343
|
filter_defaults = {}
|
@@ -44,7 +44,23 @@ module Avo
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def search_resource(resource)
|
47
|
-
|
47
|
+
query = resource.search_query.call(params: params).limit(8)
|
48
|
+
|
49
|
+
# Figure oute if this is a belongs_to search
|
50
|
+
if params[:via_reflection_class].present? && params[:via_reflection_id].present?
|
51
|
+
# Fetch the field
|
52
|
+
field = belongs_to_field
|
53
|
+
|
54
|
+
if field.scope.present?
|
55
|
+
# Fetch the parent
|
56
|
+
parent = params[:via_reflection_class].safe_constantize.find params[:via_reflection_id]
|
57
|
+
|
58
|
+
# Add to the query
|
59
|
+
query = Avo::Hosts::AssociationScopeHost.new(block: belongs_to_field.scope, query: query, parent: parent).handle
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
results = apply_search_metadata(query, resource)
|
48
64
|
|
49
65
|
result_object = {
|
50
66
|
header: resource.name.pluralize,
|
@@ -75,5 +91,10 @@ module Avo
|
|
75
91
|
result
|
76
92
|
end
|
77
93
|
end
|
94
|
+
|
95
|
+
def belongs_to_field
|
96
|
+
fields = ::Avo::App.get_resource_by_model_name(params[:via_reflection_class]).get_field_definitions
|
97
|
+
fields.find { |f| f.id.to_s == params[:via_association_id] }
|
98
|
+
end
|
78
99
|
end
|
79
100
|
end
|
@@ -59,11 +59,11 @@ module Avo
|
|
59
59
|
|
60
60
|
def related_resources_path(
|
61
61
|
parent_model,
|
62
|
-
|
62
|
+
record,
|
63
63
|
keep_query_params: false,
|
64
64
|
**args
|
65
65
|
)
|
66
|
-
return if
|
66
|
+
return if record.nil?
|
67
67
|
|
68
68
|
existing_params = {}
|
69
69
|
|
@@ -75,7 +75,7 @@ module Avo
|
|
75
75
|
rescue
|
76
76
|
end
|
77
77
|
|
78
|
-
avo.resources_associations_index_path(
|
78
|
+
avo.resources_associations_index_path(parent_model.model_name.route_key, record.id, **existing_params, **args)
|
79
79
|
end
|
80
80
|
|
81
81
|
def order_up_resource_path(model:, resource:, **args)
|
@@ -4,6 +4,10 @@ import URI from 'urijs'
|
|
4
4
|
export default class extends Controller {
|
5
5
|
static targets = ['urlRedirect']
|
6
6
|
|
7
|
+
static values = {
|
8
|
+
keepFiltersPanelOpen: Boolean,
|
9
|
+
}
|
10
|
+
|
7
11
|
// eslint-disable-next-line class-methods-use-this
|
8
12
|
uriParams() {
|
9
13
|
return URI(window.location.toString()).query(true)
|
@@ -78,6 +82,11 @@ export default class extends Controller {
|
|
78
82
|
...url.query(true),
|
79
83
|
}
|
80
84
|
|
85
|
+
if (this.keepFiltersPanelOpenValue) {
|
86
|
+
// eslint-disable-next-line camelcase
|
87
|
+
query.keep_filters_panel_open = this.keepFiltersPanelOpenValue
|
88
|
+
}
|
89
|
+
|
81
90
|
if (encodedFilters) {
|
82
91
|
query.filters = encodedFilters
|
83
92
|
} else {
|
@@ -68,8 +68,15 @@ export default class extends Controller {
|
|
68
68
|
}
|
69
69
|
|
70
70
|
if (this.isBelongsToSearch) {
|
71
|
-
|
72
|
-
|
71
|
+
params = {
|
72
|
+
...params,
|
73
|
+
// eslint-disable-next-line camelcase
|
74
|
+
via_association_id: this.dataset.viaAssociationId,
|
75
|
+
// eslint-disable-next-line camelcase
|
76
|
+
via_reflection_class: this.dataset.viaReflectionClass,
|
77
|
+
// eslint-disable-next-line camelcase
|
78
|
+
via_reflection_id: this.dataset.viaReflectionId,
|
79
|
+
}
|
73
80
|
}
|
74
81
|
|
75
82
|
return url.segment(segments).search(params).toString()
|
@@ -1,20 +1,28 @@
|
|
1
|
-
<div
|
1
|
+
<div
|
2
|
+
data-controller="boolean-filter"
|
3
|
+
data-filter-name="<%= filter.name %>"
|
4
|
+
data-boolean-filter-keep-filters-panel-open-value="<%= @resource.keep_filters_panel_open %>"
|
5
|
+
>
|
2
6
|
<%= filter_wrapper name: filter.name do %>
|
3
7
|
<div class="flex items-center">
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
8
|
+
<% if filter.options.empty? %>
|
9
|
+
<div class="text-sm text-gray-600"><%= filter.class.empty_message %></div>
|
10
|
+
<% else %>
|
11
|
+
<div class="space-y-2">
|
12
|
+
<% filter.options.each do |value, label| %>
|
13
|
+
<label class="flex items-center text-gray-700 text-sm">
|
14
|
+
<%= check_box_tag filter.id, value, filter.selected_value(value.to_s, @applied_filters),
|
15
|
+
class: 'mr-2 text-lg h-4 w-4',
|
16
|
+
id: "avo_filters_#{filter.id.parameterize.underscore}",
|
17
|
+
'data-filter-class': filter.class,
|
18
|
+
'data-boolean-filter-target': 'option',
|
19
|
+
'data-action': 'input->boolean-filter#changeFilter'
|
20
|
+
%>
|
21
|
+
<%= label %>
|
22
|
+
</label>
|
23
|
+
<% end %>
|
24
|
+
</div>
|
25
|
+
<% end %>
|
18
26
|
<%= link_to 'url_redirect', request.url, data: { 'boolean-filter-target': 'urlRedirect', 'turbo-frame': params[:turbo_frame] }, style: 'hidden', class: 'hidden' %>
|
19
27
|
</div>
|
20
28
|
<% end %>
|
@@ -1,4 +1,8 @@
|
|
1
|
-
<div
|
1
|
+
<div
|
2
|
+
data-controller="multiple-select-filter"
|
3
|
+
data-filter-name="<%= filter.name %>"
|
4
|
+
data-multiple-select-filter-keep-filters-panel-open-value="<%= @resource.keep_filters_panel_open %>"
|
5
|
+
>
|
2
6
|
<%= filter_wrapper name: filter.name do %>
|
3
7
|
<%= select_tag filter.id, options_for_select(filter.options.invert, filter.selected_value(@applied_filters)),
|
4
8
|
class: input_classes('w-full mb-0'),
|
@@ -1,4 +1,8 @@
|
|
1
|
-
<div
|
1
|
+
<div
|
2
|
+
data-controller="select-filter"
|
3
|
+
data-filter-name="<%= filter.name %>"
|
4
|
+
data-select-filter-keep-filters-panel-open-value="<%= @resource.keep_filters_panel_open %>"
|
5
|
+
>
|
2
6
|
<%= filter_wrapper name: filter.name do %>
|
3
7
|
<%= select_tag filter.id, options_for_select(filter.options.invert, filter.applied_or_default_value(@applied_filters)),
|
4
8
|
class: input_classes('w-full mb-0'),
|
@@ -1,4 +1,8 @@
|
|
1
|
-
<div
|
1
|
+
<div
|
2
|
+
data-controller="text-filter"
|
3
|
+
data-filter-name="<%= filter.name %>"
|
4
|
+
data-text-filter-keep-filters-panel-open-value="<%= @resource.keep_filters_panel_open %>"
|
5
|
+
>
|
2
6
|
<%= filter_wrapper name: filter.name do %>
|
3
7
|
<%= text_field_tag filter.id, filter.applied_or_default_value(@applied_filters),
|
4
8
|
class: input_classes('w-full mb-0'),
|
data/db/factories.rb
CHANGED
@@ -25,7 +25,7 @@ FactoryBot.define do
|
|
25
25
|
Time.now - rand(10...365).days
|
26
26
|
end
|
27
27
|
end
|
28
|
-
status {
|
28
|
+
status { ::Post.statuses.keys.sample }
|
29
29
|
end
|
30
30
|
|
31
31
|
factory :project do
|
@@ -42,11 +42,11 @@ FactoryBot.define do
|
|
42
42
|
end
|
43
43
|
|
44
44
|
factory :comment do
|
45
|
-
body { Faker::Lorem.paragraphs(number: rand(4...10)).join(
|
45
|
+
body { Faker::Lorem.paragraphs(number: rand(4...10)).join(" ") }
|
46
46
|
end
|
47
47
|
|
48
48
|
factory :review do
|
49
|
-
body { Faker::Lorem.paragraphs(number: rand(4...10)).join(
|
49
|
+
body { Faker::Lorem.paragraphs(number: rand(4...10)).join(" ") }
|
50
50
|
end
|
51
51
|
|
52
52
|
factory :person do
|
@@ -64,6 +64,8 @@ FactoryBot.define do
|
|
64
64
|
|
65
65
|
factory :course do
|
66
66
|
name { Faker::Educator.unique.course_name }
|
67
|
+
country { Course.countries.sample }
|
68
|
+
city { Course.cities.stringify_keys[country].sample }
|
67
69
|
end
|
68
70
|
|
69
71
|
factory :course_link, class: "Course::Link" do
|
data/lib/avo/base_resource.rb
CHANGED
@@ -62,6 +62,8 @@ module Avo
|
|
62
62
|
attr_reader :relation_method
|
63
63
|
attr_reader :types # for Polymorphic associations
|
64
64
|
attr_reader :allow_via_detaching
|
65
|
+
attr_reader :scope
|
66
|
+
attr_reader :polymorphic_help
|
65
67
|
|
66
68
|
def initialize(id, **args, &block)
|
67
69
|
args[:placeholder] ||= I18n.t("avo.choose_an_option")
|
@@ -73,6 +75,8 @@ module Avo
|
|
73
75
|
@types = args[:types]
|
74
76
|
@relation_method = id.to_s.parameterize.underscore
|
75
77
|
@allow_via_detaching = args[:allow_via_detaching] == true
|
78
|
+
@scope = args[:scope]
|
79
|
+
@polymorphic_help = args[:polymorphic_help]
|
76
80
|
end
|
77
81
|
|
78
82
|
def searchable
|
@@ -111,7 +115,13 @@ module Avo
|
|
111
115
|
resource = target_resource
|
112
116
|
resource = App.get_resource_by_model_name model if model.present?
|
113
117
|
|
114
|
-
|
118
|
+
query = Avo::Services::AuthorizationService.apply_policy(user, resource.class.query_scope)
|
119
|
+
|
120
|
+
if scope.present?
|
121
|
+
query = Avo::Hosts::AssociationScopeHost.new(block: scope, query: query, parent: get_model).handle
|
122
|
+
end
|
123
|
+
|
124
|
+
query.all.map do |model|
|
115
125
|
[model.send(resource.class.title), model.id]
|
116
126
|
end
|
117
127
|
end
|