avo 1.16.3 → 1.18.0.pre.1

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 +13 -13
  4. data/app/components/avo/fields/common/multiple_file_viewer_component.rb +2 -1
  5. data/app/components/avo/fields/common/single_file_viewer_component.rb +2 -1
  6. data/app/components/avo/fields/file_field/edit_component.html.erb +1 -1
  7. data/app/components/avo/fields/files_field/edit_component.html.erb +1 -1
  8. data/app/controllers/avo/actions_controller.rb +3 -1
  9. data/app/packs/entrypoints/application.js +2 -0
  10. data/app/packs/js/controllers/filter_controller.js +19 -2
  11. data/config/routes.rb +1 -0
  12. data/lib/avo/app.rb +2 -2
  13. data/lib/avo/base_action.rb +4 -2
  14. data/lib/avo/base_resource.rb +16 -5
  15. data/lib/avo/engine.rb +0 -1
  16. data/lib/avo/fields/base_field.rb +18 -4
  17. data/lib/avo/fields/date_time_field.rb +1 -1
  18. data/lib/avo/fields/file_field.rb +2 -0
  19. data/lib/avo/fields/files_field.rb +7 -0
  20. data/lib/avo/version.rb +1 -1
  21. data/lib/generators/avo/templates/action.tt +3 -1
  22. data/lib/generators/avo/templates/filters/boolean_filter.tt +1 -1
  23. data/public/avo-packs/css/application-2b4685ca.css.map +1 -1
  24. data/public/avo-packs/css/application-2b4685ca.css.map.br +0 -0
  25. data/public/avo-packs/css/application-2b4685ca.css.map.gz +0 -0
  26. data/public/avo-packs/js/application-6842378de4da9b615e18.js +26 -0
  27. data/public/avo-packs/js/{application-124d087ff9491dbf3511.js.LICENSE.txt → application-6842378de4da9b615e18.js.LICENSE.txt} +0 -0
  28. data/public/avo-packs/js/application-6842378de4da9b615e18.js.br +0 -0
  29. data/public/avo-packs/js/application-6842378de4da9b615e18.js.gz +0 -0
  30. data/public/avo-packs/js/application-6842378de4da9b615e18.js.map +1 -0
  31. data/public/avo-packs/js/application-6842378de4da9b615e18.js.map.br +0 -0
  32. data/public/avo-packs/js/application-6842378de4da9b615e18.js.map.gz +0 -0
  33. data/public/avo-packs/manifest.json +8 -8
  34. metadata +11 -11
  35. data/public/avo-packs/js/application-124d087ff9491dbf3511.js +0 -26
  36. data/public/avo-packs/js/application-124d087ff9491dbf3511.js.br +0 -0
  37. data/public/avo-packs/js/application-124d087ff9491dbf3511.js.gz +0 -0
  38. data/public/avo-packs/js/application-124d087ff9491dbf3511.js.map +0 -1
  39. data/public/avo-packs/js/application-124d087ff9491dbf3511.js.map.br +0 -0
  40. data/public/avo-packs/js/application-124d087ff9491dbf3511.js.map.gz +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 24fb847d8c6ebd7ba3c45926bc5431d7d100b3baf56391e316d4f30cebbae4f7
4
- data.tar.gz: 7eb97752916fd9159f0210e5f500a9b4c563c9d250ffa53b59dd1ad54b5ff770
3
+ metadata.gz: ccd552281f8ac8b77ea15f6d9000271a447a01190cb3c46905898f94df366009
4
+ data.tar.gz: c97173ac80821f5ef2de0f3d1060be50fe1c3b2c19d1b2f8eb177c9fc750f2d2
5
5
  SHA512:
6
- metadata.gz: 99780816253684b5de953532a0da805fecf38ab55115475438d94553ebe24989912e45172f7028d4c468482427f3da1686ea78d5c698ad3f24ff771fc0be72dc
7
- data.tar.gz: 54104ca33a97fb1508133b6f1db18772cf94db9404d2c4dde5b507bc64b2c80fba54c00501bad998f6998a83f533902c18dd6425b541c451c9d55c917b11699f
6
+ metadata.gz: 84703917f0960fb186bd79b5b7463298afd544e625f0b9ef83af6373c56d673e22479c2e88528cd2df1add04bd2ced0c31d50ea4bc6d856cfb26dd00a07cac42
7
+ data.tar.gz: f0e6a6d3b59bf79dac877bb012da1f56c979bf72897241e0f9d1633c7745e7fc1ce769d72610105d42b1e37d4a86f19e8a1e39370e709a2be24869a4b7a20981
data/Gemfile CHANGED
@@ -115,7 +115,7 @@ gem "hotwire-rails"
115
115
 
116
116
  gem "active_link_to"
117
117
 
118
- gem "view_component", require: "view_component/engine"
118
+ gem "view_component"
119
119
 
120
120
  gem "addressable"
121
121
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avo (1.16.3)
4
+ avo (1.18.0.pre.1)
5
5
  active_link_to
6
6
  addressable
7
7
  breadcrumbs_on_rails
@@ -107,7 +107,7 @@ GEM
107
107
  aws-eventstream (~> 1, >= 1.0.2)
108
108
  bcrypt (3.1.16)
109
109
  bindex (0.8.1)
110
- bootsnap (1.7.3)
110
+ bootsnap (1.9.3)
111
111
  msgpack (~> 1.0)
112
112
  breadcrumbs_on_rails (4.0.0)
113
113
  rails (>= 5.0)
@@ -123,7 +123,7 @@ GEM
123
123
  regexp_parser (~> 1.5)
124
124
  xpath (~> 3.2)
125
125
  childprocess (3.0.0)
126
- concurrent-ruby (1.1.8)
126
+ concurrent-ruby (1.1.9)
127
127
  countries (3.1.0)
128
128
  i18n_data (~> 0.11.0)
129
129
  sixarm_ruby_unaccent (~> 1.1)
@@ -131,7 +131,7 @@ GEM
131
131
  crack (0.4.4)
132
132
  crass (1.0.6)
133
133
  database_cleaner (1.8.5)
134
- devise (4.7.3)
134
+ devise (4.8.1)
135
135
  bcrypt (~> 3.0)
136
136
  orm_adapter (~> 0.1)
137
137
  railties (>= 4.1.0)
@@ -168,7 +168,7 @@ GEM
168
168
  httparty (0.18.1)
169
169
  mime-types (~> 3.0)
170
170
  multi_xml (>= 0.5.2)
171
- i18n (1.8.10)
171
+ i18n (1.8.11)
172
172
  concurrent-ruby (~> 1.0)
173
173
  i18n_data (0.11.0)
174
174
  image_processing (1.12.1)
@@ -184,7 +184,7 @@ GEM
184
184
  listen (3.5.1)
185
185
  rb-fsevent (~> 0.10, >= 0.10.3)
186
186
  rb-inotify (~> 0.9, >= 0.9.10)
187
- loofah (2.9.1)
187
+ loofah (2.13.0)
188
188
  crass (~> 1.0.2)
189
189
  nokogiri (>= 1.5.9)
190
190
  mail (2.7.1)
@@ -202,7 +202,7 @@ GEM
202
202
  mini_magick (4.11.0)
203
203
  mini_mime (1.0.3)
204
204
  mini_portile2 (2.6.1)
205
- minitest (5.14.4)
205
+ minitest (5.15.0)
206
206
  msgpack (1.4.2)
207
207
  multi_xml (0.6.0)
208
208
  nio4r (2.5.8)
@@ -210,7 +210,7 @@ GEM
210
210
  mini_portile2 (~> 2.6.1)
211
211
  racc (~> 1.4)
212
212
  orm_adapter (0.5.0)
213
- pagy (4.11.0)
213
+ pagy (5.6.6)
214
214
  parallel (1.20.1)
215
215
  parser (3.0.0.0)
216
216
  ast (~> 2.4.1)
@@ -220,7 +220,7 @@ GEM
220
220
  nio4r (~> 2.0)
221
221
  pundit (2.1.0)
222
222
  activesupport (>= 3.0.0)
223
- racc (1.5.2)
223
+ racc (1.6.0)
224
224
  rack (2.2.3)
225
225
  rack-proxy (0.6.5)
226
226
  rack
@@ -248,7 +248,7 @@ GEM
248
248
  rails-dom-testing (2.0.3)
249
249
  activesupport (>= 4.2.0)
250
250
  nokogiri (>= 1.6)
251
- rails-html-sanitizer (1.3.0)
251
+ rails-html-sanitizer (1.4.2)
252
252
  loofah (~> 2.3)
253
253
  railties (6.1.3.2)
254
254
  actionpack (= 6.1.3.2)
@@ -257,7 +257,7 @@ GEM
257
257
  rake (>= 0.8.7)
258
258
  thor (~> 1.0)
259
259
  rainbow (3.0.0)
260
- rake (13.0.3)
260
+ rake (13.0.6)
261
261
  ransack (2.4.2)
262
262
  activerecord (>= 5.2.4)
263
263
  activesupport (>= 5.2.4)
@@ -379,7 +379,7 @@ GEM
379
379
  websocket-extensions (0.1.5)
380
380
  xpath (3.2.0)
381
381
  nokogiri (~> 1.8)
382
- zeitwerk (2.4.2)
382
+ zeitwerk (2.5.2)
383
383
 
384
384
  PLATFORMS
385
385
  ruby
@@ -439,4 +439,4 @@ DEPENDENCIES
439
439
  zeitwerk (~> 2.3)
440
440
 
441
441
  BUNDLED WITH
442
- 2.2.29
442
+ 2.2.32
@@ -3,10 +3,11 @@
3
3
  class Avo::Fields::Common::MultipleFileViewerComponent < ViewComponent::Base
4
4
  include Avo::ApplicationHelper
5
5
 
6
- def initialize(id:, file:, is_image:, resource:, button_size: :md)
6
+ def initialize(id:, file:, is_image:, direct_upload: false, resource:, button_size: :md)
7
7
  @id = id
8
8
  @file = file
9
9
  @is_image = is_image
10
+ @direct_upload = direct_upload
10
11
  @button_size = button_size
11
12
  @resource = resource
12
13
  end
@@ -3,10 +3,11 @@
3
3
  class Avo::Fields::Common::SingleFileViewerComponent < ViewComponent::Base
4
4
  include Avo::ApplicationHelper
5
5
 
6
- def initialize(id:, file:, is_image:, resource:, button_size: :md)
6
+ def initialize(id:, file:, is_image:, direct_upload: false, resource:, button_size: :md)
7
7
  @id = id
8
8
  @file = file
9
9
  @is_image = is_image
10
+ @direct_upload = direct_upload
10
11
  @button_size = button_size
11
12
  @resource = resource
12
13
  end
@@ -6,6 +6,6 @@
6
6
  <% end %>
7
7
 
8
8
  <% if @resource.authorization.authorize_action(:upload_attachments?, raise_exception: false) %>
9
- <%= @form.file_field @field.id, disabled: @field.readonly %>
9
+ <%= @form.file_field @field.id, disabled: @field.readonly, direct_upload: @field.direct_upload %>
10
10
  <% end %>
11
11
  <% end %>
@@ -2,6 +2,6 @@
2
2
  <%= render Avo::Fields::Common::FilesListViewerComponent.new(field: @field, resource: @resource) if @field.value.present? %>
3
3
 
4
4
  <% if @resource.authorization.authorize_action(:upload_attachments?, raise_exception: false) %>
5
- <%= @form.file_field @field.id, disabled: @field.readonly, multiple: true %>
5
+ <%= @form.file_field @field.id, disabled: @field.readonly, multiple: true, direct_upload: @field.direct_upload %>
6
6
  <% end %>
7
7
  <% end %>
@@ -19,7 +19,9 @@ module Avo
19
19
  end
20
20
 
21
21
  args = {
22
- fields: fields
22
+ fields: fields,
23
+ current_user: _current_user,
24
+ resource: resource,
23
25
  }
24
26
 
25
27
  args[:models] = models unless @action.standalone
@@ -2,6 +2,7 @@
2
2
  import 'core-js/stable'
3
3
  // eslint-disable-next-line import/no-extraneous-dependencies
4
4
  import 'regenerator-runtime/runtime'
5
+ import * as ActiveStorage from '@rails/activestorage'
5
6
  import * as Mousetrap from 'mousetrap'
6
7
  import { Application } from 'stimulus'
7
8
  import { Turbo } from '@hotwired/turbo-rails'
@@ -32,6 +33,7 @@ function initTippy() {
32
33
  window.initTippy = initTippy
33
34
 
34
35
  const application = Application.start()
36
+ ActiveStorage.start()
35
37
 
36
38
  const context = require.context('./../js/controllers', true, /\.js$/)
37
39
  application.load(definitionsFromContext(context))
@@ -21,6 +21,23 @@ export default class extends Controller {
21
21
  return param
22
22
  }
23
23
 
24
+ b64EncodeUnicode(str) {
25
+ // first we use encodeURIComponent to get percent-encoded UTF-8,
26
+ // then we convert the percent encodings into raw bytes which
27
+ // can be fed into btoa.
28
+ return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,
29
+ function toSolidBytes(match, p1) {
30
+ return String.fromCharCode('0x' + p1);
31
+ }));
32
+ }
33
+
34
+ b64DecodeUnicode(str) {
35
+ // Going backwards: from bytestream, to percent-encoding, to original string.
36
+ return decodeURIComponent(atob(str).split('').map(function(c) {
37
+ return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
38
+ }).join(''));
39
+ }
40
+
24
41
  changeFilter() {
25
42
  const value = this.getFilterValue()
26
43
  const filterClass = this.getFilterClass()
@@ -28,7 +45,7 @@ export default class extends Controller {
28
45
  let filters = this.uriParams()[this.uriParam('filters')]
29
46
 
30
47
  if (filters) {
31
- filters = JSON.parse(atob(filters))
48
+ filters = JSON.parse(this.b64DecodeUnicode(filters))
32
49
  } else {
33
50
  filters = {}
34
51
  }
@@ -46,7 +63,7 @@ export default class extends Controller {
46
63
  let encodedFilters
47
64
 
48
65
  if (filtered && Object.keys(filtered).length > 0) {
49
- encodedFilters = btoa(JSON.stringify(filtered))
66
+ encodedFilters = this.b64EncodeUnicode(JSON.stringify(filtered))
50
67
  }
51
68
 
52
69
  const url = new URI(this.urlRedirectTarget.href)
data/config/routes.rb CHANGED
@@ -2,6 +2,7 @@ Avo::Engine.routes.draw do
2
2
  root "home#index"
3
3
 
4
4
  get "resources", to: redirect("/admin")
5
+ post "/rails/active_storage/direct_uploads", to: "/active_storage/direct_uploads#create"
5
6
 
6
7
  scope "avo_api", as: "avo_api" do
7
8
  get "/search", to: "search#index"
data/lib/avo/app.rb CHANGED
@@ -32,9 +32,9 @@ module Avo
32
32
 
33
33
  # Set the current host for ActiveStorage
34
34
  begin
35
- ActiveStorage::Current.host = request.base_url
35
+ ActiveStorage::Current.url_options = request.base_url
36
36
  rescue => exception
37
- Rails.logger.debug "[Avo] Failed to set ActiveStorage::Current.host, #{exception.inspect}"
37
+ Rails.logger.debug "[Avo] Failed to set ActiveStorage::Current.url_options, #{exception.inspect}"
38
38
  end
39
39
 
40
40
  init_resources
@@ -70,7 +70,7 @@ module Avo
70
70
  end
71
71
 
72
72
  def handle_action(**args)
73
- models, fields = args.values_at(:models, :fields)
73
+ models, fields, current_user, resource = args.values_at(:models, :fields, :current_user, :resource)
74
74
  avo_fields = get_fields.map { |field| [field.id, field] }.to_h
75
75
 
76
76
  if fields.present?
@@ -84,7 +84,9 @@ module Avo
84
84
  end
85
85
 
86
86
  args = {
87
- fields: processed_fields
87
+ fields: processed_fields,
88
+ current_user: current_user,
89
+ resource: resource,
88
90
  }
89
91
 
90
92
  args[:models] = models unless standalone
@@ -16,6 +16,7 @@ module Avo
16
16
  class_attribute :includes, default: []
17
17
  class_attribute :model_class
18
18
  class_attribute :translation_key
19
+ class_attribute :translation_enabled
19
20
  class_attribute :default_view_type, default: :table
20
21
  class_attribute :devise_password_optional, default: false
21
22
  class_attribute :actions_loader
@@ -94,7 +95,7 @@ module Avo
94
95
  return [] if self.class.fields.blank?
95
96
 
96
97
  fields = self.class.fields.map do |field|
97
- field.hydrate(resource: self, panel_name: default_panel_name, user: user)
98
+ field.hydrate(resource: self, panel_name: default_panel_name, user: user, translation_enabled: translation_enabled)
98
99
  end
99
100
 
100
101
  if Avo::App.license.lacks_with_trial(:custom_fields)
@@ -192,12 +193,16 @@ module Avo
192
193
  ]
193
194
  end
194
195
 
196
+ def class_name_without_resource
197
+ self.class.name.demodulize.chomp("Resource")
198
+ end
199
+
195
200
  def model_class
196
201
  return self.class.model_class if self.class.model_class.present?
197
202
 
198
203
  return @model.class if @model.present?
199
204
 
200
- self.class.name.demodulize.chomp("Resource").safe_constantize
205
+ class_name_without_resource.safe_constantize
201
206
  end
202
207
 
203
208
  def model_title
@@ -206,12 +211,18 @@ module Avo
206
211
  name
207
212
  end
208
213
 
214
+ def translation_key
215
+ return "avo.resource_translations.#{class_name_without_resource.underscore}" if self.class.translation_enabled
216
+
217
+ self.class.translation_key
218
+ end
219
+
209
220
  def name
210
221
  return @name if @name.present?
211
222
 
212
- return I18n.t(self.class.translation_key, count: 1).capitalize if self.class.translation_key
223
+ return I18n.t(translation_key, count: 1).capitalize if translation_key
213
224
 
214
- self.class.name.demodulize.chomp("Resource").titlecase
225
+ class_name_without_resource.titlecase
215
226
  end
216
227
 
217
228
  def singular_name
@@ -219,7 +230,7 @@ module Avo
219
230
  end
220
231
 
221
232
  def plural_name
222
- return I18n.t(self.class.translation_key, count: 2).capitalize if self.class.translation_key
233
+ return I18n.t(translation_key, count: 2).capitalize if translation_key
223
234
 
224
235
  name.pluralize
225
236
  end
data/lib/avo/engine.rb CHANGED
@@ -2,7 +2,6 @@
2
2
  Gem.loaded_specs["avo"].dependencies.each do |d|
3
3
  require d.name
4
4
  end
5
- require "view_component/engine"
6
5
 
7
6
  module Avo
8
7
  class Engine < ::Rails::Engine
@@ -6,8 +6,6 @@ module Avo
6
6
  include Avo::Fields::FieldExtensions::VisibleInDifferentViews
7
7
 
8
8
  attr_reader :id
9
- attr_reader :name
10
- attr_reader :translation_key
11
9
  attr_reader :block
12
10
  attr_reader :required
13
11
  attr_reader :readonly
@@ -43,8 +41,9 @@ module Avo
43
41
  super(id, **args, &block)
44
42
 
45
43
  @id = id
46
- @name = args[:name] || id.to_s.humanize(keep_id_suffix: true)
44
+ @name = args[:name]
47
45
  @translation_key = args[:translation_key]
46
+ @translation_enabled = false
48
47
  @block = block
49
48
  @required = args[:required] || false
50
49
  @readonly = args[:readonly] || false
@@ -72,17 +71,32 @@ module Avo
72
71
  except_on args[:except_on] if args[:except_on].present?
73
72
  end
74
73
 
75
- def hydrate(model: nil, resource: nil, action: nil, view: nil, panel_name: nil, user: nil)
74
+ def hydrate(model: nil, resource: nil, action: nil, view: nil, panel_name: nil, user: nil, translation_enabled: nil)
76
75
  @model = model if model.present?
77
76
  @view = view if view.present?
78
77
  @resource = resource if resource.present?
79
78
  @action = action if action.present?
80
79
  @user = user if user.present?
81
80
  @panel_name = panel_name if panel_name.present?
81
+ @translation_enabled = translation_enabled if translation_enabled.present?
82
82
 
83
83
  self
84
84
  end
85
85
 
86
+ def translation_key
87
+ return "avo.field_translations.#{@id}" if @translation_enabled
88
+
89
+ @translation_key
90
+ end
91
+
92
+ def name
93
+ return @name if @name.present?
94
+
95
+ return I18n.t(translation_key, count: 1).capitalize if translation_key
96
+
97
+ @id.to_s.humanize(keep_id_suffix: true)
98
+ end
99
+
86
100
  def visible?
87
101
  if visible.present? && visible.respond_to?(:call)
88
102
  visible.call resource: @resource
@@ -17,7 +17,7 @@ module Avo
17
17
  return nil if value.nil?
18
18
 
19
19
  if @format.is_a?(Symbol)
20
- value.to_time.in_time_zone(timezone).to_s(@format)
20
+ value.to_time.in_time_zone(timezone).to_formatted_s(@format)
21
21
  else
22
22
  value.to_time.in_time_zone(timezone).strftime(@format)
23
23
  end
@@ -4,6 +4,7 @@ module Avo
4
4
  attr_accessor :link_to_resource
5
5
  attr_accessor :is_avatar
6
6
  attr_accessor :is_image
7
+ attr_accessor :direct_upload
7
8
 
8
9
  def initialize(id, **args, &block)
9
10
  super(id, **args, &block)
@@ -11,6 +12,7 @@ module Avo
11
12
  @link_to_resource = args[:link_to_resource].present? ? args[:link_to_resource] : false
12
13
  @is_avatar = args[:is_avatar].present? ? args[:is_avatar] : false
13
14
  @is_image = args[:is_image].present? ? args[:is_image] : @is_avatar
15
+ @direct_upload = args[:direct_upload].present? ? args[:direct_upload] : false
14
16
  end
15
17
 
16
18
  def path
@@ -2,11 +2,13 @@ module Avo
2
2
  module Fields
3
3
  class FilesField < BaseField
4
4
  attr_accessor :is_image
5
+ attr_accessor :direct_upload
5
6
 
6
7
  def initialize(id, **args, &block)
7
8
  super(id, **args, &block)
8
9
 
9
10
  @is_image = args[:is_image].present? ? args[:is_image] : @is_avatar
11
+ @direct_upload = args[:direct_upload].present? ? args[:direct_upload] : false
10
12
  end
11
13
 
12
14
  def view_component_name
@@ -21,6 +23,11 @@ module Avo
21
23
  return model unless model.methods.include? key.to_sym
22
24
 
23
25
  value.each do |file|
26
+ # Skip empty values
27
+ next unless file.present?
28
+ # Skip Capybara Nil files in tests
29
+ next unless file.class === Capybara::RackTest::Form::NilUploadedFile
30
+
24
31
  model.send(key).attach file
25
32
  end
26
33
 
data/lib/avo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Avo
2
- VERSION = "1.16.3"
2
+ VERSION = "1.18.0.pre.1"
3
3
  end
@@ -1,7 +1,9 @@
1
1
  class <%= class_name.camelize %> < Avo::BaseAction
2
2
  self.name = '<%= name.underscore.humanize %>'
3
3
 
4
- def handle(models:, fields:)
4
+ def handle(**args)
5
+ models, fields, current_user, resource = args.values_at(:models, :fields, :current_user, :resource)
6
+
5
7
  models.each do |model|
6
8
  # Do something with your models.
7
9
  end
@@ -1,7 +1,7 @@
1
1
  class <%= class_name.camelize %> < Avo::Filters::BooleanFilter
2
2
  self.name = '<%= name.underscore.humanize %>'
3
3
 
4
- def apply(request, query, value)
4
+ def apply(request, query, values)
5
5
  query
6
6
  end
7
7