avo 3.0.0.beta1 → 3.0.0.pre1

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 (215) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -5
  3. data/Gemfile.lock +81 -92
  4. data/{public/avo-assets/avo.css → app/assets/builds/avo.base.css} +686 -728
  5. data/app/assets/builds/avo.base.js +93804 -0
  6. data/app/assets/builds/avo.base.js.map +7 -0
  7. data/app/assets/stylesheets/avo.base.css +2 -1
  8. data/app/assets/svgs/failed_to_load.svg +1 -0
  9. data/app/assets/svgs/grid-empty-state.svg +1 -0
  10. data/app/assets/svgs/table-empty-state.svg +1 -0
  11. data/app/assets/svgs/triangle-up.svg +1 -1
  12. data/app/components/avo/actions_component.html.erb +1 -1
  13. data/app/components/avo/actions_component.rb +16 -42
  14. data/app/components/avo/alert_component.html.erb +1 -1
  15. data/app/components/avo/base_component.rb +7 -7
  16. data/app/components/avo/field_wrapper_component.html.erb +4 -4
  17. data/app/components/avo/field_wrapper_component.rb +1 -1
  18. data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +5 -5
  19. data/app/components/avo/fields/belongs_to_field/edit_component.rb +4 -8
  20. data/app/components/avo/fields/boolean_field/edit_component.html.erb +0 -1
  21. data/app/components/avo/fields/boolean_group_field/edit_component.html.erb +1 -1
  22. data/app/components/avo/fields/code_field/edit_component.html.erb +0 -1
  23. data/app/components/avo/fields/common/files_list_viewer_component.html.erb +5 -0
  24. data/app/components/avo/fields/common/files_list_viewer_component.rb +8 -0
  25. data/app/components/avo/fields/common/heading_component.html.erb +1 -1
  26. data/app/components/avo/fields/common/single_file_viewer_component.html.erb +56 -0
  27. data/app/components/avo/fields/common/single_file_viewer_component.rb +55 -0
  28. data/app/components/avo/fields/country_field/edit_component.html.erb +1 -3
  29. data/app/components/avo/fields/file_field/edit_component.html.erb +2 -4
  30. data/app/components/avo/fields/file_field/edit_component.rb +0 -1
  31. data/app/components/avo/fields/file_field/index_component.rb +2 -2
  32. data/app/components/avo/fields/file_field/show_component.html.erb +1 -1
  33. data/app/components/avo/fields/files_field/edit_component.html.erb +2 -4
  34. data/app/components/avo/fields/files_field/edit_component.rb +0 -1
  35. data/app/components/avo/fields/files_field/show_component.html.erb +1 -1
  36. data/app/components/avo/fields/has_many_field/show_component.html.erb +1 -1
  37. data/app/components/avo/fields/has_one_field/show_component.html.erb +4 -5
  38. data/app/components/avo/fields/has_one_field/show_component.rb +2 -6
  39. data/app/components/avo/fields/index_component.rb +0 -1
  40. data/app/components/avo/fields/markdown_field/edit_component.html.erb +3 -4
  41. data/app/components/avo/fields/markdown_field/show_component.html.erb +3 -3
  42. data/app/components/avo/fields/number_field/edit_component.html.erb +1 -3
  43. data/app/components/avo/fields/password_field/edit_component.html.erb +1 -3
  44. data/app/components/avo/fields/progress_bar_field/edit_component.html.erb +0 -1
  45. data/app/components/avo/fields/select_field/edit_component.html.erb +1 -2
  46. data/app/components/avo/fields/status_field/edit_component.html.erb +1 -1
  47. data/app/components/avo/fields/text_field/edit_component.html.erb +2 -3
  48. data/app/components/avo/fields/textarea_field/edit_component.html.erb +0 -1
  49. data/app/components/avo/fields/trix_field/edit_component.html.erb +1 -2
  50. data/app/components/avo/fields/trix_field/show_component.html.erb +1 -1
  51. data/app/components/avo/index/field_wrapper_component.html.erb +1 -1
  52. data/app/components/avo/index/field_wrapper_component.rb +12 -0
  53. data/app/components/avo/index/grid_item_component.html.erb +35 -9
  54. data/app/components/avo/index/grid_item_component.rb +10 -36
  55. data/app/components/avo/index/resource_controls_component.rb +11 -8
  56. data/app/components/avo/index/resource_table_component.rb +1 -1
  57. data/app/components/avo/item_switcher_component.html.erb +5 -10
  58. data/app/components/avo/item_switcher_component.rb +1 -2
  59. data/app/components/avo/modal_component.html.erb +1 -1
  60. data/app/components/avo/panel_component.html.erb +1 -6
  61. data/app/components/avo/panel_component.rb +0 -1
  62. data/app/components/avo/profile_item_component.html.erb +2 -17
  63. data/app/components/avo/profile_item_component.rb +1 -13
  64. data/app/components/avo/referrer_params_component.html.erb +0 -2
  65. data/app/components/avo/resource_component.rb +6 -69
  66. data/app/components/avo/resource_sidebar_component.rb +1 -1
  67. data/app/components/avo/sidebar/link_component.html.erb +0 -2
  68. data/app/components/avo/sidebar/link_component.rb +3 -5
  69. data/app/components/avo/sidebar_component.html.erb +3 -3
  70. data/app/components/avo/sidebar_component.rb +4 -4
  71. data/app/components/avo/sidebar_profile_component.html.erb +27 -27
  72. data/app/components/avo/views/resource_edit_component.html.erb +5 -5
  73. data/app/components/avo/views/resource_edit_component.rb +1 -1
  74. data/app/components/avo/views/resource_index_component.html.erb +10 -19
  75. data/app/components/avo/views/resource_index_component.rb +16 -22
  76. data/app/components/avo/views/resource_show_component.html.erb +4 -4
  77. data/app/controllers/avo/actions_controller.rb +20 -20
  78. data/app/controllers/avo/application_controller.rb +67 -90
  79. data/app/controllers/avo/associations_controller.rb +7 -5
  80. data/app/controllers/avo/attachments_controller.rb +7 -22
  81. data/app/controllers/avo/base_controller.rb +35 -47
  82. data/app/controllers/avo/home_controller.rb +1 -1
  83. data/app/controllers/avo/search_controller.rb +16 -20
  84. data/app/controllers/concerns/avo/initializes_avo.rb +8 -3
  85. data/app/helpers/avo/application_helper.rb +6 -13
  86. data/app/javascript/js/application.js +0 -2
  87. data/app/javascript/js/controllers/fields/{easy_mde_controller.js → simple_mde_controller.js} +3 -4
  88. data/app/javascript/js/controllers/search_controller.js +1 -3
  89. data/app/javascript/js/controllers.js +2 -2
  90. data/app/views/avo/actions/show.html.erb +3 -5
  91. data/app/views/avo/associations/new.html.erb +3 -3
  92. data/app/views/avo/debug/status.html.erb +5 -6
  93. data/app/views/avo/home/index.html.erb +1 -1
  94. data/app/views/avo/partials/_custom_tools_alert.html.erb +2 -2
  95. data/app/views/avo/partials/_footer.html.erb +1 -1
  96. data/app/views/avo/partials/_javascript.html.erb +1 -1
  97. data/app/views/avo/partials/_navbar.html.erb +1 -1
  98. data/app/views/avo/partials/_table_header.html.erb +8 -0
  99. data/app/views/avo/partials/_view_toggle_button.html.erb +0 -9
  100. data/app/views/avo/private/design.html.erb +2 -2
  101. data/app/views/layouts/avo/application.html.erb +3 -2
  102. data/avo.gemspec +1 -2
  103. data/config/initializers/pagy.rb +10 -12
  104. data/config/routes.rb +5 -5
  105. data/db/factories.rb +0 -17
  106. data/lib/avo/app.rb +165 -0
  107. data/lib/avo/base_action.rb +18 -31
  108. data/lib/avo/base_resource.rb +213 -238
  109. data/lib/avo/concerns/breadcrumbs.rb +2 -2
  110. data/lib/avo/concerns/can_replace_items.rb +7 -3
  111. data/lib/avo/concerns/filters_session_handler.rb +4 -5
  112. data/lib/avo/concerns/has_item_type.rb +0 -4
  113. data/lib/avo/concerns/has_items.rb +115 -93
  114. data/lib/avo/concerns/is_visible.rb +1 -1
  115. data/lib/avo/concerns/model_class_constantized.rb +2 -0
  116. data/lib/avo/configuration.rb +8 -9
  117. data/lib/avo/current.rb +1 -35
  118. data/lib/avo/dsl/field_parser.rb +1 -1
  119. data/lib/avo/dynamic_router.rb +2 -13
  120. data/lib/avo/engine.rb +13 -11
  121. data/lib/avo/execution_context.rb +2 -4
  122. data/lib/avo/fields/base_field.rb +14 -51
  123. data/lib/avo/fields/belongs_to_field.rb +13 -20
  124. data/lib/avo/fields/concerns/is_searchable.rb +1 -1
  125. data/lib/avo/fields/concerns/use_resource.rb +1 -1
  126. data/lib/avo/fields/date_field.rb +3 -16
  127. data/lib/avo/fields/field_manager.rb +3 -13
  128. data/lib/avo/fields/file_field.rb +0 -2
  129. data/lib/avo/fields/files_field.rb +0 -6
  130. data/lib/avo/fields/has_base_field.rb +5 -5
  131. data/lib/avo/fields/has_one_field.rb +1 -2
  132. data/lib/avo/fields/id_field.rb +1 -2
  133. data/lib/avo/filters/base_filter.rb +0 -9
  134. data/lib/avo/grid_collector.rb +40 -0
  135. data/lib/avo/html/builder.rb +1 -3
  136. data/lib/avo/licensing/h_q.rb +6 -11
  137. data/lib/avo/licensing/license.rb +1 -1
  138. data/lib/avo/licensing/license_manager.rb +1 -1
  139. data/lib/avo/licensing/{nil_license.rb → null_license.rb} +1 -1
  140. data/lib/avo/loaders/fields_loader.rb +1 -7
  141. data/lib/avo/plugin.rb +0 -10
  142. data/lib/avo/plugin_manager.rb +4 -2
  143. data/lib/avo/reloader.rb +1 -1
  144. data/lib/avo/resources/controls/actions_list.rb +1 -2
  145. data/lib/avo/resources/controls/create_button.rb +1 -1
  146. data/lib/avo/resources/controls/delete_button.rb +1 -1
  147. data/lib/avo/resources/controls/detach_button.rb +1 -1
  148. data/lib/avo/resources/controls/edit_button.rb +1 -1
  149. data/lib/avo/resources/controls/show_button.rb +1 -1
  150. data/lib/avo/resources/items/holder.rb +5 -13
  151. data/lib/avo/resources/items/item_group.rb +0 -1
  152. data/lib/avo/resources/resource_manager.rb +18 -11
  153. data/lib/avo/services/debug_service.rb +5 -6
  154. data/lib/avo/services/telemetry_service.rb +2 -3
  155. data/lib/avo/version.rb +1 -1
  156. data/lib/avo.rb +25 -109
  157. data/lib/generators/avo/action_generator.rb +8 -8
  158. data/lib/generators/avo/card/chartkick_generator.rb +18 -0
  159. data/lib/generators/avo/card/metric_generator.rb +18 -0
  160. data/lib/generators/avo/card/partial_generator.rb +19 -0
  161. data/lib/generators/avo/eject_generator.rb +0 -1
  162. data/lib/generators/avo/filter_generator.rb +8 -8
  163. data/lib/generators/avo/install_generator.rb +1 -11
  164. data/lib/generators/avo/resource_generator.rb +4 -22
  165. data/lib/generators/avo/tailwindcss/install_generator.rb +1 -4
  166. data/lib/generators/avo/templates/action.tt +5 -7
  167. data/lib/generators/avo/templates/cards/chartkick_card.tt +1 -1
  168. data/lib/generators/avo/templates/cards/chartkick_card_sample.tt +1 -1
  169. data/lib/generators/avo/templates/cards/metric_card.tt +1 -1
  170. data/lib/generators/avo/templates/cards/metric_card_sample.tt +1 -1
  171. data/lib/generators/avo/templates/cards/partial_card.tt +1 -1
  172. data/lib/generators/avo/templates/cards/partial_card_sample.tt +1 -1
  173. data/lib/generators/avo/templates/dashboards/dashboard.tt +3 -5
  174. data/lib/generators/avo/templates/initializer/avo.tt +2 -4
  175. data/lib/generators/avo/templates/resource/resource.tt +6 -6
  176. data/lib/generators/avo/templates/scope.tt +1 -1
  177. data/lib/generators/avo/templates/standalone_action.tt +8 -0
  178. data/lib/generators/avo/templates/tailwindcss/Procfile.dev +1 -1
  179. data/lib/tasks/avo_tasks.rake +0 -5
  180. metadata +19 -56
  181. data/app/assets/svgs/map-empty-state.svg +0 -35
  182. data/app/assets/svgs/map-view-type.svg +0 -3
  183. data/app/components/avo/fields/area_field/edit_component.html.erb +0 -7
  184. data/app/components/avo/fields/area_field/edit_component.rb +0 -4
  185. data/app/components/avo/fields/area_field/show_component.html.erb +0 -8
  186. data/app/components/avo/fields/area_field/show_component.rb +0 -4
  187. data/app/components/avo/fields/common/files/controls_component.html.erb +0 -29
  188. data/app/components/avo/fields/common/files/controls_component.rb +0 -19
  189. data/app/components/avo/fields/common/files/list_viewer_component.html.erb +0 -20
  190. data/app/components/avo/fields/common/files/list_viewer_component.rb +0 -41
  191. data/app/components/avo/fields/common/files/view_type/grid_component.html.erb +0 -27
  192. data/app/components/avo/fields/common/files/view_type/grid_component.rb +0 -51
  193. data/app/components/avo/fields/common/files/view_type/list_component.html.erb +0 -22
  194. data/app/components/avo/fields/common/files/view_type/list_component.rb +0 -15
  195. data/app/components/avo/fields/location_field/edit_component.html.erb +0 -22
  196. data/app/components/avo/fields/location_field/edit_component.rb +0 -4
  197. data/app/components/avo/fields/location_field/show_component.html.erb +0 -7
  198. data/app/components/avo/fields/location_field/show_component.rb +0 -4
  199. data/app/components/avo/index/resource_map_component.html.erb +0 -16
  200. data/app/components/avo/index/resource_map_component.rb +0 -109
  201. data/app/components/avo/row_component.html.erb +0 -3
  202. data/app/components/avo/row_component.rb +0 -12
  203. data/app/views/avo/attachments/destroy.turbo_stream.erb +0 -7
  204. data/app/views/avo/partials/_profile_menu_extra.html.erb +0 -2
  205. data/lib/avo/concerns/has_description.rb +0 -23
  206. data/lib/avo/fields/area_field.rb +0 -39
  207. data/lib/avo/fields/concerns/file_authorization.rb +0 -31
  208. data/lib/avo/fields/location_field.rb +0 -86
  209. data/lib/avo/resources/items/row.rb +0 -54
  210. data/lib/generators/avo/card_generator.rb +0 -27
  211. data/public/avo-assets/avo.base.css +0 -10542
  212. data/public/avo-assets/avo.base.js +0 -949
  213. data/public/avo-assets/avo.base.js.map +0 -7
  214. data/public/avo-assets/avo.js +0 -513
  215. data/public/avo-assets/avo.js.map +0 -7
@@ -7,10 +7,10 @@ module Avo
7
7
  end
8
8
 
9
9
  include Avo::InitializesAvo
10
+ include Pagy::Backend
10
11
  include Avo::ApplicationHelper
11
12
  include Avo::UrlHelpers
12
13
  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,49 +61,6 @@ 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
-
107
64
  def set_resource_name
108
65
  @resource_name = resource_name
109
66
  end
@@ -115,18 +72,23 @@ module Avo
115
72
  def set_resource
116
73
  raise ActionController::RoutingError.new "No route matches" if resource.nil?
117
74
 
118
- @resource = resource.new(view: action_name.to_sym, user: _current_user, params: params)
119
-
120
- set_authorization
75
+ @resource = resource.hydrate(params: params)
121
76
  end
122
77
 
123
78
  def set_related_resource
124
- @related_resource = related_resource.new(params: params, view: action_name.to_sym, user: _current_user, record: @related_record)
79
+ @related_resource = related_resource.hydrate(params: params)
125
80
  end
126
81
 
127
82
  def set_record
128
83
  @record = @resource.find_record(params[:id], query: model_find_scope, params: params)
129
- @resource.hydrate(record: @record)
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
130
92
  end
131
93
 
132
94
  def set_related_record
@@ -136,16 +98,6 @@ module Avo
136
98
  else
137
99
  @related_resource.find_record params[:related_id], query: eager_load_files(@related_resource, @record.send(association_name)), params: params
138
100
  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
149
101
  end
150
102
 
151
103
  def set_view
@@ -155,34 +107,23 @@ module Avo
155
107
  def set_record_to_fill
156
108
  @record_to_fill = @resource.model_class.new if @view == :create
157
109
  @record_to_fill = @record if @view == :update
158
-
159
- # If resource.record is nil, most likely the user is creating a new record.
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
162
- @resource.hydrate(record: @record_to_fill) if @resource.record.nil?
163
110
  end
164
111
 
165
112
  def fill_record
166
113
  # We have to skip filling the the record if this is an attach action
167
- return if is_attach_action?
114
+ is_attach_action = params[model_param_key].blank? && params[:related_name].present? && params[:fields].present?
168
115
 
169
- @record = @resource.fill_record(@record_to_fill, cast_nullable(model_params), extra_params: extra_params)
170
- assign_default_value_to_disabled_fields if @view == :create
116
+ unless is_attach_action
117
+ @record = @resource.fill_record(@record_to_fill, cast_nullable(model_params), extra_params: extra_params)
118
+ end
171
119
  end
172
120
 
173
- def is_attach_action?
174
- params[model_param_key].blank? && params[:related_name].present? && params[:fields].present?
121
+ def hydrate_resource
122
+ @resource.hydrate(view: action_name.to_sym, user: _current_user, record: @record)
175
123
  end
176
124
 
177
- def assign_default_value_to_disabled_fields
178
- @resource.get_field_definitions.select do |field|
179
- field.is_disabled? && field.visible? && !field.computed
180
- end.each do |field|
181
- # Get the default value from the field default definition
182
- # If there is no default value specified on the resource, get the value from the record (DB, Callbacks, etc.)
183
- default_value = field.default || @record.send(field.id)
184
- field.fill_field @record, field.id, default_value, params
185
- end
125
+ def hydrate_related_resource
126
+ @related_resource.hydrate(view: action_name.to_sym, user: _current_user, record: @related_record)
186
127
  end
187
128
 
188
129
  def authorize_base_action
@@ -198,16 +139,52 @@ module Avo
198
139
  @authorization.set_record(class_to_authorize).authorize_action action_to_authorize.to_sym
199
140
  end
200
141
 
201
- def eager_load_files(resource, query)
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
142
+ # Get the pluralized resource name for this request
143
+ # Ex: projects, teams, users
144
+ def resource_name
145
+ return params[:resource_name] if params[:resource_name].present?
146
+
147
+ return controller_name if controller_name.present?
148
+
149
+ begin
150
+ request.path
151
+ .match(/\/?#{Avo::App.root_path.delete('/')}\/resources\/([a-z1-9\-_]*)\/?/mi)
152
+ .captures
153
+ .first
154
+ rescue
155
+ end
156
+ end
208
157
 
209
- if attachment_fields.present?
210
- attachment_fields.map do |field|
158
+ def related_resource_name
159
+ params[:related_name]
160
+ end
161
+
162
+ # Gets the Avo resource for this request based on the request from the `resource_name` "param"
163
+ # Ex: Avo::Resources::Project, Avo::Resources::Team, Avo::Resources::User
164
+ def resource
165
+ resource = Avo::App.resources.get_resource @resource_name.to_s.camelize.singularize
166
+
167
+ return resource if resource.present?
168
+
169
+ Avo::App.resources.get_resource_by_controller_name @resource_name
170
+ end
171
+
172
+ def related_resource
173
+ # Find the field from the parent resource
174
+ field = @resource.get_field params[:related_name]
175
+
176
+ return field.use_resource if field&.use_resource.present?
177
+
178
+ reflection = @record._reflections[params[:related_name]]
179
+
180
+ reflected_model = reflection.klass
181
+
182
+ Avo::App.resources.get_resource_by_model_class reflected_model
183
+ end
184
+
185
+ def eager_load_files(resource, query)
186
+ if resource.attached_file_fields.present?
187
+ resource.attached_file_fields.map do |field|
211
188
  attachment = case field.class.to_s
212
189
  when "Avo::Fields::FileField"
213
190
  "attachment"
@@ -243,8 +220,8 @@ module Avo
243
220
  def set_authorization
244
221
  # We need to set @resource_name for the #resource method to work properly
245
222
  set_resource_name
246
- @authorization = if @resource
247
- @resource.authorization(user: _current_user)
223
+ @authorization = if resource
224
+ resource.authorization(user: _current_user)
248
225
  else
249
226
  Services::AuthorizationService.new _current_user
250
227
  end
@@ -308,7 +285,7 @@ module Avo
308
285
  if Rails::VERSION::MAJOR === 6
309
286
  ActiveStorage::Current.host = request.base_url
310
287
  elsif Rails::VERSION::MAJOR === 7
311
- ActiveStorage::Current.url_options = {protocol: request.protocol, host: request.host, port: request.port}
288
+ ActiveStorage::Current.url_options = request.base_url
312
289
  end
313
290
  end
314
291
  rescue => exception
@@ -3,11 +3,13 @@ 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]
6
7
  before_action :set_related_resource_name
7
8
  before_action :set_related_resource, only: [:show, :index, :new, :create, :destroy]
8
9
  before_action :set_related_authorization
9
10
  before_action :set_reflection_field
10
11
  before_action :set_related_record, only: [:show]
12
+ before_action :hydrate_related_resource, only: [:show, :index, :create, :destroy]
11
13
  before_action :set_reflection
12
14
  before_action :set_attachment_class, only: [:show, :index, :new, :create, :destroy]
13
15
  before_action :set_attachment_resource, only: [:show, :index, :new, :create, :destroy]
@@ -52,7 +54,7 @@ module Avo
52
54
  end
53
55
 
54
56
  @options = query.all.map do |record|
55
- [@attachment_resource.new(record: record).record_title, record.id]
57
+ [record.send(@attachment_resource.class.title), record.id]
56
58
  end
57
59
  end
58
60
  end
@@ -79,7 +81,7 @@ module Avo
79
81
  association_name = BaseResource.valid_association_name(@record, params[:related_name])
80
82
 
81
83
  if reflection_class == "HasManyReflection"
82
- @record.send(association_name).destroy @attachment_record
84
+ @record.send(association_name).delete @attachment_record
83
85
  else
84
86
  @record.send("#{association_name}=", nil)
85
87
  end
@@ -100,7 +102,7 @@ module Avo
100
102
  end
101
103
 
102
104
  def set_attachment_resource
103
- @attachment_resource = @field.use_resource || (Avo.resource_manager.get_resource_by_model_class @attachment_class)
105
+ @attachment_resource = @field.use_resource || (Avo::App.resources.get_resource_by_model_class @attachment_class)
104
106
  end
105
107
 
106
108
  def set_attachment_record
@@ -149,8 +151,8 @@ module Avo
149
151
  private
150
152
 
151
153
  def set_related_authorization
152
- @related_authorization = if @related_resource.present?
153
- @related_resource.authorization(user: _current_user)
154
+ @related_authorization = if related_resource
155
+ related_resource.authorization(user: _current_user)
154
156
  else
155
157
  Services::AuthorizationService.new _current_user
156
158
  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].to_io, filename: params[:filename]
10
+ blob = ActiveStorage::Blob.create_and_upload! io: params[:file], filename: params[:filename]
11
11
  association_name = BaseResource.valid_attachment_name(@record, params[:attachment_key])
12
12
 
13
13
  if association_name.blank?
@@ -23,31 +23,16 @@ module Avo
23
23
  end
24
24
 
25
25
  def destroy
26
- if authorized_to :delete
27
- attachment = ActiveStorage::Attachment.find(params[:attachment_id])
26
+ attachment = ActiveStorage::Attachment.find(params[:attachment_id])
27
+ path = resource_path(record: @record, resource: @resource)
28
28
 
29
- flash[:notice] = if attachment.present?
30
- @destroyed = attachment.destroy
29
+ if attachment.present?
30
+ attachment.destroy
31
31
 
32
- t("avo.attachment_destroyed")
33
- else
34
- t("avo.failed_to_find_attachment")
35
- end
32
+ redirect_to params[:referrer] || path, notice: t("avo.attachment_destroyed")
36
33
  else
37
- flash[:notice] = t("avo.not_authorized")
34
+ redirect_back fallback_location: path, notice: t("avo.failed_to_find_attachment")
38
35
  end
39
-
40
- respond_to do |format|
41
- format.turbo_stream do
42
- render "destroy"
43
- end
44
- end
45
- end
46
-
47
- private
48
-
49
- def authorized_to(action)
50
- @resource.authorization.authorize_action("#{action}_#{params[:attachment_name]}?", record: @record, raise_exception: false)
51
36
  end
52
37
  end
53
38
  end
@@ -6,6 +6,7 @@ module Avo
6
6
 
7
7
  before_action :set_resource_name
8
8
  before_action :set_resource
9
+ before_action :hydrate_resource
9
10
  before_action :set_applied_filters, only: :index
10
11
  before_action :set_record, only: [:show, :edit, :destroy, :update, :preview]
11
12
  before_action :set_record_to_fill
@@ -28,6 +29,11 @@ module Avo
28
29
  @query = @resource.class.query_scope
29
30
  end
30
31
 
32
+ # Remove default_scope for index view if no parent_resource present
33
+ if @resource.unscoped_queries_on_index && @parent_resource.blank?
34
+ @query = @query.unscoped
35
+ end
36
+
31
37
  # Eager load the associations
32
38
  if @resource.includes.present?
33
39
  @query = @query.includes(*@resource.includes)
@@ -46,7 +52,7 @@ module Avo
46
52
  field_id = @index_params[:sort_by].to_sym
47
53
  field = @resource.get_field_definitions.find { |field| field.id == field_id }
48
54
  @query = if field&.sortable.is_a?(Proc)
49
- Avo::ExecutionContext.new(target: field.sortable, query: @query, direction: @index_params[:sort_direction]).handle
55
+ field.sortable.call(@query, @index_params[:sort_direction])
50
56
  else
51
57
  @query.order("#{@resource.model_class.table_name}.#{@index_params[:sort_by]} #{@index_params[:sort_direction]}")
52
58
  end
@@ -67,7 +73,18 @@ module Avo
67
73
  end
68
74
 
69
75
  safe_call :set_and_apply_scopes
70
- safe_call :apply_dynamic_filters
76
+
77
+ if Avo.avo_filters_installed? && params[AvoFilters.configuration.param_key].present?
78
+ # Apply dynamic filters
79
+ query_builder = AvoFilters::QueryBuilder.new(resource: @resource, params: params, query: @query)
80
+ @query = @query.ransack(**query_builder.ransack_query)
81
+ end
82
+
83
+ pagy_query = if @query.instance_of?(Ransack::Search)
84
+ @query.result(distinct: false)
85
+ else
86
+ @query
87
+ end
71
88
 
72
89
  @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)
73
90
 
@@ -78,7 +95,7 @@ module Avo
78
95
  end
79
96
 
80
97
  def show
81
- @resource.hydrate(record: @record, view: :show, user: _current_user, params: params).detect_fields
98
+ @resource.hydrate(record: @record, view: :show, user: _current_user, params: params)
82
99
 
83
100
  set_actions
84
101
 
@@ -86,9 +103,9 @@ module Avo
86
103
 
87
104
  # If we're accessing this resource via another resource add the parent to the breadcrumbs.
88
105
  if params[:via_resource_class].present? && params[:via_record_id].present?
89
- via_resource = Avo.resource_manager.get_resource(params[:via_resource_class])
106
+ via_resource = Avo::App.resources.get_resource(params[:via_resource_class]).dup
90
107
  via_record = via_resource.find_record params[:via_record_id], params: params
91
- via_resource = via_resource.new record: via_record
108
+ via_resource.hydrate record: via_record
92
109
 
93
110
  add_breadcrumb via_resource.plural_name, resources_path(resource: via_resource)
94
111
  add_breadcrumb via_resource.record_title, resource_path(record: via_record, resource: via_resource)
@@ -109,9 +126,9 @@ module Avo
109
126
  @page_title = @resource.default_panel_name.to_s
110
127
 
111
128
  if is_associated_record?
112
- via_resource = Avo.resource_manager.get_resource_by_model_class(params[:via_relation_class])
129
+ via_resource = Avo::App.resources.get_resource_by_model_class(params[:via_relation_class]).dup
113
130
  via_record = via_resource.find_record params[:via_record_id], params: params
114
- via_resource = via_resource.new record: via_record
131
+ via_resource.hydrate record: via_record
115
132
 
116
133
  add_breadcrumb via_resource.plural_name, resources_path(resource: via_resource)
117
134
  add_breadcrumb via_resource.record_title, resource_path(record: via_record, resource: via_resource)
@@ -134,7 +151,7 @@ module Avo
134
151
  # Fills in the required infor for belongs_to and has_many
135
152
  # Get the foreign key and set it to the id we received in the params
136
153
  if @reflection.is_a?(ActiveRecord::Reflection::BelongsToReflection) || @reflection.is_a?(ActiveRecord::Reflection::HasManyReflection)
137
- related_resource = Avo.resource_manager.get_resource_by_model_class params[:via_relation_class]
154
+ related_resource = Avo::App.resources.get_resource_by_model_class params[:via_relation_class]
138
155
  related_record = related_resource.find_record params[:via_record_id], params: params
139
156
 
140
157
  @record.send("#{@reflection.foreign_key}=", related_record.id)
@@ -144,16 +161,11 @@ module Avo
144
161
  # For when working with has_one, has_one_through, has_many_through, has_and_belongs_to_many, polymorphic
145
162
  if @reflection.is_a? ActiveRecord::Reflection::ThroughReflection
146
163
  # find the record
147
- via_resource = Avo.resource_manager.get_resource_by_model_class(params[:via_relation_class])
164
+ via_resource = ::Avo::App.resources.get_resource_by_model_class(params[:via_relation_class]).dup
148
165
  @related_record = via_resource.find_record params[:via_record_id], params: params
149
166
  association_name = BaseResource.valid_association_name(@record, params[:via_relation])
150
167
 
151
- if params[:via_association_type] == "has_one"
152
- # On has_one scenarios we should switch the @record and @related_record
153
- @related_record.send("#{@reflection.parent_reflection.inverse_of.name}=", @record)
154
- else
155
- @record.send(association_name) << @related_record
156
- end
168
+ @record.send(association_name) << @related_record
157
169
  end
158
170
  end
159
171
 
@@ -203,24 +215,16 @@ module Avo
203
215
 
204
216
  def save_record
205
217
  perform_action_and_record_errors do
206
- save_record_action
218
+ @record.save!
207
219
  end
208
220
  end
209
221
 
210
- def save_record_action
211
- @record.save!
212
- end
213
-
214
222
  def destroy_model
215
223
  perform_action_and_record_errors do
216
- destroy_record_action
224
+ @record.destroy!
217
225
  end
218
226
  end
219
227
 
220
- def destroy_record_action
221
- @record.destroy!
222
- end
223
-
224
228
  def perform_action_and_record_errors(&block)
225
229
  begin
226
230
  succeeded = block.call
@@ -249,7 +253,7 @@ module Avo
249
253
  end
250
254
 
251
255
  def permitted_params
252
- @resource.get_field_definitions.select(&:updatable).map(&:to_permitted_param).concat(extra_params).uniq
256
+ @resource.get_field_definitions.select(&:updatable).map(&:to_permitted_param).concat extra_params
253
257
  end
254
258
 
255
259
  def extra_params
@@ -309,20 +313,8 @@ module Avo
309
313
  @index_params[:sort_direction] = params[:sort_direction] || :desc
310
314
 
311
315
  # View types
312
- available_view_types = @resource.available_view_types
313
- @index_params[:available_view_types] = available_view_types
314
-
315
- @index_params[:view_type] = if params[:view_type].present?
316
- params[:view_type]
317
- elsif available_view_types.size == 1
318
- available_view_types.first
319
- else
320
- @resource.default_view_type || Avo.configuration.default_view_type
321
- end
322
-
323
- if available_view_types.exclude? @index_params[:view_type].to_sym
324
- raise "View type '#{@index_params[:view_type]}' is unavailable for #{@resource.class}."
325
- end
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
326
318
  end
327
319
 
328
320
  def set_filters
@@ -400,9 +392,9 @@ module Avo
400
392
  last_crumb_args = {}
401
393
  # If we're accessing this resource via another resource add the parent to the breadcrumbs.
402
394
  if params[:via_resource_class].present? && params[:via_record_id].present?
403
- via_resource = Avo.resource_manager.get_resource(params[:via_resource_class])
395
+ via_resource = Avo::App.resources.get_resource(params[:via_resource_class]).dup
404
396
  via_record = via_resource.find_record params[:via_record_id], params: params
405
- via_resource = via_resource.new record: via_record
397
+ via_resource.hydrate record: via_record
406
398
 
407
399
  add_breadcrumb via_resource.plural_name, resources_path(resource: @resource)
408
400
  add_breadcrumb via_resource.record_title, resource_path(record: via_record, resource: via_resource)
@@ -443,7 +435,7 @@ module Avo
443
435
  def after_create_path
444
436
  # If this is an associated record return to the association show page
445
437
  if is_associated_record?
446
- parent_resource = Avo.resource_manager.get_resource_by_model_class(params[:via_relation_class])
438
+ parent_resource = ::Avo::App.resources.get_resource_by_model_class(params[:via_relation_class]).dup
447
439
  association_name = BaseResource.valid_association_name(@record, params[:via_relation])
448
440
 
449
441
  return resource_view_path(
@@ -536,9 +528,5 @@ module Avo
536
528
  def safe_call(method)
537
529
  send(method) if respond_to?(method, true)
538
530
  end
539
-
540
- def pagy_query
541
- @query
542
- end
543
531
  end
544
532
  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.resource_manager.all.min_by { |resource| resource.model_key }
17
+ resource = Avo::App.resources.min_by { |resource| resource.model_key }
18
18
  redirect_to resources_path(resource: resource)
19
19
  end
20
20
  end
@@ -17,7 +17,7 @@ module Avo
17
17
  resources
18
18
  .map do |resource|
19
19
  # Apply authorization
20
- next unless @authorization.set_record(resource.model_class).authorize_action(:search, raise_exception: false)
20
+ next unless @authorization.set_record(resource.model_class).authorize_action(:index, raise_exception: false)
21
21
  # Filter out the models without a search_query
22
22
  next if resource.search_query.nil?
23
23
 
@@ -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.query_scope
40
+ scope: resource.class.scope
41
41
  ).handle
42
42
 
43
43
  # Get the count
44
- results_count = query.reselect(resource.model_class.primary_key).count
44
+ results_count = query.reselect(:id).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.fetch_search(:help) || "",
61
+ help: resource.class.search_query_help,
62
62
  results: results,
63
63
  count: results.count
64
64
  }
@@ -101,36 +101,31 @@ 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
+ scope = parent.send(association_name)
104
105
 
105
- # Get association records
106
- query = parent.send(association_name)
107
-
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
106
+ Avo::ExecutionContext.new(target: @resource.search_query, params: params, scope: scope).handle
112
107
  end
113
108
 
114
109
  def apply_search_metadata(records, avo_resource)
115
110
  records.map do |record|
116
- resource = avo_resource.new(record: record)
111
+ resource = avo_resource.dup.hydrate(record: record).hydrate_fields
117
112
 
118
- fetch_result_information record, resource, resource.class.fetch_search(:item, record: record)
113
+ fetch_result_information record, resource
119
114
  end
120
115
  end
121
116
 
122
117
  private
123
118
 
124
- def fetch_result_information(record, resource, item)
119
+ def fetch_result_information(record, resource)
125
120
  {
126
121
  _id: record.id,
127
- _label: item&.dig(:title) || resource.record_title,
128
- _url: resource.class.fetch_search(:result_path, record: resource.record) || resource.record_path
122
+ _label: resource.label,
123
+ _url: resource.record_path,
129
124
  }
130
125
  end
131
126
 
132
127
  def should_apply_has_many_scope?
133
- params[:via_association] == "has_many" && @resource.class.search_query.present?
128
+ params[:via_association] == "has_many" && @resource.search_query.present?
134
129
  end
135
130
 
136
131
  def should_apply_attach_scope?
@@ -154,15 +149,16 @@ module Avo
154
149
  end
155
150
 
156
151
  def fetch_field
157
- fields = Avo.resource_manager.get_resource_by_model_class(params[:via_reflection_class]).new.get_field_definitions
152
+ fields = ::Avo::App.resources.get_resource_by_model_class(params[:via_reflection_class]).get_field_definitions
158
153
  fields.find { |f| f.id.to_s == params[:via_association_id] }
159
154
  end
160
155
 
161
156
  def fetch_parent
162
157
  return unless params[:via_reflection_id].present?
163
158
 
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
159
+ parent_class = BaseResource.get_model_by_name params[:via_reflection_class]
160
+
161
+ parent_class.find params[:via_reflection_id]
166
162
  end
167
163
  end
168
164
  end
@@ -1,13 +1,18 @@
1
1
  module Avo
2
2
  module InitializesAvo
3
3
  def init_app
4
- Avo::Current.license = Avo::Licensing::NilLicense.new
4
+ Avo::Current.license = Avo::Licensing::NullLicense.new
5
+ Avo::Current.params = request.params
6
+ Avo::Current.request = request
5
7
  Avo::Current.context = context
6
- Avo::Current.user = _current_user
8
+ Avo::Current.current_user = _current_user
7
9
  Avo::Current.view_context = view_context
8
- Avo.init
10
+ Avo::Current.app = Avo::App.build request: request, context: context, current_user: _current_user, view_context: view_context
11
+ Avo::Current.app.init
9
12
  Avo::Current.license = Licensing::LicenseManager.new(Licensing::HQ.new(request).response).license
10
13
  Avo.plugin_manager.init_plugins
14
+
15
+ @license = Avo::App.license
11
16
  end
12
17
 
13
18
  def _current_user