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
@@ -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 }
@@ -86,7 +86,14 @@ module Avo
86
86
 
87
87
  def get_attributes_for_action
88
88
  get_fields.map do |field|
89
- [field.id, field.value || field.default]
89
+ value = field.value || Avo::ExecutionContext.new(
90
+ target: field.default,
91
+ record: self.class.record,
92
+ resource: self.class.resource,
93
+ view: view
94
+ ).handle
95
+
96
+ [field.id, value]
90
97
  end.to_h
91
98
  end
92
99
 
@@ -94,12 +101,15 @@ module Avo
94
101
  records, fields, current_user, resource = args.values_at(:records, :fields, :current_user, :resource)
95
102
  # Fetching the field definitions and not the actual fields (get_fields) because they will break if the user uses a `visible` block and adds a condition using the `params` variable. The params are different in the show method and the handle method.
96
103
  action_fields = get_field_definitions.map { |field| [field.id, field] }.to_h
104
+ puts ["action_fields->", action_fields].inspect
97
105
 
98
106
  # For some fields, like belongs_to, the id and database_id differ (user vs user_id).
99
107
  # That's why we need to fetch the database_id for when we process the action.
100
108
  action_fields_by_database_id = action_fields.map do |id, value|
101
109
  [value.database_id.to_sym, value]
102
110
  end.to_h
111
+ puts ["action_fields_by_database_id->", action_fields_by_database_id].inspect
112
+ abort 1.inspect
103
113
 
104
114
  if fields.present?
105
115
  processed_fields = fields.to_unsafe_h.map do |name, value|
@@ -121,7 +131,7 @@ module Avo
121
131
  resource: resource
122
132
  }
123
133
 
124
- args[:records] = records unless standalone
134
+ args[:records] = records
125
135
 
126
136
  handle(**args)
127
137
 
@@ -38,19 +38,17 @@ module Avo
38
38
  attr_accessor :record
39
39
 
40
40
  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
41
+ class_attribute :title
42
+ class_attribute :search, default: {}
45
43
  class_attribute :includes, default: []
46
44
  class_attribute :authorization_policy
47
45
  class_attribute :translation_key
48
46
  class_attribute :default_view_type, default: :table
49
47
  class_attribute :devise_password_optional, default: false
50
- class_attribute :actions_loader
51
48
  class_attribute :scopes_loader
52
49
  class_attribute :filters_loader
53
- class_attribute :grid_loader
50
+ class_attribute :view_types
51
+ class_attribute :grid_view
54
52
  class_attribute :visible_on_sidebar, default: true
55
53
  class_attribute :index_query, default: -> {
56
54
  query
@@ -58,7 +56,6 @@ module Avo
58
56
  class_attribute :find_record_method, default: -> {
59
57
  query.find id
60
58
  }
61
- class_attribute :hide_from_global_search, default: false
62
59
  class_attribute :after_create_path, default: :show
63
60
  class_attribute :after_update_path, default: :show
64
61
  class_attribute :record_selector, default: true
@@ -74,42 +71,21 @@ module Avo
74
71
  delegate :t, to: ::I18n
75
72
  delegate :context, to: ::Avo::Current
76
73
 
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
74
  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
75
+ deprecated_dsl_api __method__, "actions"
89
76
  end
90
77
 
91
78
  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
79
+ deprecated_dsl_api __method__, "filters"
102
80
  end
103
81
 
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
82
+ def scope(scope_class)
83
+ deprecated_dsl_api __method__, "scopes"
110
84
  end
111
85
 
112
86
  # This resolves the scope when doing "where" queries (not find queries)
87
+ #
88
+ # It's used to apply the authorization feature.
113
89
  def query_scope
114
90
  authorization.apply_policy Avo::ExecutionContext.new(
115
91
  target: index_query,
@@ -118,6 +94,8 @@ module Avo
118
94
  end
119
95
 
120
96
  # This resolves the scope when finding records (not "where" queries)
97
+ #
98
+ # It's used to apply the authorization feature.
121
99
  def find_scope
122
100
  authorization.apply_policy model_class
123
101
  end
@@ -153,8 +131,31 @@ module Avo
153
131
  end
154
132
  end
155
133
 
134
+ # Returns the model class being used for this resource.
135
+ #
136
+ # The Resource instance has a model_class method too so it can support the STI use cases
137
+ # where we figure out the model class from the record
138
+ def model_class(record_class: nil)
139
+ # get the model class off of the static property
140
+ return @model_class if @model_class.present?
141
+
142
+ # get the model class off of the record for STI models
143
+ return record_class if record_class.present?
144
+
145
+ # generate a model class
146
+ class_name.safe_constantize
147
+ end
148
+
149
+ # This is used as the model class ID
150
+ # We use this instead of the route_key to maintain compatibility with uncountable models
151
+ # With uncountable models route key appends an _index suffix (Fish->fish_index)
152
+ # Example: User->users, MediaItem->media_items, Fish->fish
153
+ def model_key
154
+ model_class.model_name.plural
155
+ end
156
+
156
157
  def class_name
157
- name.demodulize
158
+ to_s.demodulize
158
159
  end
159
160
 
160
161
  def route_key
@@ -164,11 +165,81 @@ module Avo
164
165
  def singular_route_key
165
166
  route_key.singularize
166
167
  end
168
+
169
+ def translation_key
170
+ @translation_key || "avo.resource_translations.#{class_name.underscore}"
171
+ end
172
+
173
+ def name
174
+ default = class_name.underscore.humanize
175
+
176
+ if translation_key
177
+ t(translation_key, count: 1, default: default).capitalize
178
+ else
179
+ default
180
+ end
181
+ end
182
+ alias_method :singular_name, :name
183
+
184
+ def plural_name
185
+ default = name.pluralize
186
+
187
+ if translation_key
188
+ t(translation_key, count: 2, default: default).capitalize
189
+ else
190
+ default
191
+ end
192
+ end
193
+
194
+ def underscore_name
195
+ return @name if @name.present?
196
+
197
+ name.demodulize.underscore
198
+ end
199
+
200
+ def navigation_label
201
+ plural_name.humanize
202
+ end
203
+
204
+ def find_record(id, query: nil, params: nil)
205
+ Avo::ExecutionContext.new(
206
+ target: find_record_method,
207
+ query: query || find_scope, # If no record is given we'll use the default
208
+ id: id,
209
+ params: params
210
+ ).handle
211
+ end
212
+
213
+ def search_query
214
+ search.dig(:query)
215
+ end
216
+
217
+ def fetch_search(key, record: nil)
218
+ # self.class.fetch_search
219
+ Avo::ExecutionContext.new(target: search[key], resource: self, record: record).handle
220
+ end
167
221
  end
168
222
 
169
223
  delegate :context, to: ::Avo::Current
224
+ delegate :name, to: :class
225
+ delegate :singular_name, to: :class
226
+ delegate :plural_name, to: :class
227
+ delegate :underscore_name, to: :class
228
+ delegate :underscore_name, to: :class
229
+ delegate :find_record, to: :class
230
+ delegate :model_key, to: :class
231
+
232
+ def initialize(record: nil, view: nil, user: nil, params: nil)
233
+ @view = view if view.present?
234
+ @user = user if user.present?
235
+ @params = params if params.present?
236
+
237
+ if record.present?
238
+ @record = record
239
+
240
+ hydrate_model_with_default_values if @view == :new
241
+ end
170
242
 
171
- def initialize
172
243
  detect_fields
173
244
 
174
245
  unless self.class.model_class.present?
@@ -195,54 +266,47 @@ module Avo
195
266
  # blank fields method
196
267
  end
197
268
 
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
269
+ [:action, :filter, :scope].each do |entity|
270
+ plural_entity = entity.to_s.pluralize
205
271
 
206
- hydrate_model_with_default_values if @view == :new
272
+ # def actions / def filters / def scopes
273
+ define_method plural_entity do
274
+ # blank entity method
207
275
  end
208
276
 
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
277
+ # def action / def filter / def scope
278
+ define_method entity do |entity_class, arguments: {}|
279
+ entity_loader(entity).use({class: entity_class, arguments: arguments})
280
+ end
223
281
 
224
- def get_filter_arguments(filter_class)
225
- filter = get_filters.find { |filter| filter[:class] == filter_class.constantize }
282
+ # def get_actions / def get_filters / def get_scopes
283
+ define_method "get_#{plural_entity}" do
284
+ return entity_loader(entity).bag if entity_loader(entity).present?
226
285
 
227
- filter[:arguments]
228
- end
286
+ instance_variable_set("@#{plural_entity}_loader", Avo::Loaders::Loader.new)
287
+ send plural_entity
229
288
 
230
- def get_actions
231
- return [] if self.class.actions_loader.blank?
289
+ entity_loader(entity).bag
290
+ end
232
291
 
233
- self.class.actions_loader.bag
292
+ # def get_action_arguments / def get_filter_arguments / def get_scope_arguments
293
+ define_method "get_#{entity}_arguments" do |entity_class|
294
+ send("get_#{plural_entity}").find { |entity| entity[:class].to_s == entity_class.to_s }[:arguments]
295
+ end
234
296
  end
235
297
 
236
- def get_action_arguments(action_class)
237
- action = get_actions.find { |action| action[:class].to_s == action_class.to_s }
298
+ def hydrate(record: nil, view: nil, user: nil, params: nil)
299
+ @view = view if view.present?
300
+ @user = user if user.present?
301
+ @params = params if params.present?
238
302
 
239
- action[:arguments]
240
- end
303
+ if record.present?
304
+ @record = record
241
305
 
242
- def get_scopes
243
- return [] if self.class.scopes_loader.blank?
306
+ hydrate_model_with_default_values if @view == :new
307
+ end
244
308
 
245
- self.class.scopes_loader.bag
309
+ self
246
310
  end
247
311
 
248
312
  def default_panel_name
@@ -258,86 +322,59 @@ module Avo
258
322
  end
259
323
  end
260
324
 
325
+ # Returns the model class being used for this resource.
326
+ #
327
+ # We use the class method as a fallback but we pass it the record too so it can support the STI use cases
328
+ # where we figure out the model class from that record.
261
329
  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?
330
+ record_class = @record&.class
264
331
 
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
332
+ self.class.model_class record_class: record_class
270
333
  end
271
334
 
272
335
  def record_title
273
336
  return name if @record.nil?
274
337
 
275
- the_title = @record.send title
276
- return the_title if the_title.present?
338
+ # Get the title from the record if title is not set, try to get the name, title or label, or fallback to the id
339
+ return @record.try(:name) || @record.try(:title) || @record.try(:label) || @record.id if title.nil?
277
340
 
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
341
+ # If the title is a symbol, get the value from the record else execute the block/string
342
+ case title
343
+ when Symbol
344
+ @record.send title
345
+ when Proc
346
+ Avo::ExecutionContext.new(target: title, resource: self, record: @record).handle
296
347
  end
297
348
  end
298
349
 
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
350
+ def available_view_types
351
+ if self.class.view_types.present?
352
+ return Array(
353
+ Avo::ExecutionContext.new(
354
+ target: self.class.view_types,
355
+ resource: self,
356
+ record: record
357
+ ).handle
358
+ )
310
359
  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
360
 
323
- def available_view_types
324
361
  view_types = [:table]
325
362
 
326
- view_types << :grid if get_grid_fields.present?
363
+ view_types << :grid if self.class.grid_view.present?
327
364
  view_types << :map if map_view.present?
328
365
 
329
366
  view_types
330
367
  end
331
368
 
332
- def attached_file_fields
369
+ def attachment_fields
333
370
  get_field_definitions.select do |field|
334
371
  [Avo::Fields::FileField, Avo::Fields::FilesField].include? field.class
335
372
  end
336
373
  end
337
374
 
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
375
+ # Map the received params to their actual fields
376
+ def fields_by_database_id
377
+ get_field_definitions
341
378
  .reject do |field|
342
379
  field.computed
343
380
  end
@@ -345,7 +382,9 @@ module Avo
345
382
  [field.database_id.to_s, field]
346
383
  end
347
384
  .to_h
385
+ end
348
386
 
387
+ def fill_record(record, params, extra_params: [])
349
388
  # Write the field values
350
389
  params.each do |key, value|
351
390
  field = fields_by_database_id[key]
@@ -402,20 +441,18 @@ module Avo
402
441
  !field.computed
403
442
  end
404
443
  .map do |field|
405
- id = field.id
406
444
  value = field.value
407
445
 
408
446
  if field.type == "belongs_to"
409
- id = field.foreign_key.to_sym
410
447
 
411
448
  reflection = @record._reflections[@params[:via_relation]]
412
449
 
413
450
  if field.polymorphic_as.present? && field.types.map(&:to_s).include?(@params[:via_relation_class])
414
451
  # set the value to the actual record
415
- via_resource = Avo::App.resources.get_resource_by_model_class(@params[:via_relation_class])
452
+ via_resource = Avo.resource_manager.get_resource_by_model_class(@params[:via_relation_class])
416
453
  value = via_resource.find_record(@params[:via_record_id])
417
454
  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]
455
+ resource = Avo.resource_manager.get_resource_by_model_class params[:via_relation_class]
419
456
  record = resource.find_record @params[:via_record_id], params: params
420
457
  id_param = reflection.options[:primary_key] || :id
421
458
 
@@ -423,28 +460,18 @@ module Avo
423
460
  end
424
461
  end
425
462
 
426
- [id, value]
463
+ [field, value]
427
464
  end
428
465
  .to_h
429
- .select do |id, value|
466
+ .select do |_, value|
430
467
  value.present?
431
468
  end
432
469
 
433
- default_values.each do |id, value|
434
- if @record.send(id).nil?
435
- @record.send("#{id}=", value)
436
- end
470
+ default_values.each do |field, value|
471
+ field.assign_value record: @record, value: value
437
472
  end
438
473
  end
439
474
 
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
475
  def model_name
449
476
  model_class.model_name
450
477
  end
@@ -461,18 +488,6 @@ module Avo
461
488
  resources_path(resource: self)
462
489
  end
463
490
 
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
491
  def avatar_field
477
492
  get_field_definitions.find do |field|
478
493
  field.as_avatar.present?
@@ -497,18 +512,6 @@ module Avo
497
512
  nil
498
513
  end
499
514
 
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
515
  def form_scope
513
516
  model_class.base_class.to_s.underscore.downcase
514
517
  end
@@ -517,15 +520,6 @@ module Avo
517
520
  record.present? && record_id.present?
518
521
  end
519
522
 
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
523
  def id_attribute
530
524
  :id
531
525
  end
@@ -541,5 +535,11 @@ module Avo
541
535
  record: record
542
536
  }
543
537
  end
538
+
539
+ private
540
+
541
+ def entity_loader(entity)
542
+ instance_variable_get("@#{entity.to_s.pluralize}_loader")
543
+ end
544
544
  end
545
545
  end
@@ -1,4 +1,3 @@
1
-
2
1
  module Avo
3
2
  module Concerns
4
3
  module FiltersSessionHandler
@@ -33,6 +33,10 @@ module Avo
33
33
  def is_sidebar?
34
34
  self.class.ancestors.include?(Avo::Resources::Items::Sidebar)
35
35
  end
36
+
37
+ def is_row?
38
+ self.class.respond_to?(:item_type) && self.class.item_type == :row
39
+ end
36
40
  end
37
41
  end
38
42
  end