avo 3.0.0.pre13 → 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.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +2 -1
- data/app/components/avo/alert_component.html.erb +1 -1
- data/app/components/avo/base_component.rb +7 -7
- data/app/components/avo/field_wrapper_component.rb +1 -1
- data/app/components/avo/fields/area_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +5 -5
- data/app/components/avo/fields/belongs_to_field/edit_component.rb +4 -4
- data/app/components/avo/fields/boolean_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/boolean_group_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/code_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/country_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/file_field/index_component.rb +2 -2
- data/app/components/avo/fields/has_one_field/show_component.html.erb +1 -0
- data/app/components/avo/fields/index_component.rb +1 -0
- data/app/components/avo/fields/location_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/markdown_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/number_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/password_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/progress_bar_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/status_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/text_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/textarea_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/trix_field/edit_component.html.erb +2 -1
- data/app/components/avo/fields/trix_field/show_component.html.erb +1 -1
- data/app/components/avo/index/resource_controls_component.rb +6 -6
- data/app/components/avo/item_switcher_component.html.erb +9 -4
- data/app/components/avo/item_switcher_component.rb +2 -1
- data/app/components/avo/resource_component.rb +5 -3
- data/app/components/avo/resource_sidebar_component.rb +1 -1
- data/app/components/avo/row_component.html.erb +3 -0
- data/app/components/avo/row_component.rb +12 -0
- data/app/components/avo/sidebar/link_component.html.erb +2 -0
- data/app/components/avo/sidebar/link_component.rb +5 -3
- data/app/components/avo/sidebar_component.html.erb +3 -3
- data/app/components/avo/sidebar_component.rb +4 -4
- data/app/components/avo/sidebar_profile_component.html.erb +3 -3
- data/app/components/avo/views/resource_edit_component.rb +1 -1
- data/app/components/avo/views/resource_index_component.html.erb +1 -1
- data/app/components/avo/views/resource_index_component.rb +8 -8
- data/app/controllers/avo/actions_controller.rb +11 -7
- data/app/controllers/avo/application_controller.rb +71 -66
- data/app/controllers/avo/associations_controller.rb +4 -6
- data/app/controllers/avo/attachments_controller.rb +1 -1
- data/app/controllers/avo/base_controller.rb +22 -15
- data/app/controllers/avo/home_controller.rb +1 -1
- data/app/controllers/avo/search_controller.rb +14 -12
- data/app/controllers/concerns/avo/initializes_avo.rb +2 -5
- data/app/javascript/js/controllers/fields/easy_mde_controller.js +1 -0
- data/app/views/avo/associations/new.html.erb +1 -1
- data/app/views/avo/debug/status.html.erb +1 -1
- data/app/views/avo/partials/_custom_tools_alert.html.erb +2 -2
- data/app/views/avo/partials/_footer.html.erb +1 -1
- data/app/views/avo/partials/_javascript.html.erb +1 -1
- data/app/views/avo/partials/_navbar.html.erb +1 -1
- data/app/views/layouts/avo/application.html.erb +2 -2
- data/avo.gemspec +1 -0
- data/config/initializers/pagy.rb +12 -10
- data/config/routes.rb +3 -3
- data/db/factories.rb +2 -1
- data/lib/avo/base_action.rb +4 -1
- data/lib/avo/base_resource.rb +118 -89
- data/lib/avo/concerns/has_item_type.rb +4 -0
- data/lib/avo/concerns/has_items.rb +20 -15
- data/lib/avo/concerns/model_class_constantized.rb +0 -2
- data/lib/avo/current.rb +22 -1
- data/lib/avo/dsl/field_parser.rb +1 -1
- data/lib/avo/dynamic_router.rb +12 -1
- data/lib/avo/engine.rb +4 -7
- data/lib/avo/fields/base_field.rb +25 -3
- data/lib/avo/fields/belongs_to_field.rb +8 -7
- data/lib/avo/fields/concerns/is_searchable.rb +1 -1
- data/lib/avo/fields/concerns/use_resource.rb +1 -1
- data/lib/avo/fields/field_manager.rb +13 -3
- data/lib/avo/fields/has_base_field.rb +4 -4
- data/lib/avo/fields/has_one_field.rb +1 -1
- data/lib/avo/fields/location_field.rb +18 -1
- data/lib/avo/licensing/h_q.rb +11 -6
- data/lib/avo/licensing/license.rb +1 -1
- data/lib/avo/licensing/license_manager.rb +1 -1
- data/lib/avo/licensing/{null_license.rb → nil_license.rb} +1 -1
- data/lib/avo/loaders/fields_loader.rb +7 -1
- data/lib/avo/plugin_manager.rb +2 -4
- data/lib/avo/reloader.rb +1 -1
- data/lib/avo/resources/items/holder.rb +5 -1
- data/lib/avo/resources/items/item_group.rb +1 -0
- data/lib/avo/resources/items/row.rb +54 -0
- data/lib/avo/resources/resource_manager.rb +4 -7
- data/lib/avo/services/debug_service.rb +6 -6
- data/lib/avo/services/telemetry_service.rb +3 -3
- data/lib/avo/version.rb +1 -1
- data/lib/avo.rb +107 -25
- data/lib/generators/avo/action_generator.rb +8 -8
- data/lib/generators/avo/card_generator.rb +27 -0
- data/lib/generators/avo/filter_generator.rb +8 -8
- data/lib/generators/avo/templates/action.tt +3 -3
- data/lib/generators/avo/templates/cards/chartkick_card.tt +1 -1
- data/lib/generators/avo/templates/cards/chartkick_card_sample.tt +1 -1
- data/lib/generators/avo/templates/cards/metric_card.tt +1 -1
- data/lib/generators/avo/templates/cards/metric_card_sample.tt +1 -1
- data/lib/generators/avo/templates/cards/partial_card.tt +1 -1
- data/lib/generators/avo/templates/cards/partial_card_sample.tt +1 -1
- data/lib/generators/avo/templates/dashboards/dashboard.tt +1 -1
- data/lib/generators/avo/templates/scope.tt +1 -1
- data/lib/tasks/avo_tasks.rake +1 -28
- data/public/avo-assets/avo.base.css +26 -31
- data/public/avo-assets/avo.base.js +281 -280
- data/public/avo-assets/avo.base.js.map +3 -3
- metadata +21 -8
- data/lib/avo/app.rb +0 -170
- data/lib/generators/avo/card/chartkick_generator.rb +0 -18
- data/lib/generators/avo/card/metric_generator.rb +0 -18
- data/lib/generators/avo/card/partial_generator.rb +0 -19
- data/lib/generators/avo/templates/standalone_action.tt +0 -15
data/config/initializers/pagy.rb
CHANGED
@@ -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
|
-
|
9
|
-
{
|
10
|
-
{
|
11
|
-
{
|
12
|
-
{
|
13
|
-
{
|
14
|
-
{
|
15
|
-
{
|
16
|
-
{
|
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
|
8
|
-
mount
|
9
|
-
mount
|
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
|
-
|
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 }
|
data/lib/avo/base_action.rb
CHANGED
@@ -101,12 +101,15 @@ module Avo
|
|
101
101
|
records, fields, current_user, resource = args.values_at(:records, :fields, :current_user, :resource)
|
102
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.
|
103
103
|
action_fields = get_field_definitions.map { |field| [field.id, field] }.to_h
|
104
|
+
puts ["action_fields->", action_fields].inspect
|
104
105
|
|
105
106
|
# For some fields, like belongs_to, the id and database_id differ (user vs user_id).
|
106
107
|
# That's why we need to fetch the database_id for when we process the action.
|
107
108
|
action_fields_by_database_id = action_fields.map do |id, value|
|
108
109
|
[value.database_id.to_sym, value]
|
109
110
|
end.to_h
|
111
|
+
puts ["action_fields_by_database_id->", action_fields_by_database_id].inspect
|
112
|
+
abort 1.inspect
|
110
113
|
|
111
114
|
if fields.present?
|
112
115
|
processed_fields = fields.to_unsafe_h.map do |name, value|
|
@@ -128,7 +131,7 @@ module Avo
|
|
128
131
|
resource: resource
|
129
132
|
}
|
130
133
|
|
131
|
-
args[:records] = records
|
134
|
+
args[:records] = records
|
132
135
|
|
133
136
|
handle(**args)
|
134
137
|
|
data/lib/avo/base_resource.rb
CHANGED
@@ -84,6 +84,8 @@ module Avo
|
|
84
84
|
end
|
85
85
|
|
86
86
|
# This resolves the scope when doing "where" queries (not find queries)
|
87
|
+
#
|
88
|
+
# It's used to apply the authorization feature.
|
87
89
|
def query_scope
|
88
90
|
authorization.apply_policy Avo::ExecutionContext.new(
|
89
91
|
target: index_query,
|
@@ -92,6 +94,8 @@ module Avo
|
|
92
94
|
end
|
93
95
|
|
94
96
|
# This resolves the scope when finding records (not "where" queries)
|
97
|
+
#
|
98
|
+
# It's used to apply the authorization feature.
|
95
99
|
def find_scope
|
96
100
|
authorization.apply_policy model_class
|
97
101
|
end
|
@@ -127,8 +131,31 @@ module Avo
|
|
127
131
|
end
|
128
132
|
end
|
129
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
|
+
|
130
157
|
def class_name
|
131
|
-
|
158
|
+
to_s.demodulize
|
132
159
|
end
|
133
160
|
|
134
161
|
def route_key
|
@@ -138,11 +165,81 @@ module Avo
|
|
138
165
|
def singular_route_key
|
139
166
|
route_key.singularize
|
140
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
|
141
221
|
end
|
142
222
|
|
143
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
|
144
242
|
|
145
|
-
def initialize
|
146
243
|
detect_fields
|
147
244
|
|
148
245
|
unless self.class.model_class.present?
|
@@ -194,7 +291,7 @@ module Avo
|
|
194
291
|
|
195
292
|
# def get_action_arguments / def get_filter_arguments / def get_scope_arguments
|
196
293
|
define_method "get_#{entity}_arguments" do |entity_class|
|
197
|
-
send("get_#{plural_entity}").find { |entity| entity[:class] == entity_class.
|
294
|
+
send("get_#{plural_entity}").find { |entity| entity[:class].to_s == entity_class.to_s }[:arguments]
|
198
295
|
end
|
199
296
|
end
|
200
297
|
|
@@ -225,15 +322,14 @@ module Avo
|
|
225
322
|
end
|
226
323
|
end
|
227
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.
|
228
329
|
def model_class
|
229
|
-
|
230
|
-
return self.class.model_class if self.class.model_class.present?
|
231
|
-
|
232
|
-
# get the model class off of the record
|
233
|
-
return @record.base_class if @record.present?
|
330
|
+
record_class = @record&.class
|
234
331
|
|
235
|
-
|
236
|
-
class_name.safe_constantize
|
332
|
+
self.class.model_class record_class: record_class
|
237
333
|
end
|
238
334
|
|
239
335
|
def record_title
|
@@ -251,46 +347,6 @@ module Avo
|
|
251
347
|
end
|
252
348
|
end
|
253
349
|
|
254
|
-
def translation_key
|
255
|
-
self.class.translation_key || "avo.resource_translations.#{class_name.underscore}"
|
256
|
-
end
|
257
|
-
|
258
|
-
def name
|
259
|
-
return @name if @name.present?
|
260
|
-
|
261
|
-
default = class_name.underscore.humanize
|
262
|
-
|
263
|
-
if translation_key
|
264
|
-
t(translation_key, count: 1, default: default).capitalize
|
265
|
-
else
|
266
|
-
default
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
def singular_name
|
271
|
-
name
|
272
|
-
end
|
273
|
-
|
274
|
-
def plural_name
|
275
|
-
default = name.pluralize
|
276
|
-
|
277
|
-
if translation_key
|
278
|
-
t(translation_key, count: 2, default: default).capitalize
|
279
|
-
else
|
280
|
-
default
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
|
-
def underscore_name
|
285
|
-
return @name if @name.present?
|
286
|
-
|
287
|
-
self.class.name.demodulize.underscore
|
288
|
-
end
|
289
|
-
|
290
|
-
def navigation_label
|
291
|
-
plural_name.humanize
|
292
|
-
end
|
293
|
-
|
294
350
|
def available_view_types
|
295
351
|
if self.class.view_types.present?
|
296
352
|
return Array(
|
@@ -310,15 +366,15 @@ module Avo
|
|
310
366
|
view_types
|
311
367
|
end
|
312
368
|
|
313
|
-
def
|
369
|
+
def attachment_fields
|
314
370
|
get_field_definitions.select do |field|
|
315
371
|
[Avo::Fields::FileField, Avo::Fields::FilesField].include? field.class
|
316
372
|
end
|
317
373
|
end
|
318
374
|
|
319
|
-
|
320
|
-
|
321
|
-
|
375
|
+
# Map the received params to their actual fields
|
376
|
+
def fields_by_database_id
|
377
|
+
get_field_definitions
|
322
378
|
.reject do |field|
|
323
379
|
field.computed
|
324
380
|
end
|
@@ -326,7 +382,9 @@ module Avo
|
|
326
382
|
[field.database_id.to_s, field]
|
327
383
|
end
|
328
384
|
.to_h
|
385
|
+
end
|
329
386
|
|
387
|
+
def fill_record(record, params, extra_params: [])
|
330
388
|
# Write the field values
|
331
389
|
params.each do |key, value|
|
332
390
|
field = fields_by_database_id[key]
|
@@ -383,20 +441,18 @@ module Avo
|
|
383
441
|
!field.computed
|
384
442
|
end
|
385
443
|
.map do |field|
|
386
|
-
id = field.id
|
387
444
|
value = field.value
|
388
445
|
|
389
446
|
if field.type == "belongs_to"
|
390
|
-
id = field.foreign_key.to_sym
|
391
447
|
|
392
448
|
reflection = @record._reflections[@params[:via_relation]]
|
393
449
|
|
394
450
|
if field.polymorphic_as.present? && field.types.map(&:to_s).include?(@params[:via_relation_class])
|
395
451
|
# set the value to the actual record
|
396
|
-
via_resource = Avo
|
452
|
+
via_resource = Avo.resource_manager.get_resource_by_model_class(@params[:via_relation_class])
|
397
453
|
value = via_resource.find_record(@params[:via_record_id])
|
398
454
|
elsif reflection.present? && reflection.foreign_key.present? && field.id.to_s == @params[:via_relation].to_s
|
399
|
-
resource = Avo
|
455
|
+
resource = Avo.resource_manager.get_resource_by_model_class params[:via_relation_class]
|
400
456
|
record = resource.find_record @params[:via_record_id], params: params
|
401
457
|
id_param = reflection.options[:primary_key] || :id
|
402
458
|
|
@@ -404,28 +460,18 @@ module Avo
|
|
404
460
|
end
|
405
461
|
end
|
406
462
|
|
407
|
-
[
|
463
|
+
[field, value]
|
408
464
|
end
|
409
465
|
.to_h
|
410
|
-
.select do |
|
466
|
+
.select do |_, value|
|
411
467
|
value.present?
|
412
468
|
end
|
413
469
|
|
414
|
-
default_values.each do |
|
415
|
-
|
416
|
-
@record.send("#{id}=", value)
|
417
|
-
end
|
470
|
+
default_values.each do |field, value|
|
471
|
+
field.assign_value record: @record, value: value
|
418
472
|
end
|
419
473
|
end
|
420
474
|
|
421
|
-
# This is used as the model class ID
|
422
|
-
# We use this instead of the route_key to maintain compatibility with uncountable models
|
423
|
-
# With uncountable models route key appends an _index suffix (Fish->fish_index)
|
424
|
-
# Example: User->users, MediaItem->media_items, Fish->fish
|
425
|
-
def model_key
|
426
|
-
model_class.model_name.plural
|
427
|
-
end
|
428
|
-
|
429
475
|
def model_name
|
430
476
|
model_class.model_name
|
431
477
|
end
|
@@ -474,15 +520,6 @@ module Avo
|
|
474
520
|
record.present? && record_id.present?
|
475
521
|
end
|
476
522
|
|
477
|
-
def find_record(id, query: nil, params: nil)
|
478
|
-
Avo::ExecutionContext.new(
|
479
|
-
target: self.class.find_record_method,
|
480
|
-
query: query || self.class.find_scope,
|
481
|
-
id: id,
|
482
|
-
params: params
|
483
|
-
).handle
|
484
|
-
end
|
485
|
-
|
486
523
|
def id_attribute
|
487
524
|
:id
|
488
525
|
end
|
@@ -499,14 +536,6 @@ module Avo
|
|
499
536
|
}
|
500
537
|
end
|
501
538
|
|
502
|
-
def search_query
|
503
|
-
self.class.search.dig(:query)
|
504
|
-
end
|
505
|
-
|
506
|
-
def fetch_search(key)
|
507
|
-
Avo::ExecutionContext.new(target: self.class.search[key], resource: self, record: record).handle
|
508
|
-
end
|
509
|
-
|
510
539
|
private
|
511
540
|
|
512
541
|
def entity_loader(entity)
|
@@ -18,6 +18,10 @@ module Avo
|
|
18
18
|
deprecated_dsl_api __method__, "fields"
|
19
19
|
end
|
20
20
|
|
21
|
+
def row(**args, &block)
|
22
|
+
deprecated_dsl_api __method__, "fields"
|
23
|
+
end
|
24
|
+
|
21
25
|
def tabs(**args, &block)
|
22
26
|
deprecated_dsl_api __method__, "fields"
|
23
27
|
end
|
@@ -42,6 +46,7 @@ module Avo
|
|
42
46
|
|
43
47
|
delegate :field, to: :items_holder
|
44
48
|
delegate :panel, to: :items_holder
|
49
|
+
delegate :row, to: :items_holder
|
45
50
|
delegate :tabs, to: :items_holder
|
46
51
|
delegate :tool, to: :items_holder
|
47
52
|
delegate :heading, to: :items_holder
|
@@ -96,6 +101,10 @@ module Avo
|
|
96
101
|
if item.is_field?
|
97
102
|
fields << item
|
98
103
|
end
|
104
|
+
|
105
|
+
if item.is_row?
|
106
|
+
fields << extract_fields_from_items(tab)
|
107
|
+
end
|
99
108
|
end
|
100
109
|
|
101
110
|
fields.flatten
|
@@ -213,8 +222,10 @@ module Avo
|
|
213
222
|
panelfull_items.grep(Avo::Resources::Items::TabGroup).each do |tab_group|
|
214
223
|
tab_group.items.grep(Avo::Resources::Items::Tab).each do |tab|
|
215
224
|
tab.items.grep(Avo::Resources::Items::Panel).each do |panel|
|
216
|
-
panel.items.grep(Avo::Fields::BelongsToField)
|
217
|
-
|
225
|
+
set_target_to_top panel.items.grep(Avo::Fields::BelongsToField)
|
226
|
+
|
227
|
+
panel.items.grep(Avo::Resources::Items::Row).each do |row|
|
228
|
+
set_target_to_top row.items.grep(Avo::Fields::BelongsToField)
|
218
229
|
end
|
219
230
|
end
|
220
231
|
end
|
@@ -250,9 +261,6 @@ module Avo
|
|
250
261
|
|
251
262
|
item
|
252
263
|
end
|
253
|
-
.select do |item|
|
254
|
-
item.visible_in_view?(view: view)
|
255
|
-
end
|
256
264
|
.select do |item|
|
257
265
|
item.visible?
|
258
266
|
end
|
@@ -264,7 +272,8 @@ module Avo
|
|
264
272
|
end
|
265
273
|
end
|
266
274
|
.select do |item|
|
267
|
-
|
275
|
+
# On location field we can have field coordinates and setters with different names like latitude and longitude
|
276
|
+
if !item.is_a?(Avo::Fields::LocationField) && !item.is_heading? && view.in?([:edit, :update, :new, :create])
|
268
277
|
if item.respond_to?(:id)
|
269
278
|
item.resource.record.respond_to?("#{item.id}=")
|
270
279
|
else
|
@@ -290,25 +299,21 @@ module Avo
|
|
290
299
|
visible_items.blank?
|
291
300
|
end
|
292
301
|
|
293
|
-
|
294
|
-
super(**args)
|
302
|
+
private
|
295
303
|
|
296
|
-
|
297
|
-
|
304
|
+
def set_target_to_top(fields)
|
305
|
+
fields.each do |field|
|
306
|
+
field.target = :_top
|
298
307
|
end
|
299
|
-
|
300
|
-
self
|
301
308
|
end
|
302
309
|
|
303
|
-
private
|
304
|
-
|
305
310
|
def extract_fields_from_items(thing)
|
306
311
|
fields = []
|
307
312
|
|
308
313
|
thing.items.each do |item|
|
309
314
|
if item.is_field?
|
310
315
|
fields << item
|
311
|
-
elsif item.is_panel?
|
316
|
+
elsif item.is_panel? || item.is_row?
|
312
317
|
fields << extract_fields_from_items(item)
|
313
318
|
end
|
314
319
|
end
|
data/lib/avo/current.rb
CHANGED
@@ -1,9 +1,30 @@
|
|
1
1
|
class Avo::Current < ActiveSupport::CurrentAttributes
|
2
|
+
# if Rails.env.development?
|
3
|
+
# singleton_class.attr_accessor :previous_attributes
|
4
|
+
# before_reset {
|
5
|
+
# puts ["before_reset->", self.previous_attributes].inspect
|
6
|
+
# if attributes.present?
|
7
|
+
# puts ["has attributes->"].inspect
|
8
|
+
# self.previous_attributes = attributes
|
9
|
+
# end
|
10
|
+
# puts ["before_reset->", self.previous_attributes].inspect
|
11
|
+
# }
|
12
|
+
|
13
|
+
# attr_accessor :previous_attributes
|
14
|
+
|
15
|
+
# def previous_attributes=(value)
|
16
|
+
# @previous_attributes = value
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
|
2
20
|
attribute :app
|
3
21
|
attribute :license
|
4
22
|
attribute :context, :current_user, :view_context
|
23
|
+
attribute :error_manager
|
24
|
+
attribute :resource_manager
|
25
|
+
attribute :tool_manager
|
26
|
+
attribute :plugin_manager
|
5
27
|
|
6
|
-
delegate :request, to: :view_context
|
7
28
|
delegate :params, to: :request
|
8
29
|
|
9
30
|
def request
|
data/lib/avo/dsl/field_parser.rb
CHANGED
data/lib/avo/dynamic_router.rb
CHANGED
@@ -1,12 +1,23 @@
|
|
1
1
|
module Avo
|
2
2
|
class DynamicRouter
|
3
|
+
def self.eager_load(entity)
|
4
|
+
paths = Avo::ENTITIES.fetch entity
|
5
|
+
|
6
|
+
return unless paths.present?
|
7
|
+
|
8
|
+
pathname = Rails.root.join(*paths)
|
9
|
+
if pathname.directory?
|
10
|
+
Rails.autoloaders.main.eager_load_dir(pathname.to_s)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
3
14
|
def self.routes
|
4
15
|
Avo::Engine.routes.draw do
|
5
16
|
scope "resources", as: "resources" do
|
6
17
|
# Check if the user chose to manually register the resource files.
|
7
18
|
# If so, eager_load the resources dir.
|
8
19
|
if Avo.configuration.resources.nil?
|
9
|
-
Avo::
|
20
|
+
Avo::DynamicRouter.eager_load(:resources) unless Rails.application.config.eager_load
|
10
21
|
end
|
11
22
|
|
12
23
|
Avo::Resources::ResourceManager.fetch_resources
|
data/lib/avo/engine.rb
CHANGED
@@ -3,6 +3,8 @@ Gem.loaded_specs["avo"].dependencies.each do |d|
|
|
3
3
|
case d.name
|
4
4
|
when "activerecord"
|
5
5
|
require "active_record/railtie"
|
6
|
+
when "activesupport"
|
7
|
+
require "active_support/railtie"
|
6
8
|
when "actionview"
|
7
9
|
require "action_view/railtie"
|
8
10
|
when "activestorage"
|
@@ -23,7 +25,7 @@ module Avo
|
|
23
25
|
::Avo.asset_manager.reset
|
24
26
|
|
25
27
|
# Boot Avo
|
26
|
-
::Avo
|
28
|
+
::Avo.boot
|
27
29
|
|
28
30
|
# After deploy we want to make sure the license response is being cleared.
|
29
31
|
# We need a fresh license response.
|
@@ -40,7 +42,7 @@ module Avo
|
|
40
42
|
# Ensure we reboot the app when something changes
|
41
43
|
config.to_prepare do
|
42
44
|
# Boot Avo
|
43
|
-
::Avo
|
45
|
+
::Avo.boot
|
44
46
|
end
|
45
47
|
|
46
48
|
initializer "avo.autoload" do |app|
|
@@ -55,10 +57,6 @@ module Avo
|
|
55
57
|
end
|
56
58
|
end
|
57
59
|
|
58
|
-
initializer "avo.init_fields" do |app|
|
59
|
-
::Avo::App.init_fields
|
60
|
-
end
|
61
|
-
|
62
60
|
initializer "avo.reloader" do |app|
|
63
61
|
Avo::Reloader.new.tap do |reloader|
|
64
62
|
reloader.execute
|
@@ -94,7 +92,6 @@ module Avo
|
|
94
92
|
|
95
93
|
initializer "avo.locales" do |app|
|
96
94
|
I18n.load_path += Dir[Avo::Engine.root.join("lib", "generators", "avo", "templates", "locales", "*.{rb,yml}")]
|
97
|
-
I18n.load_path += Dir[Rails.root.join("config", "locales", "*.{rb,yml}")]
|
98
95
|
end
|
99
96
|
end
|
100
97
|
end
|
@@ -65,6 +65,7 @@ module Avo
|
|
65
65
|
@nullable = args[:nullable] || false
|
66
66
|
@null_values = args[:null_values] || [nil, ""]
|
67
67
|
@format_using = args[:format_using] || nil
|
68
|
+
@update_using = args[:update_using] || nil
|
68
69
|
@placeholder = args[:placeholder]
|
69
70
|
@autocomplete = args[:autocomplete] || nil
|
70
71
|
@help = args[:help] || nil
|
@@ -170,8 +171,8 @@ module Avo
|
|
170
171
|
target: format_using,
|
171
172
|
value: final_value,
|
172
173
|
record: record,
|
173
|
-
resource:
|
174
|
-
view:
|
174
|
+
resource: resource,
|
175
|
+
view: view,
|
175
176
|
field: self,
|
176
177
|
include: self.class.included_modules
|
177
178
|
).handle
|
@@ -180,10 +181,22 @@ module Avo
|
|
180
181
|
final_value
|
181
182
|
end
|
182
183
|
|
184
|
+
# Fills the record with the received value on create and update actions.
|
183
185
|
def fill_field(record, key, value, params)
|
184
186
|
return record unless record.methods.include? key.to_sym
|
185
187
|
|
186
|
-
|
188
|
+
if @update_using.present?
|
189
|
+
value = Avo::ExecutionContext.new(
|
190
|
+
target: @update_using,
|
191
|
+
record: record,
|
192
|
+
key: key,
|
193
|
+
value: value,
|
194
|
+
resource: resource,
|
195
|
+
field: self
|
196
|
+
).handle
|
197
|
+
end
|
198
|
+
|
199
|
+
record.public_send("#{key}=", value)
|
187
200
|
|
188
201
|
record
|
189
202
|
end
|
@@ -264,6 +277,15 @@ module Avo
|
|
264
277
|
!is_disabled? && visible?
|
265
278
|
end
|
266
279
|
|
280
|
+
# Used by Avo to fill the record with the default value on :new and :edit views
|
281
|
+
def assign_value(record:, value:)
|
282
|
+
id = type == "belongs_to" ? foreign_key : database_id
|
283
|
+
|
284
|
+
if record.send(id).nil?
|
285
|
+
record.send("#{id}=", value)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
267
289
|
private
|
268
290
|
|
269
291
|
def model_or_class(model)
|