avo 2.7.1.pre.1 → 2.8.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 +5 -5
- 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 +10 -3
- 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 +13 -4
- data/app/components/avo/fields/trix_field/edit_component.rb +3 -0
- data/app/components/avo/fields/trix_field/show_component.html.erb +1 -1
- 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/views/resource_edit_component.html.erb +7 -4
- data/app/components/avo/views/resource_edit_component.rb +2 -1
- data/app/components/avo/views/resource_index_component.html.erb +6 -3
- data/app/components/avo/views/resource_index_component.rb +7 -1
- data/app/components/avo/views/resource_new_component.html.erb +7 -2
- data/app/components/avo/views/resource_new_component.rb +2 -1
- data/app/components/avo/views/resource_show_component.html.erb +9 -7
- 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 +14 -8
- data/app/controllers/avo/search_controller.rb +7 -1
- data/app/javascript/js/controllers/custom/course_resource_controller.js +102 -0
- 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 +10 -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/partials/_logo.html.erb +3 -2
- data/app/views/avo/partials/_navbar.html.erb +1 -1
- data/config/routes.rb +1 -1
- data/db/factories.rb +1 -0
- data/lib/avo/base_action.rb +9 -2
- data/lib/avo/base_card.rb +0 -23
- data/lib/avo/base_resource.rb +17 -15
- data/lib/avo/concerns/has_fields.rb +93 -0
- data/lib/avo/concerns/has_html_attributes.rb +110 -0
- data/lib/avo/concerns/has_stimulus_controllers.rb +42 -0
- data/lib/avo/fields/base_field.rb +23 -13
- data/lib/avo/fields/select_field.rb +1 -1
- data/lib/avo/grid_collector.rb +4 -4
- data/lib/avo/html/builder.rb +117 -0
- data/lib/avo/licensing/pro_license.rb +1 -0
- data/lib/avo/version.rb +1 -1
- data/lib/avo.rb +4 -0
- 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 +28 -8
- data/public/avo-assets/avo.js +148 -148
- data/public/avo-assets/avo.js.map +3 -3
- data/public/avo-assets/logomark.png +0 -0
- metadata +13 -10
- data/app/assets/builds/action_cable.js +0 -2
- data/app/assets/builds/action_cable.js.map +0 -7
- data/app/assets/builds/avo.css +0 -9610
- data/app/assets/builds/avo.js +0 -512
- data/app/assets/builds/avo.js.map +0 -7
- data/lib/avo/fields_collector.rb +0 -70
data/lib/avo/base_action.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
module Avo
|
2
2
|
class BaseAction
|
3
|
-
extend FieldsCollector
|
4
3
|
extend HasContext
|
5
4
|
|
5
|
+
include Avo::Concerns::HasFields
|
6
|
+
|
6
7
|
class_attribute :name, default: nil
|
7
8
|
class_attribute :message
|
8
9
|
class_attribute :confirm_button_label
|
@@ -12,7 +13,6 @@ module Avo
|
|
12
13
|
class_attribute :view
|
13
14
|
class_attribute :user
|
14
15
|
class_attribute :resource
|
15
|
-
class_attribute :fields
|
16
16
|
class_attribute :invalid_fields
|
17
17
|
class_attribute :standalone, default: false
|
18
18
|
class_attribute :visible
|
@@ -153,6 +153,13 @@ module Avo
|
|
153
153
|
self
|
154
154
|
end
|
155
155
|
|
156
|
+
# Add a placeholder silent message from when a user wants to do a redirect action or something similar
|
157
|
+
def silent
|
158
|
+
add_message nil, :silent
|
159
|
+
|
160
|
+
self
|
161
|
+
end
|
162
|
+
|
156
163
|
def redirect_to(path = nil, &block)
|
157
164
|
response[:type] = :redirect
|
158
165
|
response[:path] = if block.present?
|
data/lib/avo/base_card.rb
CHANGED
@@ -52,29 +52,6 @@ module Avo
|
|
52
52
|
@refresh_every || self.class.refresh_every
|
53
53
|
end
|
54
54
|
|
55
|
-
def translated_range(range)
|
56
|
-
return "#{range} days" if range.is_a? Integer
|
57
|
-
|
58
|
-
case range
|
59
|
-
when "MTD"
|
60
|
-
"Month to date"
|
61
|
-
when "QTD"
|
62
|
-
"Quarter to date"
|
63
|
-
when "YTD"
|
64
|
-
"Year to date"
|
65
|
-
when "TODAY"
|
66
|
-
"Today"
|
67
|
-
else
|
68
|
-
range
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def parsed_ranges
|
73
|
-
return unless ranges.present?
|
74
|
-
|
75
|
-
ranges.map { |range| [translated_range(range), range] }
|
76
|
-
end
|
77
|
-
|
78
55
|
def turbo_frame
|
79
56
|
"#{dashboard.id}_#{id}"
|
80
57
|
end
|
data/lib/avo/base_resource.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
module Avo
|
2
2
|
class BaseResource
|
3
3
|
extend ActiveSupport::DescendantsTracker
|
4
|
-
extend FieldsCollector
|
5
4
|
extend HasContext
|
6
5
|
|
7
6
|
include ActionView::Helpers::UrlHelper
|
8
7
|
include Avo::Concerns::HasTools
|
8
|
+
include Avo::Concerns::HasFields
|
9
|
+
include Avo::Concerns::HasStimulusControllers
|
9
10
|
|
10
|
-
delegate :view_context, to:
|
11
|
+
delegate :view_context, to: ::Avo::App
|
12
|
+
delegate :simple_format, :content_tag, to: :view_context
|
11
13
|
delegate :main_app, to: :view_context
|
12
14
|
delegate :avo, to: :view_context
|
13
15
|
delegate :resource_path, to: :view_context
|
@@ -28,12 +30,10 @@ module Avo
|
|
28
30
|
class_attribute :includes, default: []
|
29
31
|
class_attribute :model_class
|
30
32
|
class_attribute :translation_key
|
31
|
-
class_attribute :translation_enabled, default: false
|
32
33
|
class_attribute :default_view_type, default: :table
|
33
34
|
class_attribute :devise_password_optional, default: false
|
34
35
|
class_attribute :actions_loader
|
35
36
|
class_attribute :filters_loader
|
36
|
-
class_attribute :fields
|
37
37
|
class_attribute :grid_loader
|
38
38
|
class_attribute :visible_on_sidebar, default: true
|
39
39
|
class_attribute :unscoped_queries_on_index, default: false
|
@@ -106,8 +106,6 @@ module Avo
|
|
106
106
|
self.class.model_class = model_class.base_class
|
107
107
|
end
|
108
108
|
end
|
109
|
-
|
110
|
-
self.class.translation_enabled = ::Avo::App.translation_enabled
|
111
109
|
end
|
112
110
|
|
113
111
|
def hydrate(model: nil, view: nil, user: nil, params: nil)
|
@@ -128,7 +126,7 @@ module Avo
|
|
128
126
|
return [] if self.class.fields.blank?
|
129
127
|
|
130
128
|
fields = self.class.fields.map do |field|
|
131
|
-
field.hydrate(resource: self, panel_name: default_panel_name, user: user
|
129
|
+
field.hydrate(resource: self, panel_name: default_panel_name, user: user)
|
132
130
|
end
|
133
131
|
|
134
132
|
if Avo::App.license.lacks_with_trial(:custom_fields)
|
@@ -139,7 +137,7 @@ module Avo
|
|
139
137
|
|
140
138
|
if Avo::App.license.lacks_with_trial(:advanced_fields)
|
141
139
|
fields = fields.reject do |field|
|
142
|
-
field.type ==
|
140
|
+
field.type == "tags"
|
143
141
|
end
|
144
142
|
end
|
145
143
|
|
@@ -288,7 +286,7 @@ module Avo
|
|
288
286
|
end
|
289
287
|
|
290
288
|
def translation_key
|
291
|
-
return "avo.resource_translations.#{class_name_without_resource.underscore}" if
|
289
|
+
return "avo.resource_translations.#{class_name_without_resource.underscore}" if ::Avo::App.translation_enabled
|
292
290
|
|
293
291
|
self.class.translation_key
|
294
292
|
end
|
@@ -298,9 +296,11 @@ module Avo
|
|
298
296
|
|
299
297
|
return @name if @name.present?
|
300
298
|
|
301
|
-
|
302
|
-
|
303
|
-
|
299
|
+
if translation_key && ::Avo::App.translation_enabled
|
300
|
+
t(translation_key, count: 1, default: default).capitalize
|
301
|
+
else
|
302
|
+
default
|
303
|
+
end
|
304
304
|
end
|
305
305
|
|
306
306
|
def singular_name
|
@@ -310,9 +310,11 @@ module Avo
|
|
310
310
|
def plural_name
|
311
311
|
default = name.pluralize
|
312
312
|
|
313
|
-
|
314
|
-
|
315
|
-
|
313
|
+
if translation_key && ::Avo::App.translation_enabled
|
314
|
+
t(translation_key, count: 2, default: default).capitalize
|
315
|
+
else
|
316
|
+
default
|
317
|
+
end
|
316
318
|
end
|
317
319
|
|
318
320
|
def underscore_name
|
@@ -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
|
@@ -5,10 +5,13 @@ 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
|
+
|
13
|
+
delegate :view_context, to: ::Avo::App
|
14
|
+
delegate :simple_format, :content_tag, to: :view_context
|
12
15
|
delegate :main_app, to: :view_context
|
13
16
|
delegate :avo, to: :view_context
|
14
17
|
delegate :t, to: ::I18n
|
@@ -51,7 +54,6 @@ module Avo
|
|
51
54
|
@id = id
|
52
55
|
@name = args[:name]
|
53
56
|
@translation_key = args[:translation_key]
|
54
|
-
@translation_enabled = ::Avo::App.translation_enabled
|
55
57
|
@block = block
|
56
58
|
@required = args[:required] || false
|
57
59
|
@readonly = args[:readonly] || false
|
@@ -67,6 +69,7 @@ module Avo
|
|
67
69
|
@as_avatar = args[:as_avatar] || false
|
68
70
|
@as_description = args[:as_description] || false
|
69
71
|
@index_text_align = args[:index_text_align] || :left
|
72
|
+
@html = args[:html] || nil
|
70
73
|
|
71
74
|
@updatable = true
|
72
75
|
@computable = true
|
@@ -80,22 +83,21 @@ module Avo
|
|
80
83
|
except_on args[:except_on] if args[:except_on].present?
|
81
84
|
end
|
82
85
|
|
83
|
-
def hydrate(model: nil, resource: nil, action: nil, view: nil, panel_name: nil, user: nil
|
86
|
+
def hydrate(model: nil, resource: nil, action: nil, view: nil, panel_name: nil, user: nil)
|
84
87
|
@model = model if model.present?
|
85
88
|
@view = view if view.present?
|
86
89
|
@resource = resource if resource.present?
|
87
90
|
@action = action if action.present?
|
88
91
|
@user = user if user.present?
|
89
92
|
@panel_name = panel_name if panel_name.present?
|
90
|
-
@translation_enabled = translation_enabled if translation_enabled.present?
|
91
93
|
|
92
94
|
self
|
93
95
|
end
|
94
96
|
|
95
97
|
def translation_key
|
96
|
-
return
|
98
|
+
return @translation_key if @translation_key.present?
|
97
99
|
|
98
|
-
@
|
100
|
+
"avo.field_translations.#{@id}"
|
99
101
|
end
|
100
102
|
|
101
103
|
# Getting the name of the resource (user/users, post/posts)
|
@@ -105,19 +107,27 @@ module Avo
|
|
105
107
|
def name
|
106
108
|
default = @id.to_s.humanize(keep_id_suffix: true)
|
107
109
|
|
108
|
-
return @name if
|
110
|
+
return @name if custom_name?
|
109
111
|
|
110
|
-
|
111
|
-
|
112
|
-
|
112
|
+
if translation_key && ::Avo::App.translation_enabled
|
113
|
+
t(translation_key, count: 1, default: default).capitalize
|
114
|
+
else
|
115
|
+
default
|
116
|
+
end
|
113
117
|
end
|
114
118
|
|
115
119
|
def plural_name
|
116
120
|
default = name.pluralize
|
117
121
|
|
118
|
-
|
122
|
+
if translation_key && ::Avo::App.translation_enabled
|
123
|
+
t(translation_key, count: 2, default: default).capitalize
|
124
|
+
else
|
125
|
+
default
|
126
|
+
end
|
127
|
+
end
|
119
128
|
|
120
|
-
|
129
|
+
def custom_name?
|
130
|
+
@name.present?
|
121
131
|
end
|
122
132
|
|
123
133
|
def placeholder
|
@@ -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/version.rb
CHANGED
data/lib/avo.rb
CHANGED
@@ -5,7 +5,17 @@ class <%= class_name.camelize %> < Avo::Dashboards::ChartkickCard
|
|
5
5
|
# self.description = "Some tiny description"
|
6
6
|
# self.cols = 2
|
7
7
|
# self.initial_range = 30
|
8
|
-
# self.ranges =
|
8
|
+
# self.ranges = {
|
9
|
+
# "7 days": 7,
|
10
|
+
# "30 days": 30,
|
11
|
+
# "60 days": 60,
|
12
|
+
# "365 days": 365,
|
13
|
+
# Today: "TODAY",
|
14
|
+
# "Month to date": "MTD",
|
15
|
+
# "Quarter to date": "QTD",
|
16
|
+
# "Year to date": "YTD",
|
17
|
+
# All: "ALL",
|
18
|
+
# }
|
9
19
|
# self.chart_options = { library: { plugins: { legend: { display: true } } } }
|
10
20
|
# self.flush = true
|
11
21
|
|