avo 2.18.1 → 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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -5
  3. data/Gemfile.lock +75 -76
  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 +17 -0
  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/fields/index_component.rb +4 -3
  10. data/app/components/avo/filters_component.html.erb +1 -1
  11. data/app/components/avo/filters_component.rb +2 -2
  12. data/app/components/avo/index/grid_item_component.rb +2 -2
  13. data/app/components/avo/index/resource_controls_component.rb +2 -2
  14. data/app/components/avo/index/table_row_component.html.erb +1 -1
  15. data/app/components/avo/item_switcher_component.html.erb +1 -1
  16. data/app/components/avo/resource_component.rb +1 -1
  17. data/app/components/avo/resource_sidebar_component.rb +1 -6
  18. data/app/components/avo/sidebar_profile_component.rb +3 -1
  19. data/app/components/avo/tab_group_component.rb +1 -1
  20. data/app/components/avo/views/resource_show_component.html.erb +1 -1
  21. data/app/controllers/avo/application_controller.rb +6 -0
  22. data/app/controllers/avo/base_controller.rb +14 -7
  23. data/app/controllers/avo/dashboards/cards_controller.rb +37 -0
  24. data/app/helpers/avo/application_helper.rb +5 -1
  25. data/app/javascript/js/controllers/search_controller.js +11 -2
  26. data/app/views/avo/{cards → dashboards/cards}/_chartkick_card.html.erb +0 -0
  27. data/app/views/avo/{cards → dashboards/cards}/_metric_card.html.erb +0 -0
  28. data/app/views/avo/{cards → dashboards/cards}/chartkick_missing.html.erb +0 -0
  29. data/app/views/avo/{cards → dashboards/cards}/show.html.erb +0 -0
  30. data/app/views/avo/partials/_branding.html.erb +1 -0
  31. data/avo.gemspec +1 -1
  32. data/bin/init +11 -1
  33. data/bin/test +1 -0
  34. data/config/routes.rb +2 -2
  35. data/db/factories.rb +10 -0
  36. data/lib/avo/app.rb +11 -1
  37. data/lib/avo/base_action.rb +19 -9
  38. data/lib/avo/base_resource.rb +3 -6
  39. data/lib/avo/concerns/filters_session_handler.rb +43 -0
  40. data/lib/avo/concerns/has_fields.rb +2 -0
  41. data/lib/avo/concerns/visible_items.rb +44 -0
  42. data/lib/avo/configuration/branding.rb +10 -2
  43. data/lib/avo/configuration.rb +3 -0
  44. data/lib/avo/dynamic_router.rb +16 -15
  45. data/lib/avo/engine.rb +6 -9
  46. data/lib/avo/fields/base_field.rb +21 -12
  47. data/lib/avo/fields/concerns/has_default.rb +17 -0
  48. data/lib/avo/fields/concerns/is_readonly.rb +1 -1
  49. data/lib/avo/fields/concerns/is_required.rb +2 -2
  50. data/lib/avo/fields/has_base_field.rb +2 -0
  51. data/lib/avo/fields/key_value_field.rb +1 -1
  52. data/lib/avo/filters/base_filter.rb +17 -2
  53. data/lib/avo/hosts/resource_view_record_host.rb +7 -0
  54. data/lib/avo/hosts/visibility_host.rb +11 -0
  55. data/lib/avo/panel.rb +4 -1
  56. data/lib/avo/resources/controls/action.rb +1 -3
  57. data/lib/avo/sidebar.rb +1 -31
  58. data/lib/avo/tab.rb +5 -22
  59. data/lib/avo/version.rb +1 -1
  60. data/lib/avo.rb +9 -0
  61. data/lib/generators/avo/resource_generator.rb +281 -0
  62. data/lib/generators/avo/templates/action.tt +3 -0
  63. data/lib/generators/avo/templates/filters/boolean_filter.tt +3 -0
  64. data/lib/generators/avo/templates/filters/multiple_select_filter.tt +3 -0
  65. data/lib/generators/avo/templates/filters/select_filter.tt +3 -0
  66. data/lib/generators/avo/templates/filters/text_filter.tt +3 -0
  67. data/lib/generators/avo/templates/initializer/avo.tt +4 -0
  68. data/lib/generators/avo/templates/resource/controller.tt +1 -1
  69. data/lib/generators/avo/templates/resource/resource.tt +2 -2
  70. data/lib/generators/model_generator.rb +10 -0
  71. data/lib/generators/rails/avo_resource_generator.rb +11 -0
  72. data/public/avo-assets/avo.base.css +10 -10
  73. data/public/avo-assets/avo.base.js +1 -1
  74. data/public/avo-assets/avo.base.js.map +2 -2
  75. data/public/avo-assets/favicon.ico +0 -0
  76. data/{app/assets/svgs → public/avo-assets}/placeholder.svg +0 -0
  77. metadata +18 -11
  78. data/app/controllers/avo/cards_controller.rb +0 -35
  79. data/config/master.key +0 -1
@@ -1,5 +1,11 @@
1
1
  module Avo
2
2
  class ApplicationController < ::ActionController::Base
3
+ if defined?(Pundit::Authorization)
4
+ Avo::ApplicationController.include Pundit::Authorization
5
+ elsif defined?(Pundit)
6
+ Avo::ApplicationController.include Pundit
7
+ end
8
+
3
9
  include Pagy::Backend
4
10
  include Avo::ApplicationHelper
5
11
  include Avo::UrlHelpers
@@ -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
@@ -0,0 +1,37 @@
1
+ require_dependency "avo/application_controller"
2
+
3
+ module Avo
4
+ module Dashboards
5
+ class CardsController < ApplicationController
6
+ before_action :set_dashboard
7
+ before_action :set_card
8
+ before_action :detect_chartkick
9
+
10
+ def show
11
+ render(:chartkick_missing) unless @chartkick_installed
12
+ end
13
+
14
+ private
15
+
16
+ def set_dashboard
17
+ @dashboard = Avo::App.get_dashboard_by_id params[:dashboard_id]
18
+
19
+ raise ActionController::RoutingError.new("Not Found") if @dashboard.nil? || @dashboard.is_hidden?
20
+ end
21
+
22
+ def set_card
23
+ @card = @dashboard.item_at_index(params[:index].to_i).tap do |card|
24
+ card.hydrate(dashboard: @dashboard, params: params)
25
+ end
26
+ end
27
+
28
+ def detect_chartkick
29
+ @chartkick_installed = if @card.class.ancestors.map(&:to_s).include?("Avo::Dashboards::ChartkickCard")
30
+ defined?(Chartkick)
31
+ else
32
+ true
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -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/avo.gemspec CHANGED
@@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
35
35
  spec.add_dependency "activerecord", ">= 6.0"
36
36
  spec.add_dependency "actionview", ">= 6.0"
37
37
  spec.add_dependency "pagy"
38
- spec.add_dependency "zeitwerk"
38
+ spec.add_dependency "zeitwerk", ">= 2.6.2"
39
39
  spec.add_dependency "httparty"
40
40
  spec.add_dependency "active_link_to"
41
41
  spec.add_dependency "view_component"
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/config/routes.rb CHANGED
@@ -7,7 +7,7 @@ Avo::Engine.routes.draw do
7
7
  post "/rails/active_storage/direct_uploads", to: "/active_storage/direct_uploads#create"
8
8
 
9
9
  resources :dashboards do
10
- resources :cards
10
+ resources :cards, controller: "dashboards/cards"
11
11
  end
12
12
 
13
13
  scope "avo_api", as: "avo_api" do
@@ -33,7 +33,7 @@ Avo::Engine.routes.draw do
33
33
 
34
34
  # Generate resource routes as below:
35
35
  # resources :posts
36
- Avo::DynamicRouter.routes(self)
36
+ Avo::DynamicRouter.routes
37
37
 
38
38
  # Associations
39
39
  get "/:resource_name/:id/:related_name/new", to: "associations#new", as: "associations_new"
data/db/factories.rb CHANGED
@@ -60,6 +60,16 @@ FactoryBot.define do
60
60
  type { "Spouse" }
61
61
  end
62
62
 
63
+ factory :sibling do
64
+ name { "#{Faker::Name.first_name} #{Faker::Name.last_name}" }
65
+ type { "Sibling" }
66
+ end
67
+
68
+ factory :brother do
69
+ name { "#{Faker::Name.first_name} #{Faker::Name.last_name}" }
70
+ type { "Brother" }
71
+ end
72
+
63
73
  factory :fish do
64
74
  name { %w[Tilapia Salmon Trout Catfish Pangasius Carp].sample }
65
75
  end
data/lib/avo/app.rb CHANGED
@@ -17,6 +17,14 @@ module Avo
17
17
  class_attribute :error_messages
18
18
 
19
19
  class << self
20
+ def eager_load(entity)
21
+ paths = Avo::ENTITIES.fetch entity
22
+
23
+ return unless paths.present?
24
+
25
+ Rails.autoloaders.main.eager_load_dir(Rails.root.join(*paths).to_s)
26
+ end
27
+
20
28
  def boot
21
29
  init_fields
22
30
 
@@ -91,7 +99,7 @@ module Avo
91
99
  has_model = resource.model_class.present?
92
100
 
93
101
  unless has_model
94
- possible_model = resource.class.to_s.gsub 'Resource', ''
102
+ possible_model = resource.class.to_s.gsub "Resource", ""
95
103
 
96
104
  Avo::App.error_messages.push({
97
105
  url: "https://docs.avohq.io/2.0/resources.html#custom-model-class",
@@ -119,6 +127,8 @@ module Avo
119
127
  end
120
128
 
121
129
  def init_dashboards
130
+ eager_load :dashboards unless Rails.application.config.eager_load
131
+
122
132
  self.dashboards = Dashboards::BaseDashboard.descendants
123
133
  .select do |dashboard|
124
134
  dashboard != Dashboards::BaseDashboard
@@ -34,9 +34,9 @@ module Avo
34
34
  def form_data_attributes
35
35
  # We can't respond with a file download from Turbo se we disable it on the form
36
36
  if may_download_file
37
- {turbo: false, remote: false}
37
+ {turbo: false, remote: false, action_target: :form}
38
38
  else
39
- {"turbo-frame": "_top", "action-target": "form"}
39
+ {turbo_frame: :_top, action_target: :form}
40
40
  end
41
41
  end
42
42
 
@@ -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
@@ -49,6 +49,7 @@ module Avo
49
49
  class_attribute :record_selector, default: true
50
50
  class_attribute :keep_filters_panel_open, default: false
51
51
  class_attribute :extra_params
52
+ class_attribute :link_to_child_resource, default: false
52
53
 
53
54
  class << self
54
55
  delegate :t, to: ::I18n
@@ -422,9 +423,7 @@ module Avo
422
423
  end
423
424
 
424
425
  def label
425
- label_field.value || model_title
426
- rescue
427
- model_title
426
+ label_field&.value || model_title
428
427
  end
429
428
 
430
429
  def avatar_field
@@ -460,9 +459,7 @@ module Avo
460
459
  end
461
460
 
462
461
  def description
463
- description_field.value
464
- rescue
465
- nil
462
+ description_field&.value
466
463
  end
467
464
 
468
465
  def form_scope
@@ -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
@@ -270,6 +270,8 @@ module Avo
270
270
  end
271
271
  # each field has it's own visibility checker
272
272
  if item.respond_to? :visible?
273
+ item.hydrate(view: view) if item.view.nil?
274
+
273
275
  next unless item.visible?
274
276
  end
275
277
  # check if the user is authorized to view it
@@ -0,0 +1,44 @@
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
+ if items_holder.present?
8
+ items_holder.items
9
+ else
10
+ []
11
+ end
12
+ end
13
+
14
+ def visible_items
15
+ items
16
+ .map do |item|
17
+ visible(item) ? item : nil
18
+ end
19
+ .compact
20
+ end
21
+
22
+ def visible(item)
23
+ if item.is_field?
24
+ item.visible? && item.visible_on?(view)
25
+ else
26
+ item.visible?
27
+ end
28
+ end
29
+
30
+ def visible?
31
+ any_item_visible = visible_items.any?
32
+ return any_item_visible unless respond_to?(:visible_on?)
33
+
34
+ visible_on?(view) && any_item_visible
35
+ end
36
+
37
+ def hydrate(view: nil)
38
+ @view = view
39
+
40
+ self
41
+ end
42
+ end
43
+ end
44
+ 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",
@@ -16,7 +17,8 @@ class Avo::Configuration::Branding
16
17
  @default_chart_colors = ["#0B8AE2", "#34C683", "#2AB1EE", "#34C6A8"]
17
18
  @default_logo = "/avo-assets/logo.png"
18
19
  @default_logomark = "/avo-assets/logomark.png"
19
- @default_placeholder = "placeholder.svg"
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
@@ -1,21 +1,22 @@
1
1
  module Avo
2
- module DynamicRouter
3
- def self.routes(router)
4
- Rails.application.eager_load! unless Rails.env.production?
2
+ class DynamicRouter
3
+ def self.routes
4
+ Avo::Engine.routes.draw do
5
+ scope "resources", as: "resources" do
6
+ Avo::App.eager_load(:resources) unless Rails.application.config.eager_load
5
7
 
6
- BaseResource.descendants
7
- .select do |resource|
8
- resource != :BaseResource
9
- end
10
- .select do |resource|
11
- resource.is_a? Class
12
- end
13
- # .select do |resource|
14
- # resource.model_class.present?
15
- # end
16
- .map do |resource|
17
- router.resources resource.new.route_key
8
+ BaseResource.descendants
9
+ .select do |resource|
10
+ resource != :BaseResource
11
+ end
12
+ .select do |resource|
13
+ resource.is_a? Class
14
+ end
15
+ .map do |resource|
16
+ resources resource.new.route_key
17
+ end
18
18
  end
19
+ end
19
20
  end
20
21
  end
21
22
  end
data/lib/avo/engine.rb CHANGED
@@ -27,15 +27,7 @@ module Avo
27
27
  end
28
28
 
29
29
  initializer "avo.autoload" do |app|
30
- [
31
- ["app", "avo", "fields"],
32
- ["app", "avo", "filters"],
33
- ["app", "avo", "actions"],
34
- ["app", "avo", "resources"],
35
- ["app", "avo", "dashboards"],
36
- ["app", "avo", "cards"],
37
- ["app", "avo", "resource_tools"]
38
- ].each do |path_params|
30
+ Avo::ENTITIES.values.each do |path_params|
39
31
  path = Rails.root.join(*path_params)
40
32
 
41
33
  if File.directory? path.to_s
@@ -72,6 +64,11 @@ module Avo
72
64
  g.test_framework :rspec, view_specs: false
73
65
  end
74
66
 
67
+ generators do |app|
68
+ Rails::Generators.configure! app.config.generators
69
+ require_relative "../generators/model_generator"
70
+ end
71
+
75
72
  # After deploy we want to make sure the license response is being cleared.
76
73
  # We need a fresh license response.
77
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
@@ -83,7 +84,7 @@ module Avo
83
84
 
84
85
  @args = args
85
86
 
86
- @updatable = true
87
+ @updatable = !readonly
87
88
  @computable = true
88
89
  @computed = block.present?
89
90
  @computed_value = nil
@@ -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