avo 1.21.0.pre.1 → 1.22.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.

Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -1
  3. data/Gemfile.lock +61 -61
  4. data/README.md +1 -1
  5. data/app/assets/svgs/x.svg +3 -0
  6. data/app/components/avo/fields/belongs_to_field/autocomplete_component.html.erb +29 -0
  7. data/app/components/avo/fields/belongs_to_field/autocomplete_component.rb +77 -0
  8. data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +73 -46
  9. data/app/components/avo/fields/belongs_to_field/edit_component.rb +37 -0
  10. data/app/components/avo/navigation_link_component.html.erb +1 -1
  11. data/app/components/avo/navigation_link_component.rb +2 -1
  12. data/app/components/avo/views/resource_index_component.html.erb +1 -1
  13. data/app/controllers/avo/application_controller.rb +16 -14
  14. data/app/controllers/avo/base_controller.rb +1 -4
  15. data/app/controllers/avo/relations_controller.rb +4 -4
  16. data/app/controllers/avo/search_controller.rb +0 -1
  17. data/app/javascript/js/controllers/fields/belongs_to_field_controller.js +96 -33
  18. data/app/javascript/js/controllers/fields/date_field_controller.js +10 -2
  19. data/app/javascript/js/controllers/item_selector_controller.js +29 -19
  20. data/app/javascript/js/controllers/search_controller.js +88 -17
  21. data/app/views/avo/partials/_global_search.html.erb +0 -1
  22. data/app/views/avo/partials/_javascript.html.erb +1 -0
  23. data/app/views/avo/partials/_logo.html.erb +3 -1
  24. data/app/views/avo/partials/_resource_search.html.erb +0 -1
  25. data/app/views/avo/partials/_turbo_frame_wrap.html.erb +7 -1
  26. data/app/views/avo/sidebar/_sidebar.html.erb +1 -3
  27. data/db/factories.rb +11 -3
  28. data/lib/avo/base_resource.rb +16 -14
  29. data/lib/avo/fields/base_field.rb +1 -1
  30. data/lib/avo/fields/belongs_to_field.rb +19 -2
  31. data/lib/avo/fields/files_field.rb +2 -1
  32. data/lib/avo/fields/key_value_field.rb +28 -8
  33. data/lib/avo/licensing/pro_license.rb +2 -1
  34. data/lib/avo/version.rb +1 -1
  35. data/lib/generators/avo/templates/locales/avo.en.yml +2 -0
  36. data/lib/generators/avo/templates/locales/avo.nb-NO.yml +1 -0
  37. data/lib/generators/avo/templates/locales/avo.pt-BR.yml +1 -0
  38. data/lib/generators/avo/templates/locales/avo.ro.yml +1 -0
  39. data/public/avo-assets/avo.css +20 -4
  40. data/public/avo-assets/avo.js +330 -237
  41. data/public/avo-assets/avo.js.map +2 -2
  42. metadata +7 -7
  43. data/app/assets/builds/avo.css +0 -8590
  44. data/app/assets/builds/avo.js +0 -87755
  45. data/app/assets/builds/avo.js.map +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2009c14b639e720209ef1c2d56c84ac7936cfa96cb71dd4306b02695cae3ade5
4
- data.tar.gz: 4e99a479bc58b1da03e2e13f63e1921b1e652724b2d5b8d394964dad6a43a8ae
3
+ metadata.gz: 629be34248470405b26afdad89b08373587cd4ea00fb10f910315072338b5f39
4
+ data.tar.gz: ef5eb75f5e6b863af0d69fdefee87455a44283a17333000adcb2ab076f827fb2
5
5
  SHA512:
6
- metadata.gz: 91a4af05f9cc03bdf76751a140697a0ef6d5782f5a049e39023d7dffba3074c16d01204f36608c2f8d776b6f3f72d885bd91f49b6e38ab14ac7b951df13667c9
7
- data.tar.gz: 18d41c5e64b507ab27025b4af7fe7b99987d45897b6e717022fcebe8e5debd32dab26aa96a24611a8534ffcaa0f6744932d277d37421e1865722b0f728234516
6
+ metadata.gz: 35cc7ab3e7086fd1b701e8600f25a33f3a7b779d03626ea293b75e19f375e4de5bc4ab29dc243d49eeb9bd0afe5411d35c87165aac01ca029b2de9cee6f6e1f1
7
+ data.tar.gz: 0b4e462976362acfaf3ecf5673a70f474f1c0c4b0e11d7f502c81cf3a9f53def31306988defa28599de643c10f9a4ee27b77182e1f6231d509cd1374e9cebd84
data/Gemfile CHANGED
@@ -30,7 +30,7 @@ gem "rails", "~> 6.1.0"
30
30
  # Use postgresql as the database for Active Record
31
31
  gem "pg", ">= 0.18", "< 2.0"
32
32
  # Use Puma as the app server
33
- gem "puma", "~> 5.5.1"
33
+ gem "puma", "~> 5.6.2"
34
34
  # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
35
35
  # gem "jbuilder", "~> 2.7"
36
36
  # Use Redis adapter to run Action Cable in production
@@ -77,6 +77,8 @@ group :development do
77
77
  # gem 'ruby-prof'
78
78
 
79
79
  # gem 'pry-rails'
80
+
81
+ gem 'htmlbeautifier'
80
82
  end
81
83
 
82
84
  group :development, :test do
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avo (1.21.0.pre.1)
4
+ avo (1.22.0)
5
5
  active_link_to
6
6
  addressable
7
7
  breadcrumbs_on_rails
@@ -19,40 +19,40 @@ PATH
19
19
  GEM
20
20
  remote: https://rubygems.org/
21
21
  specs:
22
- actioncable (6.1.4.4)
23
- actionpack (= 6.1.4.4)
24
- activesupport (= 6.1.4.4)
22
+ actioncable (6.1.4.6)
23
+ actionpack (= 6.1.4.6)
24
+ activesupport (= 6.1.4.6)
25
25
  nio4r (~> 2.0)
26
26
  websocket-driver (>= 0.6.1)
27
- actionmailbox (6.1.4.4)
28
- actionpack (= 6.1.4.4)
29
- activejob (= 6.1.4.4)
30
- activerecord (= 6.1.4.4)
31
- activestorage (= 6.1.4.4)
32
- activesupport (= 6.1.4.4)
27
+ actionmailbox (6.1.4.6)
28
+ actionpack (= 6.1.4.6)
29
+ activejob (= 6.1.4.6)
30
+ activerecord (= 6.1.4.6)
31
+ activestorage (= 6.1.4.6)
32
+ activesupport (= 6.1.4.6)
33
33
  mail (>= 2.7.1)
34
- actionmailer (6.1.4.4)
35
- actionpack (= 6.1.4.4)
36
- actionview (= 6.1.4.4)
37
- activejob (= 6.1.4.4)
38
- activesupport (= 6.1.4.4)
34
+ actionmailer (6.1.4.6)
35
+ actionpack (= 6.1.4.6)
36
+ actionview (= 6.1.4.6)
37
+ activejob (= 6.1.4.6)
38
+ activesupport (= 6.1.4.6)
39
39
  mail (~> 2.5, >= 2.5.4)
40
40
  rails-dom-testing (~> 2.0)
41
- actionpack (6.1.4.4)
42
- actionview (= 6.1.4.4)
43
- activesupport (= 6.1.4.4)
41
+ actionpack (6.1.4.6)
42
+ actionview (= 6.1.4.6)
43
+ activesupport (= 6.1.4.6)
44
44
  rack (~> 2.0, >= 2.0.9)
45
45
  rack-test (>= 0.6.3)
46
46
  rails-dom-testing (~> 2.0)
47
47
  rails-html-sanitizer (~> 1.0, >= 1.2.0)
48
- actiontext (6.1.4.4)
49
- actionpack (= 6.1.4.4)
50
- activerecord (= 6.1.4.4)
51
- activestorage (= 6.1.4.4)
52
- activesupport (= 6.1.4.4)
48
+ actiontext (6.1.4.6)
49
+ actionpack (= 6.1.4.6)
50
+ activerecord (= 6.1.4.6)
51
+ activestorage (= 6.1.4.6)
52
+ activesupport (= 6.1.4.6)
53
53
  nokogiri (>= 1.8.5)
54
- actionview (6.1.4.4)
55
- activesupport (= 6.1.4.4)
54
+ actionview (6.1.4.6)
55
+ activesupport (= 6.1.4.6)
56
56
  builder (~> 3.1)
57
57
  erubi (~> 1.4)
58
58
  rails-dom-testing (~> 2.0)
@@ -60,22 +60,22 @@ GEM
60
60
  active_link_to (1.0.5)
61
61
  actionpack
62
62
  addressable
63
- activejob (6.1.4.4)
64
- activesupport (= 6.1.4.4)
63
+ activejob (6.1.4.6)
64
+ activesupport (= 6.1.4.6)
65
65
  globalid (>= 0.3.6)
66
- activemodel (6.1.4.4)
67
- activesupport (= 6.1.4.4)
68
- activerecord (6.1.4.4)
69
- activemodel (= 6.1.4.4)
70
- activesupport (= 6.1.4.4)
71
- activestorage (6.1.4.4)
72
- actionpack (= 6.1.4.4)
73
- activejob (= 6.1.4.4)
74
- activerecord (= 6.1.4.4)
75
- activesupport (= 6.1.4.4)
66
+ activemodel (6.1.4.6)
67
+ activesupport (= 6.1.4.6)
68
+ activerecord (6.1.4.6)
69
+ activemodel (= 6.1.4.6)
70
+ activesupport (= 6.1.4.6)
71
+ activestorage (6.1.4.6)
72
+ actionpack (= 6.1.4.6)
73
+ activejob (= 6.1.4.6)
74
+ activerecord (= 6.1.4.6)
75
+ activesupport (= 6.1.4.6)
76
76
  marcel (~> 1.0.0)
77
77
  mini_mime (>= 1.1.0)
78
- activesupport (6.1.4.4)
78
+ activesupport (6.1.4.6)
79
79
  concurrent-ruby (~> 1.0, >= 1.0.2)
80
80
  i18n (>= 1.6, < 2)
81
81
  minitest (>= 5.1)
@@ -175,10 +175,11 @@ GEM
175
175
  rails (>= 6.0.0)
176
176
  stimulus-rails
177
177
  turbo-rails
178
+ htmlbeautifier (1.4.1)
178
179
  httparty (0.20.0)
179
180
  mime-types (~> 3.0)
180
181
  multi_xml (>= 0.5.2)
181
- i18n (1.9.1)
182
+ i18n (1.10.0)
182
183
  concurrent-ruby (~> 1.0)
183
184
  i18n_data (0.15.0)
184
185
  simple_po_parser (~> 1.1)
@@ -196,7 +197,7 @@ GEM
196
197
  listen (3.7.1)
197
198
  rb-fsevent (~> 0.10, >= 0.10.3)
198
199
  rb-inotify (~> 0.9, >= 0.9.10)
199
- loofah (2.13.0)
200
+ loofah (2.14.0)
200
201
  crass (~> 1.0.2)
201
202
  nokogiri (>= 1.5.9)
202
203
  mail (2.7.1)
@@ -229,8 +230,6 @@ GEM
229
230
  nokogiri (1.13.1)
230
231
  mini_portile2 (~> 2.7.0)
231
232
  racc (~> 1.4)
232
- nokogiri (1.13.1-x86_64-linux)
233
- racc (~> 1.4)
234
233
  orm_adapter (0.5.0)
235
234
  pagy (5.10.1)
236
235
  activesupport
@@ -239,28 +238,28 @@ GEM
239
238
  ast (~> 2.4.1)
240
239
  pg (1.3.1)
241
240
  public_suffix (4.0.6)
242
- puma (5.5.2)
241
+ puma (5.6.2)
243
242
  nio4r (~> 2.0)
244
- pundit (2.1.1)
243
+ pundit (2.2.0)
245
244
  activesupport (>= 3.0.0)
246
245
  racc (1.6.0)
247
246
  rack (2.2.3)
248
247
  rack-test (1.1.0)
249
248
  rack (>= 1.0, < 3)
250
- rails (6.1.4.4)
251
- actioncable (= 6.1.4.4)
252
- actionmailbox (= 6.1.4.4)
253
- actionmailer (= 6.1.4.4)
254
- actionpack (= 6.1.4.4)
255
- actiontext (= 6.1.4.4)
256
- actionview (= 6.1.4.4)
257
- activejob (= 6.1.4.4)
258
- activemodel (= 6.1.4.4)
259
- activerecord (= 6.1.4.4)
260
- activestorage (= 6.1.4.4)
261
- activesupport (= 6.1.4.4)
249
+ rails (6.1.4.6)
250
+ actioncable (= 6.1.4.6)
251
+ actionmailbox (= 6.1.4.6)
252
+ actionmailer (= 6.1.4.6)
253
+ actionpack (= 6.1.4.6)
254
+ actiontext (= 6.1.4.6)
255
+ actionview (= 6.1.4.6)
256
+ activejob (= 6.1.4.6)
257
+ activemodel (= 6.1.4.6)
258
+ activerecord (= 6.1.4.6)
259
+ activestorage (= 6.1.4.6)
260
+ activesupport (= 6.1.4.6)
262
261
  bundler (>= 1.15.0)
263
- railties (= 6.1.4.4)
262
+ railties (= 6.1.4.6)
264
263
  sprockets-rails (>= 2.0.0)
265
264
  rails-controller-testing (1.0.5)
266
265
  actionpack (>= 5.0.1.rc1)
@@ -271,9 +270,9 @@ GEM
271
270
  nokogiri (>= 1.6)
272
271
  rails-html-sanitizer (1.4.2)
273
272
  loofah (~> 2.3)
274
- railties (6.1.4.4)
275
- actionpack (= 6.1.4.4)
276
- activesupport (= 6.1.4.4)
273
+ railties (6.1.4.6)
274
+ actionpack (= 6.1.4.6)
275
+ activesupport (= 6.1.4.6)
277
276
  method_source
278
277
  rake (>= 0.13)
279
278
  thor (~> 1.0)
@@ -419,6 +418,7 @@ DEPENDENCIES
419
418
  fuubar
420
419
  gem-release
421
420
  hotwire-rails
421
+ htmlbeautifier
422
422
  httparty
423
423
  image_processing (~> 1.2)
424
424
  iso
@@ -429,7 +429,7 @@ DEPENDENCIES
429
429
  meta-tags
430
430
  net-smtp
431
431
  pg (>= 0.18, < 2.0)
432
- puma (~> 5.5.1)
432
+ puma (~> 5.6.2)
433
433
  pundit
434
434
  rails (~> 6.1.0)
435
435
  rails-controller-testing
data/README.md CHANGED
@@ -54,7 +54,7 @@ $ bundle install
54
54
 
55
55
  # Quick Purchase
56
56
 
57
- Use [this](https://buy.stripe.com/9AQ6rX0uIbLF2CQdQQ) link to quickly purchase a Pro license to support this project. Thank you 🙏
57
+ Use [this](https://avohq.io/purchase/pro) link to quickly purchase a Pro license to support this project. Thank you 🙏
58
58
 
59
59
  # Contributing
60
60
 
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
2
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
3
+ </svg>
@@ -0,0 +1,29 @@
1
+ <div data-controller="search" class="resource-search flex items-center h-full w-full" data-turbo-remove-before-cache>
2
+ <div class="w-full hidden"
3
+ data-search-target="autocomplete"
4
+ data-search-resource="<%= @model_key %>"
5
+ data-translation-keys='{"no_item_found": "<%= I18n.translate 'avo.no_item_found' %>"}'
6
+ data-via-association="belongs_to"
7
+ ></div>
8
+ <div class="relative w-full" autocomplete="off">
9
+ <%= @form.text_field @field.foreign_key,
10
+ value: field_label,
11
+ class: helpers.input_classes('w-full', has_error: @field.model_errors.include?(@field.id)),
12
+ placeholder: @field.placeholder,
13
+ 'data-search-target': 'button clearValue',
14
+ # This instructs the search_controller if it should enable/disabled this field when the user switches polymorphic associations
15
+ # It should not enable the field if the record is being created through an association
16
+ 'data-should-be-disabled': @disabled,
17
+ disabled: true %>
18
+ <% unless @disabled %>
19
+ <div class="absolute top-1/2 left-auto right-3 mr-px -mt-2 cursor-pointer hidden text-gray-500"
20
+ data-tippy="tooltip"
21
+ data-search-target="clearButton"
22
+ title="<%= I18n.translate 'avo.clear_value' %>"
23
+ data-action="click->search#clearValue"
24
+ ><%= helpers.svg 'x', class: 'h-4' %>
25
+ </div>
26
+ <% end %>
27
+ </div>
28
+ <%= @form.hidden_field @foreign_key, value: field_value, 'data-search-target': 'hiddenId clearValue' %>
29
+ </div>
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::Fields::BelongsToField::AutocompleteComponent < ViewComponent::Base
4
+ def initialize(form:, field:, model_key:, foreign_key:, disabled:, type: nil, resource: nil, polymorphic_record: nil)
5
+ @form = form
6
+ @field = field
7
+ @type = type
8
+ @model_key = model_key
9
+ @foreign_key = foreign_key
10
+ @resource = resource
11
+ @disabled = disabled
12
+ @polymorphic_record = polymorphic_record
13
+ end
14
+
15
+ def field_label
16
+ if searchable?
17
+ # New records won't have the value (instantiated model) present but the polymorphic_type and polymorphic_id prefilled
18
+ if new_record? && has_polymorphic_association?
19
+ @polymorphic_record.send(polymorphic_fields[:label])
20
+ else
21
+ @field.value&.class == @type ? @field.field_label : nil
22
+ end
23
+ else
24
+ @field.field_label
25
+ end
26
+ end
27
+
28
+ def field_value
29
+ if searchable?
30
+ # New records won't have the value (instantiated model) present but the polymorphic_type and polymorphic_id prefilled
31
+ if new_record? && has_polymorphic_association?
32
+ @polymorphic_record.send(polymorphic_fields[:id])
33
+ else
34
+ @field.value&.class == @type ? @field.field_value : nil
35
+ end
36
+ else
37
+ @field.field_value
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def searchable?
44
+ @type.present?
45
+ end
46
+
47
+ def new_record?
48
+ @resource.model.new_record?
49
+ end
50
+
51
+ def has_polymorphic_association?
52
+ polymorphic_class.present? && polymorphic_id.present?
53
+ end
54
+
55
+ # Get the polymorphic class
56
+ def polymorphic_class
57
+ @resource.model["#{@field.foreign_key}_type"]
58
+ end
59
+
60
+ # Get the polymorphic id
61
+ def polymorphic_id
62
+ @resource.model["#{@field.foreign_key}_id"]
63
+ end
64
+
65
+ # Get the resource for that polymorphic class
66
+ def polymorphic_resource
67
+ ::Avo::App.get_resource_by_model_name polymorphic_class
68
+ end
69
+
70
+ # Extract the needed fields to identify the record for polymorphic associations
71
+ def polymorphic_fields
72
+ {
73
+ id: polymorphic_resource.id,
74
+ label: polymorphic_resource.title
75
+ }
76
+ end
77
+ end
@@ -1,68 +1,95 @@
1
- <% if @field.types.present? %>
2
- <div data-controller="belongs-to-field">
3
- <%= edit_field_wrapper field: @field, index: @index, form: @form, resource: @resource, displayed_in_modal: @displayed_in_modal do %>
4
- <%= @form.select "#{@field.foreign_key}_type", @field.types.map { |type| [type.to_s.underscore.humanize, type.to_s] },
5
- {
6
- include_blank: @field.placeholder,
7
- },
8
- {
9
- class: helpers.input_classes('w-full', has_error: @field.model_errors.include?(@field.id)),
10
- disabled: disabled,
11
- 'data-belongs-to-field-target': "select",
12
- 'data-action': 'change->belongs-to-field#changedType'
13
- }
14
- %>
15
- <%
1
+ <%
2
+ if is_polymorphic?
3
+
4
+ # Set the model keys so we can pass them over
5
+ model_keys = @field.types.map do |type|
6
+ resource = Avo::App.get_resource_by_model_name(type.to_s)
7
+ [type.to_s, resource.model_key]
8
+ end.to_h
9
+ %>
10
+ <div data-controller="belongs-to-field"
11
+ data-searchable="<%= @field.searchable %>"
12
+ data-association="<%= @field.id %>"
13
+ data-association-class="<%= @field&.target_resource&.model_class || nil %>"
14
+ >
15
+ <%= edit_field_wrapper field: @field, index: @index, form: @form, resource: @resource, displayed_in_modal: @displayed_in_modal do %>
16
+ <%= @form.select "#{@field.foreign_key}_type", @field.types.map { |type| [type.to_s.underscore.humanize, type.to_s] },
17
+ {
18
+ value: @field.value,
19
+ include_blank: @field.placeholder,
20
+ },
21
+ {
22
+ class: helpers.input_classes('w-full', has_error: @field.model_errors.include?(@field.id)),
23
+ disabled: disabled,
24
+ 'data-belongs-to-field-target': "select",
25
+ 'data-action': 'change->belongs-to-field#changeType'
26
+ }
27
+ %>
28
+ <%
16
29
  # If the select field is disabled, no value will be sent. It's how HTML works.
17
30
  # Thus the extra hidden field to actually send the related id to the server.
18
- if disabled
19
- %>
20
- <%= @form.hidden_field "#{@field.foreign_key}_type" %>
21
- <% end %>
31
+ if disabled %>
32
+ <%= @form.hidden_field "#{@field.foreign_key}_type" %>
22
33
  <% end %>
23
- <% @field.types.each do |type| %>
24
- <div class="hidden"
34
+ <% end %>
35
+ <% @field.types.each do |type| %>
36
+ <div class="hidden"
25
37
  data-belongs-to-field-target="type"
26
38
  data-type="<%= type %>"
27
39
  >
28
- <%= edit_field_wrapper field: @field, index: @index, form: @form, resource: @resource, displayed_in_modal: @displayed_in_modal, label: type.to_s.underscore.humanize do %>
29
- <%= @form.select "#{@field.foreign_key}_id", @field.values_for_type(type),
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,
43
+ field: @field,
44
+ type: type,
45
+ model_key: model_keys[type.to_s],
46
+ foreign_key: "#{@field.foreign_key}_id",
47
+ resource: @resource,
48
+ disabled: disabled,
49
+ polymorphic_record: polymorphic_record
50
+ %>
51
+ <% else %>
52
+ <%= @form.select "#{@field.foreign_key}_id", options_for_select(@field.values_for_type(type), @resource.present? && @resource.model.present? ? @resource.model["#{@field.foreign_key}_id"] : nil),
30
53
  {
54
+ value: @resource.model["#{@field.foreign_key}_id"].to_s,
31
55
  include_blank: @field.placeholder,
32
56
  },
33
57
  {
34
58
  class: helpers.input_classes('w-full', has_error: @field.model_errors.include?(@field.id)),
35
59
  disabled: disabled
36
60
  }
37
- %>
38
- <%
39
- # If the select field is disabled, no value will be sent. It's how HTML works.
40
- # Thus the extra hidden field to actually send the related id to the server.
41
- if disabled
42
61
  %>
43
- <%= @form.hidden_field "#{@field.foreign_key}_id" %>
44
- <% end %>
45
62
  <% end %>
46
- </div>
47
- <% end %>
48
- </div>
63
+ <% end %>
64
+ </div>
65
+ <% end %>
66
+ </div>
49
67
  <% else %>
50
68
  <%= edit_field_wrapper field: @field, index: @index, form: @form, resource: @resource, displayed_in_modal: @displayed_in_modal do %>
51
- <%= @form.select @field.foreign_key, @field.options.map { |o| [o[:label], o[:value]] },
52
- {
53
- include_blank: @field.placeholder,
54
- },
55
- {
56
- class: helpers.input_classes('w-full', has_error: @field.model_errors.include?(@field.id)),
69
+ <% if @field.searchable %>
70
+ <%= render Avo::Fields::BelongsToField::AutocompleteComponent.new form: @form,
71
+ field: @field,
72
+ model_key: @field.target_resource&.model_key,
73
+ foreign_key: @field.foreign_key,
74
+ resource: @resource,
57
75
  disabled: disabled
58
- }
59
76
  %>
60
- <%
61
- # If the select field is disabled, no value will be sent. It's how HTML works.
62
- # Thus the extra hidden field to actually send the related id to the server.
63
- if disabled
64
- %>
65
- <%= @form.hidden_field @field.foreign_key %>
77
+ <% else %>
78
+ <%= @form.select @field.foreign_key, @field.options.map { |o| [o[:label], o[:value]] },
79
+ {
80
+ include_blank: @field.placeholder,
81
+ },
82
+ {
83
+ class: helpers.input_classes('w-full', has_error: @field.model_errors.include?(@field.id)),
84
+ disabled: disabled
85
+ }
86
+ %>
87
+ <%
88
+ # If the select field is disabled, no value will be sent. It's how HTML works.
89
+ # Thus the extra hidden field to actually send the related id to the server.
90
+ if disabled %>
91
+ <%= @form.hidden_field @field.foreign_key %>
92
+ <% end %>
66
93
  <% end %>
67
94
  <% end %>
68
95
  <% end %>
@@ -1,6 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Avo::Fields::BelongsToField::EditComponent < Avo::Fields::EditComponent
4
+ def initialize(field: nil, resource: nil, index: 0, form: nil, displayed_in_modal: false)
5
+ super field: field, resource: resource, index: index, form: form, displayed_in_modal: displayed_in_modal
6
+
7
+ @polymorphic_record = nil
8
+ end
9
+
4
10
  def disabled
5
11
  return true if @field.readonly
6
12
  return true if @field.target_resource.present? && @field.target_resource.model_class.name == params[:via_resource_class]
@@ -8,4 +14,35 @@ class Avo::Fields::BelongsToField::EditComponent < Avo::Fields::EditComponent
8
14
 
9
15
  false
10
16
  end
17
+
18
+ def is_polymorphic?
19
+ @field.types.present?
20
+ end
21
+
22
+ def has_polymorphic_association?
23
+ polymorphic_class.present? && polymorphic_id.present?
24
+ end
25
+
26
+ # Get the polymorphic class
27
+ def polymorphic_class
28
+ @resource.model["#{@field.foreign_key}_type"]
29
+ end
30
+
31
+ # Get the polymorphic id
32
+ def polymorphic_id
33
+ @resource.model["#{@field.foreign_key}_id"]
34
+ end
35
+
36
+ # Get the actual resource
37
+ def polymorphic_record
38
+ return unless has_polymorphic_association?
39
+
40
+ return unless is_polymorphic?
41
+
42
+ return @polymorphic_record if @polymorphic_record.present?
43
+
44
+ @polymorphic_record = polymorphic_class.safe_constantize.find polymorphic_id
45
+
46
+ @polymorphic_record
47
+ end
11
48
  end
@@ -1,3 +1,3 @@
1
- <%= active_link_to @path, class: 'text-gray-800 py-2 px-4 block font-normal hover:bg-gray-100 rounded-md mb-1 mx-3 text-sm leading-none', active: @active do %>
1
+ <%= active_link_to @path, class: 'text-gray-800 py-2 px-4 block font-normal hover:bg-gray-100 rounded-md mb-1 mx-3 text-sm leading-none', active: @active, target: @target do %>
2
2
  <div class="w-4"></div> <%= @label %>
3
3
  <% end %>
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Avo::NavigationLinkComponent < ViewComponent::Base
4
- def initialize(label: nil, path: nil, active: :inclusive, size: :md)
4
+ def initialize(label: nil, path: nil, active: :inclusive, size: :md, target: "_self")
5
5
  @label = label
6
6
  @path = path
7
7
  @active = active
8
8
  @size = size
9
+ @target = target
9
10
  end
10
11
  end
@@ -24,7 +24,7 @@
24
24
  data-selected-resources="[]"
25
25
  >
26
26
  <div class="flex items-center px-6 w-64">
27
- <%= render partial: 'avo/partials/resource_search', locals: {resource: @resource.model_class.model_name.plural} if @resource.search_query.present? %>
27
+ <%= render partial: 'avo/partials/resource_search', locals: {resource: @resource.model_key} if @resource.search_query.present? %>
28
28
  </div>
29
29
  <div class="flex justify-end items-center px-6 space-x-3">
30
30
  <%= render partial: 'avo/partials/view_toggle_button', locals: { available_view_types: available_view_types, view_type: view_type, turbo_frame: @turbo_frame } if @models.present? %>
@@ -1,6 +1,11 @@
1
1
  module Avo
2
2
  class ApplicationController < ::ActionController::Base
3
- include Pundit
3
+ if defined?(Pundit::Authorization)
4
+ include Pundit::Authorization
5
+ else
6
+ include Pundit
7
+ end
8
+
4
9
  include Pagy::Backend
5
10
  include Avo::ApplicationHelper
6
11
  include Avo::UrlHelpers
@@ -111,7 +116,12 @@ module Avo
111
116
  end
112
117
 
113
118
  def fill_model
114
- @model = @resource.fill_model(@model_to_fill, cast_nullable(model_params))
119
+ # We have to skip filling the the model if this is an attach action
120
+ is_attach_action = params[model_param_key].blank? && params[:related_name].present? && params[:fields].present?
121
+
122
+ unless is_attach_action
123
+ @model = @resource.fill_model(@model_to_fill, cast_nullable(model_params))
124
+ end
115
125
  end
116
126
 
117
127
  def hydrate_resource
@@ -187,18 +197,6 @@ module Avo
187
197
  query
188
198
  end
189
199
 
190
- # def authorize_user
191
- # return if params[:controller] == 'avo/search'
192
-
193
- # model = record = resource.model
194
-
195
- # if ['show', 'edit', 'update'].include?(params[:action]) && params[:controller] == 'avo/resources'
196
- # record = resource
197
- # end
198
-
199
- # # AuthorizationService::authorize_action _current_user, record, params[:action] return render_unauthorized unless
200
- # end
201
-
202
200
  def _authenticate!
203
201
  instance_eval(&Avo.configuration.authenticate)
204
202
  end
@@ -243,5 +241,9 @@ module Avo
243
241
  def on_api_path
244
242
  request.original_url.match?(/.*#{Avo::App.root_path}\/avo_api\/.*/)
245
243
  end
244
+
245
+ def model_param_key
246
+ @resource.form_scope
247
+ end
246
248
  end
247
249
  end