avo 2.26.0 → 2.26.2.pre.pr1579
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 +2 -0
- data/Gemfile.lock +15 -10
- data/app/assets/stylesheets/css/tags.css +9 -0
- data/app/components/avo/base_component.rb +2 -2
- data/app/components/avo/field_wrapper_component.rb +2 -1
- data/app/components/avo/fields/belongs_to_field/edit_component.rb +1 -1
- data/app/components/avo/fields/belongs_to_field/show_component.rb +1 -1
- data/app/components/avo/fields/has_one_field/show_component.rb +3 -3
- data/app/components/avo/fields/index_component.rb +1 -1
- data/app/components/avo/fields/tags_field/edit_component.html.erb +13 -10
- data/app/components/avo/index/grid_item_component.rb +1 -1
- data/app/components/avo/index/ordering/button_component.rb +1 -1
- data/app/components/avo/index/resource_controls_component.rb +2 -2
- data/app/components/avo/resource_component.rb +1 -1
- data/app/components/avo/views/resource_index_component.rb +6 -4
- data/app/controllers/avo/actions_controller.rb +1 -1
- data/app/controllers/avo/application_controller.rb +2 -3
- data/app/controllers/avo/associations_controller.rb +2 -2
- data/app/controllers/avo/base_controller.rb +8 -5
- data/app/javascript/js/controllers/fields/tags_field_controller.js +62 -25
- data/app/views/avo/associations/new.html.erb +6 -1
- data/app/views/avo/partials/_footer.html.erb +1 -1
- data/app/views/layouts/avo/application.html.erb +2 -0
- data/config/master.key +1 -0
- data/lib/avo/base_resource.rb +15 -1
- data/lib/avo/engine.rb +6 -0
- data/lib/avo/fields/tags_field.rb +20 -13
- data/lib/avo/services/uri_service.rb +10 -9
- data/lib/avo/version.rb +1 -1
- data/public/avo-assets/avo.base.css +79 -66
- data/public/avo-assets/avo.base.js +161 -161
- data/public/avo-assets/avo.base.js.map +3 -3
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff9b60d0d2f1fc8e8f3536899e3559d78886342441ab558991dc2b374fbc45ac
|
4
|
+
data.tar.gz: 3bab366736547f5d041c5e1283b76b569d8ae788d25eafc4bf919ffb17d3a3e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b159c53be13567f56c149d7cf5d7c16af84dcf1f55f69662d09317c54b5151b628798fc26cf02175a6dd9b19b734e7a4fc3918cbf4b860aff50f53f82d1b9f46
|
7
|
+
data.tar.gz: e74aa9525374ede47f68c0ca70b0ecf4824ddaae4bb2430538462c4226d53a431f35dbfd54ed6dfbd8dad528e21174ada30f9dec34459a5480ad3dd0ebb71a23
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
avo (2.26.
|
4
|
+
avo (2.26.2.pre.pr1579)
|
5
5
|
actionview (>= 6.0)
|
6
6
|
active_link_to
|
7
7
|
activerecord (>= 6.0)
|
@@ -141,7 +141,6 @@ GEM
|
|
141
141
|
regexp_parser (>= 1.5, < 3.0)
|
142
142
|
xpath (~> 3.2)
|
143
143
|
chartkick (4.2.1)
|
144
|
-
childprocess (4.1.0)
|
145
144
|
concurrent-ruby (1.2.0)
|
146
145
|
countries (4.2.3)
|
147
146
|
i18n_data (~> 0.16.0)
|
@@ -192,6 +191,7 @@ GEM
|
|
192
191
|
groupdate (6.1.0)
|
193
192
|
activesupport (>= 5.2)
|
194
193
|
hashdiff (1.0.1)
|
194
|
+
hashids (1.0.6)
|
195
195
|
highline (2.1.0)
|
196
196
|
hightop (0.3.0)
|
197
197
|
activesupport (>= 5.2)
|
@@ -267,10 +267,10 @@ GEM
|
|
267
267
|
net-smtp (0.3.3)
|
268
268
|
net-protocol
|
269
269
|
nio4r (2.5.8)
|
270
|
-
nokogiri (1.14.
|
270
|
+
nokogiri (1.14.2)
|
271
271
|
mini_portile2 (~> 2.8.0)
|
272
272
|
racc (~> 1.4)
|
273
|
-
nokogiri (1.14.
|
273
|
+
nokogiri (1.14.2-x86_64-linux)
|
274
274
|
racc (~> 1.4)
|
275
275
|
orm_adapter (0.5.0)
|
276
276
|
pagy (6.0.1)
|
@@ -278,7 +278,10 @@ GEM
|
|
278
278
|
parser (3.2.0.0)
|
279
279
|
ast (~> 2.4.1)
|
280
280
|
pg (1.4.5)
|
281
|
-
|
281
|
+
prefixed_ids (1.3.0)
|
282
|
+
hashids (>= 1.0.0, < 2.0.0)
|
283
|
+
rails (>= 6.0.0)
|
284
|
+
public_suffix (5.0.1)
|
282
285
|
puma (5.6.5)
|
283
286
|
nio4r (~> 2.0)
|
284
287
|
pundit (2.2.0)
|
@@ -330,7 +333,7 @@ GEM
|
|
330
333
|
rb-inotify (0.10.1)
|
331
334
|
ffi (~> 1.0)
|
332
335
|
redis (4.8.0)
|
333
|
-
regexp_parser (2.
|
336
|
+
regexp_parser (2.7.0)
|
334
337
|
responders (3.0.1)
|
335
338
|
actionpack (>= 5.0)
|
336
339
|
railties (>= 5.0)
|
@@ -375,10 +378,10 @@ GEM
|
|
375
378
|
ruby-vips (2.1.4)
|
376
379
|
ffi (~> 1.12)
|
377
380
|
rubyzip (2.3.2)
|
378
|
-
selenium-webdriver (4.1
|
379
|
-
childprocess (>= 0.5, < 5.0)
|
381
|
+
selenium-webdriver (4.8.1)
|
380
382
|
rexml (~> 3.2, >= 3.2.5)
|
381
|
-
rubyzip (>= 1.2.2)
|
383
|
+
rubyzip (>= 1.2.2, < 3.0)
|
384
|
+
websocket (~> 1.0)
|
382
385
|
simple_po_parser (1.1.6)
|
383
386
|
simplecov (0.22.0)
|
384
387
|
docile (~> 1.1)
|
@@ -409,7 +412,7 @@ GEM
|
|
409
412
|
test-prof (1.0.10)
|
410
413
|
thor (1.2.1)
|
411
414
|
timeout (0.3.0)
|
412
|
-
turbo-rails (1.3.
|
415
|
+
turbo-rails (1.3.3)
|
413
416
|
actionpack (>= 6.0.0)
|
414
417
|
activejob (>= 6.0.0)
|
415
418
|
railties (>= 6.0.0)
|
@@ -435,6 +438,7 @@ GEM
|
|
435
438
|
addressable (>= 2.8.0)
|
436
439
|
crack (>= 0.3.2)
|
437
440
|
hashdiff (>= 0.4.0, < 2.0.0)
|
441
|
+
websocket (1.2.9)
|
438
442
|
websocket-driver (0.7.5)
|
439
443
|
websocket-extensions (>= 0.1.0)
|
440
444
|
websocket-extensions (0.1.5)
|
@@ -491,6 +495,7 @@ DEPENDENCIES
|
|
491
495
|
meta-tags
|
492
496
|
net-smtp
|
493
497
|
pg (>= 0.18, < 2.0)
|
498
|
+
prefixed_ids
|
494
499
|
puma (~> 5.6.4)
|
495
500
|
pundit
|
496
501
|
rails (~> 6.1.0)
|
@@ -14,6 +14,11 @@ tags.tagify {
|
|
14
14
|
|
15
15
|
span.tagify__input {
|
16
16
|
@apply my-1;
|
17
|
+
|
18
|
+
&:after {
|
19
|
+
/* The loader is not centered by default. This will make it look better. */
|
20
|
+
margin-top: 0.25rem;
|
21
|
+
}
|
17
22
|
}
|
18
23
|
}
|
19
24
|
|
@@ -21,3 +26,7 @@ tag.tagify__tag {
|
|
21
26
|
@apply text-sm my-1 mb-0;
|
22
27
|
}
|
23
28
|
|
29
|
+
/* When the tags field is used to select just one value there's a weird ZeroWidthSpace (\u200B) character that breaks the vertical spacing. */
|
30
|
+
[data-tags-field-mode-value="select"] tags.tagify {
|
31
|
+
height: 40px;
|
32
|
+
}
|
@@ -23,10 +23,10 @@ class Avo::BaseComponent < ViewComponent::Base
|
|
23
23
|
|
24
24
|
model_klass = ::Avo::BaseResource.valid_model_class model_class_name
|
25
25
|
|
26
|
-
model = model_klass.find params[:via_resource_id]
|
27
|
-
|
28
26
|
resource = ::Avo::App.get_resource_by_model_name model_klass if resource.blank?
|
29
27
|
|
28
|
+
model = resource.find_record params[:via_resource_id], query: model_klass, params: params
|
29
|
+
|
30
30
|
resource.dup.hydrate model: model
|
31
31
|
end
|
32
32
|
|
@@ -44,7 +44,7 @@ class Avo::Fields::BelongsToField::EditComponent < Avo::Fields::EditComponent
|
|
44
44
|
|
45
45
|
return @polymorphic_record if @polymorphic_record.present?
|
46
46
|
|
47
|
-
@polymorphic_record = polymorphic_class.safe_constantize
|
47
|
+
@polymorphic_record = @resource.find_record polymorphic_id, query: polymorphic_class.safe_constantize, params: params
|
48
48
|
|
49
49
|
@polymorphic_record
|
50
50
|
end
|
@@ -6,7 +6,7 @@ class Avo::Fields::BelongsToField::ShowComponent < Avo::Fields::ShowComponent
|
|
6
6
|
model: @field.value,
|
7
7
|
resource: @field.target_resource,
|
8
8
|
via_resource_class: @resource.class.to_s,
|
9
|
-
via_resource_id: @resource.model.
|
9
|
+
via_resource_id: @resource.model.to_param
|
10
10
|
)
|
11
11
|
end
|
12
12
|
end
|
@@ -21,11 +21,11 @@ class Avo::Fields::HasOneField::ShowComponent < Avo::Fields::ShowComponent
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def attach_path
|
24
|
-
helpers.avo.resources_associations_new_path(@resource.singular_model_key, @resource.model.
|
24
|
+
helpers.avo.resources_associations_new_path(@resource.singular_model_key, @resource.model.to_param, @field.id)
|
25
25
|
end
|
26
26
|
|
27
27
|
def can_see_the_create_button?
|
28
|
-
create = "create_#{@field.id
|
28
|
+
create = "create_#{@field.id}?"
|
29
29
|
|
30
30
|
authorization_service = @resource.authorization
|
31
31
|
|
@@ -39,7 +39,7 @@ class Avo::Fields::HasOneField::ShowComponent < Avo::Fields::ShowComponent
|
|
39
39
|
args = {
|
40
40
|
via_relation: @resource.singular_model_key,
|
41
41
|
via_relation_class: @resource.model_class.to_s,
|
42
|
-
via_resource_id: @resource.model.
|
42
|
+
via_resource_id: @resource.model.to_param
|
43
43
|
}
|
44
44
|
helpers.new_resource_path(resource: @field.target_resource, **args)
|
45
45
|
end
|
@@ -1,10 +1,19 @@
|
|
1
|
-
<%= field_wrapper **field_wrapper_args
|
2
|
-
|
1
|
+
<%= field_wrapper **field_wrapper_args, data: {
|
2
|
+
controller: "tags-field",
|
3
|
+
tags_field_mode_value: @field.mode,
|
4
|
+
tags_field_whitelist_items_value: @field.suggestions.to_json,
|
5
|
+
tags_field_disallowed_items_value: @field.disallowed.to_json,
|
6
|
+
tags_field_enforce_suggestions_value: @field.enforce_suggestions,
|
7
|
+
tags_field_close_on_select_value: @field.close_on_select,
|
8
|
+
tags_field_delimiters_value: @field.delimiters,
|
9
|
+
tags_field_fetch_values_from_value: @field.fetch_values_from,
|
10
|
+
} do %>
|
11
|
+
<%# We use a dummy field so the back action from Turbo does not brake the field %>
|
3
12
|
<%# dummy field %>
|
4
13
|
<%= text_field_tag "#{@field.id}-dummy", '',
|
5
14
|
class: classes("w-full"),
|
6
15
|
data: {
|
7
|
-
|
16
|
+
tags_field_target: :fakeInput,
|
8
17
|
},
|
9
18
|
disabled: disabled?,
|
10
19
|
placeholder: @field.placeholder,
|
@@ -15,17 +24,11 @@
|
|
15
24
|
<%= @form.text_field @field.id,
|
16
25
|
class: classes("hidden w-full border-primary-500 focus-within:border-primary-500"),
|
17
26
|
data: {
|
18
|
-
|
19
|
-
'whitelist-items': @field.suggestions.to_json,
|
20
|
-
'disallowed-items': @field.disallowed.to_json,
|
21
|
-
'enforce-suggestions': @field.enforce_suggestions ? 1 : 0,
|
22
|
-
'delimiters': @field.delimiters,
|
23
|
-
'close-on-select': @field.close_on_select ? 1 : 0,
|
27
|
+
tags_field_target: :input,
|
24
28
|
},
|
25
29
|
disabled: disabled?,
|
26
30
|
placeholder: @field.placeholder,
|
27
31
|
style: @field.get_html(:style, view: view, element: :input),
|
28
32
|
value: @field.field_value.to_json
|
29
33
|
%>
|
30
|
-
</div>
|
31
34
|
<% end %>
|
@@ -18,6 +18,6 @@ class Avo::Index::Ordering::ButtonComponent < Avo::Index::Ordering::BaseComponen
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def order_path(args)
|
21
|
-
Avo::App.view_context.avo.reorder_order_path(resource.route_key, resource.model.
|
21
|
+
Avo::App.view_context.avo.reorder_order_path(resource.route_key, resource.model.to_param, **args)
|
22
22
|
end
|
23
23
|
end
|
@@ -37,7 +37,7 @@ class Avo::Index::ResourceControlsComponent < Avo::ResourceComponent
|
|
37
37
|
if @parent_model.present?
|
38
38
|
args = {
|
39
39
|
via_resource_class: parent_resource.class.to_s,
|
40
|
-
via_resource_id: @parent_model.
|
40
|
+
via_resource_id: @parent_model.to_param
|
41
41
|
}
|
42
42
|
end
|
43
43
|
|
@@ -51,7 +51,7 @@ class Avo::Index::ResourceControlsComponent < Avo::ResourceComponent
|
|
51
51
|
if @parent_model.present?
|
52
52
|
args = {
|
53
53
|
via_resource_class: parent_resource.class.to_s,
|
54
|
-
via_resource_id: @parent_model.
|
54
|
+
via_resource_id: @parent_model.to_param
|
55
55
|
}
|
56
56
|
end
|
57
57
|
|
@@ -26,7 +26,7 @@ class Avo::ResourceComponent < Avo::BaseComponent
|
|
26
26
|
def detach_path
|
27
27
|
return "/" if @reflection.blank?
|
28
28
|
|
29
|
-
helpers.resource_detach_path(params[:resource_name], params[:id], @reflection.name.to_s, @resource.model.
|
29
|
+
helpers.resource_detach_path(params[:resource_name], params[:id], @reflection.name.to_s, @resource.model.to_param)
|
30
30
|
end
|
31
31
|
|
32
32
|
def can_see_the_edit_button?
|
@@ -74,7 +74,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
|
|
74
74
|
if @reflection.present?
|
75
75
|
args = {
|
76
76
|
via_relation_class: reflection_model_class,
|
77
|
-
via_resource_id: @parent_model.
|
77
|
+
via_resource_id: @parent_model.to_param
|
78
78
|
}
|
79
79
|
|
80
80
|
if @reflection.is_a? ActiveRecord::Reflection::ThroughReflection
|
@@ -98,7 +98,9 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def attach_path
|
101
|
-
|
101
|
+
current_path = CGI.unescape(request.env["PATH_INFO"]).split("/").select(&:present?)
|
102
|
+
|
103
|
+
Avo::App.root_path(paths: [*current_path, "new"])
|
102
104
|
end
|
103
105
|
|
104
106
|
def singular_resource_name
|
@@ -142,10 +144,10 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
|
|
142
144
|
return unless @reflection.present?
|
143
145
|
|
144
146
|
{
|
145
|
-
association:
|
147
|
+
association: "has_many",
|
146
148
|
association_id: @reflection.name,
|
147
149
|
class: reflection_model_class,
|
148
|
-
id: @parent_model.
|
150
|
+
id: @parent_model.to_param
|
149
151
|
}
|
150
152
|
end
|
151
153
|
end
|
@@ -128,7 +128,7 @@ module Avo
|
|
128
128
|
end
|
129
129
|
|
130
130
|
def set_model
|
131
|
-
@model =
|
131
|
+
@model = @resource.find_record(params[:id], query: model_find_scope, params: params)
|
132
132
|
end
|
133
133
|
|
134
134
|
def model_find_scope
|
@@ -141,11 +141,10 @@ module Avo
|
|
141
141
|
|
142
142
|
def set_related_model
|
143
143
|
association_name = BaseResource.valid_association_name(@model, params[:related_name])
|
144
|
-
|
145
144
|
@related_model = if @field.is_a? Avo::Fields::HasOneField
|
146
145
|
@model.send association_name
|
147
146
|
else
|
148
|
-
eager_load_files(@related_resource, @model.send(association_name))
|
147
|
+
@related_resource.find_record params[:related_id], query: eager_load_files(@related_resource, @model.send(association_name)), params: params
|
149
148
|
end
|
150
149
|
end
|
151
150
|
|
@@ -21,7 +21,7 @@ module Avo
|
|
21
21
|
def index
|
22
22
|
@parent_resource = @resource.dup
|
23
23
|
@resource = @related_resource
|
24
|
-
@parent_model = @parent_resource.
|
24
|
+
@parent_model = @parent_resource.find_record(params[:id], params: params)
|
25
25
|
@parent_resource.hydrate(model: @parent_model)
|
26
26
|
association_name = BaseResource.valid_association_name(@parent_model, params[:related_name])
|
27
27
|
@query = @related_authorization.apply_policy @parent_model.send(association_name)
|
@@ -113,7 +113,7 @@ module Avo
|
|
113
113
|
end
|
114
114
|
|
115
115
|
def set_attachment_model
|
116
|
-
@attachment_model = @
|
116
|
+
@attachment_model = @related_resource.find_record attachment_id, params: params
|
117
117
|
end
|
118
118
|
|
119
119
|
def set_reflection_field
|
@@ -90,7 +90,7 @@ module Avo
|
|
90
90
|
# If we're accessing this resource via another resource add the parent to the breadcrumbs.
|
91
91
|
if params[:via_resource_class].present? && params[:via_resource_id].present?
|
92
92
|
via_resource = Avo::App.get_resource(params[:via_resource_class]).dup
|
93
|
-
via_model = via_resource.
|
93
|
+
via_model = via_resource.find_record params[:via_resource_id], params: params
|
94
94
|
via_resource.hydrate model: via_model
|
95
95
|
|
96
96
|
add_breadcrumb via_resource.plural_name, resources_path(resource: via_resource)
|
@@ -113,7 +113,7 @@ module Avo
|
|
113
113
|
|
114
114
|
if is_associated_record?
|
115
115
|
via_resource = Avo::App.get_resource_by_model_name(params[:via_relation_class]).dup
|
116
|
-
via_model = via_resource.
|
116
|
+
via_model = via_resource.find_record params[:via_resource_id], params: params
|
117
117
|
via_resource.hydrate model: via_model
|
118
118
|
|
119
119
|
add_breadcrumb via_resource.plural_name, resources_path(resource: via_resource)
|
@@ -137,7 +137,10 @@ module Avo
|
|
137
137
|
# Fills in the required infor for belongs_to and has_many
|
138
138
|
# Get the foreign key and set it to the id we received in the params
|
139
139
|
if @reflection.is_a?(ActiveRecord::Reflection::BelongsToReflection) || @reflection.is_a?(ActiveRecord::Reflection::HasManyReflection)
|
140
|
-
|
140
|
+
related_resource = Avo::App.get_resource_by_model_name params[:via_relation_class]
|
141
|
+
related_record = related_resource.find_record params[:via_resource_id], params: params
|
142
|
+
|
143
|
+
@model.send("#{@reflection.foreign_key}=", related_record.id)
|
141
144
|
@model.save
|
142
145
|
end
|
143
146
|
|
@@ -145,7 +148,7 @@ module Avo
|
|
145
148
|
if @reflection.is_a? ActiveRecord::Reflection::ThroughReflection
|
146
149
|
# find the record
|
147
150
|
via_resource = ::Avo::App.get_resource_by_model_name(params[:via_relation_class]).dup
|
148
|
-
@related_record = via_resource.
|
151
|
+
@related_record = via_resource.find_record params[:via_resource_id], params: params
|
149
152
|
association_name = BaseResource.valid_association_name(@model, params[:via_relation])
|
150
153
|
|
151
154
|
@model.send(association_name) << @related_record
|
@@ -385,7 +388,7 @@ module Avo
|
|
385
388
|
# If we're accessing this resource via another resource add the parent to the breadcrumbs.
|
386
389
|
if params[:via_resource_class].present? && params[:via_resource_id].present?
|
387
390
|
via_resource = Avo::App.get_resource(params[:via_resource_class]).dup
|
388
|
-
via_model = via_resource.
|
391
|
+
via_model = via_resource.find_record params[:via_resource_id], params: params
|
389
392
|
via_resource.hydrate model: via_model
|
390
393
|
|
391
394
|
add_breadcrumb via_resource.plural_name, resources_path(resource: @resource)
|
@@ -1,62 +1,64 @@
|
|
1
1
|
import { first, isObject, merge } from 'lodash'
|
2
2
|
import Tagify from '@yaireo/tagify'
|
3
|
-
|
4
|
-
import BaseController from '../base_controller'
|
3
|
+
import URI from 'urijs'
|
5
4
|
|
6
5
|
import { suggestionItemTemplate, tagTemplate } from './tags_field_helpers'
|
6
|
+
import BaseController from '../base_controller'
|
7
|
+
import debouncePromise from '../../helpers/debounce_promise'
|
7
8
|
|
8
9
|
export default class extends BaseController {
|
9
10
|
static targets = ['input', 'fakeInput'];
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
static values = {
|
13
|
+
whitelistItems: { type: Array, default: [] },
|
14
|
+
disallowedItems: { type: Array, default: [] },
|
15
|
+
enforceSuggestions: { type: Boolean, default: false },
|
16
|
+
closeOnSelect: { type: Boolean, default: false },
|
17
|
+
delimiters: { type: Array, default: [] },
|
18
|
+
mode: String,
|
19
|
+
fetchValuesFrom: String,
|
15
20
|
}
|
16
21
|
|
17
|
-
|
18
|
-
return this.getJsonAttribute(this.inputTarget, 'data-disallowed-items', [])
|
19
|
-
}
|
20
|
-
|
21
|
-
get enforceSuggestions() {
|
22
|
-
return this.getBooleanAttribute(this.inputTarget, 'data-enforce-suggestions')
|
23
|
-
}
|
22
|
+
tagify = null;
|
24
23
|
|
25
|
-
|
26
|
-
return this.getBooleanAttribute(this.inputTarget, 'data-close-on-select')
|
27
|
-
}
|
24
|
+
searchDebounce = 500
|
28
25
|
|
29
|
-
|
30
|
-
return this.getJsonAttribute(this.inputTarget, 'data-delimiters', [])
|
31
|
-
}
|
26
|
+
debouncedFetch = debouncePromise(fetch, this.searchDebounce);
|
32
27
|
|
33
28
|
get suggestionsAreObjects() {
|
34
|
-
return isObject(first(this.
|
29
|
+
return isObject(first(this.whitelistItemsValue)) || this.fetchValuesFromValue
|
35
30
|
}
|
36
31
|
|
37
32
|
get tagifyOptions() {
|
38
33
|
let options = {
|
39
|
-
whitelist: this.
|
40
|
-
blacklist: this.
|
41
|
-
enforceWhitelist: this.
|
42
|
-
delimiters: this.
|
34
|
+
whitelist: this.whitelistItemsValue,
|
35
|
+
blacklist: this.disallowedItemsValue,
|
36
|
+
enforceWhitelist: this.enforceSuggestionsValue || this.fetchValuesFromValue,
|
37
|
+
delimiters: this.delimitersValue.join('|'),
|
43
38
|
dropdown: {
|
44
39
|
maxItems: 20,
|
45
40
|
enabled: 0,
|
46
|
-
|
41
|
+
searchKeys: [this.labelAttributeValue],
|
42
|
+
closeOnSelect: this.closeOnSelectValue,
|
47
43
|
},
|
48
44
|
}
|
49
45
|
|
46
|
+
if (this.modeValue) {
|
47
|
+
options.mode = this.modeValue // null or "select"
|
48
|
+
}
|
49
|
+
|
50
50
|
if (this.suggestionsAreObjects) {
|
51
51
|
options = merge(options, {
|
52
52
|
tagTextProp: 'label',
|
53
53
|
dropdown: {
|
54
54
|
searchKeys: ['label'],
|
55
|
+
mapValueTo: 'value',
|
55
56
|
},
|
56
57
|
templates: {
|
57
58
|
tag: tagTemplate,
|
58
59
|
dropdownItem: suggestionItemTemplate,
|
59
60
|
},
|
61
|
+
originalInputValueFormat: (valuesArr) => valuesArr.map((item) => item.value),
|
60
62
|
})
|
61
63
|
}
|
62
64
|
|
@@ -73,6 +75,41 @@ export default class extends BaseController {
|
|
73
75
|
|
74
76
|
initTagify() {
|
75
77
|
this.tagify = new Tagify(this.inputTarget, this.tagifyOptions)
|
78
|
+
const that = this
|
79
|
+
|
80
|
+
function onInput(e) {
|
81
|
+
// Create the URL from which to fetch the values
|
82
|
+
const query = e.detail.value
|
83
|
+
const uri = new URI(that.fetchValuesFromValue)
|
84
|
+
uri.addSearch({
|
85
|
+
q: query,
|
86
|
+
})
|
87
|
+
|
88
|
+
// reset current whitelist
|
89
|
+
that.tagify.whitelist = null
|
90
|
+
// show the loader animation
|
91
|
+
that.tagify.loading(true)
|
92
|
+
|
93
|
+
// get new whitelist from a request
|
94
|
+
that.fetchResults(uri.toString())
|
95
|
+
.then((result) => {
|
96
|
+
that.tagify.settings.whitelist = result // add already-existing tags to the new whitelist array
|
97
|
+
|
98
|
+
that.tagify
|
99
|
+
.loading(false)
|
100
|
+
.dropdown.show(e.detail.value) // render the suggestions dropdown.
|
101
|
+
})
|
102
|
+
.catch(() => that.tagify.dropdown.hide())
|
103
|
+
}
|
104
|
+
|
105
|
+
if (this.fetchValuesFromValue) {
|
106
|
+
this.tagify.on('input', onInput)
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
fetchResults(endpoint) {
|
111
|
+
return this.debouncedFetch(endpoint)
|
112
|
+
.then((response) => response.json())
|
76
113
|
}
|
77
114
|
|
78
115
|
hideFakeInput() {
|
@@ -1,6 +1,11 @@
|
|
1
1
|
<%= turbo_frame_tag 'attach_modal' do %>
|
2
|
+
<%
|
3
|
+
url = Avo::Services::URIService.parse(avo.root_url.to_s)
|
4
|
+
.append_paths('resources', params[:resource_name], params[:id], params[:related_name])
|
5
|
+
.to_s
|
6
|
+
%>
|
2
7
|
<%= form_with scope: 'fields',
|
3
|
-
url:
|
8
|
+
url: url,
|
4
9
|
local: true,
|
5
10
|
data: {
|
6
11
|
'turbo-frame': '_top'
|
@@ -1,3 +1,3 @@
|
|
1
1
|
<div class="text-center text-sm text-gray-700 <%= 'print:hidden' if Avo.configuration.hide_layout_when_printing %>">
|
2
|
-
<a href="https://avohq.io/" target="_blank">Avo</a> · © <%= Date.today.year %> AvoHQ · <span title="<%= Avo::App.license.valid ? 'valid' : 'invalid'%> <%= Avo::App.license.id %> license">v<%= Avo::VERSION %></span>
|
2
|
+
<a href="https://avohq.io/" target="_blank">Avo</a> · © <%= Date.today.year %> AvoHQ · <span title="<%= Avo::App.license.valid ? 'valid' : 'invalid'%> <%= Avo::App.license.id %> license">v<%= Avo::VERSION %></span> · Current.user.id = <%= Current.user&.id %>
|
3
3
|
</div>
|
@@ -1,4 +1,5 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
|
+
<!-- ✨ Built with Avo • https://www.avohq.io/ -->
|
2
3
|
<html>
|
3
4
|
<head>
|
4
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
@@ -62,3 +63,4 @@
|
|
62
63
|
<!-- License valid?: <%= Avo::App.license.valid ? "valid" : "invalid" %> -->
|
63
64
|
</body>
|
64
65
|
</html>
|
66
|
+
<!-- ✨ Built with Avo • https://www.avohq.io/ -->
|
data/config/master.key
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2aeb23d82b909d9c6b5abb62f7058c2a
|
data/lib/avo/base_resource.rb
CHANGED
@@ -42,6 +42,10 @@ module Avo
|
|
42
42
|
class_attribute :unscoped_queries_on_index, default: false
|
43
43
|
class_attribute :resolve_query_scope
|
44
44
|
class_attribute :resolve_find_scope
|
45
|
+
# TODO: refactor this into a Host without args
|
46
|
+
class_attribute :find_record_method, default: ->(model_class:, id:, params:) {
|
47
|
+
model_class.find id
|
48
|
+
}
|
45
49
|
class_attribute :ordering
|
46
50
|
class_attribute :hide_from_global_search, default: false
|
47
51
|
class_attribute :after_create_path, default: :show
|
@@ -379,7 +383,11 @@ module Avo
|
|
379
383
|
# set the value to the actual record
|
380
384
|
value = @params[:via_relation_class].safe_constantize.find(@params[:via_resource_id])
|
381
385
|
elsif reflection.present? && reflection.foreign_key.present? && field.id.to_s == @params[:via_relation].to_s
|
382
|
-
|
386
|
+
resource = Avo::App.get_resource_by_model_name params[:via_relation_class]
|
387
|
+
model = resource.find_record @params[:via_resource_id], params: params
|
388
|
+
id_param = reflection.options[:primary_key] || :id
|
389
|
+
|
390
|
+
value = model.send(id_param)
|
383
391
|
end
|
384
392
|
end
|
385
393
|
|
@@ -488,5 +496,11 @@ module Avo
|
|
488
496
|
def has_model_id?
|
489
497
|
model.present? && model.id.present?
|
490
498
|
end
|
499
|
+
|
500
|
+
def find_record(id, query: nil, params: nil)
|
501
|
+
query ||= self.class.find_scope
|
502
|
+
|
503
|
+
self.class.find_record_method.call(model_class: query, id: id, params: params)
|
504
|
+
end
|
491
505
|
end
|
492
506
|
end
|
data/lib/avo/engine.rb
CHANGED
@@ -54,6 +54,12 @@ module Avo
|
|
54
54
|
# app.config.logger = ::Logger.new(STDOUT)
|
55
55
|
end
|
56
56
|
|
57
|
+
initializer "avo.test_buddy" do |app|
|
58
|
+
if Avo::IN_DEVELOPMENT
|
59
|
+
Rails.autoloaders.main.push_dir Avo::Engine.root.join("spec", "helpers")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
57
63
|
config.app_middleware.use(
|
58
64
|
Rack::Static,
|
59
65
|
urls: ["/avo-assets"],
|