avo 3.0.0.pre13 → 3.0.0.pre15

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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +2 -1
  4. data/app/components/avo/alert_component.html.erb +1 -1
  5. data/app/components/avo/base_component.rb +7 -7
  6. data/app/components/avo/field_wrapper_component.rb +1 -1
  7. data/app/components/avo/fields/area_field/edit_component.html.erb +1 -1
  8. data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +5 -5
  9. data/app/components/avo/fields/belongs_to_field/edit_component.rb +4 -4
  10. data/app/components/avo/fields/boolean_field/edit_component.html.erb +1 -0
  11. data/app/components/avo/fields/boolean_group_field/edit_component.html.erb +1 -1
  12. data/app/components/avo/fields/code_field/edit_component.html.erb +1 -0
  13. data/app/components/avo/fields/country_field/edit_component.html.erb +1 -0
  14. data/app/components/avo/fields/file_field/index_component.rb +2 -2
  15. data/app/components/avo/fields/has_one_field/show_component.html.erb +1 -0
  16. data/app/components/avo/fields/index_component.rb +1 -0
  17. data/app/components/avo/fields/location_field/show_component.html.erb +1 -1
  18. data/app/components/avo/fields/markdown_field/edit_component.html.erb +1 -0
  19. data/app/components/avo/fields/number_field/edit_component.html.erb +1 -0
  20. data/app/components/avo/fields/password_field/edit_component.html.erb +1 -0
  21. data/app/components/avo/fields/progress_bar_field/edit_component.html.erb +1 -0
  22. data/app/components/avo/fields/status_field/edit_component.html.erb +1 -1
  23. data/app/components/avo/fields/text_field/edit_component.html.erb +1 -1
  24. data/app/components/avo/fields/textarea_field/edit_component.html.erb +1 -0
  25. data/app/components/avo/fields/trix_field/edit_component.html.erb +2 -1
  26. data/app/components/avo/fields/trix_field/show_component.html.erb +1 -1
  27. data/app/components/avo/index/resource_controls_component.rb +6 -6
  28. data/app/components/avo/index/resource_table_component.rb +1 -1
  29. data/app/components/avo/item_switcher_component.html.erb +9 -4
  30. data/app/components/avo/item_switcher_component.rb +2 -1
  31. data/app/components/avo/resource_component.rb +5 -3
  32. data/app/components/avo/resource_sidebar_component.rb +1 -1
  33. data/app/components/avo/row_component.html.erb +3 -0
  34. data/app/components/avo/row_component.rb +12 -0
  35. data/app/components/avo/sidebar/link_component.html.erb +2 -0
  36. data/app/components/avo/sidebar/link_component.rb +5 -3
  37. data/app/components/avo/sidebar_component.html.erb +3 -3
  38. data/app/components/avo/sidebar_component.rb +4 -4
  39. data/app/components/avo/sidebar_profile_component.html.erb +4 -4
  40. data/app/components/avo/views/resource_edit_component.rb +1 -1
  41. data/app/components/avo/views/resource_index_component.html.erb +1 -1
  42. data/app/components/avo/views/resource_index_component.rb +8 -8
  43. data/app/controllers/avo/actions_controller.rb +5 -7
  44. data/app/controllers/avo/application_controller.rb +71 -66
  45. data/app/controllers/avo/associations_controller.rb +4 -6
  46. data/app/controllers/avo/attachments_controller.rb +1 -1
  47. data/app/controllers/avo/base_controller.rb +25 -25
  48. data/app/controllers/avo/home_controller.rb +1 -1
  49. data/app/controllers/avo/search_controller.rb +14 -12
  50. data/app/controllers/concerns/avo/initializes_avo.rb +3 -6
  51. data/app/javascript/js/controllers/fields/easy_mde_controller.js +1 -0
  52. data/app/views/avo/associations/new.html.erb +1 -1
  53. data/app/views/avo/debug/status.html.erb +1 -1
  54. data/app/views/avo/partials/_custom_tools_alert.html.erb +2 -2
  55. data/app/views/avo/partials/_footer.html.erb +1 -1
  56. data/app/views/avo/partials/_javascript.html.erb +1 -1
  57. data/app/views/avo/partials/_navbar.html.erb +1 -1
  58. data/app/views/layouts/avo/application.html.erb +2 -2
  59. data/avo.gemspec +1 -0
  60. data/config/initializers/pagy.rb +12 -10
  61. data/config/routes.rb +3 -3
  62. data/db/factories.rb +2 -1
  63. data/lib/avo/base_action.rb +4 -2
  64. data/lib/avo/base_resource.rb +123 -92
  65. data/lib/avo/concerns/has_item_type.rb +4 -0
  66. data/lib/avo/concerns/has_items.rb +20 -15
  67. data/lib/avo/concerns/model_class_constantized.rb +0 -2
  68. data/lib/avo/current.rb +29 -2
  69. data/lib/avo/dsl/field_parser.rb +1 -1
  70. data/lib/avo/dynamic_router.rb +12 -1
  71. data/lib/avo/engine.rb +4 -7
  72. data/lib/avo/execution_context.rb +1 -1
  73. data/lib/avo/fields/base_field.rb +25 -3
  74. data/lib/avo/fields/belongs_to_field.rb +8 -7
  75. data/lib/avo/fields/concerns/is_searchable.rb +1 -1
  76. data/lib/avo/fields/concerns/use_resource.rb +1 -1
  77. data/lib/avo/fields/field_manager.rb +13 -3
  78. data/lib/avo/fields/has_base_field.rb +4 -4
  79. data/lib/avo/fields/has_one_field.rb +1 -1
  80. data/lib/avo/fields/location_field.rb +18 -1
  81. data/lib/avo/filters/base_filter.rb +3 -1
  82. data/lib/avo/html/builder.rb +3 -1
  83. data/lib/avo/licensing/h_q.rb +11 -6
  84. data/lib/avo/licensing/license.rb +1 -1
  85. data/lib/avo/licensing/license_manager.rb +1 -1
  86. data/lib/avo/licensing/{null_license.rb → nil_license.rb} +1 -1
  87. data/lib/avo/loaders/fields_loader.rb +7 -1
  88. data/lib/avo/plugin_manager.rb +2 -4
  89. data/lib/avo/reloader.rb +1 -1
  90. data/lib/avo/resources/items/holder.rb +5 -1
  91. data/lib/avo/resources/items/item_group.rb +1 -0
  92. data/lib/avo/resources/items/row.rb +54 -0
  93. data/lib/avo/resources/resource_manager.rb +4 -7
  94. data/lib/avo/services/debug_service.rb +6 -6
  95. data/lib/avo/services/telemetry_service.rb +3 -3
  96. data/lib/avo/version.rb +1 -1
  97. data/lib/avo.rb +107 -25
  98. data/lib/generators/avo/action_generator.rb +8 -8
  99. data/lib/generators/avo/card_generator.rb +27 -0
  100. data/lib/generators/avo/filter_generator.rb +8 -8
  101. data/lib/generators/avo/templates/action.tt +3 -3
  102. data/lib/generators/avo/templates/cards/chartkick_card.tt +1 -1
  103. data/lib/generators/avo/templates/cards/chartkick_card_sample.tt +1 -1
  104. data/lib/generators/avo/templates/cards/metric_card.tt +1 -1
  105. data/lib/generators/avo/templates/cards/metric_card_sample.tt +1 -1
  106. data/lib/generators/avo/templates/cards/partial_card.tt +1 -1
  107. data/lib/generators/avo/templates/cards/partial_card_sample.tt +1 -1
  108. data/lib/generators/avo/templates/dashboards/dashboard.tt +1 -1
  109. data/lib/generators/avo/templates/scope.tt +1 -1
  110. data/lib/tasks/avo_tasks.rake +1 -28
  111. data/public/avo-assets/avo.base.css +26 -31
  112. data/public/avo-assets/avo.base.js +281 -280
  113. data/public/avo-assets/avo.base.js.map +3 -3
  114. metadata +21 -8
  115. data/lib/avo/app.rb +0 -170
  116. data/lib/generators/avo/card/chartkick_generator.rb +0 -18
  117. data/lib/generators/avo/card/metric_generator.rb +0 -18
  118. data/lib/generators/avo/card/partial_generator.rb +0 -19
  119. data/lib/generators/avo/templates/standalone_action.tt +0 -15
@@ -100,7 +100,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
100
100
  def attach_path
101
101
  current_path = CGI.unescape(request.env["PATH_INFO"]).split("/").select(&:present?)
102
102
 
103
- Avo::App.root_path(paths: [*current_path, "new"])
103
+ Avo.root_path(paths: [*current_path, "new"])
104
104
  end
105
105
 
106
106
  def singular_resource_name
@@ -126,7 +126,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
126
126
 
127
127
  def show_search_input
128
128
  return false unless authorized_to_search?
129
- return false unless resource.search_query.present?
129
+ return false unless resource.class.search_query.present?
130
130
  return false if field&.hide_search_input
131
131
 
132
132
  true
@@ -143,7 +143,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
143
143
  def render_dynamic_filters_button
144
144
  return unless Avo.avo_filters_installed?
145
145
  return unless resource.has_filters?
146
- return if AvoFilters.configuration.always_expanded
146
+ return if Avo::DynamicFilters.configuration.always_expanded
147
147
 
148
148
  a_button size: :sm,
149
149
  color: :primary,
@@ -152,12 +152,12 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
152
152
  controller: "avo-filters",
153
153
  action: "click->avo-filters#toggleFiltersArea",
154
154
  } do
155
- AvoFilters.configuration.button_label
155
+ Avo::DynamicFilters.configuration.button_label
156
156
  end
157
157
  end
158
158
 
159
159
  def scopes_list
160
- AvoPro::Scopes::ListComponent.new(
160
+ Avo::Pro::Scopes::ListComponent.new(
161
161
  scopes: scopes,
162
162
  resource: resource,
163
163
  turbo_frame: turbo_frame,
@@ -166,7 +166,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
166
166
  end
167
167
 
168
168
  def can_render_scopes?
169
- defined?(AvoPro)
169
+ defined?(Avo::Pro)
170
170
  end
171
171
 
172
172
  private
@@ -191,11 +191,11 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
191
191
  end
192
192
 
193
193
  def header_visible?
194
- search_query_present? || filters_present? || has_many_view_types? || (Avo.avo_filters_installed? && resource.has_filters? && AvoFilters.configuration.always_expanded)
194
+ search_query_present? || filters_present? || has_many_view_types? || (Avo.avo_filters_installed? && resource.has_filters? && Avo::DynamicFilters.configuration.always_expanded)
195
195
  end
196
196
 
197
197
  def search_query_present?
198
- @resource.search_query.present?
198
+ @resource.class.search_query.present?
199
199
  end
200
200
 
201
201
  def filters_present?
@@ -31,12 +31,10 @@ module Avo
31
31
  resource: resource
32
32
  }
33
33
 
34
- unless @action.standalone
35
- args[:records] = if @selected_query.present?
36
- @resource.model_class.find_by_sql decrypted_query
37
- else
38
- @resource.find_record resource_ids, params: params
39
- end
34
+ args[:records] = if @selected_query.present?
35
+ @resource.model_class.find_by_sql decrypted_query
36
+ else
37
+ @resource.find_record resource_ids, params: params
40
38
  end
41
39
 
42
40
  performed_action = @action.handle_action(**args)
@@ -47,7 +45,7 @@ module Avo
47
45
  private
48
46
 
49
47
  def action_params
50
- params.permit(:authenticity_token, :resource_name, :action_id, fields: {})
48
+ params.permit(:authenticity_token, :resource_name, :action_id, :button, fields: {})
51
49
  end
52
50
 
53
51
  def set_action
@@ -7,10 +7,10 @@ module Avo
7
7
  end
8
8
 
9
9
  include Avo::InitializesAvo
10
- include Pagy::Backend
11
10
  include Avo::ApplicationHelper
12
11
  include Avo::UrlHelpers
13
12
  include Avo::Concerns::Breadcrumbs
13
+ include Pagy::Backend
14
14
 
15
15
  protect_from_forgery with: :exception
16
16
  around_action :set_avo_locale
@@ -61,6 +61,49 @@ module Avo
61
61
 
62
62
  private
63
63
 
64
+ # Get the pluralized resource name for this request
65
+ # Ex: projects, teams, users
66
+ def resource_name
67
+ return params[:resource_name] if params[:resource_name].present?
68
+
69
+ return controller_name if controller_name.present?
70
+
71
+ begin
72
+ request.path
73
+ .match(/\/?#{Avo.root_path.delete('/')}\/resources\/([a-z1-9\-_]*)\/?/mi)
74
+ .captures
75
+ .first
76
+ rescue
77
+ end
78
+ end
79
+
80
+ def related_resource_name
81
+ params[:related_name]
82
+ end
83
+
84
+ # Gets the Avo resource for this request based on the request from the `resource_name` "param"
85
+ # Ex: Avo::Resources::Project, Avo::Resources::Team, Avo::Resources::User
86
+ def resource
87
+ resource = Avo.resource_manager.get_resource @resource_name.to_s.camelize.singularize
88
+
89
+ return resource if resource.present?
90
+
91
+ Avo.resource_manager.get_resource_by_controller_name @resource_name
92
+ end
93
+
94
+ def related_resource
95
+ # Find the field from the parent resource
96
+ field = @resource.get_field params[:related_name]
97
+
98
+ return field.use_resource if field&.use_resource.present?
99
+
100
+ reflection = @record._reflections[params[:related_name]]
101
+
102
+ reflected_model = reflection.klass
103
+
104
+ Avo.resource_manager.get_resource_by_model_class reflected_model
105
+ end
106
+
64
107
  def set_resource_name
65
108
  @resource_name = resource_name
66
109
  end
@@ -72,23 +115,18 @@ module Avo
72
115
  def set_resource
73
116
  raise ActionController::RoutingError.new "No route matches" if resource.nil?
74
117
 
75
- @resource = resource.hydrate(params: params)
118
+ @resource = resource.new(view: action_name.to_sym, user: _current_user, params: params)
119
+
120
+ set_authorization
76
121
  end
77
122
 
78
123
  def set_related_resource
79
- @related_resource = related_resource.hydrate(params: params)
124
+ @related_resource = related_resource.new(params: params, view: action_name.to_sym, user: _current_user, record: @related_record)
80
125
  end
81
126
 
82
127
  def set_record
83
128
  @record = @resource.find_record(params[:id], query: model_find_scope, params: params)
84
- end
85
-
86
- def model_find_scope
87
- eager_load_files(@resource, model_scope)
88
- end
89
-
90
- def model_scope
91
- @resource.class.find_scope
129
+ @resource.hydrate(record: @record)
92
130
  end
93
131
 
94
132
  def set_related_record
@@ -98,6 +136,16 @@ module Avo
98
136
  else
99
137
  @related_resource.find_record params[:related_id], query: eager_load_files(@related_resource, @record.send(association_name)), params: params
100
138
  end
139
+ @related_resource.hydrate(record: @related_record)
140
+ end
141
+
142
+ def model_find_scope
143
+ eager_load_files(@resource, model_scope)
144
+ end
145
+
146
+ def model_scope
147
+ # abort @resource.inspect
148
+ @resource.class.find_scope
101
149
  end
102
150
 
103
151
  def set_view
@@ -110,6 +158,7 @@ module Avo
110
158
 
111
159
  # If resource.record is nil, most likely the user is creating a new record.
112
160
  # In that case, to access resource.record in visible and readonly blocks we hydrate the resource with a new record.
161
+ # TODO: commented this
113
162
  @resource.hydrate(record: @record_to_fill) if @resource.record.nil?
114
163
  end
115
164
 
@@ -136,14 +185,6 @@ module Avo
136
185
  end
137
186
  end
138
187
 
139
- def hydrate_resource
140
- @resource.hydrate(view: action_name.to_sym, user: _current_user, record: @record)
141
- end
142
-
143
- def hydrate_related_resource
144
- @related_resource.hydrate(view: action_name.to_sym, user: _current_user, record: @related_record)
145
- end
146
-
147
188
  def authorize_base_action
148
189
  class_to_authorize = @record || @resource.model_class
149
190
 
@@ -157,52 +198,16 @@ module Avo
157
198
  @authorization.set_record(class_to_authorize).authorize_action action_to_authorize.to_sym
158
199
  end
159
200
 
160
- # Get the pluralized resource name for this request
161
- # Ex: projects, teams, users
162
- def resource_name
163
- return params[:resource_name] if params[:resource_name].present?
164
-
165
- return controller_name if controller_name.present?
166
-
167
- begin
168
- request.path
169
- .match(/\/?#{Avo::App.root_path.delete('/')}\/resources\/([a-z1-9\-_]*)\/?/mi)
170
- .captures
171
- .first
172
- rescue
173
- end
174
- end
175
-
176
- def related_resource_name
177
- params[:related_name]
178
- end
179
-
180
- # Gets the Avo resource for this request based on the request from the `resource_name` "param"
181
- # Ex: Avo::Resources::Project, Avo::Resources::Team, Avo::Resources::User
182
- def resource
183
- resource = Avo::App.resources.get_resource @resource_name.to_s.camelize.singularize
184
-
185
- return resource if resource.present?
186
-
187
- Avo::App.resources.get_resource_by_controller_name @resource_name
188
- end
189
-
190
- def related_resource
191
- # Find the field from the parent resource
192
- field = @resource.get_field params[:related_name]
193
-
194
- return field.use_resource if field&.use_resource.present?
195
-
196
- reflection = @record._reflections[params[:related_name]]
197
-
198
- reflected_model = reflection.klass
199
-
200
- Avo::App.resources.get_resource_by_model_class reflected_model
201
- end
202
-
203
201
  def eager_load_files(resource, query)
204
- if resource.attached_file_fields.present?
205
- resource.attached_file_fields.map do |field|
202
+ # Get the non-computed file fields and try to eager load them
203
+ attachment_fields = resource
204
+ .attachment_fields
205
+ .reject do |field|
206
+ field.computed
207
+ end
208
+
209
+ if attachment_fields.present?
210
+ attachment_fields.map do |field|
206
211
  attachment = case field.class.to_s
207
212
  when "Avo::Fields::FileField"
208
213
  "attachment"
@@ -238,8 +243,8 @@ module Avo
238
243
  def set_authorization
239
244
  # We need to set @resource_name for the #resource method to work properly
240
245
  set_resource_name
241
- @authorization = if resource
242
- resource.authorization(user: _current_user)
246
+ @authorization = if @resource
247
+ @resource.authorization(user: _current_user)
243
248
  else
244
249
  Services::AuthorizationService.new _current_user
245
250
  end
@@ -3,13 +3,11 @@ require_dependency "avo/base_controller"
3
3
  module Avo
4
4
  class AssociationsController < BaseController
5
5
  before_action :set_record, only: [:show, :index, :new, :create, :destroy]
6
- before_action :hydrate_resource, only: [:show, :index, :new, :create, :destroy]
7
6
  before_action :set_related_resource_name
8
7
  before_action :set_related_resource, only: [:show, :index, :new, :create, :destroy]
9
8
  before_action :set_related_authorization
10
9
  before_action :set_reflection_field
11
10
  before_action :set_related_record, only: [:show]
12
- before_action :hydrate_related_resource, only: [:show, :index, :create, :destroy]
13
11
  before_action :set_reflection
14
12
  before_action :set_attachment_class, only: [:show, :index, :new, :create, :destroy]
15
13
  before_action :set_attachment_resource, only: [:show, :index, :new, :create, :destroy]
@@ -54,7 +52,7 @@ module Avo
54
52
  end
55
53
 
56
54
  @options = query.all.map do |record|
57
- [@attachment_resource.hydrate(record: record).record_title, record.id]
55
+ [@attachment_resource.new(record: record).record_title, record.id]
58
56
  end
59
57
  end
60
58
  end
@@ -102,7 +100,7 @@ module Avo
102
100
  end
103
101
 
104
102
  def set_attachment_resource
105
- @attachment_resource = @field.use_resource || (Avo::App.resources.get_resource_by_model_class @attachment_class)
103
+ @attachment_resource = @field.use_resource || (Avo.resource_manager.get_resource_by_model_class @attachment_class)
106
104
  end
107
105
 
108
106
  def set_attachment_record
@@ -151,8 +149,8 @@ module Avo
151
149
  private
152
150
 
153
151
  def set_related_authorization
154
- @related_authorization = if related_resource
155
- related_resource.authorization(user: _current_user)
152
+ @related_authorization = if @related_resource.present?
153
+ @related_resource.authorization(user: _current_user)
156
154
  else
157
155
  Services::AuthorizationService.new _current_user
158
156
  end
@@ -7,7 +7,7 @@ module Avo
7
7
  before_action :set_record, only: [:destroy, :create]
8
8
 
9
9
  def create
10
- blob = ActiveStorage::Blob.create_and_upload! io: params[:file], filename: params[:filename]
10
+ blob = ActiveStorage::Blob.create_and_upload! io: params[:file].to_io, filename: params[:filename]
11
11
  association_name = BaseResource.valid_attachment_name(@record, params[:attachment_key])
12
12
 
13
13
  if association_name.blank?
@@ -6,7 +6,6 @@ module Avo
6
6
 
7
7
  before_action :set_resource_name
8
8
  before_action :set_resource
9
- before_action :hydrate_resource
10
9
  before_action :set_applied_filters, only: :index
11
10
  before_action :set_record, only: [:show, :edit, :destroy, :update, :preview]
12
11
  before_action :set_record_to_fill
@@ -68,18 +67,7 @@ module Avo
68
67
  end
69
68
 
70
69
  safe_call :set_and_apply_scopes
71
-
72
- if Avo.avo_filters_installed? && params[AvoFilters.configuration.param_key].present?
73
- # Apply dynamic filters
74
- query_builder = AvoFilters::QueryBuilder.new(resource: @resource, params: params, query: @query)
75
- @query = @query.ransack(**query_builder.ransack_query)
76
- end
77
-
78
- pagy_query = if @query.instance_of?(Ransack::Search)
79
- @query.result(distinct: false)
80
- else
81
- @query
82
- end
70
+ safe_call :apply_dynamic_filters
83
71
 
84
72
  @pagy, @records = pagy(pagy_query, items: @index_params[:per_page], link_extra: "data-turbo-frame=\"#{params[:turbo_frame]}\"", size: [1, 2, 2, 1], params: extra_pagy_params)
85
73
 
@@ -98,9 +86,9 @@ module Avo
98
86
 
99
87
  # If we're accessing this resource via another resource add the parent to the breadcrumbs.
100
88
  if params[:via_resource_class].present? && params[:via_record_id].present?
101
- via_resource = Avo::App.resources.get_resource(params[:via_resource_class]).dup
89
+ via_resource = Avo.resource_manager.get_resource(params[:via_resource_class])
102
90
  via_record = via_resource.find_record params[:via_record_id], params: params
103
- via_resource.hydrate record: via_record
91
+ via_resource = via_resource.new record: via_record
104
92
 
105
93
  add_breadcrumb via_resource.plural_name, resources_path(resource: via_resource)
106
94
  add_breadcrumb via_resource.record_title, resource_path(record: via_record, resource: via_resource)
@@ -121,9 +109,9 @@ module Avo
121
109
  @page_title = @resource.default_panel_name.to_s
122
110
 
123
111
  if is_associated_record?
124
- via_resource = Avo::App.resources.get_resource_by_model_class(params[:via_relation_class]).dup
112
+ via_resource = Avo.resource_manager.get_resource_by_model_class(params[:via_relation_class])
125
113
  via_record = via_resource.find_record params[:via_record_id], params: params
126
- via_resource.hydrate record: via_record
114
+ via_resource = via_resource.new record: via_record
127
115
 
128
116
  add_breadcrumb via_resource.plural_name, resources_path(resource: via_resource)
129
117
  add_breadcrumb via_resource.record_title, resource_path(record: via_record, resource: via_resource)
@@ -146,7 +134,7 @@ module Avo
146
134
  # Fills in the required infor for belongs_to and has_many
147
135
  # Get the foreign key and set it to the id we received in the params
148
136
  if @reflection.is_a?(ActiveRecord::Reflection::BelongsToReflection) || @reflection.is_a?(ActiveRecord::Reflection::HasManyReflection)
149
- related_resource = Avo::App.resources.get_resource_by_model_class params[:via_relation_class]
137
+ related_resource = Avo.resource_manager.get_resource_by_model_class params[:via_relation_class]
150
138
  related_record = related_resource.find_record params[:via_record_id], params: params
151
139
 
152
140
  @record.send("#{@reflection.foreign_key}=", related_record.id)
@@ -156,7 +144,7 @@ module Avo
156
144
  # For when working with has_one, has_one_through, has_many_through, has_and_belongs_to_many, polymorphic
157
145
  if @reflection.is_a? ActiveRecord::Reflection::ThroughReflection
158
146
  # find the record
159
- via_resource = ::Avo::App.resources.get_resource_by_model_class(params[:via_relation_class]).dup
147
+ via_resource = Avo.resource_manager.get_resource_by_model_class(params[:via_relation_class])
160
148
  @related_record = via_resource.find_record params[:via_record_id], params: params
161
149
  association_name = BaseResource.valid_association_name(@record, params[:via_relation])
162
150
 
@@ -215,16 +203,24 @@ module Avo
215
203
 
216
204
  def save_record
217
205
  perform_action_and_record_errors do
218
- @record.save!
206
+ save_record_action
219
207
  end
220
208
  end
221
209
 
210
+ def save_record_action
211
+ @record.save!
212
+ end
213
+
222
214
  def destroy_model
223
215
  perform_action_and_record_errors do
224
- @record.destroy!
216
+ destroy_record_action
225
217
  end
226
218
  end
227
219
 
220
+ def destroy_record_action
221
+ @record.destroy!
222
+ end
223
+
228
224
  def perform_action_and_record_errors(&block)
229
225
  begin
230
226
  succeeded = block.call
@@ -253,7 +249,7 @@ module Avo
253
249
  end
254
250
 
255
251
  def permitted_params
256
- @resource.get_field_definitions.select(&:updatable).map(&:to_permitted_param).concat extra_params
252
+ @resource.get_field_definitions.select(&:updatable).map(&:to_permitted_param).concat(extra_params).uniq
257
253
  end
258
254
 
259
255
  def extra_params
@@ -404,9 +400,9 @@ module Avo
404
400
  last_crumb_args = {}
405
401
  # If we're accessing this resource via another resource add the parent to the breadcrumbs.
406
402
  if params[:via_resource_class].present? && params[:via_record_id].present?
407
- via_resource = Avo::App.resources.get_resource(params[:via_resource_class]).dup
403
+ via_resource = Avo.resource_manager.get_resource(params[:via_resource_class])
408
404
  via_record = via_resource.find_record params[:via_record_id], params: params
409
- via_resource.hydrate record: via_record
405
+ via_resource = via_resource.new record: via_record
410
406
 
411
407
  add_breadcrumb via_resource.plural_name, resources_path(resource: @resource)
412
408
  add_breadcrumb via_resource.record_title, resource_path(record: via_record, resource: via_resource)
@@ -447,7 +443,7 @@ module Avo
447
443
  def after_create_path
448
444
  # If this is an associated record return to the association show page
449
445
  if is_associated_record?
450
- parent_resource = ::Avo::App.resources.get_resource_by_model_class(params[:via_relation_class]).dup
446
+ parent_resource = Avo.resource_manager.get_resource_by_model_class(params[:via_relation_class])
451
447
  association_name = BaseResource.valid_association_name(@record, params[:via_relation])
452
448
 
453
449
  return resource_view_path(
@@ -540,5 +536,9 @@ module Avo
540
536
  def safe_call(method)
541
537
  send(method) if respond_to?(method, true)
542
538
  end
539
+
540
+ def pagy_query
541
+ @query
542
+ end
543
543
  end
544
544
  end
@@ -14,7 +14,7 @@ module Avo
14
14
  redirect_to computed_path
15
15
  elsif !Rails.env.development?
16
16
  @page_title = "Get started"
17
- resource = Avo::Current.app.resource_manager.all.min_by { |resource| resource.model_key }
17
+ resource = Avo.resource_manager.all.min_by { |resource| resource.model_key }
18
18
  redirect_to resources_path(resource: resource)
19
19
  end
20
20
  end
@@ -37,7 +37,7 @@ module Avo
37
37
  query = Avo::ExecutionContext.new(
38
38
  target: resource.search_query,
39
39
  params: params,
40
- query: resource.class.query_scope
40
+ query: resource.query_scope
41
41
  ).handle
42
42
 
43
43
  # Get the count
@@ -101,18 +101,21 @@ module Avo
101
101
  # This scope is applied if the search is being performed on a has_many association
102
102
  def apply_has_many_scope
103
103
  association_name = BaseResource.valid_association_name(parent, params[:via_association_id])
104
+
105
+ # Get association records
104
106
  query = parent.send(association_name)
105
107
 
106
- Avo::ExecutionContext.new(target: @resource.search_query, params: params, query: query).handle
108
+ # Apply policy scope if authorization is present
109
+ query = resource.authorization&.apply_policy query
110
+
111
+ Avo::ExecutionContext.new(target: @resource.class.search_query, params: params, query: query).handle
107
112
  end
108
113
 
109
114
  def apply_search_metadata(records, avo_resource)
110
115
  records.map do |record|
111
- # TODO: refactor this
112
- # resource = avo_resource.dup.hydrate(record: record).hydrate_fields
113
- resource = avo_resource.dup.hydrate(record: record)
116
+ resource = avo_resource.new(record: record)
114
117
 
115
- fetch_result_information record, resource, resource.fetch_search(:item)
118
+ fetch_result_information record, resource, resource.class.fetch_search(:item, record: record)
116
119
  end
117
120
  end
118
121
 
@@ -122,12 +125,12 @@ module Avo
122
125
  {
123
126
  _id: record.id,
124
127
  _label: item&.dig(:title) || resource.record_title,
125
- _url: resource.fetch_search(:result_path) || resource.record_path
128
+ _url: resource.class.fetch_search(:result_path, record: resource.record) || resource.record_path
126
129
  }
127
130
  end
128
131
 
129
132
  def should_apply_has_many_scope?
130
- params[:via_association] == "has_many" && @resource.search_query.present?
133
+ params[:via_association] == "has_many" && @resource.class.search_query.present?
131
134
  end
132
135
 
133
136
  def should_apply_attach_scope?
@@ -151,16 +154,15 @@ module Avo
151
154
  end
152
155
 
153
156
  def fetch_field
154
- fields = ::Avo::App.resources.get_resource_by_model_class(params[:via_reflection_class]).get_field_definitions
157
+ fields = Avo.resource_manager.get_resource_by_model_class(params[:via_reflection_class]).new.get_field_definitions
155
158
  fields.find { |f| f.id.to_s == params[:via_association_id] }
156
159
  end
157
160
 
158
161
  def fetch_parent
159
162
  return unless params[:via_reflection_id].present?
160
163
 
161
- parent_class = BaseResource.get_model_by_name params[:via_reflection_class]
162
-
163
- parent_class.find params[:via_reflection_id]
164
+ parent_resource = Avo.resource_manager.get_resource_by_model_class params[:via_reflection_class]
165
+ parent_resource.find_record params[:via_reflection_id], params: params
164
166
  end
165
167
  end
166
168
  end
@@ -1,16 +1,13 @@
1
1
  module Avo
2
2
  module InitializesAvo
3
3
  def init_app
4
- Avo::Current.license = Avo::Licensing::NullLicense.new
4
+ Avo::Current.license = Avo::Licensing::NilLicense.new
5
5
  Avo::Current.context = context
6
- Avo::Current.current_user = _current_user
6
+ Avo::Current.user = _current_user
7
7
  Avo::Current.view_context = view_context
8
- Avo::Current.app = Avo::App.build request: request, context: context, current_user: _current_user, view_context: view_context
9
- Avo::Current.app.init
8
+ Avo.init
10
9
  Avo::Current.license = Licensing::LicenseManager.new(Licensing::HQ.new(request).response).license
11
10
  Avo.plugin_manager.init_plugins
12
-
13
- @license = Avo::App.license
14
11
  end
15
12
 
16
13
  def _current_user
@@ -20,6 +20,7 @@ export default class extends Controller {
20
20
  const options = {
21
21
  element: this.elementTarget,
22
22
  spellChecker: this.componentOptions.spell_checker,
23
+ autoRefresh: { delay: 500},
23
24
  }
24
25
 
25
26
  if (this.view === 'show') {
@@ -17,7 +17,7 @@
17
17
 
18
18
  <div class="flex-1 flex items-center justify-center px-0 lg:px-8 text-lg mt-8 mb-12">
19
19
  <% if @field.is_searchable? %>
20
- <%= render AvoPro::SearchableAssociations::AutocompleteComponent.new form: form,
20
+ <%= render Avo::Pro::SearchableAssociations::AutocompleteComponent.new form: form,
21
21
  classes: input_classes("w-full"),
22
22
  field: @field,
23
23
  model_key: @field.target_resource&.model_key,
@@ -1,5 +1,5 @@
1
1
  <%
2
- license = Avo::App.license
2
+ license = Avo.license
3
3
  information_items = [
4
4
  'license_key',
5
5
  'ruby_version',
@@ -5,8 +5,8 @@
5
5
  </a>
6
6
  </div>
7
7
  <% end %>
8
- <% if Avo::App.errors.has_errors?.present? %>
9
- <% Avo::App.errors.all.each do |error| %>
8
+ <% if Avo.error_manager.has_errors?.present? %>
9
+ <% Avo.error_manager.all.each do |error| %>
10
10
  <% if error.is_a? Hash %>
11
11
  <%
12
12
  url, message, target = error.values_at :url, :message, :target
@@ -1,3 +1,3 @@
1
1
  <div class="text-center text-sm text-gray-700 <%= 'print:hidden' if Avo.configuration.hide_layout_when_printing %>">
2
- <a href="https://avohq.io/" target="_blank">Avo</a> · &copy; <%= Date.today.year %> AvoHQ · <span title="<%= Avo::App.license.valid ? 'valid' : 'invalid'%> <%= Avo::App.license.id %> license">v<%= Avo::VERSION %></span>
2
+ <a href="https://avohq.io/" target="_blank">Avo</a> · &copy; <%= Date.today.year %> AvoHQ · <span title="<%= Avo.license.valid ? 'valid' : 'invalid'%> <%= Avo.license.id %> license">v<%= Avo::VERSION %></span>
3
3
  </div>
@@ -6,7 +6,7 @@
6
6
  Avo.configuration.cookies_key = '<%= Avo::COOKIES_KEY %>'
7
7
  <% if Avo.avo_filters_installed? %>
8
8
  Avo.configuration.avo_filters = {
9
- param_key: '<%= AvoFilters.configuration.param_key %>'
9
+ param_key: '<%= Avo::DynamicFilters.configuration.param_key %>'
10
10
  }
11
11
  <% end %>
12
12
  <% end %>
@@ -10,7 +10,7 @@
10
10
  <%= render partial: "avo/partials/logo" %>
11
11
  </div>
12
12
  <div class="flex-1 flex items-center justify-between lg:justify-start space-x-2 sm:space-x-8 lg:px-2">
13
- <%= render AvoPro::GlobalSearchComponent.new rescue nil %>
13
+ <%= render Avo::Pro::GlobalSearchComponent.new rescue nil %>
14
14
  <div class="m-0">
15
15
  <%= render partial: "avo/partials/header" %>
16
16
  </div>
@@ -60,8 +60,8 @@
60
60
  <%= render partial: "avo/partials/scripts" %>
61
61
  <!-- Avo version: <%= Avo::VERSION %> -->
62
62
  <!-- Environment: <%= Rails.env %> -->
63
- <!-- License ID: <%= Avo::App.license.id %> -->
64
- <!-- License valid?: <%= Avo::App.license.valid ? "valid" : "invalid" %> -->
63
+ <!-- License ID: <%= Avo.license.id %> -->
64
+ <!-- License valid?: <%= Avo.license.valid ? "valid" : "invalid" %> -->
65
65
  </body>
66
66
  </html>
67
67
  <!-- ✨ Built with Avo • https://www.avohq.io/ -->
data/avo.gemspec CHANGED
@@ -33,6 +33,7 @@ Gem::Specification.new do |spec|
33
33
  spec.files = Dir["{bin,app,config,db,lib,public}/**/*", "MIT-LICENSE", "Rakefile", "README.md", "avo.gemspec", "Gemfile", "Gemfile.lock"]
34
34
 
35
35
  spec.add_dependency "activerecord", ">= 6.1"
36
+ spec.add_dependency "activesupport", ">= 6.1"
36
37
  spec.add_dependency "actionview", ">= 6.1"
37
38
  spec.add_dependency "pagy"
38
39
  spec.add_dependency "zeitwerk", ">= 2.6.2"