avo 3.0.0.pre12 → 3.0.0.pre14

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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +2 -1
  4. data/app/assets/stylesheets/avo.base.css +1 -1
  5. data/app/components/avo/actions_component.html.erb +1 -1
  6. data/app/components/avo/actions_component.rb +40 -16
  7. data/app/components/avo/alert_component.html.erb +1 -1
  8. data/app/components/avo/base_component.rb +7 -7
  9. data/app/components/avo/field_wrapper_component.html.erb +2 -2
  10. data/app/components/avo/field_wrapper_component.rb +1 -1
  11. data/app/components/avo/fields/area_field/edit_component.html.erb +1 -1
  12. data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +5 -5
  13. data/app/components/avo/fields/belongs_to_field/edit_component.rb +4 -4
  14. data/app/components/avo/fields/boolean_field/edit_component.html.erb +1 -0
  15. data/app/components/avo/fields/boolean_group_field/edit_component.html.erb +1 -1
  16. data/app/components/avo/fields/code_field/edit_component.html.erb +1 -0
  17. data/app/components/avo/fields/common/heading_component.html.erb +1 -1
  18. data/app/components/avo/fields/country_field/edit_component.html.erb +1 -0
  19. data/app/components/avo/fields/file_field/index_component.rb +2 -2
  20. data/app/components/avo/fields/has_one_field/show_component.html.erb +1 -0
  21. data/app/components/avo/fields/index_component.rb +1 -0
  22. data/app/components/avo/fields/location_field/show_component.html.erb +1 -1
  23. data/app/components/avo/fields/markdown_field/edit_component.html.erb +4 -3
  24. data/app/components/avo/fields/markdown_field/show_component.html.erb +3 -3
  25. data/app/components/avo/fields/number_field/edit_component.html.erb +1 -0
  26. data/app/components/avo/fields/password_field/edit_component.html.erb +1 -0
  27. data/app/components/avo/fields/progress_bar_field/edit_component.html.erb +1 -0
  28. data/app/components/avo/fields/status_field/edit_component.html.erb +1 -1
  29. data/app/components/avo/fields/text_field/edit_component.html.erb +1 -1
  30. data/app/components/avo/fields/textarea_field/edit_component.html.erb +1 -0
  31. data/app/components/avo/fields/trix_field/edit_component.html.erb +2 -1
  32. data/app/components/avo/fields/trix_field/show_component.html.erb +1 -1
  33. data/app/components/avo/index/field_wrapper_component.html.erb +1 -1
  34. data/app/components/avo/index/grid_item_component.html.erb +9 -35
  35. data/app/components/avo/index/grid_item_component.rb +36 -10
  36. data/app/components/avo/index/resource_controls_component.rb +6 -6
  37. data/app/components/avo/item_switcher_component.html.erb +9 -4
  38. data/app/components/avo/item_switcher_component.rb +2 -1
  39. data/app/components/avo/panel_component.html.erb +1 -1
  40. data/app/components/avo/profile_item_component.html.erb +17 -2
  41. data/app/components/avo/profile_item_component.rb +13 -1
  42. data/app/components/avo/resource_component.rb +6 -3
  43. data/app/components/avo/resource_sidebar_component.rb +1 -1
  44. data/app/components/avo/row_component.html.erb +3 -0
  45. data/app/components/avo/row_component.rb +12 -0
  46. data/app/components/avo/sidebar/link_component.html.erb +2 -0
  47. data/app/components/avo/sidebar/link_component.rb +5 -3
  48. data/app/components/avo/sidebar_component.html.erb +3 -3
  49. data/app/components/avo/sidebar_component.rb +4 -4
  50. data/app/components/avo/sidebar_profile_component.html.erb +27 -27
  51. data/app/components/avo/views/resource_edit_component.rb +1 -1
  52. data/app/components/avo/views/resource_index_component.html.erb +1 -1
  53. data/app/components/avo/views/resource_index_component.rb +8 -8
  54. data/app/controllers/avo/actions_controller.rb +22 -8
  55. data/app/controllers/avo/application_controller.rb +71 -66
  56. data/app/controllers/avo/associations_controller.rb +4 -6
  57. data/app/controllers/avo/attachments_controller.rb +1 -1
  58. data/app/controllers/avo/base_controller.rb +36 -17
  59. data/app/controllers/avo/home_controller.rb +1 -1
  60. data/app/controllers/avo/search_controller.rb +18 -20
  61. data/app/controllers/concerns/avo/initializes_avo.rb +2 -5
  62. data/app/javascript/js/controllers/fields/{simple_mde_controller.js → easy_mde_controller.js} +4 -3
  63. data/app/javascript/js/controllers/search_controller.js +3 -1
  64. data/app/javascript/js/controllers.js +2 -2
  65. data/app/views/avo/actions/show.html.erb +2 -1
  66. data/app/views/avo/associations/new.html.erb +1 -1
  67. data/app/views/avo/debug/status.html.erb +1 -1
  68. data/app/views/avo/partials/_custom_tools_alert.html.erb +2 -2
  69. data/app/views/avo/partials/_footer.html.erb +1 -1
  70. data/app/views/avo/partials/_javascript.html.erb +1 -1
  71. data/app/views/avo/partials/_navbar.html.erb +1 -1
  72. data/app/views/avo/partials/_profile_menu_extra.html.erb +2 -0
  73. data/app/views/layouts/avo/application.html.erb +2 -2
  74. data/avo.gemspec +1 -0
  75. data/config/initializers/pagy.rb +12 -10
  76. data/config/routes.rb +3 -3
  77. data/db/factories.rb +2 -1
  78. data/lib/avo/base_action.rb +12 -2
  79. data/lib/avo/base_resource.rb +178 -178
  80. data/lib/avo/concerns/filters_session_handler.rb +0 -1
  81. data/lib/avo/concerns/has_item_type.rb +4 -0
  82. data/lib/avo/concerns/has_items.rb +28 -23
  83. data/lib/avo/concerns/model_class_constantized.rb +0 -2
  84. data/lib/avo/configuration.rb +6 -2
  85. data/lib/avo/current.rb +22 -1
  86. data/lib/avo/dsl/field_parser.rb +1 -1
  87. data/lib/avo/dynamic_router.rb +12 -1
  88. data/lib/avo/engine.rb +8 -6
  89. data/lib/avo/fields/base_field.rb +25 -7
  90. data/lib/avo/fields/belongs_to_field.rb +20 -13
  91. data/lib/avo/fields/concerns/is_searchable.rb +1 -1
  92. data/lib/avo/fields/concerns/use_resource.rb +1 -1
  93. data/lib/avo/fields/field_manager.rb +13 -3
  94. data/lib/avo/fields/has_base_field.rb +5 -5
  95. data/lib/avo/fields/has_one_field.rb +1 -1
  96. data/lib/avo/fields/location_field.rb +18 -1
  97. data/lib/avo/licensing/h_q.rb +11 -6
  98. data/lib/avo/licensing/license.rb +1 -1
  99. data/lib/avo/licensing/license_manager.rb +1 -1
  100. data/lib/avo/licensing/{null_license.rb → nil_license.rb} +1 -1
  101. data/lib/avo/loaders/fields_loader.rb +7 -1
  102. data/lib/avo/plugin_manager.rb +2 -4
  103. data/lib/avo/reloader.rb +1 -1
  104. data/lib/avo/resources/controls/actions_list.rb +2 -1
  105. data/lib/avo/resources/items/holder.rb +5 -1
  106. data/lib/avo/resources/items/item_group.rb +1 -0
  107. data/lib/avo/resources/items/row.rb +54 -0
  108. data/lib/avo/resources/resource_manager.rb +4 -7
  109. data/lib/avo/services/debug_service.rb +6 -6
  110. data/lib/avo/services/telemetry_service.rb +3 -3
  111. data/lib/avo/version.rb +1 -1
  112. data/lib/avo.rb +107 -25
  113. data/lib/generators/avo/action_generator.rb +8 -8
  114. data/lib/generators/avo/card_generator.rb +27 -0
  115. data/lib/generators/avo/eject_generator.rb +1 -0
  116. data/lib/generators/avo/filter_generator.rb +8 -8
  117. data/lib/generators/avo/install_generator.rb +0 -1
  118. data/lib/generators/avo/resource_generator.rb +4 -1
  119. data/lib/generators/avo/templates/action.tt +3 -3
  120. data/lib/generators/avo/templates/cards/chartkick_card.tt +1 -1
  121. data/lib/generators/avo/templates/cards/chartkick_card_sample.tt +1 -1
  122. data/lib/generators/avo/templates/cards/metric_card.tt +1 -1
  123. data/lib/generators/avo/templates/cards/metric_card_sample.tt +1 -1
  124. data/lib/generators/avo/templates/cards/partial_card.tt +1 -1
  125. data/lib/generators/avo/templates/cards/partial_card_sample.tt +1 -1
  126. data/lib/generators/avo/templates/dashboards/dashboard.tt +1 -1
  127. data/lib/generators/avo/templates/resource/resource.tt +3 -4
  128. data/lib/generators/avo/templates/scope.tt +1 -1
  129. data/lib/tasks/avo_tasks.rake +1 -1
  130. data/public/avo-assets/avo.base.css +295 -165
  131. data/public/avo-assets/avo.base.js +307 -278
  132. data/public/avo-assets/avo.base.js.map +3 -3
  133. metadata +23 -10
  134. data/lib/avo/app.rb +0 -170
  135. data/lib/avo/grid_collector.rb +0 -40
  136. data/lib/generators/avo/card/chartkick_generator.rb +0 -18
  137. data/lib/generators/avo/card/metric_generator.rb +0 -18
  138. data/lib/generators/avo/card/partial_generator.rb +0 -19
  139. data/lib/generators/avo/templates/standalone_action.tt +0 -15
@@ -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
- [record.send(@attachment_resource.class.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
@@ -69,9 +68,9 @@ module Avo
69
68
 
70
69
  safe_call :set_and_apply_scopes
71
70
 
72
- if Avo.avo_filters_installed? && params[AvoFilters.configuration.param_key].present?
71
+ if Avo.avo_filters_installed? && params[Avo::DynamicFilters.configuration.param_key].present?
73
72
  # Apply dynamic filters
74
- query_builder = AvoFilters::QueryBuilder.new(resource: @resource, params: params, query: @query)
73
+ query_builder = Avo::DynamicFilters::QueryBuilder.new(resource: @resource, params: params, query: @query)
75
74
  @query = @query.ransack(**query_builder.ransack_query)
76
75
  end
77
76
 
@@ -98,9 +97,9 @@ module Avo
98
97
 
99
98
  # If we're accessing this resource via another resource add the parent to the breadcrumbs.
100
99
  if params[:via_resource_class].present? && params[:via_record_id].present?
101
- via_resource = Avo::App.resources.get_resource(params[:via_resource_class]).dup
100
+ via_resource = Avo.resource_manager.get_resource(params[:via_resource_class])
102
101
  via_record = via_resource.find_record params[:via_record_id], params: params
103
- via_resource.hydrate record: via_record
102
+ via_resource = via_resource.new record: via_record
104
103
 
105
104
  add_breadcrumb via_resource.plural_name, resources_path(resource: via_resource)
106
105
  add_breadcrumb via_resource.record_title, resource_path(record: via_record, resource: via_resource)
@@ -121,9 +120,9 @@ module Avo
121
120
  @page_title = @resource.default_panel_name.to_s
122
121
 
123
122
  if is_associated_record?
124
- via_resource = Avo::App.resources.get_resource_by_model_class(params[:via_relation_class]).dup
123
+ via_resource = Avo.resource_manager.get_resource_by_model_class(params[:via_relation_class])
125
124
  via_record = via_resource.find_record params[:via_record_id], params: params
126
- via_resource.hydrate record: via_record
125
+ via_resource = via_resource.new record: via_record
127
126
 
128
127
  add_breadcrumb via_resource.plural_name, resources_path(resource: via_resource)
129
128
  add_breadcrumb via_resource.record_title, resource_path(record: via_record, resource: via_resource)
@@ -146,7 +145,7 @@ module Avo
146
145
  # Fills in the required infor for belongs_to and has_many
147
146
  # Get the foreign key and set it to the id we received in the params
148
147
  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]
148
+ related_resource = Avo.resource_manager.get_resource_by_model_class params[:via_relation_class]
150
149
  related_record = related_resource.find_record params[:via_record_id], params: params
151
150
 
152
151
  @record.send("#{@reflection.foreign_key}=", related_record.id)
@@ -156,7 +155,7 @@ module Avo
156
155
  # For when working with has_one, has_one_through, has_many_through, has_and_belongs_to_many, polymorphic
157
156
  if @reflection.is_a? ActiveRecord::Reflection::ThroughReflection
158
157
  # find the record
159
- via_resource = ::Avo::App.resources.get_resource_by_model_class(params[:via_relation_class]).dup
158
+ via_resource = Avo.resource_manager.get_resource_by_model_class(params[:via_relation_class])
160
159
  @related_record = via_resource.find_record params[:via_record_id], params: params
161
160
  association_name = BaseResource.valid_association_name(@record, params[:via_relation])
162
161
 
@@ -215,16 +214,24 @@ module Avo
215
214
 
216
215
  def save_record
217
216
  perform_action_and_record_errors do
218
- @record.save!
217
+ save_record_action
219
218
  end
220
219
  end
221
220
 
221
+ def save_record_action
222
+ @record.save!
223
+ end
224
+
222
225
  def destroy_model
223
226
  perform_action_and_record_errors do
224
- @record.destroy!
227
+ destroy_record_action
225
228
  end
226
229
  end
227
230
 
231
+ def destroy_record_action
232
+ @record.destroy!
233
+ end
234
+
228
235
  def perform_action_and_record_errors(&block)
229
236
  begin
230
237
  succeeded = block.call
@@ -253,7 +260,7 @@ module Avo
253
260
  end
254
261
 
255
262
  def permitted_params
256
- @resource.get_field_definitions.select(&:updatable).map(&:to_permitted_param).concat extra_params
263
+ @resource.get_field_definitions.select(&:updatable).map(&:to_permitted_param).concat(extra_params).uniq
257
264
  end
258
265
 
259
266
  def extra_params
@@ -313,8 +320,20 @@ module Avo
313
320
  @index_params[:sort_direction] = params[:sort_direction] || :desc
314
321
 
315
322
  # View types
316
- @index_params[:view_type] = params[:view_type] || @resource.default_view_type || Avo.configuration.default_view_type
317
- @index_params[:available_view_types] = @resource.available_view_types
323
+ available_view_types = @resource.available_view_types
324
+ @index_params[:available_view_types] = available_view_types
325
+
326
+ @index_params[:view_type] = if params[:view_type].present?
327
+ params[:view_type]
328
+ elsif available_view_types.size == 1
329
+ available_view_types.first
330
+ else
331
+ @resource.default_view_type || Avo.configuration.default_view_type
332
+ end
333
+
334
+ if available_view_types.exclude? @index_params[:view_type].to_sym
335
+ raise "View type '#{@index_params[:view_type]}' is unavailable for #{@resource.class}."
336
+ end
318
337
  end
319
338
 
320
339
  def set_filters
@@ -392,9 +411,9 @@ module Avo
392
411
  last_crumb_args = {}
393
412
  # If we're accessing this resource via another resource add the parent to the breadcrumbs.
394
413
  if params[:via_resource_class].present? && params[:via_record_id].present?
395
- via_resource = Avo::App.resources.get_resource(params[:via_resource_class]).dup
414
+ via_resource = Avo.resource_manager.get_resource(params[:via_resource_class])
396
415
  via_record = via_resource.find_record params[:via_record_id], params: params
397
- via_resource.hydrate record: via_record
416
+ via_resource = via_resource.new record: via_record
398
417
 
399
418
  add_breadcrumb via_resource.plural_name, resources_path(resource: @resource)
400
419
  add_breadcrumb via_resource.record_title, resource_path(record: via_record, resource: via_resource)
@@ -435,7 +454,7 @@ module Avo
435
454
  def after_create_path
436
455
  # If this is an associated record return to the association show page
437
456
  if is_associated_record?
438
- parent_resource = ::Avo::App.resources.get_resource_by_model_class(params[:via_relation_class]).dup
457
+ parent_resource = Avo.resource_manager.get_resource_by_model_class(params[:via_relation_class])
439
458
  association_name = BaseResource.valid_association_name(@record, params[:via_relation])
440
459
 
441
460
  return resource_view_path(
@@ -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::App.resources.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,11 +37,11 @@ module Avo
37
37
  query = Avo::ExecutionContext.new(
38
38
  target: resource.search_query,
39
39
  params: params,
40
- query: resource.class.scope
40
+ query: resource.query_scope
41
41
  ).handle
42
42
 
43
43
  # Get the count
44
- results_count = query.reselect(:id).count
44
+ results_count = query.reselect(resource.model_class.primary_key).count
45
45
 
46
46
  # Get the results
47
47
  query = query.limit(8)
@@ -58,7 +58,7 @@ module Avo
58
58
 
59
59
  result_object = {
60
60
  header: header,
61
- help: resource.class.search_query_help,
61
+ help: resource.fetch_search(:help) || "",
62
62
  results: results,
63
63
  count: results.count
64
64
  }
@@ -101,37 +101,36 @@ 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
118
+ fetch_result_information record, resource, resource.class.fetch_search(:item, record: record)
116
119
  end
117
120
  end
118
121
 
119
122
  private
120
123
 
121
- def fetch_result_information(record, resource)
124
+ def fetch_result_information(record, resource, item)
122
125
  {
123
126
  _id: record.id,
124
- _label: resource.label,
125
- _url: Avo::ExecutionContext.new(
126
- target: resource.search_result_path || resource.record_path,
127
- resource: resource,
128
- record: record
129
- ).handle,
127
+ _label: item&.dig(:title) || resource.record_title,
128
+ _url: resource.class.fetch_search(:result_path, record: resource.record) || resource.record_path
130
129
  }
131
130
  end
132
131
 
133
132
  def should_apply_has_many_scope?
134
- params[:via_association] == "has_many" && @resource.search_query.present?
133
+ params[:via_association] == "has_many" && @resource.class.search_query.present?
135
134
  end
136
135
 
137
136
  def should_apply_attach_scope?
@@ -155,16 +154,15 @@ module Avo
155
154
  end
156
155
 
157
156
  def fetch_field
158
- 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
159
158
  fields.find { |f| f.id.to_s == params[:via_association_id] }
160
159
  end
161
160
 
162
161
  def fetch_parent
163
162
  return unless params[:via_reflection_id].present?
164
163
 
165
- parent_class = BaseResource.get_model_by_name params[:via_reflection_class]
166
-
167
- 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
168
166
  end
169
167
  end
170
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
6
  Avo::Current.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
@@ -1,5 +1,5 @@
1
1
  import { Controller } from '@hotwired/stimulus'
2
- import SimpleMDE from 'simplemde'
2
+ import EasyMDE from 'easymde'
3
3
 
4
4
  export default class extends Controller {
5
5
  static targets = ['element']
@@ -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') {
@@ -27,9 +28,9 @@ export default class extends Controller {
27
28
  options.status = false
28
29
  }
29
30
 
30
- const simpleMde = new SimpleMDE(options)
31
+ const easyMde = new EasyMDE(options)
31
32
  if (this.view === 'show') {
32
- simpleMde.codemirror.options.readOnly = true
33
+ easyMde.codemirror.options.readOnly = true
33
34
  }
34
35
  }
35
36
  }
@@ -211,7 +211,9 @@ export default class extends Controller {
211
211
  searchUrl(query) {
212
212
  const url = URI()
213
213
 
214
- return url.segment([window.Avo.configuration.root_path, ...this.searchSegments()]).search(this.searchParams(query)).readable().toString()
214
+ return url.segment([window.Avo.configuration.root_path, ...this.searchSegments()])
215
+ .search(this.searchParams(encodeURIComponent(query)))
216
+ .readable().toString()
215
217
  }
216
218
 
217
219
  searchSegments() {
@@ -10,6 +10,7 @@ import CodeFieldController from './controllers/fields/code_field_controller'
10
10
  import CopyToClipboardController from './controllers/copy_to_clipboard_controller'
11
11
  import DashboardCardController from './controllers/dashboard_card_controller'
12
12
  import DateFieldController from './controllers/fields/date_field_controller'
13
+ import EasyMdeController from './controllers/fields/easy_mde_controller'
13
14
  import FilterController from './controllers/filter_controller'
14
15
  import HiddenInputController from './controllers/hidden_input_controller'
15
16
  import InputAutofocusController from './controllers/input_autofocus_controller'
@@ -31,7 +32,6 @@ import SelectController from './controllers/select_controller'
31
32
  import SelectFilterController from './controllers/select_filter_controller'
32
33
  import SelfDestroyController from './controllers/self_destroy_controller'
33
34
  import SidebarController from './controllers/sidebar_controller'
34
- import SimpleMdeController from './controllers/fields/simple_mde_controller'
35
35
  import TabsController from './controllers/tabs_controller'
36
36
  import TextFilterController from './controllers/text_filter_controller'
37
37
  import TippyController from './controllers/tippy_controller'
@@ -73,9 +73,9 @@ application.register('toggle', ToggleController)
73
73
  application.register('belongs-to-field', BelongsToFieldController)
74
74
  application.register('code-field', CodeFieldController)
75
75
  application.register('date-field', DateFieldController)
76
+ application.register('easy-mde', EasyMdeController)
76
77
  application.register('key-value', KeyValueController)
77
78
  application.register('progress-bar-field', ProgressBarFieldController)
78
- application.register('simple-mde', SimpleMdeController)
79
79
  application.register('trix-field', TrixFieldController)
80
80
 
81
81
  // Custom controllers
@@ -9,7 +9,7 @@
9
9
  >
10
10
  <%= form_with model: @record,
11
11
  scope: 'fields',
12
- url: "#{@resource.records_path}/actions",
12
+ url: Avo::Services::URIService.parse(@resource.records_path).append_paths("actions").to_s,
13
13
  local: true,
14
14
  data: @action.class.form_data_attributes do |form|
15
15
  %>
@@ -23,6 +23,7 @@
23
23
  <%= hidden_field_tag :action_id, @action.param_id %>
24
24
  <%= form.hidden_field :avo_resource_ids, value: params[:id] || params[:resource_ids], 'data-action-target': 'resourceIds' %>
25
25
  <%= form.hidden_field :avo_selected_query, 'data-action-target': 'selectedAllQuery' %>
26
+ <%= form.hidden_field :arguments, value: params[:arguments] %>
26
27
  <% if @action.get_fields.present? %>
27
28
  <div class="my-4 -mx-6">
28
29
  <% @action.get_fields.each_with_index do |field, index| %>
@@ -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>
@@ -0,0 +1,2 @@
1
+ <%# Example link below %>
2
+ <%#= render Avo::ProfileItemComponent.new label: 'Profile', path: '/profile', icon: 'user-circle' %>