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.

Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +5 -5
  4. data/app/components/avo/alert_component.rb +6 -0
  5. data/app/components/avo/card_component.html.erb +2 -2
  6. data/app/components/avo/common_field_wrapper_component.html.erb +10 -3
  7. data/app/components/avo/common_field_wrapper_component.rb +27 -1
  8. data/app/components/avo/edit/field_wrapper_component.html.erb +1 -1
  9. data/app/components/avo/fields/badge_field/index_component.html.erb +1 -1
  10. data/app/components/avo/fields/badge_field/show_component.html.erb +1 -1
  11. data/app/components/avo/fields/belongs_to_field/autocomplete_component.html.erb +21 -10
  12. data/app/components/avo/fields/belongs_to_field/autocomplete_component.rb +7 -1
  13. data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +27 -15
  14. data/app/components/avo/fields/belongs_to_field/edit_component.rb +4 -0
  15. data/app/components/avo/fields/belongs_to_field/index_component.html.erb +1 -1
  16. data/app/components/avo/fields/belongs_to_field/show_component.html.erb +1 -1
  17. data/app/components/avo/fields/boolean_field/edit_component.html.erb +4 -2
  18. data/app/components/avo/fields/boolean_field/index_component.html.erb +1 -1
  19. data/app/components/avo/fields/boolean_field/show_component.html.erb +1 -1
  20. data/app/components/avo/fields/boolean_group_field/edit_component.html.erb +7 -1
  21. data/app/components/avo/fields/boolean_group_field/index_component.html.erb +1 -1
  22. data/app/components/avo/fields/boolean_group_field/show_component.html.erb +1 -1
  23. data/app/components/avo/fields/code_field/edit_component.html.erb +7 -5
  24. data/app/components/avo/fields/code_field/show_component.html.erb +2 -2
  25. data/app/components/avo/fields/common/key_value_component.html.erb +10 -4
  26. data/app/components/avo/fields/common/key_value_component.rb +2 -0
  27. data/app/components/avo/fields/country_field/edit_component.html.erb +4 -2
  28. data/app/components/avo/fields/country_field/index_component.html.erb +1 -1
  29. data/app/components/avo/fields/country_field/show_component.html.erb +1 -1
  30. data/app/components/avo/fields/date_field/edit_component.html.erb +6 -4
  31. data/app/components/avo/fields/date_field/index_component.html.erb +1 -1
  32. data/app/components/avo/fields/date_field/show_component.html.erb +1 -1
  33. data/app/components/avo/fields/date_time_field/edit_component.html.erb +6 -4
  34. data/app/components/avo/fields/date_time_field/index_component.html.erb +1 -1
  35. data/app/components/avo/fields/date_time_field/show_component.html.erb +1 -1
  36. data/app/components/avo/fields/edit_component.rb +7 -0
  37. data/app/components/avo/fields/external_image_field/edit_component.html.erb +5 -2
  38. data/app/components/avo/fields/external_image_field/index_component.html.erb +6 -4
  39. data/app/components/avo/fields/external_image_field/show_component.html.erb +1 -1
  40. data/app/components/avo/fields/file_field/edit_component.html.erb +6 -1
  41. data/app/components/avo/fields/file_field/index_component.html.erb +1 -1
  42. data/app/components/avo/fields/file_field/show_component.html.erb +1 -1
  43. data/app/components/avo/fields/files_field/edit_component.html.erb +7 -1
  44. data/app/components/avo/fields/files_field/index_component.html.erb +1 -1
  45. data/app/components/avo/fields/files_field/show_component.html.erb +1 -1
  46. data/app/components/avo/fields/gravatar_field/index_component.html.erb +1 -1
  47. data/app/components/avo/fields/gravatar_field/show_component.html.erb +1 -1
  48. data/app/components/avo/fields/has_one_field/index_component.html.erb +1 -1
  49. data/app/components/avo/fields/hidden_field/edit_component.html.erb +5 -1
  50. data/app/components/avo/fields/id_field/edit_component.html.erb +1 -1
  51. data/app/components/avo/fields/id_field/index_component.html.erb +1 -1
  52. data/app/components/avo/fields/id_field/show_component.html.erb +1 -1
  53. data/app/components/avo/fields/index_component.rb +3 -0
  54. data/app/components/avo/fields/key_value_field/edit_component.html.erb +1 -1
  55. data/app/components/avo/fields/key_value_field/show_component.html.erb +1 -1
  56. data/app/components/avo/fields/markdown_field/edit_component.html.erb +8 -5
  57. data/app/components/avo/fields/markdown_field/show_component.html.erb +1 -1
  58. data/app/components/avo/fields/number_field/edit_component.html.erb +7 -4
  59. data/app/components/avo/fields/number_field/index_component.html.erb +1 -1
  60. data/app/components/avo/fields/number_field/show_component.html.erb +1 -1
  61. data/app/components/avo/fields/password_field/edit_component.html.erb +4 -2
  62. data/app/components/avo/fields/progress_bar_field/edit_component.html.erb +7 -4
  63. data/app/components/avo/fields/progress_bar_field/index_component.html.erb +1 -1
  64. data/app/components/avo/fields/progress_bar_field/show_component.html.erb +1 -1
  65. data/app/components/avo/fields/select_field/edit_component.html.erb +9 -3
  66. data/app/components/avo/fields/select_field/index_component.html.erb +1 -1
  67. data/app/components/avo/fields/select_field/show_component.html.erb +1 -1
  68. data/app/components/avo/fields/show_component.rb +3 -0
  69. data/app/components/avo/fields/status_field/edit_component.html.erb +6 -3
  70. data/app/components/avo/fields/status_field/index_component.html.erb +1 -1
  71. data/app/components/avo/fields/status_field/show_component.html.erb +1 -1
  72. data/app/components/avo/fields/tags_field/edit_component.html.erb +19 -11
  73. data/app/components/avo/fields/tags_field/index_component.html.erb +1 -1
  74. data/app/components/avo/fields/tags_field/show_component.html.erb +1 -1
  75. data/app/components/avo/fields/text_field/edit_component.html.erb +5 -2
  76. data/app/components/avo/fields/text_field/index_component.html.erb +1 -1
  77. data/app/components/avo/fields/text_field/show_component.html.erb +1 -1
  78. data/app/components/avo/fields/textarea_field/edit_component.html.erb +6 -3
  79. data/app/components/avo/fields/textarea_field/show_component.html.erb +1 -1
  80. data/app/components/avo/fields/trix_field/edit_component.html.erb +13 -4
  81. data/app/components/avo/fields/trix_field/edit_component.rb +3 -0
  82. data/app/components/avo/fields/trix_field/show_component.html.erb +1 -1
  83. data/app/components/avo/index/field_wrapper_component.html.erb +12 -5
  84. data/app/components/avo/index/field_wrapper_component.rb +27 -3
  85. data/app/components/avo/panel_component.rb +4 -3
  86. data/app/components/avo/resource_component.rb +1 -0
  87. data/app/components/avo/show/field_wrapper_component.html.erb +1 -1
  88. data/app/components/avo/show/field_wrapper_component.rb +2 -1
  89. data/app/components/avo/views/resource_edit_component.html.erb +7 -4
  90. data/app/components/avo/views/resource_edit_component.rb +2 -1
  91. data/app/components/avo/views/resource_index_component.html.erb +6 -3
  92. data/app/components/avo/views/resource_index_component.rb +7 -1
  93. data/app/components/avo/views/resource_new_component.html.erb +7 -2
  94. data/app/components/avo/views/resource_new_component.rb +2 -1
  95. data/app/components/avo/views/resource_show_component.html.erb +9 -7
  96. data/app/components/avo/views/resource_show_component.rb +1 -0
  97. data/app/controllers/avo/actions_controller.rb +4 -1
  98. data/app/controllers/avo/base_controller.rb +14 -8
  99. data/app/controllers/avo/search_controller.rb +7 -1
  100. data/app/javascript/js/controllers/custom/course_resource_controller.js +102 -0
  101. data/app/javascript/js/controllers/fields/code_field_controller.js +7 -1
  102. data/app/javascript/js/controllers/fields/key_value_controller.js +1 -0
  103. data/app/javascript/js/controllers/fields/tags_field_controller.js +0 -1
  104. data/app/javascript/js/controllers/menu_controller.js +4 -3
  105. data/app/javascript/js/controllers/resource_edit_controller.js +72 -0
  106. data/app/javascript/js/controllers/resource_index_controller.js +4 -0
  107. data/app/javascript/js/controllers/resource_show_controller.js +4 -0
  108. data/app/javascript/js/controllers/search_controller.js +28 -5
  109. data/app/javascript/js/controllers.js +10 -0
  110. data/app/views/avo/associations/new.html.erb +2 -1
  111. data/app/views/avo/base/_select_filter.html.erb +1 -1
  112. data/app/views/avo/base/_text_filter.html.erb +1 -0
  113. data/app/views/avo/partials/_logo.html.erb +3 -2
  114. data/app/views/avo/partials/_navbar.html.erb +1 -1
  115. data/config/routes.rb +1 -1
  116. data/db/factories.rb +1 -0
  117. data/lib/avo/base_action.rb +9 -2
  118. data/lib/avo/base_card.rb +0 -23
  119. data/lib/avo/base_resource.rb +17 -15
  120. data/lib/avo/concerns/has_fields.rb +93 -0
  121. data/lib/avo/concerns/has_html_attributes.rb +110 -0
  122. data/lib/avo/concerns/has_stimulus_controllers.rb +42 -0
  123. data/lib/avo/fields/base_field.rb +23 -13
  124. data/lib/avo/fields/select_field.rb +1 -1
  125. data/lib/avo/grid_collector.rb +4 -4
  126. data/lib/avo/html/builder.rb +117 -0
  127. data/lib/avo/licensing/pro_license.rb +1 -0
  128. data/lib/avo/version.rb +1 -1
  129. data/lib/avo.rb +4 -0
  130. data/lib/generators/avo/templates/cards/chartkick_card_sample.tt +11 -1
  131. data/lib/generators/avo/templates/cards/metric_card_sample.tt +11 -1
  132. data/lib/generators/avo/templates/field/components/edit_component.html.erb.tt +1 -1
  133. data/lib/generators/avo/templates/field/components/index_component.html.erb.tt +1 -1
  134. data/lib/generators/avo/templates/field/components/show_component.html.erb.tt +1 -1
  135. data/lib/generators/avo/templates/initializer/avo.tt +1 -1
  136. data/lib/generators/avo/templates/locales/avo.en.yml +3 -3
  137. data/public/avo-assets/avo.css +28 -8
  138. data/public/avo-assets/avo.js +148 -148
  139. data/public/avo-assets/avo.js.map +3 -3
  140. data/public/avo-assets/logomark.png +0 -0
  141. metadata +13 -10
  142. data/app/assets/builds/action_cable.js +0 -2
  143. data/app/assets/builds/action_cable.js.map +0 -7
  144. data/app/assets/builds/avo.css +0 -9610
  145. data/app/assets/builds/avo.js +0 -512
  146. data/app/assets/builds/avo.js.map +0 -7
  147. data/lib/avo/fields_collector.rb +0 -70
@@ -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
@@ -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: "Avo::App"
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, translation_enabled: translation_enabled)
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 == 'tags'
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 self.class.translation_enabled
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
- return t(translation_key, count: 1, default: default).capitalize if translation_key
302
-
303
- default
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
- return t(translation_key, count: 2, default: default).capitalize if translation_key
314
-
315
- default
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
- delegate :view_context, to: "Avo::App"
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, translation_enabled: 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 "avo.field_translations.#{@id}" if @translation_enabled
98
+ return @translation_key if @translation_key.present?
97
99
 
98
- @translation_key
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 @name.present?
110
+ return @name if custom_name?
109
111
 
110
- return t(translation_key, count: 1, default: default).capitalize if translation_key
111
-
112
- default
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
- return t(translation_key, count: 2, default: default).capitalize if translation_key
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
- default
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].present? ? args[:options] : args[:enum]
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
@@ -1,6 +1,6 @@
1
1
  module Avo
2
2
  class GridCollector
3
- include FieldsCollector
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
@@ -14,6 +14,7 @@ module Avo
14
14
  :resource_ordering,
15
15
  :dashboards,
16
16
  :menu_editor,
17
+ :stimulus_js_integration,
17
18
  :advanced_fields
18
19
  ]
19
20
  end
data/lib/avo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Avo
2
- VERSION = "2.7.1.pre.1" unless const_defined?(:VERSION)
2
+ VERSION = "2.8.0" unless const_defined?(:VERSION)
3
3
  end
data/lib/avo.rb CHANGED
@@ -3,6 +3,10 @@ require_relative "avo/version"
3
3
  require_relative "avo/engine" if defined?(Rails)
4
4
 
5
5
  loader = Zeitwerk::Loader.for_gem
6
+ loader.inflector.inflect(
7
+ "html" => "HTML",
8
+ "has_html_attributes" => "HasHTMLAttributes"
9
+ )
6
10
  loader.setup
7
11
 
8
12
  # .//*,,.....,,*/(*
@@ -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 = [7, 30, 60, 365, "TODAY", "MTD", "QTD", "YTD", "ALL"]
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