avo 3.0.0.pre12 → 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 (143) 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/index/resource_table_component.rb +1 -1
  38. data/app/components/avo/item_switcher_component.html.erb +9 -4
  39. data/app/components/avo/item_switcher_component.rb +2 -1
  40. data/app/components/avo/panel_component.html.erb +1 -1
  41. data/app/components/avo/profile_item_component.html.erb +17 -2
  42. data/app/components/avo/profile_item_component.rb +13 -1
  43. data/app/components/avo/resource_component.rb +6 -3
  44. data/app/components/avo/resource_sidebar_component.rb +1 -1
  45. data/app/components/avo/row_component.html.erb +3 -0
  46. data/app/components/avo/row_component.rb +12 -0
  47. data/app/components/avo/sidebar/link_component.html.erb +2 -0
  48. data/app/components/avo/sidebar/link_component.rb +5 -3
  49. data/app/components/avo/sidebar_component.html.erb +3 -3
  50. data/app/components/avo/sidebar_component.rb +4 -4
  51. data/app/components/avo/sidebar_profile_component.html.erb +27 -27
  52. data/app/components/avo/views/resource_edit_component.rb +1 -1
  53. data/app/components/avo/views/resource_index_component.html.erb +1 -1
  54. data/app/components/avo/views/resource_index_component.rb +8 -8
  55. data/app/controllers/avo/actions_controller.rb +16 -8
  56. data/app/controllers/avo/application_controller.rb +71 -66
  57. data/app/controllers/avo/associations_controller.rb +4 -6
  58. data/app/controllers/avo/attachments_controller.rb +1 -1
  59. data/app/controllers/avo/base_controller.rb +39 -27
  60. data/app/controllers/avo/home_controller.rb +1 -1
  61. data/app/controllers/avo/search_controller.rb +18 -20
  62. data/app/controllers/concerns/avo/initializes_avo.rb +3 -6
  63. data/app/javascript/js/controllers/fields/{simple_mde_controller.js → easy_mde_controller.js} +4 -3
  64. data/app/javascript/js/controllers/search_controller.js +3 -1
  65. data/app/javascript/js/controllers.js +2 -2
  66. data/app/views/avo/actions/show.html.erb +2 -1
  67. data/app/views/avo/associations/new.html.erb +1 -1
  68. data/app/views/avo/debug/status.html.erb +1 -1
  69. data/app/views/avo/partials/_custom_tools_alert.html.erb +2 -2
  70. data/app/views/avo/partials/_footer.html.erb +1 -1
  71. data/app/views/avo/partials/_javascript.html.erb +1 -1
  72. data/app/views/avo/partials/_navbar.html.erb +1 -1
  73. data/app/views/avo/partials/_profile_menu_extra.html.erb +2 -0
  74. data/app/views/layouts/avo/application.html.erb +2 -2
  75. data/avo.gemspec +1 -0
  76. data/config/initializers/pagy.rb +12 -10
  77. data/config/routes.rb +3 -3
  78. data/db/factories.rb +2 -1
  79. data/lib/avo/base_action.rb +12 -3
  80. data/lib/avo/base_resource.rb +183 -181
  81. data/lib/avo/concerns/filters_session_handler.rb +0 -1
  82. data/lib/avo/concerns/has_item_type.rb +4 -0
  83. data/lib/avo/concerns/has_items.rb +28 -23
  84. data/lib/avo/concerns/model_class_constantized.rb +0 -2
  85. data/lib/avo/configuration.rb +6 -2
  86. data/lib/avo/current.rb +29 -2
  87. data/lib/avo/dsl/field_parser.rb +1 -1
  88. data/lib/avo/dynamic_router.rb +12 -1
  89. data/lib/avo/engine.rb +8 -6
  90. data/lib/avo/execution_context.rb +1 -1
  91. data/lib/avo/fields/base_field.rb +25 -7
  92. data/lib/avo/fields/belongs_to_field.rb +20 -13
  93. data/lib/avo/fields/concerns/is_searchable.rb +1 -1
  94. data/lib/avo/fields/concerns/use_resource.rb +1 -1
  95. data/lib/avo/fields/field_manager.rb +13 -3
  96. data/lib/avo/fields/has_base_field.rb +5 -5
  97. data/lib/avo/fields/has_one_field.rb +1 -1
  98. data/lib/avo/fields/location_field.rb +18 -1
  99. data/lib/avo/filters/base_filter.rb +3 -1
  100. data/lib/avo/html/builder.rb +3 -1
  101. data/lib/avo/licensing/h_q.rb +11 -6
  102. data/lib/avo/licensing/license.rb +1 -1
  103. data/lib/avo/licensing/license_manager.rb +1 -1
  104. data/lib/avo/licensing/{null_license.rb → nil_license.rb} +1 -1
  105. data/lib/avo/loaders/fields_loader.rb +7 -1
  106. data/lib/avo/plugin_manager.rb +2 -4
  107. data/lib/avo/reloader.rb +1 -1
  108. data/lib/avo/resources/controls/actions_list.rb +2 -1
  109. data/lib/avo/resources/items/holder.rb +5 -1
  110. data/lib/avo/resources/items/item_group.rb +1 -0
  111. data/lib/avo/resources/items/row.rb +54 -0
  112. data/lib/avo/resources/resource_manager.rb +4 -7
  113. data/lib/avo/services/debug_service.rb +6 -6
  114. data/lib/avo/services/telemetry_service.rb +3 -3
  115. data/lib/avo/version.rb +1 -1
  116. data/lib/avo.rb +107 -25
  117. data/lib/generators/avo/action_generator.rb +8 -8
  118. data/lib/generators/avo/card_generator.rb +27 -0
  119. data/lib/generators/avo/eject_generator.rb +1 -0
  120. data/lib/generators/avo/filter_generator.rb +8 -8
  121. data/lib/generators/avo/install_generator.rb +0 -1
  122. data/lib/generators/avo/resource_generator.rb +4 -1
  123. data/lib/generators/avo/templates/action.tt +3 -3
  124. data/lib/generators/avo/templates/cards/chartkick_card.tt +1 -1
  125. data/lib/generators/avo/templates/cards/chartkick_card_sample.tt +1 -1
  126. data/lib/generators/avo/templates/cards/metric_card.tt +1 -1
  127. data/lib/generators/avo/templates/cards/metric_card_sample.tt +1 -1
  128. data/lib/generators/avo/templates/cards/partial_card.tt +1 -1
  129. data/lib/generators/avo/templates/cards/partial_card_sample.tt +1 -1
  130. data/lib/generators/avo/templates/dashboards/dashboard.tt +1 -1
  131. data/lib/generators/avo/templates/resource/resource.tt +3 -4
  132. data/lib/generators/avo/templates/scope.tt +1 -1
  133. data/lib/tasks/avo_tasks.rake +1 -1
  134. data/public/avo-assets/avo.base.css +295 -165
  135. data/public/avo-assets/avo.base.js +307 -278
  136. data/public/avo-assets/avo.base.js.map +3 -3
  137. metadata +23 -10
  138. data/lib/avo/app.rb +0 -170
  139. data/lib/avo/grid_collector.rb +0 -40
  140. data/lib/generators/avo/card/chartkick_generator.rb +0 -18
  141. data/lib/generators/avo/card/metric_generator.rb +0 -18
  142. data/lib/generators/avo/card/partial_generator.rb +0 -19
  143. data/lib/generators/avo/templates/standalone_action.tt +0 -15
@@ -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' %>
@@ -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"
@@ -5,13 +5,15 @@ def pagy_locale_path(file_name)
5
5
  Avo::Engine.root.join("lib", "generators", "avo", "templates", "locales", "pagy", file_name)
6
6
  end
7
7
 
8
- Pagy::I18n.load(
9
- { locale: 'en' },
10
- { locale: 'fr' },
11
- { locale: 'nb' },
12
- { locale: 'pt-BR' },
13
- { locale: 'pt' },
14
- { locale: 'tr' },
15
- { locale: 'nn', filepath: pagy_locale_path("nn.yml") },
16
- { locale: 'ro', filepath: pagy_locale_path("ro.yml") },
17
- )
8
+ extra_locales = [
9
+ {locale: "en"},
10
+ {locale: "fr"},
11
+ {locale: "nb"},
12
+ {locale: "pt-BR"},
13
+ {locale: "pt"},
14
+ {locale: "tr"},
15
+ {locale: "nn", filepath: pagy_locale_path("nn.yml")},
16
+ {locale: "ro", filepath: pagy_locale_path("ro.yml")}
17
+ ]
18
+
19
+ Pagy::I18n.send(:build, *extra_locales)
data/config/routes.rb CHANGED
@@ -4,9 +4,9 @@ Avo::Engine.routes.draw do
4
4
  get "resources", to: redirect(Avo.configuration.root_path)
5
5
  get "dashboards", to: redirect(Avo.configuration.root_path)
6
6
 
7
- mount AvoFilters::Engine, at: "/avo_filters" if defined?(AvoFilters)
8
- mount AvoDashboards::Engine, at: "/dashboards" if defined?(AvoDashboards::Engine)
9
- mount AvoPro::Engine, at: "/avo_pro" if defined?(AvoPro)
7
+ mount Avo::DynamicFilters::Engine, at: "/avo-dynamic_filters" if defined?(Avo::DynamicFilters::Engine)
8
+ mount Avo::Dashboards::Engine, at: "/dashboards" if defined?(Avo::Dashboards::Engine)
9
+ mount Avo::Pro::Engine, at: "/avo/avo-pro" if defined?(Avo::Pro::Engine)
10
10
 
11
11
  post "/rails/active_storage/direct_uploads", to: "/active_storage/direct_uploads#create"
12
12
 
data/db/factories.rb CHANGED
@@ -110,7 +110,8 @@ FactoryBot.define do
110
110
  factory :city do
111
111
  name { Faker::Address.city }
112
112
  population { rand(10000..999000) }
113
- coordinates { [Faker::Address.latitude, Faker::Address.longitude] }
113
+ latitude { Faker::Address.latitude }
114
+ longitude { Faker::Address.longitude }
114
115
  is_capital { [true, false].sample }
115
116
  features { Faker::Address.community }
116
117
  metadata { Faker::Address.community }
@@ -24,7 +24,9 @@ module Avo
24
24
  delegate :view, to: :class
25
25
  # TODO: find a differnet way to delegate this to the uninitialized Current variable
26
26
  delegate :context, to: Avo::Current
27
- delegate :current_user, to: Avo::Current
27
+ def curent_user
28
+ Avo::Current.user
29
+ end
28
30
  delegate :params, to: Avo::Current
29
31
  delegate :view_context, to: Avo::Current
30
32
  delegate :avo, to: :view_context
@@ -86,7 +88,14 @@ module Avo
86
88
 
87
89
  def get_attributes_for_action
88
90
  get_fields.map do |field|
89
- [field.id, field.value || field.default]
91
+ value = field.value || Avo::ExecutionContext.new(
92
+ target: field.default,
93
+ record: self.class.record,
94
+ resource: self.class.resource,
95
+ view: view
96
+ ).handle
97
+
98
+ [field.id, value]
90
99
  end.to_h
91
100
  end
92
101
 
@@ -121,7 +130,7 @@ module Avo
121
130
  resource: resource
122
131
  }
123
132
 
124
- args[:records] = records unless standalone
133
+ args[:records] = records
125
134
 
126
135
  handle(**args)
127
136
 
@@ -12,7 +12,9 @@ module Avo
12
12
 
13
13
  # Avo::Current methods
14
14
  delegate :context, to: Avo::Current
15
- delegate :current_user, to: Avo::Current
15
+ def curent_user
16
+ Avo::Current.user
17
+ end
16
18
  delegate :params, to: Avo::Current
17
19
  delegate :request, to: Avo::Current
18
20
  delegate :view_context, to: Avo::Current
@@ -38,19 +40,17 @@ module Avo
38
40
  attr_accessor :record
39
41
 
40
42
  class_attribute :id, default: :id
41
- class_attribute :title, default: :id
42
- class_attribute :search_query, default: nil
43
- class_attribute :search_query_help, default: ""
44
- class_attribute :search_result_path
43
+ class_attribute :title
44
+ class_attribute :search, default: {}
45
45
  class_attribute :includes, default: []
46
46
  class_attribute :authorization_policy
47
47
  class_attribute :translation_key
48
48
  class_attribute :default_view_type, default: :table
49
49
  class_attribute :devise_password_optional, default: false
50
- class_attribute :actions_loader
51
50
  class_attribute :scopes_loader
52
51
  class_attribute :filters_loader
53
- class_attribute :grid_loader
52
+ class_attribute :view_types
53
+ class_attribute :grid_view
54
54
  class_attribute :visible_on_sidebar, default: true
55
55
  class_attribute :index_query, default: -> {
56
56
  query
@@ -58,7 +58,6 @@ module Avo
58
58
  class_attribute :find_record_method, default: -> {
59
59
  query.find id
60
60
  }
61
- class_attribute :hide_from_global_search, default: false
62
61
  class_attribute :after_create_path, default: :show
63
62
  class_attribute :after_update_path, default: :show
64
63
  class_attribute :record_selector, default: true
@@ -74,42 +73,21 @@ module Avo
74
73
  delegate :t, to: ::I18n
75
74
  delegate :context, to: ::Avo::Current
76
75
 
77
- def grid(&block)
78
- grid_collector = GridCollector.new
79
- grid_collector.instance_eval(&block)
80
-
81
- self.grid_loader = grid_collector
82
- end
83
-
84
76
  def action(action_class, arguments: {})
85
- self.actions_loader ||= Avo::Loaders::Loader.new
86
-
87
- action = {class: action_class, arguments: arguments}
88
- self.actions_loader.use action
77
+ deprecated_dsl_api __method__, "actions"
89
78
  end
90
79
 
91
80
  def filter(filter_class, arguments: {})
92
- self.filters_loader ||= Avo::Loaders::Loader.new
93
-
94
- filter = { class: filter_class , arguments: arguments }
95
- self.filters_loader.use filter
96
- end
97
-
98
- # This is the search_query scope
99
- # This should be removed and passed to the search block
100
- def scope
101
- query_scope
81
+ deprecated_dsl_api __method__, "filters"
102
82
  end
103
83
 
104
- def scopes(*args)
105
- self.scopes_loader ||= Avo::Loaders::Loader.new
106
-
107
- args.each do |scope_class|
108
- self.scopes_loader.use scope_class
109
- end
84
+ def scope(scope_class)
85
+ deprecated_dsl_api __method__, "scopes"
110
86
  end
111
87
 
112
88
  # This resolves the scope when doing "where" queries (not find queries)
89
+ #
90
+ # It's used to apply the authorization feature.
113
91
  def query_scope
114
92
  authorization.apply_policy Avo::ExecutionContext.new(
115
93
  target: index_query,
@@ -118,12 +96,14 @@ module Avo
118
96
  end
119
97
 
120
98
  # This resolves the scope when finding records (not "where" queries)
99
+ #
100
+ # It's used to apply the authorization feature.
121
101
  def find_scope
122
102
  authorization.apply_policy model_class
123
103
  end
124
104
 
125
105
  def authorization
126
- Avo::Services::AuthorizationService.new Avo::Current.current_user, model_class, policy_class: authorization_policy
106
+ Avo::Services::AuthorizationService.new Avo::Current.user, model_class, policy_class: authorization_policy
127
107
  end
128
108
 
129
109
  def get_record_associations(record)
@@ -153,8 +133,31 @@ module Avo
153
133
  end
154
134
  end
155
135
 
136
+ # Returns the model class being used for this resource.
137
+ #
138
+ # The Resource instance has a model_class method too so it can support the STI use cases
139
+ # where we figure out the model class from the record
140
+ def model_class(record_class: nil)
141
+ # get the model class off of the static property
142
+ return @model_class if @model_class.present?
143
+
144
+ # get the model class off of the record for STI models
145
+ return record_class if record_class.present?
146
+
147
+ # generate a model class
148
+ class_name.safe_constantize
149
+ end
150
+
151
+ # This is used as the model class ID
152
+ # We use this instead of the route_key to maintain compatibility with uncountable models
153
+ # With uncountable models route key appends an _index suffix (Fish->fish_index)
154
+ # Example: User->users, MediaItem->media_items, Fish->fish
155
+ def model_key
156
+ model_class.model_name.plural
157
+ end
158
+
156
159
  def class_name
157
- name.demodulize
160
+ to_s.demodulize
158
161
  end
159
162
 
160
163
  def route_key
@@ -164,11 +167,81 @@ module Avo
164
167
  def singular_route_key
165
168
  route_key.singularize
166
169
  end
170
+
171
+ def translation_key
172
+ @translation_key || "avo.resource_translations.#{class_name.underscore}"
173
+ end
174
+
175
+ def name
176
+ default = class_name.underscore.humanize
177
+
178
+ if translation_key
179
+ t(translation_key, count: 1, default: default).capitalize
180
+ else
181
+ default
182
+ end
183
+ end
184
+ alias_method :singular_name, :name
185
+
186
+ def plural_name
187
+ default = name.pluralize
188
+
189
+ if translation_key
190
+ t(translation_key, count: 2, default: default).capitalize
191
+ else
192
+ default
193
+ end
194
+ end
195
+
196
+ def underscore_name
197
+ return @name if @name.present?
198
+
199
+ name.demodulize.underscore
200
+ end
201
+
202
+ def navigation_label
203
+ plural_name.humanize
204
+ end
205
+
206
+ def find_record(id, query: nil, params: nil)
207
+ Avo::ExecutionContext.new(
208
+ target: find_record_method,
209
+ query: query || find_scope, # If no record is given we'll use the default
210
+ id: id,
211
+ params: params
212
+ ).handle
213
+ end
214
+
215
+ def search_query
216
+ search.dig(:query)
217
+ end
218
+
219
+ def fetch_search(key, record: nil)
220
+ # self.class.fetch_search
221
+ Avo::ExecutionContext.new(target: search[key], resource: self, record: record).handle
222
+ end
167
223
  end
168
224
 
169
225
  delegate :context, to: ::Avo::Current
226
+ delegate :name, to: :class
227
+ delegate :singular_name, to: :class
228
+ delegate :plural_name, to: :class
229
+ delegate :underscore_name, to: :class
230
+ delegate :underscore_name, to: :class
231
+ delegate :find_record, to: :class
232
+ delegate :model_key, to: :class
233
+
234
+ def initialize(record: nil, view: nil, user: nil, params: nil)
235
+ @view = view if view.present?
236
+ @user = user if user.present?
237
+ @params = params if params.present?
238
+
239
+ if record.present?
240
+ @record = record
241
+
242
+ hydrate_model_with_default_values if @view == :new
243
+ end
170
244
 
171
- def initialize
172
245
  detect_fields
173
246
 
174
247
  unless self.class.model_class.present?
@@ -195,54 +268,47 @@ module Avo
195
268
  # blank fields method
196
269
  end
197
270
 
198
- def hydrate(record: nil, view: nil, user: nil, params: nil)
199
- @view = view if view.present?
200
- @user = user if user.present?
201
- @params = params if params.present?
202
-
203
- if record.present?
204
- @record = record
271
+ [:action, :filter, :scope].each do |entity|
272
+ plural_entity = entity.to_s.pluralize
205
273
 
206
- hydrate_model_with_default_values if @view == :new
274
+ # def actions / def filters / def scopes
275
+ define_method plural_entity do
276
+ # blank entity method
207
277
  end
208
278
 
209
- self
210
- end
211
-
212
- def get_grid_fields
213
- return if self.class.grid_loader.blank?
214
-
215
- self.class.grid_loader.hydrate(record: @record, view: @view, resource: self)
216
- end
217
-
218
- def get_filters
219
- return [] if self.class.filters_loader.blank?
220
-
221
- self.class.filters_loader.bag
222
- end
279
+ # def action / def filter / def scope
280
+ define_method entity do |entity_class, arguments: {}|
281
+ entity_loader(entity).use({class: entity_class, arguments: arguments})
282
+ end
223
283
 
224
- def get_filter_arguments(filter_class)
225
- filter = get_filters.find { |filter| filter[:class] == filter_class.constantize }
284
+ # def get_actions / def get_filters / def get_scopes
285
+ define_method "get_#{plural_entity}" do
286
+ return entity_loader(entity).bag if entity_loader(entity).present?
226
287
 
227
- filter[:arguments]
228
- end
288
+ instance_variable_set("@#{plural_entity}_loader", Avo::Loaders::Loader.new)
289
+ send plural_entity
229
290
 
230
- def get_actions
231
- return [] if self.class.actions_loader.blank?
291
+ entity_loader(entity).bag
292
+ end
232
293
 
233
- self.class.actions_loader.bag
294
+ # def get_action_arguments / def get_filter_arguments / def get_scope_arguments
295
+ define_method "get_#{entity}_arguments" do |entity_class|
296
+ send("get_#{plural_entity}").find { |entity| entity[:class].to_s == entity_class.to_s }[:arguments]
297
+ end
234
298
  end
235
299
 
236
- def get_action_arguments(action_class)
237
- action = get_actions.find { |action| action[:class].to_s == action_class.to_s }
300
+ def hydrate(record: nil, view: nil, user: nil, params: nil)
301
+ @view = view if view.present?
302
+ @user = user if user.present?
303
+ @params = params if params.present?
238
304
 
239
- action[:arguments]
240
- end
305
+ if record.present?
306
+ @record = record
241
307
 
242
- def get_scopes
243
- return [] if self.class.scopes_loader.blank?
308
+ hydrate_model_with_default_values if @view == :new
309
+ end
244
310
 
245
- self.class.scopes_loader.bag
311
+ self
246
312
  end
247
313
 
248
314
  def default_panel_name
@@ -258,86 +324,59 @@ module Avo
258
324
  end
259
325
  end
260
326
 
327
+ # Returns the model class being used for this resource.
328
+ #
329
+ # We use the class method as a fallback but we pass it the record too so it can support the STI use cases
330
+ # where we figure out the model class from that record.
261
331
  def model_class
262
- # get the model class off of the static property
263
- return self.class.model_class if self.class.model_class.present?
332
+ record_class = @record&.class
264
333
 
265
- # get the model class off of the record
266
- return @record.base_class if @record.present?
267
-
268
- # generate a model class
269
- class_name.safe_constantize
334
+ self.class.model_class record_class: record_class
270
335
  end
271
336
 
272
337
  def record_title
273
338
  return name if @record.nil?
274
339
 
275
- the_title = @record.send title
276
- return the_title if the_title.present?
340
+ # Get the title from the record if title is not set, try to get the name, title or label, or fallback to the id
341
+ return @record.try(:name) || @record.try(:title) || @record.try(:label) || @record.id if title.nil?
277
342
 
278
- @record.id
279
- rescue
280
- name
281
- end
282
-
283
- def translation_key
284
- self.class.translation_key || "avo.resource_translations.#{class_name.underscore}"
285
- end
286
-
287
- def name
288
- default = class_name.underscore.humanize
289
-
290
- return @name if @name.present?
291
-
292
- if translation_key
293
- t(translation_key, count: 1, default: default).capitalize
294
- else
295
- default
343
+ # If the title is a symbol, get the value from the record else execute the block/string
344
+ case title
345
+ when Symbol
346
+ @record.send title
347
+ when Proc
348
+ Avo::ExecutionContext.new(target: title, resource: self, record: @record).handle
296
349
  end
297
350
  end
298
351
 
299
- def singular_name
300
- name
301
- end
302
-
303
- def plural_name
304
- default = name.pluralize
305
-
306
- if translation_key
307
- t(translation_key, count: 2, default: default).capitalize
308
- else
309
- default
352
+ def available_view_types
353
+ if self.class.view_types.present?
354
+ return Array(
355
+ Avo::ExecutionContext.new(
356
+ target: self.class.view_types,
357
+ resource: self,
358
+ record: record
359
+ ).handle
360
+ )
310
361
  end
311
- end
312
-
313
- def underscore_name
314
- return @name if @name.present?
315
-
316
- self.class.name.demodulize.underscore
317
- end
318
-
319
- def navigation_label
320
- plural_name.humanize
321
- end
322
362
 
323
- def available_view_types
324
363
  view_types = [:table]
325
364
 
326
- view_types << :grid if get_grid_fields.present?
365
+ view_types << :grid if self.class.grid_view.present?
327
366
  view_types << :map if map_view.present?
328
367
 
329
368
  view_types
330
369
  end
331
370
 
332
- def attached_file_fields
371
+ def attachment_fields
333
372
  get_field_definitions.select do |field|
334
373
  [Avo::Fields::FileField, Avo::Fields::FilesField].include? field.class
335
374
  end
336
375
  end
337
376
 
338
- def fill_record(record, params, extra_params: [])
339
- # Map the received params to their actual fields
340
- fields_by_database_id = get_field_definitions
377
+ # Map the received params to their actual fields
378
+ def fields_by_database_id
379
+ get_field_definitions
341
380
  .reject do |field|
342
381
  field.computed
343
382
  end
@@ -345,7 +384,9 @@ module Avo
345
384
  [field.database_id.to_s, field]
346
385
  end
347
386
  .to_h
387
+ end
348
388
 
389
+ def fill_record(record, params, extra_params: [])
349
390
  # Write the field values
350
391
  params.each do |key, value|
351
392
  field = fields_by_database_id[key]
@@ -365,7 +406,7 @@ module Avo
365
406
  end
366
407
 
367
408
  def authorization(user: nil)
368
- current_user = user || Avo::Current.current_user
409
+ current_user = user || Avo::Current.user
369
410
  Avo::Services::AuthorizationService.new(current_user, record || model_class, policy_class: authorization_policy)
370
411
  end
371
412
 
@@ -402,20 +443,18 @@ module Avo
402
443
  !field.computed
403
444
  end
404
445
  .map do |field|
405
- id = field.id
406
446
  value = field.value
407
447
 
408
448
  if field.type == "belongs_to"
409
- id = field.foreign_key.to_sym
410
449
 
411
450
  reflection = @record._reflections[@params[:via_relation]]
412
451
 
413
452
  if field.polymorphic_as.present? && field.types.map(&:to_s).include?(@params[:via_relation_class])
414
453
  # set the value to the actual record
415
- via_resource = Avo::App.resources.get_resource_by_model_class(@params[:via_relation_class])
454
+ via_resource = Avo.resource_manager.get_resource_by_model_class(@params[:via_relation_class])
416
455
  value = via_resource.find_record(@params[:via_record_id])
417
456
  elsif reflection.present? && reflection.foreign_key.present? && field.id.to_s == @params[:via_relation].to_s
418
- resource = Avo::App.resources.get_resource_by_model_class params[:via_relation_class]
457
+ resource = Avo.resource_manager.get_resource_by_model_class params[:via_relation_class]
419
458
  record = resource.find_record @params[:via_record_id], params: params
420
459
  id_param = reflection.options[:primary_key] || :id
421
460
 
@@ -423,28 +462,18 @@ module Avo
423
462
  end
424
463
  end
425
464
 
426
- [id, value]
465
+ [field, value]
427
466
  end
428
467
  .to_h
429
- .select do |id, value|
468
+ .select do |_, value|
430
469
  value.present?
431
470
  end
432
471
 
433
- default_values.each do |id, value|
434
- if @record.send(id).nil?
435
- @record.send("#{id}=", value)
436
- end
472
+ default_values.each do |field, value|
473
+ field.assign_value record: @record, value: value
437
474
  end
438
475
  end
439
476
 
440
- # This is used as the model class ID
441
- # We use this instead of the route_key to maintain compatibility with uncountable models
442
- # With uncountable models route key appends an _index suffix (Fish->fish_index)
443
- # Example: User->users, MediaItem->media_items, Fish->fish
444
- def model_key
445
- model_class.model_name.plural
446
- end
447
-
448
477
  def model_name
449
478
  model_class.model_name
450
479
  end
@@ -461,18 +490,6 @@ module Avo
461
490
  resources_path(resource: self)
462
491
  end
463
492
 
464
- def label_field
465
- get_field_definitions.find do |field|
466
- field.as_label.present?
467
- end
468
- rescue
469
- nil
470
- end
471
-
472
- def label
473
- label_field&.value || record_title
474
- end
475
-
476
493
  def avatar_field
477
494
  get_field_definitions.find do |field|
478
495
  field.as_avatar.present?
@@ -497,18 +514,6 @@ module Avo
497
514
  nil
498
515
  end
499
516
 
500
- def description_field
501
- get_field_definitions.find do |field|
502
- field.as_description.present?
503
- end
504
- rescue
505
- nil
506
- end
507
-
508
- def search_description
509
- description_field&.value
510
- end
511
-
512
517
  def form_scope
513
518
  model_class.base_class.to_s.underscore.downcase
514
519
  end
@@ -517,15 +522,6 @@ module Avo
517
522
  record.present? && record_id.present?
518
523
  end
519
524
 
520
- def find_record(id, query: nil, params: nil)
521
- Avo::ExecutionContext.new(
522
- target: self.class.find_record_method,
523
- query: query || self.class.find_scope,
524
- id: id,
525
- params: params
526
- ).handle
527
- end
528
-
529
525
  def id_attribute
530
526
  :id
531
527
  end
@@ -541,5 +537,11 @@ module Avo
541
537
  record: record
542
538
  }
543
539
  end
540
+
541
+ private
542
+
543
+ def entity_loader(entity)
544
+ instance_variable_get("@#{entity.to_s.pluralize}_loader")
545
+ end
544
546
  end
545
547
  end
@@ -1,4 +1,3 @@
1
-
2
1
  module Avo
3
2
  module Concerns
4
3
  module FiltersSessionHandler