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.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/app/components/avo/edit/field_wrapper_component.html.erb +1 -1
- data/app/components/avo/edit/field_wrapper_component.rb +6 -1
- data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +65 -15
- data/app/components/avo/fields/belongs_to_field/edit_component.rb +1 -1
- data/app/controllers/avo/base_controller.rb +8 -0
- data/app/packs/js/controllers/fields/belongs_to_field_controller.js +65 -0
- data/lib/avo/base_resource.rb +27 -19
- data/lib/avo/fields/base_field.rb +1 -1
- data/lib/avo/fields/belongs_to_field.rb +47 -5
- data/lib/avo/fields/boolean_group_field.rb +1 -1
- data/lib/avo/fields/date_time_field.rb +1 -1
- data/lib/avo/fields/files_field.rb +1 -1
- data/lib/avo/fields/has_one_field.rb +1 -1
- data/lib/avo/fields/key_value_field.rb +1 -1
- data/lib/avo/fields_collector.rb +0 -2
- data/lib/avo/version.rb +1 -1
- data/public/avo-packs/css/application-797341b7.css.map +1 -1
- data/public/avo-packs/css/application-797341b7.css.map.br +0 -0
- data/public/avo-packs/css/application-797341b7.css.map.gz +0 -0
- data/public/avo-packs/js/application-947ed727440d5b5d73ab.js +26 -0
- data/public/avo-packs/js/{application-b444cbf11135b4b23654.js.LICENSE.txt → application-947ed727440d5b5d73ab.js.LICENSE.txt} +0 -0
- data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.br +0 -0
- data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.gz +0 -0
- data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.map +1 -0
- data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.map.br +0 -0
- data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.map.gz +0 -0
- data/public/avo-packs/manifest.json +8 -8
- metadata +10 -9
- data/public/avo-packs/js/application-b444cbf11135b4b23654.js +0 -26
- data/public/avo-packs/js/application-b444cbf11135b4b23654.js.br +0 -0
- data/public/avo-packs/js/application-b444cbf11135b4b23654.js.gz +0 -0
- data/public/avo-packs/js/application-b444cbf11135b4b23654.js.map +0 -1
- data/public/avo-packs/js/application-b444cbf11135b4b23654.js.map.br +0 -0
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 223442cb4814fbbdbac19b17f00ccfd5db95c1020137010e9393aa24898a7d35
|
4
|
+
data.tar.gz: fcec7fbe1391bd73ef39b8f8f58643a473c0c9c0349ddddfd0e737e3fcaa0f4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
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,
|
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
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
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
|
+
}
|
data/lib/avo/base_resource.rb
CHANGED
@@ -95,18 +95,20 @@ module Avo
|
|
95
95
|
field.visible?
|
96
96
|
end
|
97
97
|
.select do |field|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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
|
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
|
308
|
-
|
309
|
-
|
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.
|
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
|
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
|
-
|
329
|
-
|
336
|
+
value.present?
|
337
|
+
end
|
330
338
|
|
331
339
|
default_values.each do |id, value|
|
332
340
|
if @model.send(id).nil?
|
@@ -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
|
-
@
|
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
|
-
|
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
|
|