avo 1.6.4.pre.1 → 1.7.3
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 +3 -1
- data/Gemfile.lock +90 -69
- data/README.md +2 -2
- data/app/components/avo/edit/field_wrapper_component.html.erb +1 -1
- data/app/components/avo/edit/field_wrapper_component.rb +6 -1
- data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +65 -15
- data/app/components/avo/fields/belongs_to_field/edit_component.rb +1 -1
- data/app/components/avo/fields/common/badge_viewer_component.html.erb +1 -1
- data/app/components/avo/fields/common/multiple_file_viewer_component.html.erb +1 -1
- data/app/components/avo/fields/common/single_file_viewer_component.html.erb +1 -1
- data/app/components/avo/fields/file_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/trix_field/edit_component.html.erb +3 -0
- data/app/components/avo/index/grid_item_component.html.erb +4 -6
- data/app/components/avo/views/resource_index_component.html.erb +48 -46
- data/app/components/avo/views/resource_index_component.rb +1 -1
- data/app/controllers/avo/application_controller.rb +11 -9
- data/app/controllers/avo/base_controller.rb +21 -0
- data/app/controllers/avo/search_controller.rb +3 -1
- data/app/packs/js/controllers/fields/belongs_to_field_controller.js +65 -0
- data/app/packs/js/controllers/fields/trix_field_controller.js +16 -0
- data/app/views/avo/actions/show.html.erb +1 -1
- data/app/views/avo/attachments/show.html.erb +1 -1
- data/app/views/avo/base/_actions.html.erb +2 -2
- data/app/views/avo/home/index.html.erb +2 -2
- data/app/views/avo/partials/_javascript.html.erb +1 -1
- data/app/views/avo/partials/_resource_search.html.erb +1 -1
- data/app/views/avo/relations/new.html.erb +1 -1
- data/app/views/avo/sidebar/_sidebar.html.erb +1 -1
- data/db/factories.rb +4 -0
- data/lib/avo/app.rb +3 -1
- data/lib/avo/base_resource.rb +40 -43
- data/lib/avo/configuration.rb +7 -1
- data/lib/avo/fields/base_field.rb +5 -3
- data/lib/avo/fields/belongs_to_field.rb +96 -12
- data/lib/avo/fields/boolean_group_field.rb +1 -1
- data/lib/avo/fields/date_time_field.rb +1 -1
- data/lib/avo/fields/file_field.rb +0 -8
- data/lib/avo/fields/files_field.rb +1 -1
- data/lib/avo/fields/has_and_belongs_to_many_field.rb +4 -4
- data/lib/avo/fields/has_many_field.rb +4 -4
- data/lib/avo/fields/has_one_field.rb +5 -5
- data/lib/avo/fields/key_value_field.rb +1 -1
- data/lib/avo/fields/trix_field.rb +6 -0
- data/lib/avo/fields_collector.rb +0 -2
- data/lib/avo/version.rb +1 -1
- data/lib/generators/avo/field_generator.rb +1 -1
- data/lib/generators/avo/install_generator.rb +1 -1
- data/lib/generators/avo/templates/initializer/avo.tt +1 -0
- data/lib/generators/avo/templates/tool/sidebar_item.tt +1 -1
- data/public/avo-packs/css/application-797341b7.css.map +1 -1
- data/public/avo-packs/css/application-797341b7.css.map.br +0 -0
- data/public/avo-packs/css/application-797341b7.css.map.gz +0 -0
- data/public/avo-packs/js/application-651ed7b9bc727c83f673.js +26 -0
- data/public/avo-packs/js/{application-b444cbf11135b4b23654.js.LICENSE.txt → application-651ed7b9bc727c83f673.js.LICENSE.txt} +0 -0
- data/public/avo-packs/js/application-651ed7b9bc727c83f673.js.br +0 -0
- data/public/avo-packs/js/application-651ed7b9bc727c83f673.js.gz +0 -0
- data/public/avo-packs/js/application-651ed7b9bc727c83f673.js.map +1 -0
- data/public/avo-packs/js/application-651ed7b9bc727c83f673.js.map.br +0 -0
- data/public/avo-packs/js/application-651ed7b9bc727c83f673.js.map.gz +0 -0
- data/public/avo-packs/manifest.json +8 -8
- metadata +12 -11
- data/public/avo-packs/js/application-b444cbf11135b4b23654.js +0 -26
- data/public/avo-packs/js/application-b444cbf11135b4b23654.js.br +0 -0
- data/public/avo-packs/js/application-b444cbf11135b4b23654.js.gz +0 -0
- data/public/avo-packs/js/application-b444cbf11135b4b23654.js.map +0 -1
- data/public/avo-packs/js/application-b444cbf11135b4b23654.js.map.br +0 -0
- data/public/avo-packs/js/application-b444cbf11135b4b23654.js.map.gz +0 -0
@@ -1,5 +1,5 @@
|
|
1
1
|
<%= javascript_tag nonce: true do %>
|
2
2
|
window.Avo = window.Avo || { configuration: {} }
|
3
3
|
Avo.configuration.timezone = '<%= Avo.configuration.timezone %>'
|
4
|
-
Avo.configuration.root_path = '<%= Avo.
|
4
|
+
Avo.configuration.root_path = '<%= Avo::App.root_path %>'
|
5
5
|
<% end %>
|
@@ -6,5 +6,5 @@
|
|
6
6
|
data-debounce-timeout='<%= Avo.configuration.search_debounce %>'
|
7
7
|
>
|
8
8
|
</div>
|
9
|
-
<div class="relative inline-flex text-gray-400 text-sm border border-gray-300 rounded-full cursor-pointer" data-search-target="button"></div>
|
9
|
+
<div class="hidden relative inline-flex text-gray-400 text-sm border border-gray-300 rounded-full cursor-pointer" data-search-target="button"></div>
|
10
10
|
</div>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<%= turbo_frame_tag 'attach_modal' do %>
|
2
2
|
<%= form_with scope: 'fields',
|
3
|
-
url: "#{
|
3
|
+
url: "#{avo.root_path}resources/#{params[:resource_name]}/#{params[:id]}/#{params[:related_name]}/",
|
4
4
|
data: {
|
5
5
|
'turbo-frame': '_top'
|
6
6
|
} do |form| %>
|
@@ -6,7 +6,7 @@
|
|
6
6
|
|
7
7
|
<div class="flex-1 flex flex-col justify-between">
|
8
8
|
<div class="tools py-4">
|
9
|
-
<%= render Avo::NavigationLinkComponent.new label: 'Get started', path:
|
9
|
+
<%= render Avo::NavigationLinkComponent.new label: 'Get started', path: avo.root_path, active: :exclusive if Rails.env.development? && Avo.configuration.home_path.nil? %>
|
10
10
|
|
11
11
|
<%= render Avo::NavigationHeadingComponent.new label: t('avo.resources') %>
|
12
12
|
|
data/db/factories.rb
CHANGED
@@ -40,4 +40,8 @@ FactoryBot.define do
|
|
40
40
|
meta { [{foo: "bar", hey: "hi"}, {bar: "baz"}, {hoho: "hohoho"}].sample }
|
41
41
|
progress { Faker::Number.between(from: 0, to: 100) }
|
42
42
|
end
|
43
|
+
|
44
|
+
factory :comment do
|
45
|
+
body { Faker::Lorem.paragraphs(number: rand(4...10)).join("\n") }
|
46
|
+
end
|
43
47
|
end
|
data/lib/avo/app.rb
CHANGED
@@ -7,6 +7,7 @@ module Avo
|
|
7
7
|
class_attribute :context, default: nil
|
8
8
|
class_attribute :license, default: nil
|
9
9
|
class_attribute :current_user, default: nil
|
10
|
+
class_attribute :root_path, default: nil
|
10
11
|
|
11
12
|
class << self
|
12
13
|
def boot
|
@@ -21,10 +22,11 @@ module Avo
|
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
24
|
-
def init(request:, context:, current_user:)
|
25
|
+
def init(request:, context:, current_user:, root_path:)
|
25
26
|
self.request = request
|
26
27
|
self.context = context
|
27
28
|
self.current_user = current_user
|
29
|
+
self.root_path = root_path
|
28
30
|
|
29
31
|
self.license = Licensing::LicenseManager.new(Licensing::HQ.new(request).response).license
|
30
32
|
|
data/lib/avo/base_resource.rb
CHANGED
@@ -22,6 +22,7 @@ module Avo
|
|
22
22
|
class_attribute :fields
|
23
23
|
class_attribute :grid_loader
|
24
24
|
class_attribute :visible_on_sidebar, default: true
|
25
|
+
class_attribute :unscoped_queries_on_index, default: false
|
25
26
|
|
26
27
|
class << self
|
27
28
|
def grid(&block)
|
@@ -77,7 +78,7 @@ module Avo
|
|
77
78
|
field.hydrate(resource: self, panel_name: default_panel_name, user: user)
|
78
79
|
end
|
79
80
|
|
80
|
-
if Avo::App.license.
|
81
|
+
if Avo::App.license.lacks_with_trial(:custom_fields)
|
81
82
|
fields = fields.reject do |field|
|
82
83
|
field.custom?
|
83
84
|
end
|
@@ -87,20 +88,30 @@ module Avo
|
|
87
88
|
end
|
88
89
|
|
89
90
|
def get_fields(panel: nil, reflection: nil)
|
90
|
-
fields = get_field_definitions
|
91
|
-
field
|
92
|
-
|
91
|
+
fields = get_field_definitions
|
92
|
+
.select do |field|
|
93
|
+
field.send("show_on_#{@view}")
|
94
|
+
end
|
93
95
|
.select do |field|
|
94
|
-
|
95
|
-
|
96
|
+
field.visible?
|
97
|
+
end
|
96
98
|
.select do |field|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
99
|
+
# Strip out the reflection field in index queries with a parent association.
|
100
|
+
if reflection.present? &&
|
101
|
+
reflection.options.present? &&
|
102
|
+
field.respond_to?(:polymorphic_as) &&
|
103
|
+
field.polymorphic_as.to_s == reflection.options[:as].to_s
|
104
|
+
next
|
105
|
+
end
|
106
|
+
if field.respond_to?(:foreign_key) &&
|
107
|
+
reflection.present? &&
|
108
|
+
reflection.respond_to?(:foreign_key) &&
|
109
|
+
reflection.foreign_key != field.foreign_key
|
110
|
+
next
|
111
|
+
end
|
112
|
+
|
101
113
|
true
|
102
114
|
end
|
103
|
-
end
|
104
115
|
|
105
116
|
if panel.present?
|
106
117
|
fields = fields.select do |field|
|
@@ -216,28 +227,6 @@ module Avo
|
|
216
227
|
self.class.context
|
217
228
|
end
|
218
229
|
|
219
|
-
def query_search(via_resource_name:, via_resource_id:, user:, query: "")
|
220
|
-
# model_class = self.model
|
221
|
-
|
222
|
-
db_query = AuthorizationService.apply_policy(user, model_class)
|
223
|
-
|
224
|
-
if via_resource_name.present?
|
225
|
-
related_model = App.get_resource_by_name(via_resource_name).model
|
226
|
-
|
227
|
-
db_query = related_model.find(via_resource_id).public_send(plural_name.downcase)
|
228
|
-
end
|
229
|
-
|
230
|
-
new_query = []
|
231
|
-
|
232
|
-
[search].flatten.each_with_index do |search_by, index|
|
233
|
-
new_query.push "or" if index != 0
|
234
|
-
|
235
|
-
new_query.push "text(#{search_by}) ILIKE '%#{query}%'"
|
236
|
-
end
|
237
|
-
|
238
|
-
db_query.where(new_query.join(" "))
|
239
|
-
end
|
240
|
-
|
241
230
|
def attached_file_fields
|
242
231
|
get_field_definitions.select do |field|
|
243
232
|
[Avo::Fields::FileField, Avo::Fields::FilesField].include? field.class
|
@@ -250,14 +239,17 @@ module Avo
|
|
250
239
|
.reject do |field|
|
251
240
|
field.computed
|
252
241
|
end
|
253
|
-
.map
|
242
|
+
.map do |field|
|
243
|
+
[field.database_id(model).to_s, field]
|
244
|
+
end
|
245
|
+
.to_h
|
254
246
|
|
255
247
|
params.each do |key, value|
|
256
248
|
field = fields_by_database_id[key]
|
257
249
|
|
258
250
|
next unless field.present?
|
259
251
|
|
260
|
-
model = field.fill_field model, key, value
|
252
|
+
model = field.fill_field model, key, value, params
|
261
253
|
end
|
262
254
|
|
263
255
|
model
|
@@ -295,19 +287,22 @@ module Avo
|
|
295
287
|
|
296
288
|
# We will not overwrite any attributes that come pre-filled in the model.
|
297
289
|
def hydrate_model_with_default_values
|
298
|
-
default_values = get_fields
|
299
|
-
|
300
|
-
|
290
|
+
default_values = get_fields
|
291
|
+
.select do |field|
|
292
|
+
!field.computed
|
293
|
+
end
|
301
294
|
.map do |field|
|
302
295
|
id = field.id
|
303
296
|
value = field.value
|
304
297
|
|
305
|
-
if field.
|
298
|
+
if field.type == "belongs_to"
|
306
299
|
id = field.foreign_key.to_sym
|
307
300
|
|
308
301
|
reflection = @model._reflections[@params[:via_relation]]
|
309
302
|
|
310
|
-
if
|
303
|
+
if field.polymorphic_as.present? && field.types.map(&:to_s).include?(@params["via_relation_class"])
|
304
|
+
value = @params["via_relation_class"].safe_constantize.find(@params[:via_resource_id])
|
305
|
+
elsif reflection.present? && reflection.foreign_key.present? && field.id.to_s == @params[:via_relation].to_s
|
311
306
|
value = @params[:via_resource_id]
|
312
307
|
end
|
313
308
|
end
|
@@ -316,8 +311,8 @@ module Avo
|
|
316
311
|
end
|
317
312
|
.to_h
|
318
313
|
.select do |id, value|
|
319
|
-
|
320
|
-
|
314
|
+
value.present?
|
315
|
+
end
|
321
316
|
|
322
317
|
default_values.each do |id, value|
|
323
318
|
if @model.send(id).nil?
|
@@ -327,7 +322,7 @@ module Avo
|
|
327
322
|
end
|
328
323
|
|
329
324
|
def avo_path
|
330
|
-
"#{Avo.
|
325
|
+
"#{Avo::App.root_path}/resources/#{model_class.model_name.route_key}/#{model.id}"
|
331
326
|
end
|
332
327
|
|
333
328
|
def label_field
|
@@ -355,6 +350,8 @@ module Avo
|
|
355
350
|
def avatar
|
356
351
|
return avatar_field.to_image if avatar_field.respond_to? :to_image
|
357
352
|
|
353
|
+
return avatar_field.value.variant(resize_to_limit: [480, 480]) if avatar_field.type == "file"
|
354
|
+
|
358
355
|
avatar_field.value
|
359
356
|
rescue
|
360
357
|
nil
|
data/lib/avo/configuration.rb
CHANGED
@@ -23,6 +23,7 @@ module Avo
|
|
23
23
|
attr_accessor :initial_breadcrumbs
|
24
24
|
attr_accessor :home_path
|
25
25
|
attr_accessor :search_debounce
|
26
|
+
attr_accessor :view_component_path
|
26
27
|
|
27
28
|
def initialize
|
28
29
|
@root_path = "/avo"
|
@@ -58,6 +59,7 @@ module Avo
|
|
58
59
|
@display_breadcrumbs = true
|
59
60
|
@home_path = nil
|
60
61
|
@search_debounce = 300
|
62
|
+
@view_component_path = "app/components"
|
61
63
|
end
|
62
64
|
|
63
65
|
def locale_tag
|
@@ -91,7 +93,7 @@ module Avo
|
|
91
93
|
end
|
92
94
|
|
93
95
|
def namespace
|
94
|
-
|
96
|
+
computed_root_path.delete "/"
|
95
97
|
end
|
96
98
|
|
97
99
|
def root_path
|
@@ -99,6 +101,10 @@ module Avo
|
|
99
101
|
|
100
102
|
@root_path
|
101
103
|
end
|
104
|
+
|
105
|
+
def computed_root_path
|
106
|
+
Avo::App.root_path
|
107
|
+
end
|
102
108
|
end
|
103
109
|
|
104
110
|
def self.configuration
|
@@ -91,9 +91,11 @@ module Avo
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
-
def value
|
94
|
+
def value(property = nil)
|
95
|
+
property ||= id
|
96
|
+
|
95
97
|
# Get model value
|
96
|
-
final_value = @model.send(
|
98
|
+
final_value = @model.send(property) if (model_or_class(@model) == "model") && @model.respond_to?(property)
|
97
99
|
|
98
100
|
if (@view === :new) || @action.present?
|
99
101
|
final_value = if default.present? && default.respond_to?(:call)
|
@@ -114,7 +116,7 @@ module Avo
|
|
114
116
|
final_value
|
115
117
|
end
|
116
118
|
|
117
|
-
def fill_field(model, key, value)
|
119
|
+
def fill_field(model, key, value, params)
|
118
120
|
return model unless model.methods.include? key.to_sym
|
119
121
|
|
120
122
|
model.send("#{key}=", value)
|
@@ -2,7 +2,9 @@ module Avo
|
|
2
2
|
module Fields
|
3
3
|
class BelongsToField < BaseField
|
4
4
|
attr_reader :searchable
|
5
|
+
attr_reader :polymorphic_as
|
5
6
|
attr_reader :relation_method
|
7
|
+
attr_reader :types
|
6
8
|
|
7
9
|
def initialize(id, **args, &block)
|
8
10
|
args[:placeholder] ||= I18n.t("avo.choose_an_option")
|
@@ -10,11 +12,17 @@ module Avo
|
|
10
12
|
super(id, **args, &block)
|
11
13
|
|
12
14
|
@searchable = args[:searchable] == true
|
15
|
+
@polymorphic_as = args[:polymorphic_as]
|
16
|
+
@types = args[:types]
|
13
17
|
@relation_method = name.to_s.parameterize.underscore
|
14
18
|
end
|
15
19
|
|
20
|
+
def value
|
21
|
+
super(polymorphic_as)
|
22
|
+
end
|
23
|
+
|
16
24
|
def options
|
17
|
-
target_resource.model_class.all.map do |model|
|
25
|
+
::Avo::Services::AuthorizationService.apply_policy(user, target_resource.model_class).all.map do |model|
|
18
26
|
{
|
19
27
|
value: model.id,
|
20
28
|
label: model.send(target_resource.class.title)
|
@@ -22,22 +30,32 @@ module Avo
|
|
22
30
|
end
|
23
31
|
end
|
24
32
|
|
33
|
+
def values_for_type(type)
|
34
|
+
::Avo::Services::AuthorizationService.apply_policy(user, type).all.map do |model|
|
35
|
+
[model.send(App.get_resource_by_model_name(type).class.title), model.id]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
25
39
|
def database_value
|
26
40
|
target_resource.id
|
27
41
|
end
|
28
42
|
|
29
43
|
def foreign_key
|
44
|
+
return polymorphic_as if polymorphic_as.present?
|
45
|
+
|
30
46
|
if @model.present?
|
31
|
-
|
32
|
-
|
33
|
-
else
|
34
|
-
@model.class.reflections[@relation_method].foreign_key
|
35
|
-
end
|
36
|
-
elsif @resource.present?
|
47
|
+
get_model_class(@model).reflections[@relation_method].foreign_key
|
48
|
+
elsif @resource.present? && @resource.model_class.reflections[@relation_method].present?
|
37
49
|
@resource.model_class.reflections[@relation_method].foreign_key
|
38
50
|
end
|
39
51
|
end
|
40
52
|
|
53
|
+
def reflection_for_key(key)
|
54
|
+
get_model_class(get_model).reflections[key.to_s]
|
55
|
+
rescue
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
|
41
59
|
def relation_model_class
|
42
60
|
@resource.model_class
|
43
61
|
end
|
@@ -47,16 +65,82 @@ module Avo
|
|
47
65
|
end
|
48
66
|
|
49
67
|
def to_permitted_param
|
68
|
+
if polymorphic_as.present?
|
69
|
+
return ["#{polymorphic_as}_type".to_sym, "#{polymorphic_as}_id".to_sym]
|
70
|
+
end
|
71
|
+
|
50
72
|
foreign_key.to_sym
|
51
73
|
end
|
52
74
|
|
75
|
+
def fill_field(model, key, value, params)
|
76
|
+
return model unless model.methods.include? key.to_sym
|
77
|
+
|
78
|
+
if polymorphic_as.present?
|
79
|
+
model.send("#{polymorphic_as}_type=", params["#{polymorphic_as}_type"])
|
80
|
+
|
81
|
+
# If the type is blank, reset the id too.
|
82
|
+
if params["#{polymorphic_as}_type"].blank?
|
83
|
+
model.send("#{polymorphic_as}_id=", nil)
|
84
|
+
else
|
85
|
+
model.send("#{polymorphic_as}_id=", params["#{polymorphic_as}_id"])
|
86
|
+
end
|
87
|
+
else
|
88
|
+
model.send("#{key}=", value)
|
89
|
+
end
|
90
|
+
|
91
|
+
model
|
92
|
+
end
|
93
|
+
|
94
|
+
def database_id(model)
|
95
|
+
# If the field is a polymorphic value, return the polymorphic_type as key and pre-fill the _id in fill_field.
|
96
|
+
return "#{polymorphic_as}_type" if polymorphic_as.present?
|
97
|
+
|
98
|
+
foreign_key
|
99
|
+
rescue
|
100
|
+
id
|
101
|
+
end
|
102
|
+
|
53
103
|
def target_resource
|
54
|
-
if
|
55
|
-
|
56
|
-
|
57
|
-
|
104
|
+
if polymorphic_as.present?
|
105
|
+
if value.present?
|
106
|
+
return App.get_resource_by_model_name(value.class)
|
107
|
+
else
|
108
|
+
return nil
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
reflection_key = polymorphic_as || id
|
113
|
+
|
114
|
+
if @model._reflections[reflection_key.to_s].klass.present?
|
115
|
+
App.get_resource_by_model_name @model._reflections[reflection_key.to_s].klass.to_s
|
116
|
+
elsif @model._reflections[reflection_key.to_s].options[:class_name].present?
|
117
|
+
App.get_resource_by_model_name @model._reflections[reflection_key.to_s].options[:class_name]
|
118
|
+
else
|
119
|
+
App.get_resource_by_name reflection_key.to_s
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def get_model
|
124
|
+
return @model if @model.present?
|
125
|
+
|
126
|
+
@resource.model
|
127
|
+
rescue
|
128
|
+
nil
|
129
|
+
end
|
130
|
+
|
131
|
+
def name
|
132
|
+
return polymorphic_as.to_s.humanize if polymorphic_as.present? && view == :index
|
133
|
+
|
134
|
+
super
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
def get_model_class(model)
|
140
|
+
if model.instance_of?(Class)
|
141
|
+
model
|
58
142
|
else
|
59
|
-
|
143
|
+
model.class
|
60
144
|
end
|
61
145
|
end
|
62
146
|
end
|