avo 3.0.0.pre18 → 3.0.0.pre19

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 (118) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/Gemfile.lock +23 -25
  4. data/Rakefile +2 -0
  5. data/{public/avo-assets/avo.css → app/assets/builds/avo.base.css} +587 -3848
  6. data/app/assets/builds/avo.base.js +124556 -0
  7. data/app/assets/builds/avo.base.js.map +7 -0
  8. data/app/assets/builds/avo.custom.js +6 -0
  9. data/app/assets/builds/avo.custom.js.map +7 -0
  10. data/app/assets/stylesheets/avo.base.css +1 -0
  11. data/app/assets/stylesheets/css/fields/tags.css +32 -0
  12. data/app/components/avo/actions_component.rb +1 -1
  13. data/app/components/avo/field_wrapper_component.html.erb +1 -1
  14. data/app/components/avo/field_wrapper_component.rb +1 -7
  15. data/app/components/avo/fields/boolean_field/index_component.html.erb +1 -1
  16. data/app/components/avo/fields/common/badge_viewer_component.html.erb +1 -24
  17. data/app/components/avo/fields/common/badge_viewer_component.rb +24 -0
  18. data/app/components/avo/fields/common/boolean_check_component.html.erb +1 -12
  19. data/app/components/avo/fields/common/boolean_check_component.rb +2 -1
  20. data/app/components/avo/fields/common/gravatar_viewer_component.html.erb +1 -1
  21. data/app/components/avo/fields/common/gravatar_viewer_component.rb +2 -2
  22. data/app/components/avo/fields/common/heading_component.html.erb +3 -8
  23. data/app/components/avo/fields/common/heading_component.rb +1 -3
  24. data/app/components/avo/fields/common/key_value_component.html.erb +2 -2
  25. data/app/components/avo/fields/common/key_value_component.rb +2 -2
  26. data/app/components/avo/fields/common/progress_bar_component.rb +3 -9
  27. data/app/components/avo/fields/common/status_viewer_component.html.erb +3 -0
  28. data/app/components/avo/fields/edit_component.rb +1 -1
  29. data/app/components/avo/fields/external_image_field/index_component.html.erb +1 -1
  30. data/app/components/avo/fields/file_field/index_component.html.erb +2 -2
  31. data/app/components/avo/fields/gravatar_field/index_component.html.erb +1 -1
  32. data/app/components/avo/fields/heading_field/edit_component.html.erb +1 -1
  33. data/app/components/avo/fields/heading_field/show_component.html.erb +1 -1
  34. data/app/components/avo/fields/id_field/index_component.html.erb +1 -1
  35. data/app/components/avo/fields/index_component.rb +1 -1
  36. data/app/components/avo/fields/show_component.rb +1 -1
  37. data/app/components/avo/fields/text_field/index_component.html.erb +1 -1
  38. data/app/components/avo/index/field_wrapper_component.rb +1 -1
  39. data/app/components/avo/index/resource_controls_component.rb +1 -1
  40. data/app/components/avo/index/resource_table_component.rb +3 -9
  41. data/app/components/avo/resource_component.rb +9 -4
  42. data/app/components/avo/sidebar_profile_component.html.erb +4 -4
  43. data/app/components/avo/tab_group_component.html.erb +1 -1
  44. data/app/components/avo/tab_switcher_component.rb +2 -2
  45. data/app/components/avo/views/resource_edit_component.html.erb +9 -20
  46. data/app/components/avo/views/resource_edit_component.rb +5 -5
  47. data/app/components/avo/views/resource_index_component.rb +1 -1
  48. data/app/components/avo/views/resource_show_component.html.erb +1 -1
  49. data/app/components/avo/views/resource_show_component.rb +1 -1
  50. data/app/controllers/avo/actions_controller.rb +9 -20
  51. data/app/controllers/avo/application_controller.rb +5 -5
  52. data/app/controllers/avo/base_controller.rb +39 -1
  53. data/app/controllers/avo/search_controller.rb +19 -2
  54. data/app/controllers/concerns/avo/initializes_avo.rb +1 -0
  55. data/app/helpers/avo/resources_helper.rb +1 -1
  56. data/app/helpers/avo/url_helpers.rb +1 -1
  57. data/app/views/avo/base/edit.html.erb +1 -1
  58. data/app/views/avo/base/index.html.erb +1 -1
  59. data/app/views/avo/base/new.html.erb +1 -1
  60. data/app/views/avo/base/show.html.erb +1 -1
  61. data/app/views/layouts/avo/application.html.erb +10 -2
  62. data/bin/dev +2 -0
  63. data/config/routes.rb +4 -3
  64. data/db/factories.rb +1 -1
  65. data/lib/avo/base_action.rb +21 -26
  66. data/lib/avo/base_resource.rb +13 -7
  67. data/lib/avo/concerns/filters_session_handler.rb +3 -3
  68. data/lib/avo/concerns/has_helpers.rb +18 -0
  69. data/lib/avo/concerns/has_items.rb +1 -5
  70. data/lib/avo/concerns/visible_in_different_views.rb +7 -1
  71. data/lib/avo/concerns/visible_items.rb +43 -0
  72. data/lib/avo/configuration.rb +28 -4
  73. data/lib/avo/current.rb +1 -6
  74. data/lib/avo/dsl/field_parser.rb +1 -1
  75. data/lib/avo/execution_context.rb +4 -1
  76. data/lib/avo/fields/badge_field.rb +1 -1
  77. data/lib/avo/fields/base_field.rb +21 -44
  78. data/lib/avo/fields/belongs_to_field.rb +1 -1
  79. data/lib/avo/fields/concerns/has_html_attributes.rb +2 -0
  80. data/lib/avo/fields/concerns/use_view_components.rb +45 -0
  81. data/lib/avo/fields/external_image_field.rb +2 -2
  82. data/lib/avo/fields/file_field.rb +2 -2
  83. data/lib/avo/fields/gravatar_field.rb +2 -2
  84. data/lib/avo/fields/has_base_field.rb +2 -2
  85. data/lib/avo/fields/heading_field.rb +5 -13
  86. data/lib/avo/fields/id_field.rb +2 -2
  87. data/lib/avo/fields/status_field.rb +3 -1
  88. data/lib/avo/fields/text_field.rb +2 -2
  89. data/lib/avo/filters/base_filter.rb +1 -1
  90. data/lib/avo/html/builder.rb +1 -1
  91. data/lib/avo/licensing/license_manager.rb +1 -1
  92. data/lib/avo/resources/items/holder.rb +0 -6
  93. data/lib/avo/resources/items/item_group.rb +2 -2
  94. data/lib/avo/resources/items/row.rb +3 -3
  95. data/lib/avo/resources/items/sidebar.rb +1 -1
  96. data/lib/avo/resources/items/tab.rb +2 -2
  97. data/lib/avo/resources/items/tab_group.rb +1 -1
  98. data/lib/avo/resources/resource_manager.rb +6 -1
  99. data/lib/avo/version.rb +1 -1
  100. data/lib/avo/view_inquirer.rb +36 -0
  101. data/lib/avo.rb +9 -0
  102. data/lib/generators/avo/concerns/parent_controller.rb +20 -0
  103. data/lib/generators/avo/controller_generator.rb +3 -0
  104. data/lib/generators/avo/eject_generator.rb +180 -15
  105. data/lib/generators/avo/field_generator.rb +49 -2
  106. data/lib/generators/avo/js/install_generator.rb +2 -2
  107. data/lib/generators/avo/resource_generator.rb +10 -7
  108. data/lib/generators/avo/tailwindcss/install_generator.rb +58 -12
  109. data/lib/generators/avo/templates/initializer/avo.tt +6 -1
  110. data/lib/generators/avo/templates/resource/controller.tt +1 -1
  111. data/lib/generators/avo/templates/tailwindcss/avo.tailwind.css +5 -3
  112. data/lib/generators/avo/templates/tailwindcss/tailwind.config.js +11 -0
  113. data/lib/tasks/avo_tasks.rake +33 -5
  114. data/public/avo-assets/avo.base.css +75 -4146
  115. metadata +14 -6
  116. data/config/master.key +0 -1
  117. data/public/avo-assets/avo.js +0 -513
  118. data/public/avo-assets/avo.js.map +0 -7
@@ -75,6 +75,8 @@ module Avo
75
75
  @resources = @records.map do |record|
76
76
  @resource.hydrate(record: record, params: params).dup
77
77
  end
78
+
79
+ set_component_for __method__
78
80
  end
79
81
 
80
82
  def show
@@ -98,6 +100,8 @@ module Avo
98
100
 
99
101
  add_breadcrumb @resource.record_title
100
102
  add_breadcrumb I18n.t("avo.details").upcase_first
103
+
104
+ set_component_for __method__
101
105
  end
102
106
 
103
107
  def new
@@ -119,6 +123,8 @@ module Avo
119
123
 
120
124
  add_breadcrumb @resource.plural_name.humanize, resources_path(resource: @resource)
121
125
  add_breadcrumb t("avo.new").humanize
126
+
127
+ set_component_for __method__, fallback_view: :edit
122
128
  end
123
129
 
124
130
  def create
@@ -161,6 +167,8 @@ module Avo
161
167
  add_breadcrumb t("avo.new").humanize
162
168
  set_actions
163
169
 
170
+ set_component_for :edit
171
+
164
172
  if saved
165
173
  create_success_action
166
174
  else
@@ -170,6 +178,8 @@ module Avo
170
178
 
171
179
  def edit
172
180
  set_actions
181
+
182
+ set_component_for __method__
173
183
  end
174
184
 
175
185
  def update
@@ -178,6 +188,8 @@ module Avo
178
188
  @resource = @resource.hydrate(record: @record, view: :edit, user: _current_user)
179
189
  set_actions
180
190
 
191
+ set_component_for :edit
192
+
181
193
  if saved
182
194
  update_success_action
183
195
  else
@@ -517,7 +529,7 @@ module Avo
517
529
 
518
530
  if @resource.class.send(action) == :index
519
531
  resources_path(resource: @resource)
520
- elsif @resource.class.send(action) == :edit || Avo.configuration.resource_default_view == :edit
532
+ elsif @resource.class.send(action) == :edit || Avo.configuration.resource_default_view.edit?
521
533
  edit_resource_path(resource: @resource, record: @resource.record)
522
534
  else
523
535
  resource_path(record: @record, resource: @resource)
@@ -540,5 +552,31 @@ module Avo
540
552
  def pagy_query
541
553
  @query
542
554
  end
555
+
556
+ # Set the view component for the current view
557
+ # It will try to use the custom component if it's set, otherwise it will use the default one
558
+ def set_component_for(view, fallback_view: nil)
559
+ # Fetch the components from the resource
560
+ components = Avo::ExecutionContext.new(
561
+ target: @resource.components,
562
+ resource: @resource,
563
+ record: @record,
564
+ view: @view
565
+ ).handle
566
+
567
+ # If the component is not set, use the default one
568
+ if (custom_component = components.dig("resource_#{view}_component".to_sym)).nil?
569
+ return @component = "Avo::Views::Resource#{(fallback_view || view).to_s.classify}Component".constantize
570
+ end
571
+
572
+ # If the component is set, try to use it
573
+ @component = custom_component.to_s.safe_constantize
574
+
575
+ # If the component is not found, raise an error
576
+ if @component.nil?
577
+ raise "The component '#{custom_component}' was not found.\n" \
578
+ "That component was fetched from 'self.components' option inside '#{@resource.class}' resource."
579
+ end
580
+ end
543
581
  end
544
582
  end
@@ -9,6 +9,8 @@ module Avo
9
9
 
10
10
  def show
11
11
  render json: search_resources([resource])
12
+ rescue => error
13
+ render_search_error(error)
12
14
  end
13
15
 
14
16
  private
@@ -40,14 +42,14 @@ module Avo
40
42
  query: resource.query_scope
41
43
  ).handle
42
44
 
45
+ query = apply_scope(query) if should_apply_any_scope?
46
+
43
47
  # Get the count
44
48
  results_count = query.reselect(resource.model_class.primary_key).count
45
49
 
46
50
  # Get the results
47
51
  query = query.limit(8)
48
52
 
49
- query = apply_scope(query) if should_apply_any_scope?
50
-
51
53
  results = apply_search_metadata(query, resource)
52
54
 
53
55
  header = resource.plural_name
@@ -164,5 +166,20 @@ module Avo
164
166
  parent_resource = Avo.resource_manager.get_resource_by_model_class params[:via_reflection_class]
165
167
  parent_resource.find_record params[:via_reflection_id], params: params
166
168
  end
169
+
170
+ def render_search_error(error)
171
+ raise error unless Rails.env.development?
172
+
173
+ render json: {
174
+ error: {
175
+ header: "🚨 An error occurred while searching. 🚨",
176
+ help: "Please see the error and fix it before deploying.",
177
+ results: {
178
+ _label: error.message
179
+ },
180
+ count: 1
181
+ }
182
+ }, status: 500
183
+ end
167
184
  end
168
185
  end
@@ -7,6 +7,7 @@ module Avo
7
7
  Avo::Current.view_context = view_context
8
8
  Avo.init
9
9
  Avo::Current.license = Licensing::LicenseManager.new(Licensing::HQ.new(request).response).license
10
+ Avo::Current.locale = locale
10
11
  Avo.plugin_manager.init_plugins
11
12
  end
12
13
 
@@ -38,7 +38,7 @@ module Avo
38
38
  end
39
39
 
40
40
  def item_selector_init(resource)
41
- "data-resource-name='#{resource.model_key}' data-resource-id='#{resource.record.id}' data-controller='item-selector'"
41
+ "data-resource-name='#{resource.model_key}' data-resource-id='#{resource.record.to_param}' data-controller='item-selector'"
42
42
  end
43
43
 
44
44
  def item_selector_input(floating: false, size: :md)
@@ -94,7 +94,7 @@ module Avo
94
94
  end
95
95
 
96
96
  def resource_view_path(**args)
97
- if Avo.configuration.resource_default_view == :edit
97
+ if Avo.configuration.resource_default_view.edit?
98
98
  edit_resource_path(**args)
99
99
  else
100
100
  resource_path(**args)
@@ -1 +1 @@
1
- <%= render Avo::Views::ResourceEditComponent.new(resource: @resource, view: @view, actions: @actions) %>
1
+ <%= render @component.new(resource: @resource, view: @view, actions: @actions) %>
@@ -1,5 +1,5 @@
1
1
  <%= render Avo::TurboFrameWrapperComponent.new(params[:turbo_frame]) do %>
2
- <%= render Avo::Views::ResourceIndexComponent.new(
2
+ <%= render @component.new(
3
3
  resource: @resource,
4
4
  resources: @resources,
5
5
  records: @records,
@@ -1,2 +1,2 @@
1
- <%= render Avo::Views::ResourceEditComponent.new(resource: @resource, record: @record, view: @view, actions: @actions) %>
1
+ <%= render @component.new(resource: @resource, record: @record, view: @view, actions: @actions) %>
2
2
 
@@ -1,5 +1,5 @@
1
1
  <%= render Avo::TurboFrameWrapperComponent.new(params[:turbo_frame]) do %>
2
- <%= render Avo::Views::ResourceShowComponent.new(
2
+ <%= render @component.new(
3
3
  resource: @resource,
4
4
  reflection: @reflection,
5
5
  actions: @actions,
@@ -12,10 +12,18 @@
12
12
  <%= render Avo::AssetManager::StylesheetComponent.new asset_manager: Avo.asset_manager %>
13
13
  <% if Avo::PACKED %>
14
14
  <%= javascript_include_tag "/avo-assets/avo.base", "data-turbo-track": "reload", defer: true %>
15
- <%= stylesheet_link_tag "/avo-assets/avo.base", "data-turbo-track": "reload", defer: true %>
15
+ <% if Rails.root.join("config", "avo", "tailwind.config.js").exist? %>
16
+ <%= stylesheet_link_tag "avo.tailwind", "data-turbo-track": "reload", defer: true %>
17
+ <% else %>
18
+ <%= stylesheet_link_tag "/avo-assets/avo.base", "data-turbo-track": "reload", defer: true %>
19
+ <% end %>
16
20
  <% else %>
17
21
  <%= javascript_include_tag "avo.base", "data-turbo-track": "reload", defer: true %>
18
- <%= stylesheet_link_tag "avo.base", "data-turbo-track": "reload", defer: true %>
22
+ <% if Rails.root.join("config", "avo", "tailwind.config.js").exist? %>
23
+ <%= stylesheet_link_tag "avo.tailwind", "data-turbo-track": "reload", defer: true %>
24
+ <% else %>
25
+ <%= stylesheet_link_tag "avo.base", "data-turbo-track": "reload", defer: true %>
26
+ <% end %>
19
27
  <% if Rails.env.development? %>
20
28
  <%= javascript_include_tag "hotwire-livereload", defer: true %>
21
29
  <% end %>
data/bin/dev CHANGED
@@ -3,6 +3,8 @@
3
3
  PORT="${PORT:-3030}"
4
4
  export PORT
5
5
 
6
+ bundle exec rake avo:sym_link
7
+
6
8
  if command -v overmind &> /dev/null; then
7
9
  overmind start -f Procfile.dev "$@"
8
10
  else
data/config/routes.rb CHANGED
@@ -4,9 +4,10 @@ Avo::Engine.routes.draw do
4
4
  get "resources", to: redirect(Avo.configuration.root_path)
5
5
  get "dashboards", to: redirect(Avo.configuration.root_path)
6
6
 
7
- mount Avo::DynamicFilters::Engine, at: "/avo-dynamic_filters" if defined?(Avo::DynamicFilters::Engine)
8
- mount Avo::Dashboards::Engine, at: "/dashboards" if defined?(Avo::Dashboards::Engine)
9
- mount Avo::Pro::Engine, at: "/avo/avo-pro" if defined?(Avo::Pro::Engine)
7
+ # Mount Avo engines routes by default but leave it configurable in case the user wants to nest these under a scope.
8
+ if Avo.configuration.mount_avo_engines
9
+ instance_exec(&Avo.mount_engines)
10
+ end
10
11
 
11
12
  post "/rails/active_storage/direct_uploads", to: "/active_storage/direct_uploads#create"
12
13
 
data/db/factories.rb CHANGED
@@ -38,7 +38,7 @@ FactoryBot.define do
38
38
  factory :project do
39
39
  name { Faker::App.name }
40
40
  status { ['closed', :rejected, :failed, 'loading', :running, :waiting].sample }
41
- stage { ["Discovery", "Idea", "Done", "On hold", "Cancelled"].sample }
41
+ stage { ["Discovery", "Idea", "Done", "On hold", "Cancelled", "Drafting"].sample }
42
42
  budget { Faker::Number.decimal(l_digits: 4) }
43
43
  country { Faker::Address.country_code }
44
44
  description { Faker::Markdown.sandwich(sentences: 5) }
@@ -25,7 +25,7 @@ module Avo
25
25
  delegate :view, to: :class
26
26
  # TODO: find a differnet way to delegate this to the uninitialized Current variable
27
27
  delegate :context, to: Avo::Current
28
- def curent_user
28
+ def current_user
29
29
  Avo::Current.user
30
30
  end
31
31
  delegate :params, to: Avo::Current
@@ -65,7 +65,7 @@ module Avo
65
65
  self.class.record = record
66
66
  self.class.resource = resource
67
67
  self.class.user = user
68
- self.class.view = view
68
+ self.class.view = Avo::ViewInquirer.new(view)
69
69
  @arguments = arguments
70
70
 
71
71
  self.class.message ||= I18n.t("avo.are_you_sure_you_want_to_run_this_option")
@@ -101,39 +101,34 @@ module Avo
101
101
  end
102
102
 
103
103
  def handle_action(**args)
104
- records, fields, current_user, resource = args.values_at(:records, :fields, :current_user, :resource)
105
- # Fetching the field definitions and not the actual fields (get_fields) because they will break if the user uses a `visible` block and adds a condition using the `params` variable. The params are different in the show method and the handle method.
106
- action_fields = get_field_definitions.map { |field| [field.id, field] }.to_h
107
-
108
- # For some fields, like belongs_to, the id and database_id differ (user vs user_id).
109
- # That's why we need to fetch the database_id for when we process the action.
110
- action_fields_by_database_id = action_fields.map do |id, value|
111
- [value.database_id.to_sym, value]
112
- end.to_h
104
+ processed_fields = if args[:fields].present?
105
+ # Fetching the field definitions and not the actual fields (get_fields) because they will break if the user uses a `visible` block and adds a condition using the `params` variable. The params are different in the show method and the handle method.
106
+ action_fields = get_field_definitions.map { |field| [field.id, field] }.to_h
107
+
108
+ # For some fields, like belongs_to, the id and database_id differ (user vs user_id).
109
+ # That's why we need to fetch the database_id for when we process the action.
110
+ action_fields_by_database_id = action_fields.map do |id, value|
111
+ [value.database_id.to_sym, value]
112
+ end.to_h
113
113
 
114
- if fields.present?
115
- processed_fields = fields.to_unsafe_h.map do |name, value|
114
+ args[:fields].to_unsafe_h.map do |name, value|
116
115
  field = action_fields_by_database_id[name.to_sym]
117
116
 
118
117
  next if field.blank?
119
118
 
120
119
  [name, field.resolve_attribute(value)]
121
- end
122
-
123
- processed_fields = processed_fields.reject(&:blank?).to_h
120
+ end.reject(&:blank?).to_h
124
121
  else
125
- processed_fields = {}
122
+ {}
126
123
  end
127
124
 
128
- args = {
125
+ handle(
129
126
  fields: processed_fields.with_indifferent_access,
130
- current_user: current_user,
131
- resource: resource
132
- }
133
-
134
- args[:records] = records
135
-
136
- handle(**args)
127
+ current_user: args[:current_user],
128
+ resource: args[:resource],
129
+ records: args[:query],
130
+ query: args[:query]
131
+ )
137
132
 
138
133
  self
139
134
  end
@@ -141,7 +136,7 @@ module Avo
141
136
  def visible_in_view(parent_resource: nil)
142
137
  if visible.blank?
143
138
  # Hide on the :new view by default
144
- return false if view == :new
139
+ return false if view.new?
145
140
 
146
141
  # Show on all other views
147
142
  return true
@@ -9,10 +9,11 @@ module Avo
9
9
  include Avo::Concerns::HasStimulusControllers
10
10
  include Avo::Concerns::ModelClassConstantized
11
11
  include Avo::Concerns::HasDescription
12
+ include Avo::Concerns::HasHelpers
12
13
 
13
14
  # Avo::Current methods
14
15
  delegate :context, to: Avo::Current
15
- def curent_user
16
+ def current_user
16
17
  Avo::Current.user
17
18
  end
18
19
  delegate :params, to: Avo::Current
@@ -65,6 +66,7 @@ module Avo
65
66
  class_attribute :extra_params
66
67
  class_attribute :link_to_child_resource, default: false
67
68
  class_attribute :map_view
69
+ class_attribute :components, default: {}
68
70
 
69
71
  # EXTRACT:
70
72
  class_attribute :ordering
@@ -232,14 +234,14 @@ module Avo
232
234
  delegate :model_key, to: :class
233
235
 
234
236
  def initialize(record: nil, view: nil, user: nil, params: nil)
235
- @view = view if view.present?
237
+ @view = Avo::ViewInquirer.new(view) if view.present?
236
238
  @user = user if user.present?
237
239
  @params = params if params.present?
238
240
 
239
241
  if record.present?
240
242
  @record = record
241
243
 
242
- hydrate_model_with_default_values if @view == :new
244
+ hydrate_model_with_default_values if @view&.new?
243
245
  end
244
246
 
245
247
  detect_fields
@@ -293,19 +295,23 @@ module Avo
293
295
 
294
296
  # def get_action_arguments / def get_filter_arguments / def get_scope_arguments
295
297
  define_method "get_#{entity}_arguments" do |entity_class|
296
- send("get_#{plural_entity}").find { |entity| entity[:class].to_s == entity_class.to_s }[:arguments]
298
+ klass = send("get_#{plural_entity}").find { |entity| entity[:class].to_s == entity_class.to_s }
299
+
300
+ raise "Couldn't find '#{entity_class}' in the 'def #{plural_entity}' method on your '#{self.class}' resource." if klass.nil?
301
+
302
+ klass[:arguments]
297
303
  end
298
304
  end
299
305
 
300
306
  def hydrate(record: nil, view: nil, user: nil, params: nil)
301
- @view = view if view.present?
307
+ @view = Avo::ViewInquirer.new(view) if view.present?
302
308
  @user = user if user.present?
303
309
  @params = params if params.present?
304
310
 
305
311
  if record.present?
306
312
  @record = record
307
313
 
308
- hydrate_model_with_default_values if @view == :new
314
+ hydrate_model_with_default_values if @view&.new?
309
315
  end
310
316
 
311
317
  self
@@ -440,7 +446,7 @@ module Avo
440
446
  def hydrate_model_with_default_values
441
447
  default_values = get_fields
442
448
  .select do |field|
443
- !field.computed
449
+ !field.computed && !field.is_a?(Avo::Fields::HeadingField)
444
450
  end
445
451
  .map do |field|
446
452
  value = field.value
@@ -26,16 +26,16 @@ module Avo
26
26
  end
27
27
 
28
28
  def filters_session_key
29
- @filters_session_key ||= '/filters/' << %w[
29
+ @filters_session_key ||= "/filters/" << %w[
30
30
  turbo_frame controller resource_name related_name
31
31
  action id
32
- ].map { |key| params[key] }.compact.join('/')
32
+ ].map { |key| params[key] }.compact.join("/")
33
33
  end
34
34
 
35
35
  def cache_resource_filters?
36
36
  Avo::ExecutionContext.new(
37
37
  target: Avo.configuration.cache_resource_filters,
38
- current_user: current_user,
38
+ current_user: _current_user,
39
39
  resource: @resource
40
40
  ).handle
41
41
  end
@@ -0,0 +1,18 @@
1
+ module Avo
2
+ module Concerns
3
+ module HasHelpers
4
+ def helpers
5
+ @helpers ||= Class.new do
6
+ def initialize
7
+ helper_names = ActionController::Base.all_helpers_from_path Rails.root.join("app", "helpers")
8
+ helpers = ActionController::Base.modules_for_helpers helper_names
9
+
10
+ helpers.each do |helper|
11
+ extend helper
12
+ end
13
+ end
14
+ end.new
15
+ end
16
+ end
17
+ end
18
+ end
@@ -30,10 +30,6 @@ module Avo
30
30
  deprecated_dsl_api __method__, "fields"
31
31
  end
32
32
 
33
- def heading(body, **args)
34
- deprecated_dsl_api __method__, "fields"
35
- end
36
-
37
33
  def sidebar(**args, &block)
38
34
  deprecated_dsl_api __method__, "fields"
39
35
  end
@@ -273,7 +269,7 @@ module Avo
273
269
  end
274
270
  .select do |item|
275
271
  # On location field we can have field coordinates and setters with different names like latitude and longitude
276
- if !item.is_a?(Avo::Fields::LocationField) && !item.is_heading? && view.in?([:edit, :update, :new, :create])
272
+ if !item.is_a?(Avo::Fields::LocationField) && !item.is_heading? && view.in?(%w[edit update new create])
277
273
  if item.respond_to?(:id)
278
274
  item.resource.record.respond_to?("#{item.id}=")
279
275
  else
@@ -61,7 +61,7 @@ module Avo
61
61
  def except_on(*where)
62
62
  show_on_all
63
63
  normalize_views(where).flatten.each do |view|
64
- show_on_view view
64
+ hide_on_view view
65
65
  end
66
66
  end
67
67
 
@@ -113,12 +113,18 @@ module Avo
113
113
 
114
114
  def normalize_views(*views_and_groups)
115
115
  forms = views_and_groups.flatten! & [:forms]
116
+ display = views_and_groups & [:display]
116
117
 
117
118
  if forms.present?
118
119
  views_and_groups -= forms
119
120
  views_and_groups += [:new, :edit]
120
121
  end
121
122
 
123
+ if display.present?
124
+ views_and_groups -= display
125
+ views_and_groups += [:index, :show]
126
+ end
127
+
122
128
  views_and_groups.flatten.uniq
123
129
  end
124
130
  end
@@ -0,0 +1,43 @@
1
+ # This concern helps us figure out what items are visible for each tab, panel or sidebar
2
+ module Avo
3
+ module Concerns
4
+ module VisibleItems
5
+ extend ActiveSupport::Concern
6
+ def items
7
+ items_holder&.items || []
8
+ end
9
+
10
+ def visible_items
11
+ items
12
+ .select do |item|
13
+ if item.respond_to? :hydrate
14
+ item.hydrate(view: view, resource: resource)
15
+ end
16
+
17
+ visible(item)
18
+ end
19
+ end
20
+
21
+ def visible(item)
22
+ return item.visible? if !item.is_field?
23
+
24
+ return false if item.respond_to?(:authorized?) && item.resource.present? && !item.authorized?
25
+
26
+ item.visible? && item.visible_in_view?(view: view)
27
+ end
28
+
29
+ def visible?
30
+ any_item_visible = visible_items.any?
31
+ return any_item_visible if !respond_to?(:visible_on?)
32
+
33
+ visible_on?(view) && any_item_visible
34
+ end
35
+
36
+ def hydrate(view: nil)
37
+ @view = view
38
+
39
+ self
40
+ end
41
+ end
42
+ end
43
+ end
@@ -12,7 +12,6 @@ module Avo
12
12
  attr_accessor :locale
13
13
  attr_accessor :currency
14
14
  attr_accessor :default_view_type
15
- attr_accessor :license
16
15
  attr_accessor :license_key
17
16
  attr_accessor :authorization_methods
18
17
  attr_accessor :authenticate
@@ -37,12 +36,14 @@ module Avo
37
36
  attr_accessor :main_menu
38
37
  attr_accessor :profile_menu
39
38
  attr_accessor :model_resource_mapping
40
- attr_accessor :resource_default_view
39
+ attr_reader :resource_default_view
41
40
  attr_accessor :authorization_client
42
41
  attr_accessor :field_wrapper_layout
43
42
  attr_accessor :sign_out_path_name
44
43
  attr_accessor :resources
45
44
  attr_accessor :prefix_path
45
+ attr_accessor :resource_parent_controller
46
+ attr_accessor :mount_avo_engines
46
47
 
47
48
  def initialize
48
49
  @root_path = "/avo"
@@ -54,7 +55,6 @@ module Avo
54
55
  @locale = nil
55
56
  @currency = "USD"
56
57
  @default_view_type = :table
57
- @license = "community"
58
58
  @license_key = nil
59
59
  @current_user = proc {}
60
60
  @authenticate = proc {}
@@ -89,10 +89,12 @@ module Avo
89
89
  @main_menu = nil
90
90
  @profile_menu = nil
91
91
  @model_resource_mapping = {}
92
- @resource_default_view = :show
92
+ @resource_default_view = Avo::ViewInquirer.new("show")
93
93
  @authorization_client = :pundit
94
94
  @field_wrapper_layout = :inline
95
95
  @resources = nil
96
+ @resource_parent_controller = "Avo::ResourcesController"
97
+ @mount_avo_engines = true
96
98
  end
97
99
 
98
100
  def current_user_method(&block)
@@ -140,6 +142,28 @@ module Avo
140
142
  def app_name
141
143
  Avo::ExecutionContext.new(target: @app_name).handle
142
144
  end
145
+
146
+ def license=(value)
147
+ if Rails.env.development?
148
+ puts "[Avo DEPRECATION WARNING]: The `config.license` configuration option is no longer supported and will be removed in future versions. Please discontinue its use and solely utilize the `license_key` instead."
149
+ end
150
+ end
151
+
152
+ def license
153
+ gems = Gem::Specification.map {|gem| gem.name}
154
+
155
+ @license ||= if gems.include?("avo-advanced")
156
+ "advanced"
157
+ elsif gems.include?("avo-pro")
158
+ "pro"
159
+ elsif gems.include?("avo")
160
+ "community"
161
+ end
162
+ end
163
+
164
+ def resource_default_view=(view)
165
+ @resource_default_view = Avo::ViewInquirer.new(view.to_s)
166
+ end
143
167
  end
144
168
 
145
169
  def self.configuration
data/lib/avo/current.rb CHANGED
@@ -24,16 +24,11 @@ class Avo::Current < ActiveSupport::CurrentAttributes
24
24
  attribute :resource_manager
25
25
  attribute :tool_manager
26
26
  attribute :plugin_manager
27
+ attribute :locale
27
28
 
28
29
  delegate :params, to: :request
29
30
 
30
31
  def request
31
32
  view_context.request || ActionDispatch::Request.empty
32
33
  end
33
-
34
- def current_user
35
- Rails.logger.warn "DEPRECATION WARNING: Avo::Current.current_user become deprecated and will become obsolete on futhure versions. Please use Avo::Current.user instead."
36
-
37
- user
38
- end
39
34
  end
@@ -47,7 +47,7 @@ module Avo
47
47
  else
48
48
  # The symbol can be transformed to a class and found.
49
49
  class_name = as.to_s.camelize
50
- field_class = "#{class_name}Field"
50
+ field_class = "Avo::Fields::#{class_name}Field"
51
51
 
52
52
  # Discover & load custom field classes
53
53
  if Object.const_defined? field_class
@@ -1,6 +1,8 @@
1
1
  module Avo
2
2
  class ExecutionContext
3
- attr_accessor :target, :context, :params, :view_context, :current_user, :request, :include, :main_app, :avo
3
+ include Avo::Concerns::HasHelpers
4
+
5
+ attr_accessor :target, :context, :params, :view_context, :current_user, :request, :include, :main_app, :avo, :locale
4
6
 
5
7
  def initialize(**args)
6
8
  # Extend the class with custom modules if required.
@@ -24,6 +26,7 @@ module Avo
24
26
  @params ||= Avo::Current.params
25
27
  @request ||= Avo::Current.request
26
28
  @view_context ||= Avo::Current.view_context
29
+ @locale ||= Avo::Current.locale
27
30
  @main_app ||= @view_context.main_app
28
31
  @avo ||= @view_context.avo
29
32
  end