avo 1.6.0 → 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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +6 -6
  4. data/app/components/avo/edit/field_wrapper_component.html.erb +1 -1
  5. data/app/components/avo/edit/field_wrapper_component.rb +6 -1
  6. data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +65 -15
  7. data/app/components/avo/fields/belongs_to_field/edit_component.rb +1 -1
  8. data/app/controllers/avo/application_controller.rb +5 -5
  9. data/app/controllers/avo/base_controller.rb +8 -0
  10. data/app/packs/js/controllers/fields/belongs_to_field_controller.js +65 -0
  11. data/db/factories.rb +4 -0
  12. data/lib/avo/base_resource.rb +36 -19
  13. data/lib/avo/configuration.rb +7 -1
  14. data/lib/avo/fields/base_field.rb +5 -3
  15. data/lib/avo/fields/belongs_to_field.rb +95 -11
  16. data/lib/avo/fields/boolean_group_field.rb +1 -1
  17. data/lib/avo/fields/date_time_field.rb +1 -1
  18. data/lib/avo/fields/files_field.rb +1 -1
  19. data/lib/avo/fields/has_one_field.rb +1 -1
  20. data/lib/avo/fields/key_value_field.rb +1 -1
  21. data/lib/avo/fields_collector.rb +0 -2
  22. data/lib/avo/version.rb +1 -1
  23. data/lib/generators/avo/templates/initializer/avo.tt +1 -1
  24. data/lib/generators/avo/tool_generator.rb +8 -2
  25. data/public/avo-packs/css/application-797341b7.css.map +1 -1
  26. data/public/avo-packs/css/application-797341b7.css.map.br +0 -0
  27. data/public/avo-packs/css/application-797341b7.css.map.gz +0 -0
  28. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js +26 -0
  29. data/public/avo-packs/js/{application-b444cbf11135b4b23654.js.LICENSE.txt → application-947ed727440d5b5d73ab.js.LICENSE.txt} +0 -0
  30. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.br +0 -0
  31. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.gz +0 -0
  32. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.map +1 -0
  33. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.map.br +0 -0
  34. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.map.gz +0 -0
  35. data/public/avo-packs/manifest.json +8 -8
  36. metadata +12 -11
  37. data/public/avo-packs/js/application-b444cbf11135b4b23654.js +0 -26
  38. data/public/avo-packs/js/application-b444cbf11135b4b23654.js.br +0 -0
  39. data/public/avo-packs/js/application-b444cbf11135b4b23654.js.gz +0 -0
  40. data/public/avo-packs/js/application-b444cbf11135b4b23654.js.map +0 -1
  41. data/public/avo-packs/js/application-b444cbf11135b4b23654.js.map.br +0 -0
  42. 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: e23dcd11fb8a2c14c28dbc870d0fdba61e3fc8b8d7dfab30951c99f09efca8e2
4
- data.tar.gz: c7965d1d7e75025d3f385d404988374ad171d279737cd107cab55f94c40ed922
3
+ metadata.gz: 223442cb4814fbbdbac19b17f00ccfd5db95c1020137010e9393aa24898a7d35
4
+ data.tar.gz: fcec7fbe1391bd73ef39b8f8f58643a473c0c9c0349ddddfd0e737e3fcaa0f4f
5
5
  SHA512:
6
- metadata.gz: f8ee298228beec756ad7b78fbc792c1c13e84a14e189c87376f6936d2371ade820b0b26fa4a8124ec9d821334954e3f4f568e70e2be51c1623d94ac5d84a4aaa
7
- data.tar.gz: bcc4e5da23176fa624743f05a9d2c1b9736c91869b263239868156f940bd85bd72b6f5ef362503200a7b005cd2c203b65c3a584c0454360918a9d2b39f4cc3ef
6
+ metadata.gz: ed74295ce9b330ff686202d2ad75ec0120d32ccbc43437ea6eb1a81a365895fb7b43948d734221d0a71b8a987fd8670b0951020ad22107167760548c52a020d0
7
+ data.tar.gz: 2b826242331414096f2260d62fb25749456d9f7e2ccaa02a6a467d2de146e77224f462ea17dec59c492b9997fad36d5ffa1f036066859f5fea0f177c7e8a863e
data/Gemfile CHANGED
@@ -30,7 +30,7 @@ gem "rails", "~> 6.0.2", ">= 6.0.2.2"
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", "~> 4.3.5"
33
+ gem "puma", "~> 5.3.1"
34
34
  # Use SCSS for stylesheets
35
35
  gem "sass-rails", ">= 6"
36
36
  # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avo (1.6.0)
4
+ avo (1.6.3.pre.3)
5
5
  active_link_to
6
6
  addressable
7
7
  breadcrumbs_on_rails
@@ -184,10 +184,10 @@ GEM
184
184
  msgpack (1.4.2)
185
185
  multi_xml (0.6.0)
186
186
  nio4r (2.5.7)
187
- nokogiri (1.11.3)
187
+ nokogiri (1.11.5)
188
188
  mini_portile2 (~> 2.5.0)
189
189
  racc (~> 1.4)
190
- nokogiri (1.11.3-x86_64-linux)
190
+ nokogiri (1.11.5-x86_64-linux)
191
191
  racc (~> 1.4)
192
192
  orm_adapter (0.5.0)
193
193
  pagy (3.13.0)
@@ -196,7 +196,7 @@ GEM
196
196
  ast (~> 2.4.1)
197
197
  pg (1.2.3)
198
198
  public_suffix (4.0.6)
199
- puma (4.3.6)
199
+ puma (5.3.1)
200
200
  nio4r (~> 2.0)
201
201
  pundit (2.1.0)
202
202
  activesupport (>= 3.0.0)
@@ -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)
@@ -394,7 +394,7 @@ DEPENDENCIES
394
394
  manifester
395
395
  meta-tags
396
396
  pg (>= 0.18, < 2.0)
397
- puma (~> 4.3.5)
397
+ puma (~> 5.3.1)
398
398
  pundit
399
399
  rails (~> 6.0.2, >= 6.0.2.2)
400
400
  rails-controller-testing
@@ -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
@@ -52,11 +52,11 @@ module Avo
52
52
  if @license.lacks(:custom_tools) || @license.invalid?
53
53
  if Rails.env.development? || Rails.env.test?
54
54
  @custom_tools_alert_visible = true
55
+ elsif @license.lacks_with_trial(:custom_tools)
56
+ # Raise error in non-development environments.
57
+ raise Avo::LicenseInvalidError, "Your license is invalid or doesn't support custom tools."
55
58
  end
56
59
  end
57
-
58
- # Raise error in non-development environments.
59
- raise Avo::LicenseInvalidError, "Your license is invalid or doesn't support custom tools." if @license.lacks_with_trial(:custom_tools)
60
60
  end
61
61
  end
62
62
 
@@ -277,11 +277,11 @@ module Avo
277
277
  end
278
278
 
279
279
  def on_resources_path
280
- request.original_url.match?(/.*\/#{Avo.configuration.namespace}\/resources\/.*/)
280
+ request.original_url.match?(/.*#{Avo.configuration.root_path}\/resources\/.*/)
281
281
  end
282
282
 
283
283
  def on_api_path
284
- request.original_url.match?(/.*\/#{Avo.configuration.namespace}\/avo_api\/.*/)
284
+ request.original_url.match?(/.*#{Avo.configuration.root_path}\/avo_api\/.*/)
285
285
  end
286
286
  end
287
287
  end
@@ -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/db/factories.rb CHANGED
@@ -40,4 +40,8 @@ FactoryBot.define do
40
40
  meta { [{foo: "bar", hey: "hi"}, {bar: "baz"}, {hoho: "hohoho"}].sample }
41
41
  progress { Faker::Number.between(from: 0, to: 100) }
42
42
  end
43
+
44
+ factory :comment do
45
+ body { Faker::Lorem.paragraphs(number: rand(4...10)).join("\n") }
46
+ end
43
47
  end
@@ -87,20 +87,31 @@ module Avo
87
87
  end
88
88
 
89
89
  def get_fields(panel: nil, reflection: nil)
90
- fields = get_field_definitions.select do |field|
91
- field.send("show_on_#{@view}")
92
- end
90
+ fields = get_field_definitions
91
+ .select do |field|
92
+ field.send("show_on_#{@view}")
93
+ end
93
94
  .select do |field|
94
- field.visible?
95
- end
95
+ field.visible?
96
+ end
96
97
  .select do |field|
97
- unless field.respond_to?(:foreign_key) &&
98
- reflection.present? &&
99
- reflection.respond_to?(:foreign_key) &&
100
- 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
103
+ next
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
112
+
101
113
  true
102
114
  end
103
- end
104
115
 
105
116
  if panel.present?
106
117
  fields = fields.select do |field|
@@ -250,14 +261,17 @@ module Avo
250
261
  .reject do |field|
251
262
  field.computed
252
263
  end
253
- .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
254
268
 
255
269
  params.each do |key, value|
256
270
  field = fields_by_database_id[key]
257
271
 
258
272
  next unless field.present?
259
273
 
260
- model = field.fill_field model, key, value
274
+ model = field.fill_field model, key, value, params
261
275
  end
262
276
 
263
277
  model
@@ -295,19 +309,22 @@ module Avo
295
309
 
296
310
  # We will not overwrite any attributes that come pre-filled in the model.
297
311
  def hydrate_model_with_default_values
298
- default_values = get_fields.select do |field|
299
- !field.computed
300
- end
312
+ default_values = get_fields
313
+ .select do |field|
314
+ !field.computed
315
+ end
301
316
  .map do |field|
302
317
  id = field.id
303
318
  value = field.value
304
319
 
305
- if field.respond_to? :foreign_key
320
+ if field.type == "belongs_to"
306
321
  id = field.foreign_key.to_sym
307
322
 
308
323
  reflection = @model._reflections[@params[:via_relation]]
309
324
 
310
- 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
311
328
  value = @params[:via_resource_id]
312
329
  end
313
330
  end
@@ -316,8 +333,8 @@ module Avo
316
333
  end
317
334
  .to_h
318
335
  .select do |id, value|
319
- value.present?
320
- end
336
+ value.present?
337
+ end
321
338
 
322
339
  default_values.each do |id, value|
323
340
  if @model.send(id).nil?
@@ -1,6 +1,6 @@
1
1
  module Avo
2
2
  class Configuration
3
- attr_accessor :root_path
3
+ attr_writer :root_path
4
4
  attr_accessor :app_name
5
5
  attr_accessor :timezone
6
6
  attr_accessor :per_page
@@ -93,6 +93,12 @@ module Avo
93
93
  def namespace
94
94
  root_path.delete "/"
95
95
  end
96
+
97
+ def root_path
98
+ return "" if @root_path === "/"
99
+
100
+ @root_path
101
+ end
96
102
  end
97
103
 
98
104
  def self.configuration
@@ -91,9 +91,11 @@ module Avo
91
91
  end
92
92
  end
93
93
 
94
- def value
94
+ def value(property = nil)
95
+ property ||= id
96
+
95
97
  # Get model value
96
- final_value = @model.send(id) if (model_or_class(@model) == "model") && @model.respond_to?(id)
98
+ final_value = @model.send(property) if (model_or_class(@model) == "model") && @model.respond_to?(property)
97
99
 
98
100
  if (@view === :new) || @action.present?
99
101
  final_value = if default.present? && default.respond_to?(:call)
@@ -114,7 +116,7 @@ module Avo
114
116
  final_value
115
117
  end
116
118
 
117
- def fill_field(model, key, value)
119
+ def fill_field(model, key, value, params)
118
120
  return model unless model.methods.include? key.to_sym
119
121
 
120
122
  model.send("#{key}=", value)