avo 1.7.2 → 1.8.2

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -1
  3. data/Gemfile.lock +94 -70
  4. data/README.md +11 -0
  5. data/app/components/avo/fields/common/multiple_file_viewer_component.html.erb +1 -1
  6. data/app/components/avo/fields/common/single_file_viewer_component.html.erb +1 -1
  7. data/app/components/avo/fields/file_field/index_component.html.erb +1 -1
  8. data/app/components/avo/fields/trix_field/edit_component.html.erb +3 -0
  9. data/app/components/avo/index/grid_item_component.html.erb +4 -6
  10. data/app/components/avo/views/resource_index_component.html.erb +48 -46
  11. data/app/components/avo/views/resource_index_component.rb +1 -1
  12. data/app/controllers/avo/actions_controller.rb +2 -2
  13. data/app/controllers/avo/application_controller.rb +11 -10
  14. data/app/controllers/avo/base_controller.rb +26 -5
  15. data/app/controllers/avo/relations_controller.rb +1 -1
  16. data/app/controllers/avo/search_controller.rb +11 -8
  17. data/app/packs/js/controllers/fields/trix_field_controller.js +16 -0
  18. data/app/views/avo/actions/show.html.erb +1 -1
  19. data/app/views/avo/attachments/show.html.erb +1 -1
  20. data/app/views/avo/base/_actions.html.erb +2 -2
  21. data/app/views/avo/home/index.html.erb +2 -2
  22. data/app/views/avo/partials/_javascript.html.erb +1 -1
  23. data/app/views/avo/partials/_resource_search.html.erb +1 -1
  24. data/app/views/avo/relations/new.html.erb +1 -1
  25. data/app/views/avo/sidebar/_sidebar.html.erb +1 -1
  26. data/db/migrate/20210525143134_add_slug_to_users.rb +6 -0
  27. data/lib/avo/app.rb +3 -1
  28. data/lib/avo/base_resource.rb +22 -2
  29. data/lib/avo/configuration.rb +7 -1
  30. data/lib/avo/fields/belongs_to_field.rb +1 -1
  31. data/lib/avo/fields/file_field.rb +0 -8
  32. data/lib/avo/fields/has_and_belongs_to_many_field.rb +4 -4
  33. data/lib/avo/fields/has_many_field.rb +4 -4
  34. data/lib/avo/fields/has_one_field.rb +4 -4
  35. data/lib/avo/fields/trix_field.rb +6 -0
  36. data/lib/avo/version.rb +1 -1
  37. data/lib/generators/avo/field_generator.rb +1 -1
  38. data/lib/generators/avo/install_generator.rb +1 -1
  39. data/lib/generators/avo/templates/initializer/avo.tt +1 -0
  40. data/lib/generators/avo/templates/tool/sidebar_item.tt +1 -1
  41. data/public/avo-packs/css/application-797341b7.css.map +1 -1
  42. data/public/avo-packs/css/application-797341b7.css.map.br +0 -0
  43. data/public/avo-packs/css/application-797341b7.css.map.gz +0 -0
  44. data/public/avo-packs/js/application-651ed7b9bc727c83f673.js +26 -0
  45. data/public/avo-packs/js/{application-2a4345ecd9464d1e8850.js.LICENSE.txt → application-651ed7b9bc727c83f673.js.LICENSE.txt} +0 -0
  46. data/public/avo-packs/js/application-651ed7b9bc727c83f673.js.br +0 -0
  47. data/public/avo-packs/js/application-651ed7b9bc727c83f673.js.gz +0 -0
  48. data/public/avo-packs/js/application-651ed7b9bc727c83f673.js.map +1 -0
  49. data/public/avo-packs/js/application-651ed7b9bc727c83f673.js.map.br +0 -0
  50. data/public/avo-packs/js/application-651ed7b9bc727c83f673.js.map.gz +0 -0
  51. data/public/avo-packs/manifest.json +8 -8
  52. metadata +10 -9
  53. data/public/avo-packs/js/application-2a4345ecd9464d1e8850.js +0 -26
  54. data/public/avo-packs/js/application-2a4345ecd9464d1e8850.js.br +0 -0
  55. data/public/avo-packs/js/application-2a4345ecd9464d1e8850.js.gz +0 -0
  56. data/public/avo-packs/js/application-2a4345ecd9464d1e8850.js.map +0 -1
  57. data/public/avo-packs/js/application-2a4345ecd9464d1e8850.js.map.br +0 -0
  58. data/public/avo-packs/js/application-2a4345ecd9464d1e8850.js.map.gz +0 -0
@@ -77,7 +77,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
77
77
  end
78
78
 
79
79
  def attach_path
80
- "#{Avo.configuration.root_path}#{request.env["PATH_INFO"]}/new"
80
+ "#{Avo::App.root_path}#{request.env["PATH_INFO"]}/new"
81
81
  end
82
82
 
83
83
  def detach_path
@@ -12,7 +12,7 @@ module Avo
12
12
 
13
13
  def handle
14
14
  resource_ids = action_params[:fields][:resource_ids].split(",").map(&:to_i)
15
- models = @resource.model_class.find resource_ids
15
+ models = @resource.class.find_scope.find resource_ids
16
16
 
17
17
  fields = action_params[:fields].select do |key, value|
18
18
  key != "resource_ids"
@@ -33,7 +33,7 @@ module Avo
33
33
  action_class = params[:action_id].gsub("avo_actions_", "").classify.safe_constantize
34
34
 
35
35
  if params[:id].present?
36
- model = @resource.model_class.find params[:id]
36
+ model = @resource.class.find_scope.find params[:id]
37
37
  end
38
38
 
39
39
  @action = action_class.new(model: model, resource: resource, user: _current_user)
@@ -17,7 +17,7 @@ module Avo
17
17
  add_flash_types :info, :warning, :success, :error
18
18
 
19
19
  def init_app
20
- Avo::App.init request: request, context: context, current_user: _current_user
20
+ Avo::App.init request: request, context: context, root_path: avo.root_path.delete_suffix("/"), current_user: _current_user
21
21
 
22
22
  @license = Avo::App.license
23
23
  end
@@ -78,6 +78,7 @@ module Avo
78
78
  existing_params = Addressable::URI.parse(request.fullpath).query_values.symbolize_keys
79
79
  end
80
80
  rescue; end
81
+
81
82
  avo.send :"resources_#{model.model_name.route_key}_path", **existing_params, **args
82
83
  end
83
84
 
@@ -91,7 +92,7 @@ module Avo
91
92
  existing_params = Addressable::URI.parse(request.fullpath).query_values.symbolize_keys
92
93
  end
93
94
  rescue; end
94
- Addressable::Template.new("#{Avo.configuration.root_path}/resources/#{@parent_resource.model.model_name.route_key}/#{@parent_resource.model.id}/#{@resource.route_key}{?query*}")
95
+ Addressable::Template.new("#{Avo::App.root_path}/resources/#{@parent_resource.model.model_name.route_key}/#{@parent_resource.model.id}/#{@resource.route_key}{?query*}")
95
96
  .expand({query: {**existing_params, **args}})
96
97
  .to_str
97
98
  end
@@ -103,7 +104,7 @@ module Avo
103
104
  end
104
105
 
105
106
  def resource_attach_path(model_name, model_id, related_name, related_id = nil)
106
- path = "#{Avo.configuration.root_path}/resources/#{model_name}/#{model_id}/#{related_name}/new"
107
+ path = "#{Avo::App.root_path}/resources/#{model_name}/#{model_id}/#{related_name}/new"
107
108
 
108
109
  path += "/#{related_id}" if related_id.present?
109
110
 
@@ -111,7 +112,7 @@ module Avo
111
112
  end
112
113
 
113
114
  def resource_detach_path(model_name, model_id, related_name, related_id = nil)
114
- path = "#{Avo.configuration.root_path}/resources/#{model_name}/#{model_id}/#{related_name}"
115
+ path = "#{Avo::App.root_path}/resources/#{model_name}/#{model_id}/#{related_name}"
115
116
 
116
117
  path += "/#{related_id}" if related_id.present?
117
118
 
@@ -147,11 +148,11 @@ module Avo
147
148
  end
148
149
 
149
150
  def set_model
150
- @model = eager_load_files(@resource, @resource.model_class).find params[:id]
151
+ @model = eager_load_files(@resource, @resource.class.find_scope).find params[:id]
151
152
  end
152
153
 
153
154
  def set_related_model
154
- @related_model = eager_load_files(@related_resource, @related_resource.model_class).find params[:related_id]
155
+ @related_model = eager_load_files(@related_resource, @related_resource.class.find_scope).find params[:related_id]
155
156
  end
156
157
 
157
158
  def hydrate_resource
@@ -179,7 +180,7 @@ module Avo
179
180
 
180
181
  begin
181
182
  request.path
182
- .match(/\/?#{Avo.configuration.root_path.delete('/')}\/resources\/([a-z1-9\-_]*)\/?/mi)
183
+ .match(/\/?#{Avo::App.root_path.delete('/')}\/resources\/([a-z1-9\-_]*)\/?/mi)
183
184
  .captures
184
185
  .first
185
186
  rescue
@@ -273,15 +274,15 @@ module Avo
273
274
  end
274
275
 
275
276
  def on_root_path
276
- [Avo.configuration.root_path, "#{Avo.configuration.root_path}/"].include?(request.original_fullpath)
277
+ [Avo::App.root_path, "#{Avo::App.root_path}/"].include?(request.original_fullpath)
277
278
  end
278
279
 
279
280
  def on_resources_path
280
- request.original_url.match?(/.*#{Avo.configuration.root_path}\/resources\/.*/)
281
+ request.original_url.match?(/.*#{Avo::App.root_path}\/resources\/.*/)
281
282
  end
282
283
 
283
284
  def on_api_path
284
- request.original_url.match?(/.*#{Avo.configuration.root_path}\/avo_api\/.*/)
285
+ request.original_url.match?(/.*#{Avo::App.root_path}\/avo_api\/.*/)
285
286
  end
286
287
  end
287
288
  end
@@ -7,6 +7,8 @@ module Avo
7
7
  before_action :hydrate_resource
8
8
  before_action :authorize_action
9
9
  before_action :set_model, only: [:show, :edit, :destroy, :update]
10
+ before_action :reset_pagination_if_filters_changed, only: :index
11
+ before_action :cache_applied_filters, only: :index
10
12
 
11
13
  def index
12
14
  @page_title = resource_name.humanize
@@ -18,7 +20,7 @@ module Avo
18
20
 
19
21
  # If we don't get a query object predefined from a child controller like relations, just spin one up
20
22
  unless defined? @query
21
- @query = @authorization.apply_policy @resource.model_class
23
+ @query = @resource.class.query_scope
22
24
  end
23
25
 
24
26
  # Remove default_scope for index view
@@ -62,7 +64,7 @@ module Avo
62
64
  # If we're accessing this resource via another resource add the parent to the breadcrumbs.
63
65
  if params[:via_resource_class].present? && params[:via_resource_id].present?
64
66
  via_resource = Avo::App.get_resource_by_model_name params[:via_resource_class]
65
- via_model = via_resource.model_class.find params[:via_resource_id]
67
+ via_model = via_resource.class.find_scope.find params[:via_resource_id]
66
68
  via_resource.hydrate model: via_model
67
69
 
68
70
  add_breadcrumb via_resource.plural_name, resources_path(via_resource.model_class)
@@ -91,7 +93,7 @@ module Avo
91
93
  # If we're accessing this resource via another resource add the parent to the breadcrumbs.
92
94
  if params[:via_resource_class].present? && params[:via_resource_id].present?
93
95
  via_resource = Avo::App.get_resource_by_model_name params[:via_resource_class]
94
- via_model = via_resource.model_class.find params[:via_resource_id]
96
+ via_model = via_resource.class.find_scope.find params[:via_resource_id]
95
97
  via_resource.hydrate model: via_model
96
98
 
97
99
  add_breadcrumb via_resource.plural_name, resources_path(via_resource.model_class)
@@ -217,7 +219,12 @@ module Avo
217
219
  end
218
220
 
219
221
  # Sorting
220
- @index_params[:sort_by] = params[:sort_by] || :created_at
222
+ if params[:sort_by].present?
223
+ @index_params[:sort_by] = params[:sort_by]
224
+ elsif @resource.model_class.present? && @resource.model_class.column_names.include?("created_at")
225
+ @index_params[:sort_by] = :created_at
226
+ end
227
+
221
228
  @index_params[:sort_direction] = params[:sort_direction] || :desc
222
229
 
223
230
  # View types
@@ -235,7 +242,7 @@ module Avo
235
242
 
236
243
  def set_actions
237
244
  if params[:resource_id].present?
238
- model = @resource.model_class.find params[:resource_id]
245
+ model = @resource.class.find_scope.find params[:resource_id]
239
246
  end
240
247
 
241
248
  @actions = @resource.get_actions.map do |action|
@@ -260,5 +267,19 @@ module Avo
260
267
 
261
268
  filter_defaults
262
269
  end
270
+
271
+ def cache_applied_filters
272
+ ::Avo::App.cache_store.delete applied_filters_cache_key if params[:filters].nil?
273
+
274
+ ::Avo::App.cache_store.write(applied_filters_cache_key, params[:filters], expires_in: 7.days)
275
+ end
276
+
277
+ def reset_pagination_if_filters_changed
278
+ params[:page] = 1 if params[:filters] != ::Avo::App.cache_store.read(applied_filters_cache_key)
279
+ end
280
+
281
+ def applied_filters_cache_key
282
+ "avo.base_controller.#{@resource.route_key}.applied_filters"
283
+ end
263
284
  end
264
285
  end
@@ -15,7 +15,7 @@ module Avo
15
15
  def index
16
16
  @parent_resource = @resource.dup
17
17
  @resource = @related_resource
18
- @parent_model = @parent_resource.model_class.find(params[:id])
18
+ @parent_model = @parent_resource.class.find_scope.find(params[:id])
19
19
  @parent_resource.hydrate(model: @parent_model)
20
20
  @query = @authorization.apply_policy @parent_model.public_send(params[:related_name])
21
21
 
@@ -2,6 +2,8 @@ require_dependency "avo/application_controller"
2
2
 
3
3
  module Avo
4
4
  class SearchController < ApplicationController
5
+ include Rails.application.routes.url_helpers
6
+
5
7
  before_action :set_resource_name, only: [:show]
6
8
  before_action :set_resource, only: [:show]
7
9
 
@@ -18,14 +20,15 @@ module Avo
18
20
  private
19
21
 
20
22
  def search_resources(resources)
21
- resources.map do |resource|
22
- # Apply authorization
23
- next unless @authorization.set_record(resource.model_class).authorize_action(:index, raise_exception: false)
24
- # Filter out the models without a search_query
25
- next if resource.search_query.nil?
23
+ resources
24
+ .map do |resource|
25
+ # Apply authorization
26
+ next unless @authorization.set_record(resource.model_class).authorize_action(:index, raise_exception: false)
27
+ # Filter out the models without a search_query
28
+ next if resource.search_query.nil?
26
29
 
27
- search_resource resource
28
- end
30
+ search_resource resource
31
+ end
29
32
  .select do |payload|
30
33
  payload.present?
31
34
  end
@@ -61,7 +64,7 @@ module Avo
61
64
 
62
65
  if App.license.has_with_trial(:enhanced_search_results)
63
66
  result[:_description] = resource.description
64
- result[:_avatar] = resource.avatar
67
+ result[:_avatar] = resource.avatar.present? ? main_app.url_for(resource.avatar) : nil
65
68
  result[:_avatar_type] = resource.avatar_type
66
69
  end
67
70
 
@@ -21,6 +21,18 @@ export default class extends Controller {
21
21
  return castBoolean(this.controllerTarget.dataset.attachmentsDisabled)
22
22
  }
23
23
 
24
+ get hideAttachmentFilename() {
25
+ return castBoolean(this.controllerTarget.dataset.hideAttachmentFilename)
26
+ }
27
+
28
+ get hideAttachmentFilesize() {
29
+ return castBoolean(this.controllerTarget.dataset.hideAttachmentFilesize)
30
+ }
31
+
32
+ get hideAttachmentUrl() {
33
+ return castBoolean(this.controllerTarget.dataset.hideAttachmentUrl)
34
+ }
35
+
24
36
  get uploadUrl() {
25
37
  return `${window.location.origin}${window.Avo.configuration.root_path}/avo_api/resources/${this.resourceName}/${this.resourceId}/attachments`
26
38
  }
@@ -102,6 +114,10 @@ export default class extends Controller {
102
114
  href: response.href,
103
115
  }
104
116
 
117
+ if (this.hideAttachmentFilename) attributes.filename = null
118
+ if (this.hideAttachmentFilesize) attributes.filesize = null
119
+ if (this.hideAttachmentUrl) attributes.href = null
120
+
105
121
  successCallback(attributes)
106
122
  }
107
123
  })
@@ -7,7 +7,7 @@
7
7
  data-resource-id="<%= params[:id] %>"
8
8
  class="hidden text-blue-gray-800"
9
9
  >
10
- <%= form_with model: @model, scope: 'fields', url: "#{Avo.configuration.root_path}/resources/#{@resource.model_class.model_name.route_key}/actions/#{@action.param_id}", data: {'turbo-frame': '_top', 'action-target': 'form'} do |form| %>
10
+ <%= form_with model: @model, scope: 'fields', url: "#{avo.root_path}resources/#{@resource.model_class.model_name.route_key}/actions/#{@action.param_id}", data: {'turbo-frame': '_top', 'action-target': 'form'} do |form| %>
11
11
  <%= render Avo::ModalComponent.new do |c| %>
12
12
  <% c.heading do %>
13
13
  <%= @action.action_name %>
@@ -1,5 +1,5 @@
1
1
  <%= turbo_frame_tag 'destroy_attachment_form' do %>
2
- <%= form_with url: "#{Avo.configuration.root_path}/resources/#{params[:resource_name]}/#{params[:id]
2
+ <%= form_with url: "#{avo.root_path}resources/#{params[:resource_name]}/#{params[:id]
3
3
  }/active_storage_attachments/#{params[:attachment_name]}/#{params[:signed_attachment_id]}",
4
4
  method: :delete,
5
5
  html: {
@@ -15,8 +15,8 @@
15
15
  <%
16
16
  @actions.each_with_index do |action, index|
17
17
  path = action_name == 'show' ?
18
- "#{Avo.configuration.root_path}/resources/#{@resource.model_class.model_name.route_key}/#{@model.id}/actions/#{action.param_id}" :
19
- "#{Avo.configuration.root_path}/resources/#{@resource.model_class.model_name.route_key}/actions/#{action.param_id}"
18
+ "#{avo.root_path}resources/#{@resource.model_class.model_name.route_key}/#{@model.id}/actions/#{action.param_id}" :
19
+ "#{avo.root_path}resources/#{@resource.model_class.model_name.route_key}/actions/#{action.param_id}"
20
20
  %>
21
21
  <%= link_to path,
22
22
  'data-turbo-frame': 'actions_show',
@@ -28,8 +28,8 @@
28
28
  <li><span class="mr-2">👍</span> Authorization</li>
29
29
  <li><span class="mr-2">👍</span> Localization</li>
30
30
  <li><span class="mr-2">👍</span> Custom tools</li>
31
- <li><span class="mr-2">⏳</span> Custom fields</li>
32
- <li><span class="mr-2">⏳</span> Search</li>
31
+ <li><span class="mr-2">👍</span> Custom fields</li>
32
+ <li><span class="mr-2">👍</span> Search</li>
33
33
  <li><span class="mr-2">🕐</span> Dashboards</li>
34
34
  <li><span class="mr-2">🕐</span> Themes</li>
35
35
  </ul>
@@ -1,5 +1,5 @@
1
1
  <%= javascript_tag nonce: true do %>
2
2
  window.Avo = window.Avo || { configuration: {} }
3
3
  Avo.configuration.timezone = '<%= Avo.configuration.timezone %>'
4
- Avo.configuration.root_path = '<%= Avo.configuration.root_path %>'
4
+ Avo.configuration.root_path = '<%= Avo::App.root_path %>'
5
5
  <% end %>
@@ -6,5 +6,5 @@
6
6
  data-debounce-timeout='<%= Avo.configuration.search_debounce %>'
7
7
  >
8
8
  </div>
9
- <div class="relative inline-flex text-gray-400 text-sm border border-gray-300 rounded-full cursor-pointer" data-search-target="button"></div>
9
+ <div class="hidden relative inline-flex text-gray-400 text-sm border border-gray-300 rounded-full cursor-pointer" data-search-target="button"></div>
10
10
  </div>
@@ -1,6 +1,6 @@
1
1
  <%= turbo_frame_tag 'attach_modal' do %>
2
2
  <%= form_with scope: 'fields',
3
- url: "#{Avo.configuration.root_path}/resources/#{params[:resource_name]}/#{params[:id]}/#{params[:related_name]}/",
3
+ url: "#{avo.root_path}resources/#{params[:resource_name]}/#{params[:id]}/#{params[:related_name]}/",
4
4
  data: {
5
5
  'turbo-frame': '_top'
6
6
  } do |form| %>
@@ -6,7 +6,7 @@
6
6
 
7
7
  <div class="flex-1 flex flex-col justify-between">
8
8
  <div class="tools py-4">
9
- <%= render Avo::NavigationLinkComponent.new label: 'Get started', path: Avo.configuration.root_path, active: :exclusive if Rails.env.development? && Avo.configuration.home_path.nil? %>
9
+ <%= render Avo::NavigationLinkComponent.new label: 'Get started', path: avo.root_path, active: :exclusive if Rails.env.development? && Avo.configuration.home_path.nil? %>
10
10
 
11
11
  <%= render Avo::NavigationHeadingComponent.new label: t('avo.resources') %>
12
12
 
@@ -0,0 +1,6 @@
1
+ class AddSlugToUsers < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_column :users, :slug, :string
4
+ add_index :users, :slug, unique: true
5
+ end
6
+ end
data/lib/avo/app.rb CHANGED
@@ -7,6 +7,7 @@ module Avo
7
7
  class_attribute :context, default: nil
8
8
  class_attribute :license, default: nil
9
9
  class_attribute :current_user, default: nil
10
+ class_attribute :root_path, default: nil
10
11
 
11
12
  class << self
12
13
  def boot
@@ -21,10 +22,11 @@ module Avo
21
22
  end
22
23
  end
23
24
 
24
- def init(request:, context:, current_user:)
25
+ def init(request:, context:, current_user:, root_path:)
25
26
  self.request = request
26
27
  self.context = context
27
28
  self.current_user = current_user
29
+ self.root_path = root_path
28
30
 
29
31
  self.license = Licensing::LicenseManager.new(Licensing::HQ.new(request).response).license
30
32
 
@@ -23,6 +23,8 @@ module Avo
23
23
  class_attribute :grid_loader
24
24
  class_attribute :visible_on_sidebar, default: true
25
25
  class_attribute :unscoped_queries_on_index, default: false
26
+ class_attribute :resolve_query_scope
27
+ class_attribute :resolve_find_scope
26
28
 
27
29
  class << self
28
30
  def grid(&block)
@@ -44,8 +46,24 @@ module Avo
44
46
  self.filters_loader.use filter_class
45
47
  end
46
48
 
49
+ # This is the search_query scope
50
+ # This should be removed and passed to the search block
47
51
  def scope
48
- authorization.apply_policy model_class
52
+ self.query_scope
53
+ end
54
+
55
+ # This resolves the scope when doing "where" queries (not find queries)
56
+ def query_scope
57
+ final_scope = resolve_query_scope.present? ? resolve_query_scope.call(model_class: model_class) : model_class
58
+
59
+ authorization.apply_policy final_scope
60
+ end
61
+
62
+ # This resolves the scope when finding records (not "where" queries)
63
+ def find_scope
64
+ final_scope = resolve_find_scope.present? ? resolve_find_scope.call(model_class: model_class) : model_class
65
+
66
+ authorization.apply_policy final_scope
49
67
  end
50
68
 
51
69
  def authorization
@@ -322,7 +340,7 @@ module Avo
322
340
  end
323
341
 
324
342
  def avo_path
325
- "#{Avo.configuration.root_path}/resources/#{model_class.model_name.route_key}/#{model.id}"
343
+ "#{Avo::App.root_path}/resources/#{model_class.model_name.route_key}/#{model.id}"
326
344
  end
327
345
 
328
346
  def label_field
@@ -350,6 +368,8 @@ module Avo
350
368
  def avatar
351
369
  return avatar_field.to_image if avatar_field.respond_to? :to_image
352
370
 
371
+ return avatar_field.value.variant(resize_to_limit: [480, 480]) if avatar_field.type == "file"
372
+
353
373
  avatar_field.value
354
374
  rescue
355
375
  nil
@@ -23,6 +23,7 @@ module Avo
23
23
  attr_accessor :initial_breadcrumbs
24
24
  attr_accessor :home_path
25
25
  attr_accessor :search_debounce
26
+ attr_accessor :view_component_path
26
27
 
27
28
  def initialize
28
29
  @root_path = "/avo"
@@ -58,6 +59,7 @@ module Avo
58
59
  @display_breadcrumbs = true
59
60
  @home_path = nil
60
61
  @search_debounce = 300
62
+ @view_component_path = "app/components"
61
63
  end
62
64
 
63
65
  def locale_tag
@@ -91,7 +93,7 @@ module Avo
91
93
  end
92
94
 
93
95
  def namespace
94
- root_path.delete "/"
96
+ computed_root_path.delete "/"
95
97
  end
96
98
 
97
99
  def root_path
@@ -99,6 +101,10 @@ module Avo
99
101
 
100
102
  @root_path
101
103
  end
104
+
105
+ def computed_root_path
106
+ Avo::App.root_path
107
+ end
102
108
  end
103
109
 
104
110
  def self.configuration