avo 2.18.1.pre.1.eagerloaddirs → 2.19.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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -2
  3. data/Gemfile.lock +2 -5
  4. data/app/components/avo/actions_component.html.erb +1 -1
  5. data/app/components/avo/actions_component.rb +4 -4
  6. data/app/components/avo/base_component.rb +2 -1
  7. data/app/components/avo/field_wrapper_component.rb +7 -1
  8. data/app/components/avo/fields/has_one_field/show_component.rb +1 -2
  9. data/app/components/avo/filters_component.html.erb +1 -1
  10. data/app/components/avo/filters_component.rb +2 -2
  11. data/app/components/avo/sidebar_profile_component.rb +3 -1
  12. data/app/components/avo/views/resource_show_component.html.erb +1 -1
  13. data/app/controllers/avo/base_controller.rb +14 -7
  14. data/app/helpers/avo/application_helper.rb +5 -1
  15. data/app/javascript/js/controllers/search_controller.js +11 -2
  16. data/app/views/avo/partials/_branding.html.erb +1 -0
  17. data/bin/init +11 -1
  18. data/bin/test +1 -0
  19. data/db/factories.rb +5 -0
  20. data/lib/avo/base_action.rb +17 -7
  21. data/lib/avo/concerns/filters_session_handler.rb +43 -0
  22. data/lib/avo/configuration/branding.rb +9 -1
  23. data/lib/avo/configuration.rb +3 -0
  24. data/lib/avo/engine.rb +5 -0
  25. data/lib/avo/fields/base_field.rb +20 -11
  26. data/lib/avo/fields/concerns/has_default.rb +17 -0
  27. data/lib/avo/fields/concerns/is_readonly.rb +1 -1
  28. data/lib/avo/fields/concerns/is_required.rb +2 -2
  29. data/lib/avo/fields/key_value_field.rb +1 -1
  30. data/lib/avo/filters/base_filter.rb +17 -2
  31. data/lib/avo/hosts/resource_view_record_host.rb +7 -0
  32. data/lib/avo/hosts/visibility_host.rb +11 -0
  33. data/lib/avo/resources/controls/action.rb +1 -3
  34. data/lib/avo/services/authorization_clients/nil_client.rb +37 -0
  35. data/lib/avo/services/authorization_service.rb +11 -1
  36. data/lib/avo/version.rb +1 -1
  37. data/lib/avo.rb +2 -0
  38. data/lib/generators/avo/resource_generator.rb +281 -0
  39. data/lib/generators/avo/templates/action.tt +3 -0
  40. data/lib/generators/avo/templates/filters/boolean_filter.tt +3 -0
  41. data/lib/generators/avo/templates/filters/multiple_select_filter.tt +3 -0
  42. data/lib/generators/avo/templates/filters/select_filter.tt +3 -0
  43. data/lib/generators/avo/templates/filters/text_filter.tt +3 -0
  44. data/lib/generators/avo/templates/initializer/avo.tt +4 -0
  45. data/lib/generators/avo/templates/resource/controller.tt +1 -1
  46. data/lib/generators/avo/templates/resource/resource.tt +2 -2
  47. data/lib/generators/model_generator.rb +10 -0
  48. data/lib/generators/rails/avo_resource_generator.rb +11 -0
  49. data/public/avo-assets/avo.base.js +1 -1
  50. data/public/avo-assets/avo.base.js.map +2 -2
  51. data/public/avo-assets/favicon.ico +0 -0
  52. metadata +12 -5
  53. data/config/master.key +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dedb3bcead6abca3b563cf3c407486f240cd1f93af38c3d3c6edec9605266119
4
- data.tar.gz: '09dcd70c7db58cdd1c13a5ced9a3b75bc5b7ed5afc8ecf4c24237ade4f67f417'
3
+ metadata.gz: b2b092c8d9df1951b5ccd6a07b31c8c96a6cb68846ab2b2342f43082449a5ced
4
+ data.tar.gz: 5bb4985123f45ad9aeca49892559d43a80130a29ff823fc6c7f35127e5de3e5c
5
5
  SHA512:
6
- metadata.gz: e918b0789be4e669df92c80870d16a94c2ae9a33dd8db7ef9498a1cf1d50a06d4d7074d7eb79a1da321bf0f8e7398e3061cb3f92d2fe62a1c2902b7aa79b2a3f
7
- data.tar.gz: b6cc344b4ecc7b590219eed82708bf81ea21f006ce6a070c07e79aff53835af3ee2a12262a48f4261d223f2f96a85cd73c0eac21c2e8651a6cd002d5270b09e3
6
+ metadata.gz: e28f40d6e4559541cd2e08a76753ef87bcbfe54a48bd3ba2c7ea368436762bb287ddbac6641df9b18f6196071dd6bd7bb3f5e2f6e0bb95e2b7b10a5ab0cc6a2b
7
+ data.tar.gz: c6a64520f187b1e725b167bc396e23d6177c9c83e8f5ff2864a56cd12aed87ec757bfd34ee76955e93718268e888c9693dfa6899d6633e37f93874d2d86cbd73
data/Gemfile CHANGED
@@ -21,7 +21,7 @@ gem 'cssbundling-rails'
21
21
  # Dependencies for dummy_app
22
22
  #
23
23
  # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
24
- # gem "rails", "~> 6.1.0"
24
+ gem "rails", "~> 6.1.0"
25
25
 
26
26
  # Use postgresql as the database for Active Record
27
27
  gem "pg", ">= 0.18", "< 2.0"
@@ -123,7 +123,6 @@ gem 'meta-tags'
123
123
 
124
124
  gem 'breadcrumbs_on_rails'
125
125
 
126
- gem 'manifester'
127
126
 
128
127
  # Search
129
128
  gem 'ransack'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avo (2.18.1.pre.1.eagerloaddirs)
4
+ avo (2.19.0)
5
5
  actionview (>= 6.0)
6
6
  active_link_to
7
7
  activerecord (>= 6.0)
@@ -238,9 +238,6 @@ GEM
238
238
  nokogiri (>= 1.5.9)
239
239
  mail (2.7.1)
240
240
  mini_mime (>= 0.1.1)
241
- manifester (0.1.8)
242
- rails (>= 6.0)
243
- zeitwerk
244
241
  marcel (1.0.2)
245
242
  matrix (0.4.2)
246
243
  meta-tags (2.17.0)
@@ -485,12 +482,12 @@ DEPENDENCIES
485
482
  jsbundling-rails
486
483
  launchy
487
484
  listen (>= 3.5.1)
488
- manifester
489
485
  meta-tags
490
486
  net-smtp
491
487
  pg (>= 0.18, < 2.0)
492
488
  puma (~> 5.6.4)
493
489
  pundit
490
+ rails (~> 6.1.0)
494
491
  rails-controller-testing
495
492
  ransack
496
493
  redis (~> 4.0)
@@ -11,7 +11,7 @@
11
11
  icon_class: 'transform rotate-90',
12
12
  'data-action': "click->toggle-panel#togglePanel",
13
13
  'data-actions-dropdown-button': @resource.model_key do %>
14
- <%= t 'avo.actions' %>
14
+ <%= label %>
15
15
  <% end %>
16
16
  <div
17
17
  class="absolute flex inset-auto xl:right-0 top-full bg-white w-full sm:w-auto sm:min-w-[300px] mt-2 z-40 shadow-modal rounded overflow-hidden hidden"
@@ -2,14 +2,16 @@
2
2
 
3
3
  class Avo::ActionsComponent < ViewComponent::Base
4
4
  include Avo::ApplicationHelper
5
+ attr_reader :label
5
6
 
6
- def initialize(actions: [], resource: nil, view: nil, exclude: [], style: :outline, color: :primary)
7
+ def initialize(actions: [], resource: nil, view: nil, exclude: [], style: :outline, color: :primary, label: nil)
7
8
  @actions = actions || []
8
9
  @resource = resource
9
10
  @view = view
10
11
  @exclude = exclude
11
12
  @color = color
12
13
  @style = style
14
+ @label = label || t("avo.actions")
13
15
  end
14
16
 
15
17
  def render?
@@ -17,9 +19,7 @@ class Avo::ActionsComponent < ViewComponent::Base
17
19
  end
18
20
 
19
21
  def actions
20
- @actions.select do |action|
21
- !action.class.in?(@exclude)
22
- end
22
+ @actions.reject { |action| action.class.in?(@exclude) }
23
23
  end
24
24
 
25
25
  # When running an action for one record we should do it on a special path.
@@ -46,8 +46,9 @@ class Avo::BaseComponent < ViewComponent::Base
46
46
 
47
47
  def parent_or_child_resource
48
48
  return @resource unless link_to_child_resource_is_enabled?
49
+ return @resource if @resource.model.class.base_class == @resource.model.class
49
50
 
50
- ::Avo::App.get_resource_by_model_name(@resource.model.class).dup
51
+ ::Avo::App.get_resource_by_model_name(@resource.model.class).dup || @resource
51
52
  end
52
53
 
53
54
  def link_to_child_resource_is_enabled?
@@ -61,7 +61,13 @@ class Avo::FieldWrapperComponent < ViewComponent::Base
61
61
  end
62
62
 
63
63
  def help
64
- @help || @field.help
64
+ help_value = @help || @field.help
65
+
66
+ if help_value.respond_to?(:call)
67
+ return Avo::Hosts::ResourceViewRecordHost.new(block: help_value, record: record, resource: resource, view: view).handle
68
+ end
69
+
70
+ help_value
65
71
  end
66
72
 
67
73
  def record
@@ -38,10 +38,9 @@ class Avo::Fields::HasOneField::ShowComponent < Avo::Fields::ShowComponent
38
38
  def create_path
39
39
  args = {
40
40
  via_relation: @resource.singular_model_key,
41
- via_relation_class: @resource.name,
41
+ via_relation_class: @resource.model_class.to_s,
42
42
  via_resource_id: @resource.model.id
43
43
  }
44
-
45
44
  helpers.new_resource_path(resource: @field.target_resource, **args)
46
45
  end
47
46
  end
@@ -21,7 +21,7 @@
21
21
  <%= render partial: filter.class.template, locals: {filter: filter} %>
22
22
  <% end %>
23
23
  <div class="p-4 border-gray-300 border-t">
24
- <% if params[:filters].present? %>
24
+ <% if @applied_filters.present? %>
25
25
  <%= a_link reset_path, data: {turbo_frame: params[:turbo_frame]}, color: :gray, size: :sm, class: 'w-full justify-center' do %>
26
26
  <%= t('avo.reset_filters') %>
27
27
  <% end %>
@@ -17,9 +17,9 @@ class Avo::FiltersComponent < ViewComponent::Base
17
17
  def reset_path
18
18
  # If come from a association page
19
19
  if @parent_model.present?
20
- helpers.related_resources_path(@parent_model, @parent_model, filters: nil, keep_query_params: true)
20
+ helpers.related_resources_path(@parent_model, @parent_model, filters: nil, reset_filter: true, keep_query_params: true)
21
21
  else
22
- helpers.resources_path(resource: @resource, filters: nil, keep_query_params: true)
22
+ helpers.resources_path(resource: @resource, filters: nil, reset_filter: true, keep_query_params: true)
23
23
  end
24
24
  end
25
25
  end
@@ -34,7 +34,9 @@ class Avo::SidebarProfileComponent < ViewComponent::Base
34
34
  end
35
35
 
36
36
  def destroy_user_session_path
37
- "destroy_#{Avo.configuration.current_user_resource_name}_session_path".to_sym
37
+ # If `sign_out_path_name` is configured, use it. Otherwise construct the
38
+ # path name based on `current_user_resource_name`.
39
+ (Avo.configuration.sign_out_path_name || "destroy_#{Avo.configuration.current_user_resource_name}_session_path").to_sym
38
40
  end
39
41
 
40
42
  def can_destroy_user?
@@ -40,7 +40,7 @@
40
40
  <% end %>
41
41
  <% end %>
42
42
  <% elsif can_see_the_actions_button? && control.actions_list? %>
43
- <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view, exclude: control.exclude, style: control.style, color: control.color %>
43
+ <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view, exclude: control.exclude, style: control.style, color: control.color, label: control.label %>
44
44
  <% elsif control.edit_button? %>
45
45
  <% if @resource.authorization.authorize_action(:edit, raise_exception: false) %>
46
46
  <% end %>
@@ -2,6 +2,8 @@ require_dependency "avo/application_controller"
2
2
 
3
3
  module Avo
4
4
  class BaseController < ApplicationController
5
+ include Avo::Concerns::FiltersSessionHandler
6
+
5
7
  before_action :set_resource_name
6
8
  before_action :set_resource
7
9
  before_action :hydrate_resource
@@ -302,11 +304,14 @@ module Avo
302
304
  end
303
305
 
304
306
  def set_filters
305
- @filters = @resource.get_filters.map do |filter_class|
306
- filter = filter_class.new
307
-
308
- filter
309
- end
307
+ @filters = @resource
308
+ .get_filters
309
+ .map do |filter_class|
310
+ filter_class.new
311
+ end
312
+ .select do |filter|
313
+ filter.visible_in_view(resource: @resource, parent_model: @parent_model, parent_resource: @parent_resource)
314
+ end
310
315
  end
311
316
 
312
317
  def set_actions
@@ -316,12 +321,14 @@ module Avo
316
321
  action.new(model: @model, resource: @resource, view: @view)
317
322
  end
318
323
  .select do |action|
319
- action.visible_in_view
324
+ action.visible_in_view(parent_model: @parent_model, parent_resource: @parent_resource)
320
325
  end
321
326
  end
322
327
 
323
328
  def set_applied_filters
324
- @applied_filters = Avo::Filters::BaseFilter.decode_filters(params[Avo::Filters::BaseFilter::PARAM_KEY])
329
+ reset_filters if params[:reset_filter]
330
+
331
+ @applied_filters = Avo::Filters::BaseFilter.decode_filters(fetch_filters)
325
332
 
326
333
  # Some filters react to others and will have to be merged into this
327
334
  @applied_filters = @applied_filters.merge reactive_filters
@@ -102,7 +102,11 @@ module Avo
102
102
  end
103
103
 
104
104
  def root_path_without_url
105
- Avo::App.root_path.to_s.delete_prefix(request.base_url.to_s).delete_suffix "/"
105
+ Avo::App.root_path
106
+ .to_s
107
+ .delete_prefix(request.base_url.to_s)
108
+ .delete_suffix("/")
109
+ .gsub("/?", "?")
106
110
  rescue
107
111
  Avo.configuration.root_path
108
112
  end
@@ -76,7 +76,7 @@ export default class extends Controller {
76
76
  // This line fixes a bug where the search box would be duplicated on back navigation.
77
77
  this.autocompleteTarget.innerHTML = ''
78
78
 
79
- autocomplete({
79
+ const { destroy } = autocomplete({
80
80
  container: this.autocompleteTarget,
81
81
  placeholder: this.translationKeys.placeholder,
82
82
  translations: {
@@ -101,7 +101,7 @@ export default class extends Controller {
101
101
  })
102
102
 
103
103
  // document.addEventListener('turbo:before-render', destroy)
104
- // this.destroyMethod = destroy
104
+ this.destroyMethod = destroy
105
105
 
106
106
  // When using search for belongs-to
107
107
  if (this.buttonTarget.dataset.shouldBeDisabled !== 'true') {
@@ -109,6 +109,15 @@ export default class extends Controller {
109
109
  }
110
110
  }
111
111
 
112
+ disconnect() {
113
+ // Don't leave open autocompletes around when disconnected. Otherwise it will still
114
+ // be visible when navigating back to this page.
115
+ if (this.destroyMethod) {
116
+ this.destroyMethod()
117
+ this.destroyMethod = null
118
+ }
119
+ }
120
+
112
121
  addSource(resourceName, data) {
113
122
  const that = this
114
123
 
@@ -3,3 +3,4 @@
3
3
  <%= Avo.configuration.branding.css_colors %>
4
4
  }
5
5
  </style>
6
+ <%= favicon_link_tag Avo.configuration.branding.favicon %>
data/bin/init CHANGED
@@ -9,7 +9,17 @@ app_root do
9
9
  )
10
10
 
11
11
  header 'Configuring git'
12
- run! 'git remote add upstream https://github.com/avo-hq/avo.git'
12
+ target_upstream = "https://github.com/avo-hq/avo.git"
13
+ current_upstream = `git config --get remote.upstream.url`.chomp
14
+ if current_upstream.nil? || current_upstream.empty?
15
+ puts "Adding new remote 'upstream' to #{target_upstream}"
16
+ run! "git remote add upstream #{target_upstream}"
17
+ elsif current_upstream != target_upstream
18
+ puts "Updating existing remote 'upstream' to #{target_upstream}"
19
+ run! "git remote set-url upstream #{target_upstream}"
20
+ else
21
+ puts "Remote 'upstream' already points to #{target_upstream}, no change"
22
+ end
13
23
 
14
24
  header 'Installing gems'
15
25
  run! 'bundle install'
data/bin/test CHANGED
@@ -7,6 +7,7 @@ export NODE_ENV="test"
7
7
  if [[ -z "$1" ]] || [[ "$1" == "unit" ]]; then
8
8
  bundle exec rspec ./spec --tag type:feature
9
9
  bundle exec rspec ./spec --tag type:controller
10
+ bundle exec rspec ./spec --tag type:component
10
11
  fi;
11
12
 
12
13
  # Run system tests
data/db/factories.rb CHANGED
@@ -65,6 +65,11 @@ FactoryBot.define do
65
65
  type { "Sibling" }
66
66
  end
67
67
 
68
+ factory :brother do
69
+ name { "#{Faker::Name.first_name} #{Faker::Name.last_name}" }
70
+ type { "Brother" }
71
+ end
72
+
68
73
  factory :fish do
69
74
  name { %w[Tilapia Salmon Trout Catfish Pangasius Carp].sample }
70
75
  end
@@ -114,15 +114,25 @@ module Avo
114
114
  self
115
115
  end
116
116
 
117
- def visible_in_view
118
- # Run the visible block if available
119
- return instance_exec(resource: self.class.resource, view: view, &visible) if visible.present?
117
+ def visible_in_view(parent_model: nil, parent_resource: nil)
118
+ if visible.blank?
119
+ # Hide on the :new view by default
120
+ return false if view == :new
120
121
 
121
- # Hide on the :new view by default
122
- return false if view == :new
122
+ # Show on all other views
123
+ return true
124
+ end
123
125
 
124
- # Show on all other views
125
- true
126
+ # Run the visible block if available
127
+ Avo::Hosts::VisibilityHost.new(
128
+ block: visible,
129
+ model: self.class.model,
130
+ params: params,
131
+ parent_model: parent_model,
132
+ parent_resource: parent_resource,
133
+ resource: self.class.resource,
134
+ view: self.class.view,
135
+ ).handle
126
136
  end
127
137
 
128
138
  def param_id
@@ -0,0 +1,43 @@
1
+
2
+ module Avo
3
+ module Concerns
4
+ module FiltersSessionHandler
5
+ def reset_filters
6
+ return unless cache_resource_filters?
7
+
8
+ session.delete(filters_session_key)
9
+ end
10
+
11
+ def fetch_filters
12
+ return filters_from_params unless cache_resource_filters?
13
+
14
+ (filters_from_params && save_filters_to_session) || filters_from_session
15
+ end
16
+
17
+ def filters_from_params
18
+ params[Avo::Filters::BaseFilter::PARAM_KEY].presence
19
+ end
20
+
21
+ def save_filters_to_session
22
+ session[filters_session_key] = params[Avo::Filters::BaseFilter::PARAM_KEY]
23
+ end
24
+
25
+ def filters_from_session
26
+ session[filters_session_key]
27
+ end
28
+
29
+ def filters_session_key
30
+ @filters_session_key ||= '/filters/' << %w[
31
+ turbo_frame controller resource_name related_name
32
+ action id
33
+ ].map { |key| params[key] }.compact.join('/')
34
+ end
35
+
36
+ def cache_resource_filters?
37
+ return Avo.configuration.cache_resource_filters unless Avo.configuration.cache_resource_filters.is_a?(Proc)
38
+
39
+ Avo.configuration.cache_resource_filters.call(current_user: current_user, resource: @resource)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,10 +1,11 @@
1
1
  class Avo::Configuration::Branding
2
- def initialize(colors: nil, chart_colors: nil, logo: nil, logomark: nil, placeholder: nil)
2
+ def initialize(colors: nil, chart_colors: nil, logo: nil, logomark: nil, placeholder: nil, favicon: nil)
3
3
  @colors = colors || {}
4
4
  @chart_colors = chart_colors
5
5
  @logo = logo
6
6
  @logomark = logomark
7
7
  @placeholder = placeholder
8
+ @favicon = favicon
8
9
 
9
10
  @default_colors = {
10
11
  background: "#F6F6F7",
@@ -17,6 +18,7 @@ class Avo::Configuration::Branding
17
18
  @default_logo = "/avo-assets/logo.png"
18
19
  @default_logomark = "/avo-assets/logomark.png"
19
20
  @default_placeholder = "/avo-assets/placeholder.svg"
21
+ @default_favicon = "/avo-assets/favicon.ico"
20
22
  end
21
23
 
22
24
  def css_colors
@@ -53,6 +55,12 @@ class Avo::Configuration::Branding
53
55
  @chart_colors || @default_chart_colors
54
56
  end
55
57
 
58
+ def favicon
59
+ return @default_favicon if Avo::App.license.lacks_with_trial(:branding)
60
+
61
+ @favicon || @default_favicon
62
+ end
63
+
56
64
  private
57
65
 
58
66
  def colors
@@ -20,6 +20,7 @@ module Avo
20
20
  attr_accessor :full_width_container
21
21
  attr_accessor :full_width_index_view
22
22
  attr_accessor :cache_resources_on_index_view
23
+ attr_accessor :cache_resource_filters
23
24
  attr_accessor :context
24
25
  attr_accessor :display_breadcrumbs
25
26
  attr_accessor :hide_layout_when_printing
@@ -39,6 +40,7 @@ module Avo
39
40
  attr_accessor :resource_default_view
40
41
  attr_accessor :authorization_client
41
42
  attr_accessor :field_wrapper_layout
43
+ attr_accessor :sign_out_path_name
42
44
  attr_writer :branding
43
45
 
44
46
  def initialize
@@ -68,6 +70,7 @@ module Avo
68
70
  @full_width_container = false
69
71
  @full_width_index_view = false
70
72
  @cache_resources_on_index_view = Avo::PACKED
73
+ @cache_resource_filters = false
71
74
  @context = proc {}
72
75
  @initial_breadcrumbs = proc {
73
76
  add_breadcrumb I18n.t("avo.home").humanize, avo.root_path
data/lib/avo/engine.rb CHANGED
@@ -64,6 +64,11 @@ module Avo
64
64
  g.test_framework :rspec, view_specs: false
65
65
  end
66
66
 
67
+ generators do |app|
68
+ Rails::Generators.configure! app.config.generators
69
+ require_relative "../generators/model_generator"
70
+ end
71
+
67
72
  # After deploy we want to make sure the license response is being cleared.
68
73
  # We need a fresh license response.
69
74
  # This is disabled in development because the initialization process might be triggered more than once.
@@ -14,6 +14,7 @@ module Avo
14
14
  include Avo::Concerns::HasHTMLAttributes
15
15
  include Avo::Fields::Concerns::IsRequired
16
16
  include Avo::Fields::Concerns::IsReadonly
17
+ include Avo::Fields::Concerns::HasDefault
17
18
 
18
19
  delegate :view_context, to: ::Avo::App
19
20
  delegate :simple_format, :content_tag, to: :view_context
@@ -145,9 +146,11 @@ module Avo
145
146
  end
146
147
 
147
148
  def placeholder
148
- return @placeholder if @placeholder.present?
149
+ if @placeholder.respond_to?(:call)
150
+ return Avo::Hosts::ResourceViewRecordHost.new(block: @placeholder, record: @model, resource: @resource, view: @view).handle
151
+ end
149
152
 
150
- name
153
+ @placeholder || name
151
154
  end
152
155
 
153
156
  def visible?
@@ -166,15 +169,9 @@ module Avo
166
169
  # Get model value
167
170
  final_value = @model.send(property) if is_model?(@model) && @model.respond_to?(property)
168
171
 
169
- # On new views and actions modals we need to prefill the fields
170
- if @view.in?([:new, :create]) || @action.present?
171
- if default.present?
172
- final_value = if default.respond_to?(:call)
173
- default.call
174
- else
175
- default
176
- end
177
- end
172
+ # On new views and actions modals we need to prefill the fields with the default value
173
+ if should_fill_with_default_value? && default.present?
174
+ final_value = computed_default_value
178
175
  end
179
176
 
180
177
  # Run computable callback block if present
@@ -269,6 +266,18 @@ module Avo
269
266
  def is_model?(model)
270
267
  model_or_class(model) == "model"
271
268
  end
269
+
270
+ def should_fill_with_default_value?
271
+ on_create? || in_action?
272
+ end
273
+
274
+ def on_create?
275
+ @view.in?([:new, :create])
276
+ end
277
+
278
+ def in_action?
279
+ @action.present?
280
+ end
272
281
  end
273
282
  end
274
283
  end
@@ -0,0 +1,17 @@
1
+ module Avo
2
+ module Fields
3
+ module Concerns
4
+ module HasDefault
5
+ extend ActiveSupport::Concern
6
+
7
+ def computed_default_value
8
+ if default.respond_to? :call
9
+ Avo::Hosts::ResourceViewRecordHost.new(block: default, record: model, view: view, resource: resource).handle
10
+ else
11
+ default
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -6,7 +6,7 @@ module Avo
6
6
 
7
7
  def is_readonly?
8
8
  if readonly.respond_to? :call
9
- Avo::Hosts::ViewRecordHost.new(block: readonly, record: model, view: view).handle
9
+ Avo::Hosts::ResourceViewRecordHost.new(block: readonly, record: model, view: view, resource: resource).handle
10
10
  else
11
11
  readonly
12
12
  end
@@ -6,7 +6,7 @@ module Avo
6
6
 
7
7
  def is_required?
8
8
  if required.respond_to? :call
9
- Avo::Hosts::ViewRecordHost.new(block: required, record: model, view: view).handle
9
+ Avo::Hosts::ResourceViewRecordHost.new(block: required, record: model, view: view, resource: resource).handle
10
10
  else
11
11
  required.nil? ? required_from_validators : required
12
12
  end
@@ -18,7 +18,7 @@ module Avo
18
18
  return false if model.nil?
19
19
 
20
20
  validators.any? do |validator|
21
- validator.kind_of? ActiveModel::Validations::PresenceValidator
21
+ validator.is_a? ActiveModel::Validations::PresenceValidator
22
22
  end
23
23
  end
24
24
 
@@ -81,7 +81,7 @@ module Avo
81
81
  new_value = {}
82
82
  end
83
83
 
84
- model[key] = new_value
84
+ model.send("#{key}=", new_value)
85
85
 
86
86
  model
87
87
  end
@@ -3,11 +3,12 @@ module Avo
3
3
  class BaseFilter
4
4
  PARAM_KEY = :filters unless const_defined?(:PARAM_KEY)
5
5
 
6
- class_attribute :name, default: "Filter"
7
6
  class_attribute :component, default: "boolean-filter"
8
7
  class_attribute :default, default: nil
9
- class_attribute :template, default: "avo/base/select_filter"
10
8
  class_attribute :empty_message
9
+ class_attribute :name, default: "Filter"
10
+ class_attribute :template, default: "avo/base/select_filter"
11
+ class_attribute :visible
11
12
 
12
13
  delegate :params, to: Avo::App
13
14
 
@@ -52,6 +53,20 @@ module Avo
52
53
  def applied_filters
53
54
  self.class.decode_filters params[PARAM_KEY]
54
55
  end
56
+
57
+ def visible_in_view(resource: nil, parent_model: nil, parent_resource: nil)
58
+ return true if visible.blank?
59
+
60
+ # Run the visible block if available
61
+ Avo::Hosts::VisibilityHost.new(
62
+ block: visible,
63
+ params: params,
64
+ parent_model: parent_model,
65
+ parent_resource: parent_resource,
66
+ resource: resource
67
+ ).handle
68
+
69
+ end
55
70
  end
56
71
  end
57
72
  end
@@ -0,0 +1,7 @@
1
+ module Avo
2
+ module Hosts
3
+ class ResourceViewRecordHost < ViewRecordHost
4
+ option :resource
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ module Avo
2
+ module Hosts
3
+ class VisibilityHost < BaseHost
4
+ option :parent_model
5
+ option :parent_resource
6
+ option :resource
7
+ # View is optional because in filter context the view is always :index
8
+ option :view, optional: true
9
+ end
10
+ end
11
+ end