avo 1.6.2.pre.1 → 1.7.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +6 -6
  4. data/README.md +2 -2
  5. data/app/components/avo/edit/field_wrapper_component.html.erb +1 -1
  6. data/app/components/avo/edit/field_wrapper_component.rb +6 -1
  7. data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +65 -15
  8. data/app/components/avo/fields/belongs_to_field/edit_component.rb +1 -1
  9. data/app/controllers/avo/base_controller.rb +6 -1
  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 -41
  13. data/lib/avo/fields/base_field.rb +5 -3
  14. data/lib/avo/fields/belongs_to_field.rb +96 -12
  15. data/lib/avo/fields/boolean_group_field.rb +1 -1
  16. data/lib/avo/fields/date_time_field.rb +1 -1
  17. data/lib/avo/fields/files_field.rb +1 -1
  18. data/lib/avo/fields/has_one_field.rb +1 -1
  19. data/lib/avo/fields/key_value_field.rb +1 -1
  20. data/lib/avo/fields/select_field.rb +17 -4
  21. data/lib/avo/fields_collector.rb +0 -2
  22. data/lib/avo/version.rb +1 -1
  23. data/public/avo-packs/css/application-797341b7.css.map +1 -1
  24. data/public/avo-packs/css/application-797341b7.css.map.br +0 -0
  25. data/public/avo-packs/css/application-797341b7.css.map.gz +0 -0
  26. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js +26 -0
  27. data/public/avo-packs/js/{application-b444cbf11135b4b23654.js.LICENSE.txt → application-947ed727440d5b5d73ab.js.LICENSE.txt} +0 -0
  28. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.br +0 -0
  29. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.gz +0 -0
  30. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.map +1 -0
  31. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.map.br +0 -0
  32. data/public/avo-packs/js/application-947ed727440d5b5d73ab.js.map.gz +0 -0
  33. data/public/avo-packs/manifest.json +8 -8
  34. metadata +12 -11
  35. data/public/avo-packs/js/application-b444cbf11135b4b23654.js +0 -26
  36. data/public/avo-packs/js/application-b444cbf11135b4b23654.js.br +0 -0
  37. data/public/avo-packs/js/application-b444cbf11135b4b23654.js.gz +0 -0
  38. data/public/avo-packs/js/application-b444cbf11135b4b23654.js.map +0 -1
  39. data/public/avo-packs/js/application-b444cbf11135b4b23654.js.map.br +0 -0
  40. 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: cf908e43c93a6279deabb3a577f37296aba3d1a5b74124252cb9d34207db9424
4
- data.tar.gz: 50923e9d726393c7a59ee94e4e83db09bacd1a9075740b245c9b5861d9b0d6c5
3
+ metadata.gz: e58bf8c94a89819523d1ef5abf6390ea2fb754d589c434a5de0d9daef0a231d0
4
+ data.tar.gz: 4662ea67f1f2653a495617d02ea279ed919889d33c599642394ca3f35e726f1b
5
5
  SHA512:
6
- metadata.gz: e51719e08fdd53a991891758bde5009659743866db5ffbca0f935fa81da0f5fd006536ebf60b66efddac1362677aec405619323d1ab3268d72112178e3e1de47
7
- data.tar.gz: 93e2795fc5c0b0b5da5604afcb4a8e891329b79946675de83e2582e2e8198ff3059ea88e3a1c316d1f3e458f28fa4f1d81c2c7d64af62fe84c0e5c3a0f1625d7
6
+ metadata.gz: 6743f19e795f59bed7ac32436e67a73a8bfbfdb7d267dd12de510d93d64bfe7f592cf400c1aef2e1cab4538ada6b614191aac596ecd3f19444b9ef0fb42e8518
7
+ data.tar.gz: 16360a9602b08cc7f973cddda9106546c6cded669ce9592d80b6b647a0e53ec1f3d74468f8d04c8db632610059e234552b3b5debfa444489af0b4090677e4e96
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.2.pre.1)
4
+ avo (1.7.0)
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
data/README.md CHANGED
@@ -56,6 +56,6 @@ $ bundle install
56
56
 
57
57
  Please read [CONTRIBUTING.MD](./CONTRIBUTING.MD)
58
58
 
59
- # Upgrade guide
59
+ # Upgrade Guide
60
60
 
61
- Please read the [UPGRADE_GUIDE.MD](https://docs.avohq.io/0.5.x/upgrade.html)
61
+ Please read the [UPGRADE_GUIDE.MD](https://docs.avohq.io/1.0/upgrade.html)
@@ -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.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
+ <%
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.underscore.humanize 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
@@ -18,7 +18,12 @@ module Avo
18
18
 
19
19
  # If we don't get a query object predefined from a child controller like relations, just spin one up
20
20
  unless defined? @query
21
- @query = @authorization.apply_policy @resource.model_class.unscoped
21
+ @query = @authorization.apply_policy @resource.model_class
22
+ end
23
+
24
+ # Remove default_scope for index view
25
+ if @resource.unscoped_queries_on_index
26
+ @query = @query.unscoped
22
27
  end
23
28
 
24
29
  # Eager load the relations
@@ -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
@@ -22,6 +22,7 @@ module Avo
22
22
  class_attribute :fields
23
23
  class_attribute :grid_loader
24
24
  class_attribute :visible_on_sidebar, default: true
25
+ class_attribute :unscoped_queries_on_index, default: false
25
26
 
26
27
  class << self
27
28
  def grid(&block)
@@ -87,20 +88,30 @@ module Avo
87
88
  end
88
89
 
89
90
  def get_fields(panel: nil, reflection: nil)
90
- fields = get_field_definitions.select do |field|
91
- field.send("show_on_#{@view}")
92
- end
91
+ fields = get_field_definitions
92
+ .select do |field|
93
+ field.send("show_on_#{@view}")
94
+ end
93
95
  .select do |field|
94
- field.visible?
95
- end
96
+ field.visible?
97
+ end
96
98
  .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
99
+ # Strip out the reflection field in index queries with a parent association.
100
+ if reflection.present? &&
101
+ reflection.options.present? &&
102
+ field.respond_to?(:polymorphic_as) &&
103
+ field.polymorphic_as.to_s == reflection.options[:as].to_s
104
+ next
105
+ end
106
+ if 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|
@@ -216,28 +227,6 @@ module Avo
216
227
  self.class.context
217
228
  end
218
229
 
219
- def query_search(via_resource_name:, via_resource_id:, user:, query: "")
220
- # model_class = self.model
221
-
222
- db_query = AuthorizationService.apply_policy(user, model_class)
223
-
224
- if via_resource_name.present?
225
- related_model = App.get_resource_by_name(via_resource_name).model
226
-
227
- db_query = related_model.find(via_resource_id).public_send(plural_name.downcase)
228
- end
229
-
230
- new_query = []
231
-
232
- [search].flatten.each_with_index do |search_by, index|
233
- new_query.push "or" if index != 0
234
-
235
- new_query.push "text(#{search_by}) ILIKE '%#{query}%'"
236
- end
237
-
238
- db_query.where(new_query.join(" "))
239
- end
240
-
241
230
  def attached_file_fields
242
231
  get_field_definitions.select do |field|
243
232
  [Avo::Fields::FileField, Avo::Fields::FilesField].include? field.class
@@ -250,14 +239,17 @@ module Avo
250
239
  .reject do |field|
251
240
  field.computed
252
241
  end
253
- .map { |field| [field.database_id(model).to_s, field] }.to_h
242
+ .map do |field|
243
+ [field.database_id(model).to_s, field]
244
+ end
245
+ .to_h
254
246
 
255
247
  params.each do |key, value|
256
248
  field = fields_by_database_id[key]
257
249
 
258
250
  next unless field.present?
259
251
 
260
- model = field.fill_field model, key, value
252
+ model = field.fill_field model, key, value, params
261
253
  end
262
254
 
263
255
  model
@@ -295,19 +287,22 @@ module Avo
295
287
 
296
288
  # We will not overwrite any attributes that come pre-filled in the model.
297
289
  def hydrate_model_with_default_values
298
- default_values = get_fields.select do |field|
299
- !field.computed
300
- end
290
+ default_values = get_fields
291
+ .select do |field|
292
+ !field.computed
293
+ end
301
294
  .map do |field|
302
295
  id = field.id
303
296
  value = field.value
304
297
 
305
- if field.respond_to? :foreign_key
298
+ if field.type == "belongs_to"
306
299
  id = field.foreign_key.to_sym
307
300
 
308
301
  reflection = @model._reflections[@params[:via_relation]]
309
302
 
310
- if reflection.present? && reflection.foreign_key.present? && field.id.to_s == @params[:via_relation].to_s
303
+ if field.polymorphic_as.present? && field.types.map(&:to_s).include?(@params["via_relation_class"])
304
+ value = @params["via_relation_class"].safe_constantize.find(@params[:via_resource_id])
305
+ elsif reflection.present? && reflection.foreign_key.present? && field.id.to_s == @params[:via_relation].to_s
311
306
  value = @params[:via_resource_id]
312
307
  end
313
308
  end
@@ -316,8 +311,8 @@ module Avo
316
311
  end
317
312
  .to_h
318
313
  .select do |id, value|
319
- value.present?
320
- end
314
+ value.present?
315
+ end
321
316
 
322
317
  default_values.each do |id, value|
323
318
  if @model.send(id).nil?
@@ -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)