avo 3.0.1.beta7 → 3.0.1.beta9
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 +2 -2
- data/Gemfile.lock +23 -25
- data/{public/avo-assets/avo.css → app/assets/builds/avo.base.css} +1943 -1552
- data/app/assets/builds/avo.base.js +124556 -0
- data/app/assets/builds/avo.base.js.map +7 -0
- data/app/assets/builds/avo.custom.js +6 -0
- data/app/assets/builds/avo.custom.js.map +7 -0
- data/app/assets/stylesheets/avo.base.css +1 -0
- data/app/assets/stylesheets/css/fields/tags.css +32 -0
- data/app/components/avo/actions_component.rb +1 -1
- data/app/components/avo/field_wrapper_component.html.erb +1 -1
- data/app/components/avo/field_wrapper_component.rb +1 -7
- data/app/components/avo/fields/boolean_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/common/badge_viewer_component.html.erb +1 -24
- data/app/components/avo/fields/common/badge_viewer_component.rb +24 -0
- data/app/components/avo/fields/common/boolean_check_component.html.erb +1 -12
- data/app/components/avo/fields/common/boolean_check_component.rb +2 -1
- data/app/components/avo/fields/common/gravatar_viewer_component.html.erb +1 -1
- data/app/components/avo/fields/common/gravatar_viewer_component.rb +2 -2
- data/app/components/avo/fields/common/heading_component.html.erb +3 -8
- data/app/components/avo/fields/common/heading_component.rb +1 -3
- data/app/components/avo/fields/common/key_value_component.html.erb +2 -2
- data/app/components/avo/fields/common/key_value_component.rb +2 -2
- data/app/components/avo/fields/common/progress_bar_component.rb +3 -9
- data/app/components/avo/fields/edit_component.rb +1 -1
- data/app/components/avo/fields/external_image_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/file_field/index_component.html.erb +2 -2
- data/app/components/avo/fields/gravatar_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/heading_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/heading_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/id_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/index_component.rb +1 -1
- data/app/components/avo/fields/show_component.rb +1 -1
- data/app/components/avo/fields/text_field/index_component.html.erb +1 -1
- data/app/components/avo/index/field_wrapper_component.rb +1 -1
- data/app/components/avo/index/resource_controls_component.rb +1 -1
- data/app/components/avo/index/resource_table_component.rb +3 -9
- data/app/components/avo/resource_component.rb +9 -4
- data/app/components/avo/sidebar_profile_component.html.erb +4 -4
- data/app/components/avo/tab_group_component.html.erb +1 -1
- data/app/components/avo/tab_switcher_component.rb +2 -2
- data/app/components/avo/views/resource_edit_component.html.erb +9 -20
- data/app/components/avo/views/resource_edit_component.rb +5 -5
- data/app/components/avo/views/resource_index_component.rb +1 -1
- data/app/components/avo/views/resource_show_component.rb +1 -1
- data/app/controllers/avo/actions_controller.rb +9 -20
- data/app/controllers/avo/application_controller.rb +5 -5
- data/app/controllers/avo/base_controller.rb +1 -1
- data/app/controllers/avo/search_controller.rb +19 -2
- data/app/controllers/concerns/avo/initializes_avo.rb +1 -0
- data/app/helpers/avo/url_helpers.rb +1 -1
- data/app/views/avo/actions/show.html.erb +1 -1
- data/config/routes.rb +4 -3
- data/db/factories.rb +1 -1
- data/lib/avo/base_action.rb +20 -25
- data/lib/avo/base_resource.rb +7 -6
- data/lib/avo/concerns/filters_session_handler.rb +3 -3
- data/lib/avo/concerns/has_helpers.rb +18 -0
- data/lib/avo/concerns/has_items.rb +1 -5
- data/lib/avo/concerns/visible_in_different_views.rb +7 -1
- data/lib/avo/concerns/visible_items.rb +43 -0
- data/lib/avo/configuration.rb +8 -2
- data/lib/avo/current.rb +1 -0
- data/lib/avo/execution_context.rb +4 -1
- data/lib/avo/fields/badge_field.rb +1 -1
- data/lib/avo/fields/base_field.rb +21 -44
- data/lib/avo/fields/belongs_to_field.rb +1 -1
- data/lib/avo/fields/concerns/has_html_attributes.rb +2 -0
- data/lib/avo/fields/concerns/use_view_components.rb +45 -0
- data/lib/avo/fields/external_image_field.rb +2 -2
- data/lib/avo/fields/file_field.rb +2 -2
- data/lib/avo/fields/gravatar_field.rb +2 -2
- data/lib/avo/fields/has_base_field.rb +2 -2
- data/lib/avo/fields/heading_field.rb +5 -13
- data/lib/avo/fields/id_field.rb +2 -2
- data/lib/avo/fields/text_field.rb +2 -2
- data/lib/avo/resources/items/holder.rb +0 -6
- data/lib/avo/resources/items/item_group.rb +2 -2
- data/lib/avo/resources/items/row.rb +3 -3
- data/lib/avo/resources/items/sidebar.rb +1 -1
- data/lib/avo/resources/items/tab.rb +2 -2
- data/lib/avo/resources/items/tab_group.rb +1 -1
- data/lib/avo/resources/resource_manager.rb +6 -1
- data/lib/avo/version.rb +1 -1
- data/lib/avo/view_inquirer.rb +36 -0
- data/lib/avo.rb +9 -0
- data/lib/generators/avo/eject_generator.rb +93 -16
- data/lib/generators/avo/js/install_generator.rb +2 -2
- data/lib/generators/avo/resource_generator.rb +5 -5
- data/lib/generators/avo/tailwindcss/install_generator.rb +1 -1
- data/lib/generators/avo/templates/initializer/avo.tt +5 -0
- data/public/avo-assets/avo.base.css +54 -219
- metadata +12 -6
- data/config/master.key +0 -1
- data/public/avo-assets/avo.js +0 -513
- data/public/avo-assets/avo.js.map +0 -7
data/config/routes.rb
CHANGED
@@ -4,9 +4,10 @@ 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
|
-
|
8
|
-
|
9
|
-
|
7
|
+
# Mount Avo engines routes by default but leave it configurable in case the user wants to nest these under a scope.
|
8
|
+
if Avo.configuration.mount_avo_engines
|
9
|
+
instance_exec(&Avo.mount_engines)
|
10
|
+
end
|
10
11
|
|
11
12
|
post "/rails/active_storage/direct_uploads", to: "/active_storage/direct_uploads#create"
|
12
13
|
|
data/db/factories.rb
CHANGED
@@ -38,7 +38,7 @@ FactoryBot.define do
|
|
38
38
|
factory :project do
|
39
39
|
name { Faker::App.name }
|
40
40
|
status { ['closed', :rejected, :failed, 'loading', :running, :waiting].sample }
|
41
|
-
stage { ["Discovery", "Idea", "Done", "On hold", "Cancelled"].sample }
|
41
|
+
stage { ["Discovery", "Idea", "Done", "On hold", "Cancelled", "Drafting"].sample }
|
42
42
|
budget { Faker::Number.decimal(l_digits: 4) }
|
43
43
|
country { Faker::Address.country_code }
|
44
44
|
description { Faker::Markdown.sandwich(sentences: 5) }
|
data/lib/avo/base_action.rb
CHANGED
@@ -65,7 +65,7 @@ module Avo
|
|
65
65
|
self.class.record = record
|
66
66
|
self.class.resource = resource
|
67
67
|
self.class.user = user
|
68
|
-
self.class.view = view
|
68
|
+
self.class.view = Avo::ViewInquirer.new(view)
|
69
69
|
@arguments = arguments
|
70
70
|
|
71
71
|
self.class.message ||= I18n.t("avo.are_you_sure_you_want_to_run_this_option")
|
@@ -101,39 +101,34 @@ module Avo
|
|
101
101
|
end
|
102
102
|
|
103
103
|
def handle_action(**args)
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
104
|
+
processed_fields = if args[:fields].present?
|
105
|
+
# 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.
|
106
|
+
action_fields = get_field_definitions.map { |field| [field.id, field] }.to_h
|
107
|
+
|
108
|
+
# For some fields, like belongs_to, the id and database_id differ (user vs user_id).
|
109
|
+
# That's why we need to fetch the database_id for when we process the action.
|
110
|
+
action_fields_by_database_id = action_fields.map do |id, value|
|
111
|
+
[value.database_id.to_sym, value]
|
112
|
+
end.to_h
|
113
113
|
|
114
|
-
|
115
|
-
processed_fields = fields.to_unsafe_h.map do |name, value|
|
114
|
+
args[:fields].to_unsafe_h.map do |name, value|
|
116
115
|
field = action_fields_by_database_id[name.to_sym]
|
117
116
|
|
118
117
|
next if field.blank?
|
119
118
|
|
120
119
|
[name, field.resolve_attribute(value)]
|
121
|
-
end
|
122
|
-
|
123
|
-
processed_fields = processed_fields.reject(&:blank?).to_h
|
120
|
+
end.reject(&:blank?).to_h
|
124
121
|
else
|
125
|
-
|
122
|
+
{}
|
126
123
|
end
|
127
124
|
|
128
|
-
|
125
|
+
handle(
|
129
126
|
fields: processed_fields.with_indifferent_access,
|
130
|
-
current_user: current_user,
|
131
|
-
resource: resource
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
handle(**args)
|
127
|
+
current_user: args[:current_user],
|
128
|
+
resource: args[:resource],
|
129
|
+
records: args[:query],
|
130
|
+
query: args[:query]
|
131
|
+
)
|
137
132
|
|
138
133
|
self
|
139
134
|
end
|
@@ -141,7 +136,7 @@ module Avo
|
|
141
136
|
def visible_in_view(parent_resource: nil)
|
142
137
|
if visible.blank?
|
143
138
|
# Hide on the :new view by default
|
144
|
-
return false if view
|
139
|
+
return false if view.new?
|
145
140
|
|
146
141
|
# Show on all other views
|
147
142
|
return true
|
data/lib/avo/base_resource.rb
CHANGED
@@ -9,6 +9,7 @@ module Avo
|
|
9
9
|
include Avo::Concerns::HasStimulusControllers
|
10
10
|
include Avo::Concerns::ModelClassConstantized
|
11
11
|
include Avo::Concerns::HasDescription
|
12
|
+
include Avo::Concerns::HasHelpers
|
12
13
|
|
13
14
|
# Avo::Current methods
|
14
15
|
delegate :context, to: Avo::Current
|
@@ -233,14 +234,14 @@ module Avo
|
|
233
234
|
delegate :model_key, to: :class
|
234
235
|
|
235
236
|
def initialize(record: nil, view: nil, user: nil, params: nil)
|
236
|
-
@view = view if view.present?
|
237
|
+
@view = Avo::ViewInquirer.new(view) if view.present?
|
237
238
|
@user = user if user.present?
|
238
239
|
@params = params if params.present?
|
239
240
|
|
240
241
|
if record.present?
|
241
242
|
@record = record
|
242
243
|
|
243
|
-
hydrate_model_with_default_values if @view
|
244
|
+
hydrate_model_with_default_values if @view&.new?
|
244
245
|
end
|
245
246
|
|
246
247
|
detect_fields
|
@@ -295,7 +296,7 @@ module Avo
|
|
295
296
|
# def get_action_arguments / def get_filter_arguments / def get_scope_arguments
|
296
297
|
define_method "get_#{entity}_arguments" do |entity_class|
|
297
298
|
klass = send("get_#{plural_entity}").find { |entity| entity[:class].to_s == entity_class.to_s }
|
298
|
-
|
299
|
+
|
299
300
|
raise "Couldn't find '#{entity_class}' in the 'def #{plural_entity}' method on your '#{self.class}' resource." if klass.nil?
|
300
301
|
|
301
302
|
klass[:arguments]
|
@@ -303,14 +304,14 @@ module Avo
|
|
303
304
|
end
|
304
305
|
|
305
306
|
def hydrate(record: nil, view: nil, user: nil, params: nil)
|
306
|
-
@view = view if view.present?
|
307
|
+
@view = Avo::ViewInquirer.new(view) if view.present?
|
307
308
|
@user = user if user.present?
|
308
309
|
@params = params if params.present?
|
309
310
|
|
310
311
|
if record.present?
|
311
312
|
@record = record
|
312
313
|
|
313
|
-
hydrate_model_with_default_values if @view
|
314
|
+
hydrate_model_with_default_values if @view&.new?
|
314
315
|
end
|
315
316
|
|
316
317
|
self
|
@@ -445,7 +446,7 @@ module Avo
|
|
445
446
|
def hydrate_model_with_default_values
|
446
447
|
default_values = get_fields
|
447
448
|
.select do |field|
|
448
|
-
!field.computed
|
449
|
+
!field.computed && !field.is_a?(Avo::Fields::HeadingField)
|
449
450
|
end
|
450
451
|
.map do |field|
|
451
452
|
value = field.value
|
@@ -26,16 +26,16 @@ module Avo
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def filters_session_key
|
29
|
-
@filters_session_key ||=
|
29
|
+
@filters_session_key ||= "/filters/" << %w[
|
30
30
|
turbo_frame controller resource_name related_name
|
31
31
|
action id
|
32
|
-
].map { |key| params[key] }.compact.join(
|
32
|
+
].map { |key| params[key] }.compact.join("/")
|
33
33
|
end
|
34
34
|
|
35
35
|
def cache_resource_filters?
|
36
36
|
Avo::ExecutionContext.new(
|
37
37
|
target: Avo.configuration.cache_resource_filters,
|
38
|
-
current_user:
|
38
|
+
current_user: _current_user,
|
39
39
|
resource: @resource
|
40
40
|
).handle
|
41
41
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Avo
|
2
|
+
module Concerns
|
3
|
+
module HasHelpers
|
4
|
+
def helpers
|
5
|
+
@helpers ||= Class.new do
|
6
|
+
def initialize
|
7
|
+
helper_names = ActionController::Base.all_helpers_from_path Rails.root.join("app", "helpers")
|
8
|
+
helpers = ActionController::Base.modules_for_helpers helper_names
|
9
|
+
|
10
|
+
helpers.each do |helper|
|
11
|
+
extend helper
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end.new
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -30,10 +30,6 @@ module Avo
|
|
30
30
|
deprecated_dsl_api __method__, "fields"
|
31
31
|
end
|
32
32
|
|
33
|
-
def heading(body, **args)
|
34
|
-
deprecated_dsl_api __method__, "fields"
|
35
|
-
end
|
36
|
-
|
37
33
|
def sidebar(**args, &block)
|
38
34
|
deprecated_dsl_api __method__, "fields"
|
39
35
|
end
|
@@ -273,7 +269,7 @@ module Avo
|
|
273
269
|
end
|
274
270
|
.select do |item|
|
275
271
|
# 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?([
|
272
|
+
if !item.is_a?(Avo::Fields::LocationField) && !item.is_heading? && view.in?(%w[edit update new create])
|
277
273
|
if item.respond_to?(:id)
|
278
274
|
item.resource.record.respond_to?("#{item.id}=")
|
279
275
|
else
|
@@ -61,7 +61,7 @@ module Avo
|
|
61
61
|
def except_on(*where)
|
62
62
|
show_on_all
|
63
63
|
normalize_views(where).flatten.each do |view|
|
64
|
-
|
64
|
+
hide_on_view view
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
@@ -113,12 +113,18 @@ module Avo
|
|
113
113
|
|
114
114
|
def normalize_views(*views_and_groups)
|
115
115
|
forms = views_and_groups.flatten! & [:forms]
|
116
|
+
display = views_and_groups & [:display]
|
116
117
|
|
117
118
|
if forms.present?
|
118
119
|
views_and_groups -= forms
|
119
120
|
views_and_groups += [:new, :edit]
|
120
121
|
end
|
121
122
|
|
123
|
+
if display.present?
|
124
|
+
views_and_groups -= display
|
125
|
+
views_and_groups += [:index, :show]
|
126
|
+
end
|
127
|
+
|
122
128
|
views_and_groups.flatten.uniq
|
123
129
|
end
|
124
130
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# This concern helps us figure out what items are visible for each tab, panel or sidebar
|
2
|
+
module Avo
|
3
|
+
module Concerns
|
4
|
+
module VisibleItems
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
def items
|
7
|
+
items_holder&.items || []
|
8
|
+
end
|
9
|
+
|
10
|
+
def visible_items
|
11
|
+
items
|
12
|
+
.select do |item|
|
13
|
+
if item.respond_to? :hydrate
|
14
|
+
item.hydrate(view: view, resource: resource)
|
15
|
+
end
|
16
|
+
|
17
|
+
visible(item)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def visible(item)
|
22
|
+
return item.visible? if !item.is_field?
|
23
|
+
|
24
|
+
return false if item.respond_to?(:authorized?) && item.resource.present? && !item.authorized?
|
25
|
+
|
26
|
+
item.visible? && item.visible_in_view?(view: view)
|
27
|
+
end
|
28
|
+
|
29
|
+
def visible?
|
30
|
+
any_item_visible = visible_items.any?
|
31
|
+
return any_item_visible if !respond_to?(:visible_on?)
|
32
|
+
|
33
|
+
visible_on?(view) && any_item_visible
|
34
|
+
end
|
35
|
+
|
36
|
+
def hydrate(view: nil)
|
37
|
+
@view = view
|
38
|
+
|
39
|
+
self
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/avo/configuration.rb
CHANGED
@@ -36,13 +36,14 @@ module Avo
|
|
36
36
|
attr_accessor :main_menu
|
37
37
|
attr_accessor :profile_menu
|
38
38
|
attr_accessor :model_resource_mapping
|
39
|
-
|
39
|
+
attr_reader :resource_default_view
|
40
40
|
attr_accessor :authorization_client
|
41
41
|
attr_accessor :field_wrapper_layout
|
42
42
|
attr_accessor :sign_out_path_name
|
43
43
|
attr_accessor :resources
|
44
44
|
attr_accessor :prefix_path
|
45
45
|
attr_accessor :resource_parent_controller
|
46
|
+
attr_accessor :mount_avo_engines
|
46
47
|
|
47
48
|
def initialize
|
48
49
|
@root_path = "/avo"
|
@@ -88,11 +89,12 @@ module Avo
|
|
88
89
|
@main_menu = nil
|
89
90
|
@profile_menu = nil
|
90
91
|
@model_resource_mapping = {}
|
91
|
-
@resource_default_view =
|
92
|
+
@resource_default_view = Avo::ViewInquirer.new("show")
|
92
93
|
@authorization_client = :pundit
|
93
94
|
@field_wrapper_layout = :inline
|
94
95
|
@resources = nil
|
95
96
|
@resource_parent_controller = "Avo::ResourcesController"
|
97
|
+
@mount_avo_engines = true
|
96
98
|
end
|
97
99
|
|
98
100
|
def current_user_method(&block)
|
@@ -158,6 +160,10 @@ module Avo
|
|
158
160
|
"community"
|
159
161
|
end
|
160
162
|
end
|
163
|
+
|
164
|
+
def resource_default_view=(view)
|
165
|
+
@resource_default_view = Avo::ViewInquirer.new(view.to_s)
|
166
|
+
end
|
161
167
|
end
|
162
168
|
|
163
169
|
def self.configuration
|
data/lib/avo/current.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module Avo
|
2
2
|
class ExecutionContext
|
3
|
-
|
3
|
+
include Avo::Concerns::HasHelpers
|
4
|
+
|
5
|
+
attr_accessor :target, :context, :params, :view_context, :current_user, :request, :include, :main_app, :avo, :locale
|
4
6
|
|
5
7
|
def initialize(**args)
|
6
8
|
# Extend the class with custom modules if required.
|
@@ -24,6 +26,7 @@ module Avo
|
|
24
26
|
@params ||= Avo::Current.params
|
25
27
|
@request ||= Avo::Current.request
|
26
28
|
@view_context ||= Avo::Current.view_context
|
29
|
+
@locale ||= Avo::Current.locale
|
27
30
|
@main_app ||= @view_context.main_app
|
28
31
|
@avo ||= @view_context.avo
|
29
32
|
end
|
@@ -8,7 +8,7 @@ module Avo
|
|
8
8
|
|
9
9
|
hide_on [:edit, :new]
|
10
10
|
|
11
|
-
default_options = {info: :info, success: :success, danger: :danger, warning: :warning}
|
11
|
+
default_options = {info: :info, success: :success, danger: :danger, warning: :warning, neutral: :neutral}
|
12
12
|
@options = args[:options].present? ? default_options.merge(args[:options]) : default_options
|
13
13
|
end
|
14
14
|
end
|
@@ -7,6 +7,7 @@ module Avo
|
|
7
7
|
prepend Avo::Concerns::IsResourceItem
|
8
8
|
include Avo::Concerns::IsVisible
|
9
9
|
include Avo::Concerns::VisibleInDifferentViews
|
10
|
+
include Avo::Concerns::HasHelpers
|
10
11
|
include Avo::Fields::Concerns::HasFieldName
|
11
12
|
include Avo::Fields::Concerns::HasDefault
|
12
13
|
include Avo::Fields::Concerns::HasHTMLAttributes
|
@@ -14,6 +15,7 @@ module Avo
|
|
14
15
|
include Avo::Fields::Concerns::IsReadonly
|
15
16
|
include Avo::Fields::Concerns::IsDisabled
|
16
17
|
include Avo::Fields::Concerns::IsRequired
|
18
|
+
include Avo::Fields::Concerns::UseViewComponents
|
17
19
|
|
18
20
|
include ActionView::Helpers::UrlHelper
|
19
21
|
|
@@ -73,11 +75,12 @@ module Avo
|
|
73
75
|
@visible = args[:visible]
|
74
76
|
@as_avatar = args[:as_avatar] || false
|
75
77
|
@html = args[:html] || nil
|
76
|
-
@view = args[:view] || nil
|
78
|
+
@view = Avo::ViewInquirer.new(args[:view]) || nil
|
77
79
|
@value = args[:value] || nil
|
78
80
|
@stacked = args[:stacked] || nil
|
79
81
|
@for_presentation_only = args[:for_presentation_only] || false
|
80
82
|
@resource = args[:resource]
|
83
|
+
@components = args[:components] || {}
|
81
84
|
|
82
85
|
@args = args
|
83
86
|
|
@@ -155,14 +158,7 @@ module Avo
|
|
155
158
|
|
156
159
|
# Run computable callback block if present
|
157
160
|
if computable && block.present?
|
158
|
-
final_value =
|
159
|
-
target: block,
|
160
|
-
record: record,
|
161
|
-
resource: @resource,
|
162
|
-
view: @view,
|
163
|
-
field: self,
|
164
|
-
include: self.class.included_modules
|
165
|
-
).handle
|
161
|
+
final_value = execute_block
|
166
162
|
end
|
167
163
|
|
168
164
|
# Run the value through resolver if present
|
@@ -181,6 +177,17 @@ module Avo
|
|
181
177
|
final_value
|
182
178
|
end
|
183
179
|
|
180
|
+
def execute_block
|
181
|
+
Avo::ExecutionContext.new(
|
182
|
+
target: block,
|
183
|
+
record: record,
|
184
|
+
resource: resource,
|
185
|
+
view: view,
|
186
|
+
field: self,
|
187
|
+
include: self.class.included_modules
|
188
|
+
).handle
|
189
|
+
end
|
190
|
+
|
184
191
|
# Fills the record with the received value on create and update actions.
|
185
192
|
def fill_field(record, key, value, params)
|
186
193
|
return record unless record.methods.include? key.to_sym
|
@@ -192,7 +199,8 @@ module Avo
|
|
192
199
|
key: key,
|
193
200
|
value: value,
|
194
201
|
resource: resource,
|
195
|
-
field: self
|
202
|
+
field: self,
|
203
|
+
include: self.class.included_modules
|
196
204
|
).handle
|
197
205
|
end
|
198
206
|
|
@@ -220,35 +228,8 @@ module Avo
|
|
220
228
|
id.to_sym
|
221
229
|
end
|
222
230
|
|
223
|
-
def view_component_name
|
224
|
-
"#{type.camelize}Field"
|
225
|
-
end
|
226
|
-
|
227
|
-
# For custom components the namespace will be different than Avo::Fields so we should take that into account.
|
228
|
-
def view_component_namespace
|
229
|
-
"#{self.class.to_s.deconstantize}::#{view_component_name}"
|
230
|
-
end
|
231
|
-
|
232
|
-
# Try and build the component class or fallback to a blank one
|
233
|
-
def component_for_view(view = :index)
|
234
|
-
# Use the edit variant for all "update" views
|
235
|
-
view = :edit if view.in? [:new, :create, :update]
|
236
|
-
|
237
|
-
component_class = "#{view_component_namespace}::#{view.to_s.camelize}Component"
|
238
|
-
component_class.constantize
|
239
|
-
rescue
|
240
|
-
unless Rails.env.test?
|
241
|
-
Avo.logger.info "Failed to find component for the `#{self.class}` field on the `#{view}` view."
|
242
|
-
end
|
243
|
-
# When returning nil, a race condition happens and throws an error in some environments.
|
244
|
-
# See https://github.com/avo-hq/avo/pull/365
|
245
|
-
::Avo::BlankFieldComponent
|
246
|
-
end
|
247
|
-
|
248
231
|
def record_errors
|
249
|
-
|
250
|
-
|
251
|
-
record.errors
|
232
|
+
record.nil? ? {} : record.errors
|
252
233
|
end
|
253
234
|
|
254
235
|
def type
|
@@ -289,11 +270,7 @@ module Avo
|
|
289
270
|
private
|
290
271
|
|
291
272
|
def model_or_class(model)
|
292
|
-
|
293
|
-
"class"
|
294
|
-
else
|
295
|
-
"model"
|
296
|
-
end
|
273
|
+
model.instance_of?(String) ? "class" : "model"
|
297
274
|
end
|
298
275
|
|
299
276
|
def is_model?(model)
|
@@ -305,7 +282,7 @@ module Avo
|
|
305
282
|
end
|
306
283
|
|
307
284
|
def on_create?
|
308
|
-
@view.in?([
|
285
|
+
@view.in?(%w[new create])
|
309
286
|
end
|
310
287
|
|
311
288
|
def in_action?
|
@@ -13,6 +13,8 @@ module Avo
|
|
13
13
|
# get_html :classes, view: :show, element: :wrapper
|
14
14
|
# get_html :styles, view: :index, element: :wrapper
|
15
15
|
def get_html(name = nil, element:, view:)
|
16
|
+
view = view.to_sym if view.present?
|
17
|
+
|
16
18
|
if [view, element].any?(&:nil?)
|
17
19
|
default_attribute_value name
|
18
20
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Avo
|
2
|
+
module Fields
|
3
|
+
module Concerns
|
4
|
+
module UseViewComponents
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
attr_reader :components
|
9
|
+
end
|
10
|
+
|
11
|
+
def view_component_name
|
12
|
+
"#{type.camelize}Field"
|
13
|
+
end
|
14
|
+
|
15
|
+
# For custom components the namespace will be different than Avo::Fields so we should take that into account.
|
16
|
+
def view_component_namespace
|
17
|
+
"#{self.class.to_s.deconstantize}::#{view_component_name}"
|
18
|
+
end
|
19
|
+
|
20
|
+
# Try and build the component class or fallback to a blank one
|
21
|
+
def component_for_view(view = :index)
|
22
|
+
# Use the edit variant for all "update" views
|
23
|
+
view = :edit if view.in? [:new, :create, :update]
|
24
|
+
|
25
|
+
custom_components = Avo::ExecutionContext.new(
|
26
|
+
target: components,
|
27
|
+
resource: @resource,
|
28
|
+
record: @record,
|
29
|
+
view: view
|
30
|
+
).handle
|
31
|
+
|
32
|
+
component_class = custom_components.dig("#{view}_component".to_sym) || "#{view_component_namespace}::#{view.to_s.camelize}Component"
|
33
|
+
component_class.to_s.constantize
|
34
|
+
rescue
|
35
|
+
unless Rails.env.test?
|
36
|
+
Avo.logger.info "Failed to find component for the `#{self.class}` field on the `#{view}` view."
|
37
|
+
end
|
38
|
+
# When returning nil, a race condition happens and throws an error in some environments.
|
39
|
+
# See https://github.com/avo-hq/avo/pull/365
|
40
|
+
::Avo::BlankFieldComponent
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -4,12 +4,12 @@ module Avo
|
|
4
4
|
attr_reader :width
|
5
5
|
attr_reader :height
|
6
6
|
attr_reader :radius
|
7
|
-
attr_reader :
|
7
|
+
attr_reader :link_to_record
|
8
8
|
|
9
9
|
def initialize(id, **args, &block)
|
10
10
|
super(id, **args, &block)
|
11
11
|
|
12
|
-
@
|
12
|
+
@link_to_record = args[:link_to_record].present? ? args[:link_to_record] : false
|
13
13
|
|
14
14
|
@width = args[:width].present? ? args[:width] : 40
|
15
15
|
@height = args[:height].present? ? args[:height] : 40
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Avo
|
2
2
|
module Fields
|
3
3
|
class FileField < BaseField
|
4
|
-
attr_accessor :
|
4
|
+
attr_accessor :link_to_record
|
5
5
|
attr_accessor :is_avatar
|
6
6
|
attr_accessor :is_image
|
7
7
|
attr_accessor :is_audio
|
@@ -12,7 +12,7 @@ module Avo
|
|
12
12
|
def initialize(id, **args, &block)
|
13
13
|
super(id, **args, &block)
|
14
14
|
|
15
|
-
@
|
15
|
+
@link_to_record = args[:link_to_record].present? ? args[:link_to_record] : false
|
16
16
|
@is_avatar = args[:is_avatar].present? ? args[:is_avatar] : false
|
17
17
|
@is_image = args[:is_image].present? ? args[:is_image] : @is_avatar
|
18
18
|
@is_audio = args[:is_audio].present? ? args[:is_audio] : false
|
@@ -4,7 +4,7 @@ require "erb"
|
|
4
4
|
module Avo
|
5
5
|
module Fields
|
6
6
|
class GravatarField < BaseField
|
7
|
-
attr_reader :
|
7
|
+
attr_reader :link_to_record
|
8
8
|
attr_reader :rounded
|
9
9
|
attr_reader :size
|
10
10
|
attr_reader :default
|
@@ -16,7 +16,7 @@ module Avo
|
|
16
16
|
|
17
17
|
hide_on [:edit, :new]
|
18
18
|
|
19
|
-
@
|
19
|
+
@link_to_record = args[:link_to_record].present? ? args[:link_to_record] : false
|
20
20
|
@rounded = args[:rounded].nil? ? true : args[:rounded]
|
21
21
|
@size = args[:size].present? ? args[:size].to_i : 32
|
22
22
|
@default = args[:default].present? ? ERB::Util.url_encode(args[:default]).to_s : ""
|
@@ -79,8 +79,8 @@ module Avo
|
|
79
79
|
|
80
80
|
# Adds the view override component
|
81
81
|
# has_one, has_many, has_and_belongs_to_many fields don't have edit views
|
82
|
-
def component_for_view(view =
|
83
|
-
view =
|
82
|
+
def component_for_view(view = Avo::ViewInquirer.new("index"))
|
83
|
+
view = Avo::ViewInquirer.new("show") if view.in? %w[new create update edit]
|
84
84
|
|
85
85
|
super view
|
86
86
|
end
|
@@ -4,35 +4,27 @@ module Avo
|
|
4
4
|
module Fields
|
5
5
|
class HeadingField < BaseField
|
6
6
|
attr_reader :as_html
|
7
|
-
attr_reader :empty
|
8
|
-
|
9
|
-
def initialize(content, **args, &block)
|
10
|
-
# Mark the field as empty if there's no content passed
|
11
|
-
@empty = content.blank?
|
12
|
-
# Add dummy content
|
13
|
-
content ||= SecureRandom.hex
|
14
7
|
|
8
|
+
def initialize(id, **args, &block)
|
15
9
|
args[:updatable] = false
|
10
|
+
@label = args[:label] || id.to_s.humanize
|
16
11
|
|
17
|
-
super(
|
12
|
+
super(id, **args, &block)
|
18
13
|
|
19
14
|
# this field is not used to update anything
|
20
15
|
@for_presentation_only = true
|
21
16
|
|
22
17
|
hide_on :index
|
23
18
|
|
24
|
-
@as_html = args[:as_html].
|
19
|
+
@as_html = args[:as_html].presence || false
|
25
20
|
end
|
26
21
|
|
27
22
|
def id
|
28
23
|
"heading_#{name.to_s.parameterize.underscore}"
|
29
24
|
end
|
30
25
|
|
31
|
-
# Override the value method if the field is empty
|
32
26
|
def value
|
33
|
-
|
34
|
-
|
35
|
-
super
|
27
|
+
block.present? ? execute_block : @label
|
36
28
|
end
|
37
29
|
end
|
38
30
|
end
|