avo 2.7.0 → 2.9.0
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 -0
- data/Gemfile.lock +6 -4
- data/README.md +11 -0
- data/app/assets/stylesheets/avo.css +4 -4
- data/app/assets/stylesheets/css/{components → fields}/code.css +0 -0
- data/app/assets/stylesheets/css/{components → fields}/progress.css +0 -0
- data/app/assets/stylesheets/css/{components → fields}/status.css +0 -0
- data/app/assets/stylesheets/css/fields/trix.css +17 -0
- data/app/assets/svgs/download-solid-reversed.svg +2 -2
- data/app/components/avo/actions_component.html.erb +5 -13
- data/app/components/avo/actions_component.rb +39 -1
- data/app/components/avo/alert_component.rb +6 -0
- data/app/components/avo/card_component.html.erb +2 -2
- data/app/components/avo/common_field_wrapper_component.html.erb +11 -4
- data/app/components/avo/common_field_wrapper_component.rb +27 -1
- data/app/components/avo/edit/field_wrapper_component.html.erb +1 -1
- data/app/components/avo/fields/badge_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/badge_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/belongs_to_field/autocomplete_component.html.erb +21 -10
- data/app/components/avo/fields/belongs_to_field/autocomplete_component.rb +7 -1
- data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +27 -15
- data/app/components/avo/fields/belongs_to_field/edit_component.rb +4 -0
- data/app/components/avo/fields/belongs_to_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/belongs_to_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/boolean_field/edit_component.html.erb +4 -2
- data/app/components/avo/fields/boolean_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/boolean_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/boolean_group_field/edit_component.html.erb +7 -1
- data/app/components/avo/fields/boolean_group_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/boolean_group_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/code_field/edit_component.html.erb +7 -5
- data/app/components/avo/fields/code_field/show_component.html.erb +2 -2
- data/app/components/avo/fields/common/key_value_component.html.erb +10 -4
- data/app/components/avo/fields/common/key_value_component.rb +2 -0
- data/app/components/avo/fields/country_field/edit_component.html.erb +4 -2
- data/app/components/avo/fields/country_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/country_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/date_field/edit_component.html.erb +6 -4
- data/app/components/avo/fields/date_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/date_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/date_time_field/edit_component.html.erb +6 -4
- data/app/components/avo/fields/date_time_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/date_time_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/edit_component.rb +7 -0
- data/app/components/avo/fields/external_image_field/edit_component.html.erb +5 -2
- data/app/components/avo/fields/external_image_field/index_component.html.erb +6 -4
- data/app/components/avo/fields/external_image_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/file_field/edit_component.html.erb +6 -1
- data/app/components/avo/fields/file_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/file_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/files_field/edit_component.html.erb +7 -1
- data/app/components/avo/fields/files_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/files_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/gravatar_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/gravatar_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/has_one_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/hidden_field/edit_component.html.erb +5 -1
- data/app/components/avo/fields/id_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/id_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/id_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/index_component.rb +3 -0
- data/app/components/avo/fields/key_value_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/key_value_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/markdown_field/edit_component.html.erb +8 -5
- data/app/components/avo/fields/markdown_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/number_field/edit_component.html.erb +7 -4
- data/app/components/avo/fields/number_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/number_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/password_field/edit_component.html.erb +4 -2
- data/app/components/avo/fields/progress_bar_field/edit_component.html.erb +7 -4
- data/app/components/avo/fields/progress_bar_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/progress_bar_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/select_field/edit_component.html.erb +9 -3
- data/app/components/avo/fields/select_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/select_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/show_component.rb +3 -0
- data/app/components/avo/fields/status_field/edit_component.html.erb +6 -3
- data/app/components/avo/fields/status_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/status_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/tags_field/edit_component.html.erb +19 -11
- data/app/components/avo/fields/tags_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/tags_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/text_field/edit_component.html.erb +5 -2
- data/app/components/avo/fields/text_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/text_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/textarea_field/edit_component.html.erb +6 -3
- data/app/components/avo/fields/textarea_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/trix_field/edit_component.html.erb +14 -4
- data/app/components/avo/fields/trix_field/edit_component.rb +3 -0
- data/app/components/avo/fields/trix_field/show_component.html.erb +2 -2
- data/app/components/avo/index/field_wrapper_component.html.erb +12 -5
- data/app/components/avo/index/field_wrapper_component.rb +27 -3
- data/app/components/avo/panel_component.rb +4 -3
- data/app/components/avo/resource_component.rb +1 -0
- data/app/components/avo/show/field_wrapper_component.html.erb +1 -1
- data/app/components/avo/show/field_wrapper_component.rb +2 -1
- data/app/components/avo/sidebar/item_switcher_component.html.erb +2 -2
- data/app/components/avo/views/resource_edit_component.html.erb +13 -8
- data/app/components/avo/views/resource_edit_component.rb +32 -3
- data/app/components/avo/views/resource_index_component.html.erb +7 -4
- data/app/components/avo/views/resource_index_component.rb +7 -1
- data/app/components/avo/views/resource_show_component.html.erb +11 -9
- data/app/components/avo/views/resource_show_component.rb +1 -0
- data/app/controllers/avo/actions_controller.rb +4 -1
- data/app/controllers/avo/base_controller.rb +24 -13
- data/app/controllers/avo/cards_controller.rb +25 -0
- data/app/controllers/avo/dashboards_controller.rb +2 -8
- data/app/controllers/avo/home_controller.rb +8 -1
- data/app/controllers/avo/search_controller.rb +7 -1
- data/app/helpers/avo/url_helpers.rb +8 -9
- data/app/javascript/js/controllers/fields/code_field_controller.js +7 -1
- data/app/javascript/js/controllers/fields/key_value_controller.js +1 -0
- data/app/javascript/js/controllers/fields/tags_field_controller.js +0 -1
- data/app/javascript/js/controllers/menu_controller.js +4 -3
- data/app/javascript/js/controllers/resource_edit_controller.js +72 -0
- data/app/javascript/js/controllers/resource_index_controller.js +4 -0
- data/app/javascript/js/controllers/resource_show_controller.js +4 -0
- data/app/javascript/js/controllers/search_controller.js +28 -5
- data/app/javascript/js/controllers.js +8 -0
- data/app/views/avo/associations/new.html.erb +2 -1
- data/app/views/avo/base/_select_filter.html.erb +1 -1
- data/app/views/avo/base/_text_filter.html.erb +1 -0
- data/app/views/avo/base/edit.html.erb +2 -1
- data/app/views/avo/base/new.html.erb +1 -1
- data/app/views/avo/{dashboards → cards}/_chartkick_card.html.erb +0 -0
- data/app/views/avo/{dashboards → cards}/_metric_card.html.erb +0 -0
- data/app/views/avo/{dashboards/card.html.erb → cards/show.html.erb} +0 -0
- data/app/views/avo/partials/_custom_tools_alert.html.erb +21 -7
- data/app/views/avo/partials/_logo.html.erb +3 -2
- data/app/views/avo/partials/_navbar.html.erb +1 -1
- data/app/views/avo/partials/_table_header.html.erb +9 -1
- data/bin/test +1 -0
- data/config/routes.rb +7 -4
- data/db/factories.rb +1 -0
- data/lib/avo/app.rb +18 -1
- data/lib/avo/base_action.rb +16 -4
- data/lib/avo/base_card.rb +0 -23
- data/lib/avo/base_resource.rb +23 -16
- data/lib/avo/concerns/fetches_things.rb +19 -12
- data/lib/avo/concerns/has_fields.rb +93 -0
- data/lib/avo/concerns/has_html_attributes.rb +110 -0
- data/lib/avo/concerns/has_model.rb +11 -0
- data/lib/avo/concerns/has_stimulus_controllers.rb +42 -0
- data/lib/avo/dynamic_router.rb +1 -1
- data/lib/avo/engine.rb +1 -3
- data/lib/avo/fields/base_field.rb +24 -13
- data/lib/avo/fields/concerns/is_required.rb +17 -0
- data/lib/avo/fields/select_field.rb +1 -1
- data/lib/avo/grid_collector.rb +4 -4
- data/lib/avo/hosts/view_record_host.rb +7 -0
- data/lib/avo/html/builder.rb +117 -0
- data/lib/avo/licensing/pro_license.rb +1 -0
- data/lib/avo/menu/base_item.rb +4 -0
- data/lib/avo/menu/dashboard.rb +5 -0
- data/lib/avo/menu/resource.rb +5 -0
- data/lib/avo/version.rb +1 -1
- data/lib/avo.rb +5 -0
- data/lib/generators/avo/install_generator.rb +1 -4
- data/lib/generators/avo/templates/cards/chartkick_card_sample.tt +11 -1
- data/lib/generators/avo/templates/cards/metric_card_sample.tt +11 -1
- data/lib/generators/avo/templates/field/components/edit_component.html.erb.tt +1 -1
- data/lib/generators/avo/templates/field/components/index_component.html.erb.tt +1 -1
- data/lib/generators/avo/templates/field/components/show_component.html.erb.tt +1 -1
- data/lib/generators/avo/templates/initializer/avo.tt +1 -1
- data/lib/generators/avo/templates/locales/avo.en.yml +3 -3
- data/public/avo-assets/avo.css +473 -1055
- data/public/avo-assets/avo.js +147 -147
- data/public/avo-assets/avo.js.map +3 -3
- data/public/avo-assets/logomark.png +0 -0
- metadata +21 -11
- data/app/components/avo/views/resource_new_component.html.erb +0 -55
- data/app/components/avo/views/resource_new_component.rb +0 -38
- data/lib/avo/fields_collector.rb +0 -70
@@ -22,6 +22,13 @@ module Avo
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
# Filters out the resources that are missing the model_class
|
26
|
+
def valid_resources
|
27
|
+
resources.select do |resource|
|
28
|
+
resource.model_class.present?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
25
32
|
# Returns the Avo resource by camelized name
|
26
33
|
#
|
27
34
|
# get_resource_by_name('User') => UserResource
|
@@ -45,9 +52,10 @@ module Avo
|
|
45
52
|
# get_resource_by_name('User') => UserResource
|
46
53
|
# get_resource_by_name(User) => UserResource
|
47
54
|
def get_resource_by_model_name(name)
|
48
|
-
|
49
|
-
|
50
|
-
|
55
|
+
valid_resources
|
56
|
+
.find do |resource|
|
57
|
+
resource.model_class.model_name.name == name.to_s
|
58
|
+
end
|
51
59
|
end
|
52
60
|
|
53
61
|
# Returns the Avo resource by singular snake_cased name
|
@@ -55,9 +63,10 @@ module Avo
|
|
55
63
|
# get_resource_by_controller_name('delayed_backend_active_record_jobs') => DelayedJobResource
|
56
64
|
# get_resource_by_controller_name('users') => UserResource
|
57
65
|
def get_resource_by_controller_name(name)
|
58
|
-
|
59
|
-
|
60
|
-
|
66
|
+
valid_resources
|
67
|
+
.find do |resource|
|
68
|
+
resource.model_class.to_s.pluralize.underscore.tr("/", "_") == name.to_s
|
69
|
+
end
|
61
70
|
end
|
62
71
|
|
63
72
|
# Returns the Avo resource by some name
|
@@ -73,9 +82,10 @@ module Avo
|
|
73
82
|
end
|
74
83
|
|
75
84
|
def get_available_resources(user = nil)
|
76
|
-
|
77
|
-
|
78
|
-
|
85
|
+
valid_resources
|
86
|
+
.select do |resource|
|
87
|
+
Services::AuthorizationService.authorize user, resource.model_class, Avo.configuration.authorization_methods.stringify_keys["index"], raise_exception: false
|
88
|
+
end
|
79
89
|
.sort_by { |r| r.name }
|
80
90
|
end
|
81
91
|
|
@@ -85,9 +95,6 @@ module Avo
|
|
85
95
|
|
86
96
|
def resources_for_navigation(user = nil)
|
87
97
|
get_available_resources(current_user)
|
88
|
-
.select do |resource|
|
89
|
-
resource.model_class.present?
|
90
|
-
end
|
91
98
|
.select do |resource|
|
92
99
|
resource.visible_on_sidebar
|
93
100
|
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Avo
|
2
|
+
module Concerns
|
3
|
+
module HasFields
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
class_attribute :fields
|
8
|
+
class_attribute :fields_index, default: 0
|
9
|
+
end
|
10
|
+
|
11
|
+
class_methods do
|
12
|
+
def field(field_name, as:, **args, &block)
|
13
|
+
self.invalid_fields ||= []
|
14
|
+
|
15
|
+
field_instance = parse_field(field_name, as: as, order_index: fields_index, **args, &block)
|
16
|
+
|
17
|
+
if field_instance.present?
|
18
|
+
add_to_fields field_instance
|
19
|
+
else
|
20
|
+
self.invalid_fields << ({
|
21
|
+
name: field_name,
|
22
|
+
as: as,
|
23
|
+
resource: name,
|
24
|
+
message: "There's an invalid field configuration for this resource. <br/> <code class='px-1 py-px rounded bg-red-600'>field :#{field_name}, as: #{as}</code>"
|
25
|
+
})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse_field(field_name, as:, **args, &block)
|
30
|
+
# The field is passed as a symbol eg: :text, :color_picker, :trix
|
31
|
+
if as.is_a? Symbol
|
32
|
+
parse_symbol field_name, as: as, **args, &block
|
33
|
+
elsif as.is_a? Class
|
34
|
+
parse_class field_name, as: as, **args, &block
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def heading(body, **args)
|
39
|
+
add_to_fields Avo::Fields::HeadingField.new(body, order_index: fields_index, **args)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def add_to_fields(instance)
|
45
|
+
self.fields ||= []
|
46
|
+
self.fields << instance
|
47
|
+
self.fields_index += 1
|
48
|
+
end
|
49
|
+
|
50
|
+
def instantiate_field(field_name, klass:, **args, &block)
|
51
|
+
if block
|
52
|
+
klass.new(field_name, **args || {}, &block)
|
53
|
+
else
|
54
|
+
klass.new(field_name, **args || {})
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def field_class_from_symbol(symbol)
|
59
|
+
matched_field = Avo::App.fields.find do |field|
|
60
|
+
field[:name].to_s == symbol.to_s
|
61
|
+
end
|
62
|
+
|
63
|
+
return matched_field[:class] if matched_field.present? && matched_field[:class].present?
|
64
|
+
end
|
65
|
+
|
66
|
+
def parse_symbol(field_name, as:, **args, &block)
|
67
|
+
field_class = field_class_from_symbol(as)
|
68
|
+
|
69
|
+
if field_class.present?
|
70
|
+
# The field has been registered before.
|
71
|
+
instantiate_field(field_name, klass: field_class, **args, &block)
|
72
|
+
else
|
73
|
+
# The symbol can be transformed to a class and found.
|
74
|
+
class_name = as.to_s.camelize
|
75
|
+
field_class = "#{class_name}Field"
|
76
|
+
|
77
|
+
# Discover & load custom field classes
|
78
|
+
if Object.const_defined? field_class
|
79
|
+
instantiate_field(field_name, klass: field_class.safe_constantize, **args, &block)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def parse_class(field_name, as:, **args, &block)
|
85
|
+
# The field has been passed as a class.
|
86
|
+
if Object.const_defined? as.to_s
|
87
|
+
instantiate_field(field_name, klass: as, **args, &block)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module Avo
|
2
|
+
module Concerns
|
3
|
+
module HasHTMLAttributes
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
attr_reader :html
|
7
|
+
|
8
|
+
# Used to get attributes for elements and views
|
9
|
+
#
|
10
|
+
# examples:
|
11
|
+
# get_html :data, view: :edit, element: :input
|
12
|
+
# get_html :classes, view: :show, element: :wrapper
|
13
|
+
# get_html :styles, view: :index, element: :wrapper
|
14
|
+
def get_html(name = nil, element:, view:)
|
15
|
+
if [view, element].any?(&:nil?) || Avo::App.license.lacks_with_trial(:stimulus_js_integration)
|
16
|
+
default_attribute_value name
|
17
|
+
end
|
18
|
+
|
19
|
+
attributes = if html_builder.is_a? Hash
|
20
|
+
get_html_from_hash name, element: element, view: view
|
21
|
+
elsif html_builder.is_a? Avo::HTML::Builder
|
22
|
+
get_html_from_block name, element: element, view: view
|
23
|
+
elsif html_builder.nil?
|
24
|
+
# Handle empty html_builder by returning an empty state
|
25
|
+
default_attribute_value name
|
26
|
+
end
|
27
|
+
|
28
|
+
add_default_data_attributes attributes, name, element, view
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def html_builder
|
34
|
+
return @parsed_html if @parsed_html.present?
|
35
|
+
|
36
|
+
return if @html.nil?
|
37
|
+
|
38
|
+
# Memoize the value
|
39
|
+
@parsed_html = if @html.is_a? Hash
|
40
|
+
@html
|
41
|
+
elsif @html.respond_to? :call
|
42
|
+
Avo::HTML::Builder.parse_block(record: model, resource: resource, &@html)
|
43
|
+
end
|
44
|
+
|
45
|
+
@parsed_html
|
46
|
+
end
|
47
|
+
|
48
|
+
def default_attribute_value(name)
|
49
|
+
name == :data ? {} : ""
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_default_data_attributes(attributes, name, element, view)
|
53
|
+
if !attributes.nil? && name == :data && element == :input && view.in?([:edit, :new]) && resource.present?
|
54
|
+
extra_attributes = resource.get_stimulus_controllers
|
55
|
+
.split(" ")
|
56
|
+
.map do |controller|
|
57
|
+
[:"#{controller}-target", "#{id.to_s.underscore}_#{type.to_s.underscore}_input".camelize(:lower)]
|
58
|
+
end
|
59
|
+
.to_h
|
60
|
+
|
61
|
+
extra_attributes.merge attributes
|
62
|
+
else
|
63
|
+
attributes
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_html_from_block(name = nil, element:, view:)
|
68
|
+
values = []
|
69
|
+
|
70
|
+
# get view ancestor
|
71
|
+
values << html_builder.dig_stack(view, element, name)
|
72
|
+
# get element ancestor
|
73
|
+
values << html_builder.dig_stack(element, name)
|
74
|
+
# get direct ancestor
|
75
|
+
values << html_builder.dig_stack(name)
|
76
|
+
|
77
|
+
values_type = if name == :data
|
78
|
+
:hash
|
79
|
+
else
|
80
|
+
:string
|
81
|
+
end
|
82
|
+
|
83
|
+
merge_values_as(as: values_type, values: values)
|
84
|
+
end
|
85
|
+
|
86
|
+
def get_html_from_hash(name = nil, element:, view:)
|
87
|
+
# @todo: what if this is not a Hash but a string?
|
88
|
+
html_builder.dig(view, element, name) || {}
|
89
|
+
end
|
90
|
+
|
91
|
+
# Merge the values from all possible locations.
|
92
|
+
# If the result is "blank", return nil so the attributes are not outputted to the DOM.
|
93
|
+
#
|
94
|
+
# Ex: if the style attribute is empty return `nil` instead of an empty space `" "`
|
95
|
+
def merge_values_as(as: :array, values: [])
|
96
|
+
result = if as == :array
|
97
|
+
values.flatten
|
98
|
+
elsif as == :string
|
99
|
+
values.select do |value|
|
100
|
+
value.is_a? String
|
101
|
+
end.join " "
|
102
|
+
elsif as == :hash
|
103
|
+
values.reduce({}, :merge)
|
104
|
+
end
|
105
|
+
|
106
|
+
result if result.present?
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Avo
|
2
|
+
module Concerns
|
3
|
+
module HasStimulusControllers
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
class_attribute :stimulus_controllers, default: ""
|
8
|
+
end
|
9
|
+
|
10
|
+
def get_stimulus_controllers
|
11
|
+
return "" if view.nil?
|
12
|
+
|
13
|
+
controllers = []
|
14
|
+
|
15
|
+
case view.to_sym
|
16
|
+
when :show
|
17
|
+
controllers << "resource-show"
|
18
|
+
when :new, :edit
|
19
|
+
controllers << "resource-edit"
|
20
|
+
when :index
|
21
|
+
controllers << "resource-index"
|
22
|
+
end
|
23
|
+
|
24
|
+
controllers << self.class.stimulus_controllers
|
25
|
+
|
26
|
+
controllers.join " "
|
27
|
+
end
|
28
|
+
|
29
|
+
def stimulus_data_attributes
|
30
|
+
attributes = {
|
31
|
+
controller: get_stimulus_controllers,
|
32
|
+
}
|
33
|
+
|
34
|
+
get_stimulus_controllers.split(" ").each do |controller|
|
35
|
+
attributes["#{controller}-view-value"] = view
|
36
|
+
end
|
37
|
+
|
38
|
+
attributes
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/avo/dynamic_router.rb
CHANGED
data/lib/avo/engine.rb
CHANGED
@@ -17,8 +17,6 @@ module Avo
|
|
17
17
|
::Avo::App.boot
|
18
18
|
end
|
19
19
|
|
20
|
-
config.i18n.load_path += Dir[Avo::Engine.root.join("lib", "generators", "avo", "templates", "locales", "*.{rb,yml}")]
|
21
|
-
|
22
20
|
initializer "avo.autoload" do |app|
|
23
21
|
[
|
24
22
|
["app", "avo", "fields"],
|
@@ -73,7 +71,7 @@ module Avo
|
|
73
71
|
begin
|
74
72
|
Licensing::HQ.new.clear_response
|
75
73
|
rescue => exception
|
76
|
-
puts "Failed to clear Avo HQ response: #{
|
74
|
+
puts "Failed to clear Avo HQ response: #{exception.message}"
|
77
75
|
end
|
78
76
|
end
|
79
77
|
end
|
@@ -5,10 +5,14 @@ module Avo
|
|
5
5
|
extend Avo::Fields::FieldExtensions::HasFieldName
|
6
6
|
|
7
7
|
include Avo::Fields::FieldExtensions::VisibleInDifferentViews
|
8
|
-
include Avo::Concerns::HandlesFieldArgs
|
9
8
|
include ActionView::Helpers::UrlHelper
|
10
9
|
|
11
|
-
|
10
|
+
include Avo::Concerns::HandlesFieldArgs
|
11
|
+
include Avo::Concerns::HasHTMLAttributes
|
12
|
+
include Avo::Fields::Concerns::IsRequired
|
13
|
+
|
14
|
+
delegate :view_context, to: ::Avo::App
|
15
|
+
delegate :simple_format, :content_tag, to: :view_context
|
12
16
|
delegate :main_app, to: :view_context
|
13
17
|
delegate :avo, to: :view_context
|
14
18
|
delegate :t, to: ::I18n
|
@@ -51,7 +55,6 @@ module Avo
|
|
51
55
|
@id = id
|
52
56
|
@name = args[:name]
|
53
57
|
@translation_key = args[:translation_key]
|
54
|
-
@translation_enabled = ::Avo::App.translation_enabled
|
55
58
|
@block = block
|
56
59
|
@required = args[:required] || false
|
57
60
|
@readonly = args[:readonly] || false
|
@@ -67,6 +70,7 @@ module Avo
|
|
67
70
|
@as_avatar = args[:as_avatar] || false
|
68
71
|
@as_description = args[:as_description] || false
|
69
72
|
@index_text_align = args[:index_text_align] || :left
|
73
|
+
@html = args[:html] || nil
|
70
74
|
|
71
75
|
@updatable = true
|
72
76
|
@computable = true
|
@@ -80,22 +84,21 @@ module Avo
|
|
80
84
|
except_on args[:except_on] if args[:except_on].present?
|
81
85
|
end
|
82
86
|
|
83
|
-
def hydrate(model: nil, resource: nil, action: nil, view: nil, panel_name: nil, user: nil
|
87
|
+
def hydrate(model: nil, resource: nil, action: nil, view: nil, panel_name: nil, user: nil)
|
84
88
|
@model = model if model.present?
|
85
89
|
@view = view if view.present?
|
86
90
|
@resource = resource if resource.present?
|
87
91
|
@action = action if action.present?
|
88
92
|
@user = user if user.present?
|
89
93
|
@panel_name = panel_name if panel_name.present?
|
90
|
-
@translation_enabled = translation_enabled if translation_enabled.present?
|
91
94
|
|
92
95
|
self
|
93
96
|
end
|
94
97
|
|
95
98
|
def translation_key
|
96
|
-
return
|
99
|
+
return @translation_key if @translation_key.present?
|
97
100
|
|
98
|
-
@
|
101
|
+
"avo.field_translations.#{@id}"
|
99
102
|
end
|
100
103
|
|
101
104
|
# Getting the name of the resource (user/users, post/posts)
|
@@ -105,19 +108,27 @@ module Avo
|
|
105
108
|
def name
|
106
109
|
default = @id.to_s.humanize(keep_id_suffix: true)
|
107
110
|
|
108
|
-
return @name if
|
111
|
+
return @name if custom_name?
|
109
112
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
+
if translation_key && ::Avo::App.translation_enabled
|
114
|
+
t(translation_key, count: 1, default: default).capitalize
|
115
|
+
else
|
116
|
+
default
|
117
|
+
end
|
113
118
|
end
|
114
119
|
|
115
120
|
def plural_name
|
116
121
|
default = name.pluralize
|
117
122
|
|
118
|
-
|
123
|
+
if translation_key && ::Avo::App.translation_enabled
|
124
|
+
t(translation_key, count: 2, default: default).capitalize
|
125
|
+
else
|
126
|
+
default
|
127
|
+
end
|
128
|
+
end
|
119
129
|
|
120
|
-
|
130
|
+
def custom_name?
|
131
|
+
@name.present?
|
121
132
|
end
|
122
133
|
|
123
134
|
def placeholder
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Avo
|
2
|
+
module Fields
|
3
|
+
module Concerns
|
4
|
+
module IsRequired
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
def is_required?
|
8
|
+
if required.respond_to? :call
|
9
|
+
Avo::Hosts::ViewRecordHost.new(block: required, record: model, view: view).handle
|
10
|
+
else
|
11
|
+
required
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -10,7 +10,7 @@ module Avo
|
|
10
10
|
|
11
11
|
super(id, **args, &block)
|
12
12
|
|
13
|
-
@options = args[:options]
|
13
|
+
@options = args[:options] || args[:enum]
|
14
14
|
@options = ActiveSupport::HashWithIndifferentAccess.new @options if @options.is_a? Hash
|
15
15
|
@enum = args[:enum].present? ? args[:enum] : nil
|
16
16
|
@display_value = args[:display_value].present? ? args[:display_value] : false
|
data/lib/avo/grid_collector.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Avo
|
2
2
|
class GridCollector
|
3
|
-
include
|
3
|
+
include Avo::Concerns::HasFields
|
4
4
|
|
5
5
|
attr_accessor :cover_field
|
6
6
|
attr_accessor :title_field
|
@@ -13,15 +13,15 @@ module Avo
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def cover(field_name, as:, **args, &block)
|
16
|
-
self.cover_field = parse_field(field_name, as: as, **args, &block)
|
16
|
+
self.cover_field = self.class.parse_field(field_name, as: as, **args, &block)
|
17
17
|
end
|
18
18
|
|
19
19
|
def title(field_name, as:, **args, &block)
|
20
|
-
self.title_field = parse_field(field_name, as: as, **args, &block)
|
20
|
+
self.title_field = self.class.parse_field(field_name, as: as, **args, &block)
|
21
21
|
end
|
22
22
|
|
23
23
|
def body(field_name, as:, **args, &block)
|
24
|
-
self.body_field = parse_field(field_name, as: as, **args, &block)
|
24
|
+
self.body_field = self.class.parse_field(field_name, as: as, **args, &block)
|
25
25
|
end
|
26
26
|
|
27
27
|
def hydrate(model:, view:, resource:)
|
@@ -0,0 +1,117 @@
|
|
1
|
+
class Avo::HTML::Builder
|
2
|
+
class << self
|
3
|
+
def parse_block(record: nil, resource: nil, &block)
|
4
|
+
Docile.dsl_eval(Avo::HTML::Builder.new(record: record, resource: resource), &block).build
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_accessor :wrapper_stack
|
9
|
+
attr_accessor :data_stack
|
10
|
+
attr_accessor :style_stack
|
11
|
+
attr_accessor :classes_stack
|
12
|
+
attr_accessor :show_stack
|
13
|
+
attr_accessor :edit_stack
|
14
|
+
attr_accessor :index_stack
|
15
|
+
attr_accessor :input_stack
|
16
|
+
|
17
|
+
attr_accessor :record
|
18
|
+
attr_accessor :resource
|
19
|
+
|
20
|
+
delegate :root_path, to: Avo::App
|
21
|
+
delegate :params, to: Avo::App
|
22
|
+
delegate :current_user, to: Avo::App
|
23
|
+
|
24
|
+
def initialize(record: nil, resource: nil)
|
25
|
+
@wrapper_stack = {}
|
26
|
+
@data_stack = {}
|
27
|
+
@style_stack = ""
|
28
|
+
@classes_stack = ""
|
29
|
+
@show_stack = {}
|
30
|
+
@edit_stack = {}
|
31
|
+
@index_stack = {}
|
32
|
+
@input_stack = {}
|
33
|
+
|
34
|
+
@record = record
|
35
|
+
@resource = resource
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_stack(name = nil)
|
39
|
+
# We don't have an edit component for new so we should use edit
|
40
|
+
name = :edit if name == :new
|
41
|
+
|
42
|
+
send "#{name}_stack"
|
43
|
+
end
|
44
|
+
|
45
|
+
def dig_stack(*names)
|
46
|
+
value = get_stack names.shift
|
47
|
+
|
48
|
+
if value.is_a? self.class
|
49
|
+
value.dig_stack(*names)
|
50
|
+
else
|
51
|
+
value
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# payload or block
|
56
|
+
def data(payload = nil, &block)
|
57
|
+
assign_property :data, payload, &block
|
58
|
+
end
|
59
|
+
|
60
|
+
# payload or block
|
61
|
+
def style(payload = nil, &block)
|
62
|
+
assign_property :style, payload, &block
|
63
|
+
end
|
64
|
+
|
65
|
+
# payload or block
|
66
|
+
def classes(payload = nil, &block)
|
67
|
+
assign_property :classes, payload, &block
|
68
|
+
end
|
69
|
+
|
70
|
+
# Takes a block
|
71
|
+
def wrapper(&block)
|
72
|
+
capture_block :wrapper, &block
|
73
|
+
end
|
74
|
+
|
75
|
+
# Takes a block
|
76
|
+
def input(&block)
|
77
|
+
capture_block :input, &block
|
78
|
+
end
|
79
|
+
|
80
|
+
# Takes a block
|
81
|
+
def show(&block)
|
82
|
+
capture_block :show, &block
|
83
|
+
end
|
84
|
+
|
85
|
+
# Takes a block
|
86
|
+
def edit(&block)
|
87
|
+
capture_block :edit, &block
|
88
|
+
end
|
89
|
+
|
90
|
+
# Takes a block
|
91
|
+
def index(&block)
|
92
|
+
capture_block :index, &block
|
93
|
+
end
|
94
|
+
|
95
|
+
# Fetch the menu
|
96
|
+
def build
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
protected
|
101
|
+
|
102
|
+
# Capture and parse the blocks for the nested structure
|
103
|
+
def capture_block(property = nil, &block)
|
104
|
+
send("#{property}_stack=", self.class.parse_block(record: record, resource: resource, &block).build)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Parse the properties and assign them to the blocks
|
108
|
+
def assign_property(property = :data, payload = nil, &block)
|
109
|
+
value = if block.present?
|
110
|
+
Avo::Hosts::RecordHost.new(block: block, record: record).handle
|
111
|
+
else
|
112
|
+
payload
|
113
|
+
end
|
114
|
+
|
115
|
+
send("#{property}_stack=", value)
|
116
|
+
end
|
117
|
+
end
|
data/lib/avo/menu/base_item.rb
CHANGED
data/lib/avo/menu/dashboard.rb
CHANGED
@@ -2,6 +2,7 @@ class Avo::Menu::Dashboard < Avo::Menu::BaseItem
|
|
2
2
|
extend Dry::Initializer
|
3
3
|
|
4
4
|
option :dashboard
|
5
|
+
option :label, optional: true
|
5
6
|
|
6
7
|
def parsed_dashboard
|
7
8
|
dashboard_by_id || dashboard_by_name
|
@@ -14,4 +15,8 @@ class Avo::Menu::Dashboard < Avo::Menu::BaseItem
|
|
14
15
|
def dashboard_by_id
|
15
16
|
Avo::App.get_dashboard_by_id dashboard.to_s
|
16
17
|
end
|
18
|
+
|
19
|
+
def entity_label
|
20
|
+
parsed_dashboard.navigation_label
|
21
|
+
end
|
17
22
|
end
|
data/lib/avo/menu/resource.rb
CHANGED
@@ -2,8 +2,13 @@ class Avo::Menu::Resource < Avo::Menu::BaseItem
|
|
2
2
|
extend Dry::Initializer
|
3
3
|
|
4
4
|
option :resource
|
5
|
+
option :label, optional: true
|
5
6
|
|
6
7
|
def parsed_resource
|
7
8
|
Avo::App.guess_resource resource.to_s
|
8
9
|
end
|
10
|
+
|
11
|
+
def entity_label
|
12
|
+
parsed_resource.navigation_label
|
13
|
+
end
|
9
14
|
end
|
data/lib/avo/version.rb
CHANGED