avo 1.6.3.pre.2 → 1.6.3.pre.3

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +2 -2
  3. data/app/components/avo/edit/field_wrapper_component.html.erb +1 -1
  4. data/app/components/avo/edit/field_wrapper_component.rb +6 -1
  5. data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +65 -15
  6. data/app/components/avo/fields/belongs_to_field/edit_component.rb +1 -1
  7. data/app/controllers/avo/base_controller.rb +8 -0
  8. data/app/packs/js/controllers/fields/belongs_to_field_controller.js +65 -0
  9. data/lib/avo/base_resource.rb +27 -19
  10. data/lib/avo/fields/base_field.rb +1 -1
  11. data/lib/avo/fields/belongs_to_field.rb +47 -5
  12. data/lib/avo/fields/boolean_group_field.rb +1 -1
  13. data/lib/avo/fields/date_time_field.rb +1 -1
  14. data/lib/avo/fields/files_field.rb +1 -1
  15. data/lib/avo/fields/has_one_field.rb +1 -1
  16. data/lib/avo/fields/key_value_field.rb +1 -1
  17. data/lib/avo/fields_collector.rb +0 -2
  18. data/lib/avo/version.rb +1 -1
  19. data/public/avo-packs/css/application-797341b7.css.map +1 -1
  20. data/public/avo-packs/css/application-797341b7.css.map.br +0 -0
  21. data/public/avo-packs/css/application-797341b7.css.map.gz +0 -0
  22. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js +26 -0
  23. data/public/avo-packs/js/{application-b444cbf11135b4b23654.js.LICENSE.txt → application-947ed727440d5b5d73ab.js.LICENSE.txt} +0 -0
  24. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.br +0 -0
  25. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.gz +0 -0
  26. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.map +1 -0
  27. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.map.br +0 -0
  28. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.map.gz +0 -0
  29. data/public/avo-packs/manifest.json +8 -8
  30. metadata +10 -9
  31. data/public/avo-packs/js/application-b444cbf11135b4b23654.js +0 -26
  32. data/public/avo-packs/js/application-b444cbf11135b4b23654.js.br +0 -0
  33. data/public/avo-packs/js/application-b444cbf11135b4b23654.js.gz +0 -0
  34. data/public/avo-packs/js/application-b444cbf11135b4b23654.js.map +0 -1
  35. data/public/avo-packs/js/application-b444cbf11135b4b23654.js.map.br +0 -0
  36. data/public/avo-packs/js/application-b444cbf11135b4b23654.js.map.gz +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bba2852b5719783587af150d06434a6085a00cf84e57ffc0dc6260b8e0d31ba1
4
- data.tar.gz: 9517eeaad5198404857b26b7f7b971a418b863a14d9554de1c43c5c714bc0da8
3
+ metadata.gz: 223442cb4814fbbdbac19b17f00ccfd5db95c1020137010e9393aa24898a7d35
4
+ data.tar.gz: fcec7fbe1391bd73ef39b8f8f58643a473c0c9c0349ddddfd0e737e3fcaa0f4f
5
5
  SHA512:
6
- metadata.gz: 00fb34bedfcfb67db9febdb0cb71eebeda243b34f3d18e67ae84fa71150310d24af72c3c234f4b5c742a1c13e9d6a77dcbeabacfe98049ecef210bc08c8f4e82
7
- data.tar.gz: d8c7c6425790b622433ca48fe54647dd48b7df204c380c143e3e89438cebafa96ea09d38500f6514073a15c8f83970d67bc3313d531c4b5073e322ce9990231e
6
+ metadata.gz: ed74295ce9b330ff686202d2ad75ec0120d32ccbc43437ea6eb1a81a365895fb7b43948d734221d0a71b8a987fd8670b0951020ad22107167760548c52a020d0
7
+ data.tar.gz: 2b826242331414096f2260d62fb25749456d9f7e2ccaa02a6a467d2de146e77224f462ea17dec59c492b9997fad36d5ffa1f036066859f5fea0f177c7e8a863e
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avo (1.6.3.pre.2)
4
+ avo (1.6.3.pre.3)
5
5
  active_link_to
6
6
  addressable
7
7
  breadcrumbs_on_rails
@@ -333,7 +333,7 @@ GEM
333
333
  thread_safe (~> 0.1)
334
334
  unicode-display_width (2.0.0)
335
335
  unicode_utils (1.4.0)
336
- view_component (2.28.0)
336
+ view_component (2.32.0)
337
337
  activesupport (>= 5.0.0, < 7.0)
338
338
  warden (1.2.9)
339
339
  rack (>= 2.0.9)
@@ -1,7 +1,7 @@
1
1
  <div class="flex items-center py-0 leading-tight <%= @classes %> min-h-16" data-field-id="<%= @field.id %>" data-field-type="<%= @field.type %>">
2
2
  <div class="h-16 flex self-start items-center text-blue-gray-800">
3
3
  <div class="<% if @displayed_in_modal %> md:w-48 <% else %> md:w-64 <% end %> w-48 px-8 flex" data-slot="label">
4
- <%= @form.label @field.id, @field.name %> <% if @field.required %> <span class="text-red-600">*</span> <% end %>
4
+ <%= @form.label @field.id, label %> <% if @field.required %> <span class="text-red-600">*</span> <% end %>
5
5
  </div>
6
6
  </div>
7
7
  <div class="flex-1 flex flex-row min-h-inherit">
@@ -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: {}, **args)
4
+ def initialize(field: nil, dash_if_blank: true, full_width: false, displayed_in_modal: false, form: nil, resource: {}, label: nil, **args)
5
5
  @field = field
6
6
  @dash_if_blank = dash_if_blank
7
7
  @classes = args[:class].present? ? args[:class] : ""
@@ -11,9 +11,14 @@ class Avo::Edit::FieldWrapperComponent < ViewComponent::Base
11
11
  @resource = resource
12
12
  @model = resource.present? ? resource.model : nil
13
13
  @full_width = full_width
14
+ @label = label
14
15
 
15
16
  if (@index != 0) || @displayed_in_modal
16
17
  @classes += " border-t"
17
18
  end
18
19
  end
20
+
21
+ def label
22
+ @label || @field.name
23
+ end
19
24
  end
@@ -1,18 +1,68 @@
1
- <%= edit_field_wrapper field: @field, index: @index, form: @form, resource: @resource, displayed_in_modal: @displayed_in_modal do %>
2
- <%= @form.select @field.foreign_key, @field.options.map { |o| [o[:label], o[:value]] },
3
- {
4
- include_blank: @field.placeholder,
5
- },
6
- {
7
- class: helpers.input_classes('w-full', has_error: @field.model_errors.include?(@field.id)),
8
- disabled: disabled
9
- }
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.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
+ <%
16
+ # If the select field is disabled, no value will be sent. It's how HTML works.
17
+ # 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 %>
22
+ <% end %>
23
+ <% @field.types.each do |type| %>
24
+ <div class="hidden"
25
+ data-belongs-to-field-target="type"
26
+ data-type="<%= type %>"
27
+ >
28
+ <%= edit_field_wrapper field: @field, index: @index, form: @form, resource: @resource, displayed_in_modal: @displayed_in_modal, label: type.to_s do %>
29
+ <%= @form.select "#{@field.foreign_key}_id", @field.values_for_type(type),
30
+ {
31
+ include_blank: @field.placeholder,
32
+ },
33
+ {
34
+ class: helpers.input_classes('w-full', has_error: @field.model_errors.include?(@field.id)),
35
+ disabled: disabled
36
+ }
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
+ %>
43
+ <%= @form.hidden_field "#{@field.foreign_key}_id" %>
44
+ <% end %>
45
+ <% end %>
46
+ </div>
47
+ <% end %>
48
+ </div>
49
+ <% else %>
50
+ <%= 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)),
57
+ disabled: disabled
58
+ }
59
+ %>
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
10
64
  %>
11
- <%
12
- # If the select field is disabled, no value will be sent. It's how HTML works.
13
- # Thus the extra hidden field to actually send the related id to the server.
14
- if disabled
15
- %>
16
- <%= @form.hidden_field @field.foreign_key %>
65
+ <%= @form.hidden_field @field.foreign_key %>
66
+ <% end %>
17
67
  <% end %>
18
68
  <% end %>
@@ -3,7 +3,7 @@
3
3
  class Avo::Fields::BelongsToField::EditComponent < Avo::Fields::EditComponent
4
4
  def disabled
5
5
  return true if @field.readonly
6
- return true if @field.target_resource.model_class.name == params[:via_resource_class]
6
+ return true if @field.target_resource.present? && @field.target_resource.model_class.name == params[:via_resource_class]
7
7
  return true if @field.id.to_s == params[:via_relation].to_s
8
8
 
9
9
  false
@@ -167,6 +167,14 @@ module Avo
167
167
 
168
168
  def permitted_params
169
169
  @resource.get_field_definitions.select(&:updatable).map(&:to_permitted_param)
170
+ # ppp = []
171
+
172
+ # @resource.get_field_definitions.select(&:updatable).each do |param|
173
+ # ppp.push(*param.to_permitted_param)
174
+ # end
175
+ # # abort ppp.inspect
176
+ # puts [':ppp ->', ppp].inspect
177
+ # ppp
170
178
  end
171
179
 
172
180
  def cast_nullable(params)
@@ -0,0 +1,65 @@
1
+ import { Controller } from 'stimulus'
2
+
3
+ export default class extends Controller {
4
+ static targets = ['select', 'type']
5
+
6
+ get selectedType() {
7
+ return this.selectTarget.value
8
+ }
9
+
10
+ connect() {
11
+ this.setValidNames()
12
+ this.changedType()
13
+ }
14
+
15
+ setValidNames() {
16
+ this.typeTargets.forEach((target) => {
17
+ const { type } = target.dataset
18
+ const select = target.querySelector('select')
19
+ const name = select.getAttribute('name')
20
+
21
+ select.setAttribute('valid-name', name)
22
+ if (this.selectedType !== type) {
23
+ select.selectedIndex = 0
24
+ }
25
+ })
26
+ }
27
+
28
+ changedType() {
29
+ this.hideAllTypeTargets()
30
+ this.enableType(this.selectTarget.value)
31
+ }
32
+
33
+ hideAllTypeTargets() {
34
+ this.typeTargets.forEach((target) => {
35
+ this.hideTarget(target)
36
+ this.invalidateTarget(target)
37
+ })
38
+ }
39
+
40
+ hideTarget(target) {
41
+ target.classList.add('hidden')
42
+ }
43
+
44
+ invalidateTarget(target) {
45
+ const select = target.querySelector('select')
46
+
47
+ select.setAttribute('name', '')
48
+ }
49
+
50
+ validateTarget(target) {
51
+ const select = target.querySelector('select')
52
+ const validName = select.getAttribute('valid-name')
53
+
54
+ select.setAttribute('name', validName)
55
+ }
56
+
57
+ enableType(type) {
58
+ const target = this.typeTargets.find((typeTarget) => typeTarget.dataset.type === type)
59
+
60
+ if (target) {
61
+ target.classList.remove('hidden')
62
+ this.validateTarget(target)
63
+ }
64
+ }
65
+ }
@@ -95,18 +95,20 @@ module Avo
95
95
  field.visible?
96
96
  end
97
97
  .select do |field|
98
- if field.respond_to?(:polymorphic_for) &&
99
- field.polymorphic_for.present? &&
100
- field.polymorphic_for.to_s != field.get_model["#{field.polymorphic_as}_type"].to_s
101
- next
102
- end
103
- if !field.respond_to?(:polymorphic_for) &&
104
- field.respond_to?(:foreign_key) &&
105
- reflection.present? &&
106
- reflection.respond_to?(:foreign_key) &&
107
- reflection.foreign_key != field.foreign_key
98
+ # Strip out the reflection field in index queries with a parent association.
99
+ if reflection.present? &&
100
+ reflection.options.present? &&
101
+ field.respond_to?(:polymorphic_as) &&
102
+ field.polymorphic_as.to_s == reflection.options[:as].to_s
108
103
  next
109
104
  end
105
+ # if !field.respond_to?(:polymorphic_as) &&
106
+ # field.respond_to?(:foreign_key) &&
107
+ # reflection.present? &&
108
+ # reflection.respond_to?(:foreign_key) &&
109
+ # reflection.foreign_key != field.foreign_key
110
+ # next
111
+ # end
110
112
 
111
113
  true
112
114
  end
@@ -259,14 +261,17 @@ module Avo
259
261
  .reject do |field|
260
262
  field.computed
261
263
  end
262
- .map { |field| [field.database_id(model).to_s, field] }.to_h
264
+ .map do |field|
265
+ [field.database_id(model).to_s, field]
266
+ end
267
+ .to_h
263
268
 
264
269
  params.each do |key, value|
265
270
  field = fields_by_database_id[key]
266
271
 
267
272
  next unless field.present?
268
273
 
269
- model = field.fill_field model, key, value
274
+ model = field.fill_field model, key, value, params
270
275
  end
271
276
 
272
277
  model
@@ -304,19 +309,22 @@ module Avo
304
309
 
305
310
  # We will not overwrite any attributes that come pre-filled in the model.
306
311
  def hydrate_model_with_default_values
307
- default_values = get_fields.select do |field|
308
- !field.computed
309
- end
312
+ default_values = get_fields
313
+ .select do |field|
314
+ !field.computed
315
+ end
310
316
  .map do |field|
311
317
  id = field.id
312
318
  value = field.value
313
319
 
314
- if field.respond_to? :foreign_key
320
+ if field.type == "belongs_to"
315
321
  id = field.foreign_key.to_sym
316
322
 
317
323
  reflection = @model._reflections[@params[:via_relation]]
318
324
 
319
- if reflection.present? && reflection.foreign_key.present? && field.id.to_s == @params[:via_relation].to_s
325
+ if field.polymorphic_as.present? && field.types.map(&:to_s).include?(@params["via_relation_class"])
326
+ value = @params["via_relation_class"].safe_constantize.find(@params[:via_resource_id])
327
+ elsif reflection.present? && reflection.foreign_key.present? && field.id.to_s == @params[:via_relation].to_s
320
328
  value = @params[:via_resource_id]
321
329
  end
322
330
  end
@@ -325,8 +333,8 @@ module Avo
325
333
  end
326
334
  .to_h
327
335
  .select do |id, value|
328
- value.present?
329
- end
336
+ value.present?
337
+ end
330
338
 
331
339
  default_values.each do |id, value|
332
340
  if @model.send(id).nil?
@@ -116,7 +116,7 @@ module Avo
116
116
  final_value
117
117
  end
118
118
 
119
- def fill_field(model, key, value)
119
+ def fill_field(model, key, value, params)
120
120
  return model unless model.methods.include? key.to_sym
121
121
 
122
122
  model.send("#{key}=", value)
@@ -3,8 +3,8 @@ module Avo
3
3
  class BelongsToField < BaseField
4
4
  attr_reader :searchable
5
5
  attr_reader :polymorphic_as
6
- attr_reader :polymorphic_for
7
6
  attr_reader :relation_method
7
+ attr_reader :types
8
8
 
9
9
  def initialize(id, **args, &block)
10
10
  args[:placeholder] ||= I18n.t("avo.choose_an_option")
@@ -13,10 +13,8 @@ module Avo
13
13
 
14
14
  @searchable = args[:searchable] == true
15
15
  @polymorphic_as = args[:polymorphic_as]
16
- @polymorphic_for = args[:polymorphic_for]
16
+ @types = args[:types]
17
17
  @relation_method = name.to_s.parameterize.underscore
18
-
19
- hide_on(:edit, :new) if polymorphic_as.present?
20
18
  end
21
19
 
22
20
  def value
@@ -32,6 +30,12 @@ module Avo
32
30
  end
33
31
  end
34
32
 
33
+ def values_for_type(type)
34
+ type.all.map do |model|
35
+ [model.send(App.get_resource_by_model_name(type).class.title), model.id]
36
+ end
37
+ end
38
+
35
39
  def database_value
36
40
  target_resource.id
37
41
  end
@@ -61,11 +65,49 @@ module Avo
61
65
  end
62
66
 
63
67
  def to_permitted_param
68
+ if polymorphic_as.present?
69
+ return ["#{polymorphic_as}_type".to_sym, "#{polymorphic_as}_id".to_sym]
70
+ end
71
+
64
72
  foreign_key.to_sym
65
73
  end
66
74
 
75
+ def fill_field(model, key, value, params)
76
+ return model unless model.methods.include? key.to_sym
77
+
78
+ if polymorphic_as.present?
79
+ model.send("#{polymorphic_as}_type=", params["#{polymorphic_as}_type"])
80
+
81
+ # If the type is blank, reset the id too.
82
+ if params["#{polymorphic_as}_type"].blank?
83
+ model.send("#{polymorphic_as}_id=", nil)
84
+ else
85
+ model.send("#{polymorphic_as}_id=", params["#{polymorphic_as}_id"])
86
+ end
87
+ else
88
+ model.send("#{key}=", value)
89
+ end
90
+
91
+ model
92
+ end
93
+
94
+ def database_id(model)
95
+ # If the field is a polymorphic value, return the polymorphic_type as key and pre-fill the _id in fill_field.
96
+ return "#{polymorphic_as}_type" if polymorphic_as.present?
97
+
98
+ foreign_key
99
+ rescue
100
+ id
101
+ end
102
+
67
103
  def target_resource
68
- return App.get_resource_by_model_name(polymorphic_for) if polymorphic_for.present?
104
+ if polymorphic_as.present?
105
+ if value.present?
106
+ return App.get_resource_by_model_name(value.class)
107
+ else
108
+ return nil
109
+ end
110
+ end
69
111
 
70
112
  reflection_key = polymorphic_as || id
71
113
 
@@ -13,7 +13,7 @@ module Avo
13
13
  ["#{id}": []]
14
14
  end
15
15
 
16
- def fill_field(model, key, value)
16
+ def fill_field(model, key, value, params)
17
17
  new_value = {}
18
18
 
19
19
  # Filter out the empty ("") value boolean group generates
@@ -23,7 +23,7 @@ module Avo
23
23
  end
24
24
  end
25
25
 
26
- def fill_field(model, key, value)
26
+ def fill_field(model, key, value, params)
27
27
  if value.nil?
28
28
  model[id] = nil
29
29