avo 2.15.3 → 2.16.1.pre.1.nativefields

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 (116) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -2
  3. data/Gemfile.lock +78 -86
  4. data/app/components/avo/base_component.rb +7 -1
  5. data/app/components/avo/field_wrapper_component.html.erb +40 -0
  6. data/app/components/avo/field_wrapper_component.rb +102 -0
  7. data/app/components/avo/fields/badge_field/show_component.html.erb +1 -1
  8. data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +3 -3
  9. data/app/components/avo/fields/belongs_to_field/index_component.html.erb +2 -1
  10. data/app/components/avo/fields/belongs_to_field/show_component.html.erb +2 -2
  11. data/app/components/avo/fields/belongs_to_field/show_component.rb +8 -0
  12. data/app/components/avo/fields/boolean_field/edit_component.html.erb +1 -1
  13. data/app/components/avo/fields/boolean_field/show_component.html.erb +1 -1
  14. data/app/components/avo/fields/boolean_group_field/edit_component.html.erb +1 -1
  15. data/app/components/avo/fields/boolean_group_field/show_component.html.erb +1 -1
  16. data/app/components/avo/fields/code_field/edit_component.html.erb +2 -2
  17. data/app/components/avo/fields/code_field/show_component.html.erb +2 -2
  18. data/app/components/avo/fields/country_field/edit_component.html.erb +1 -1
  19. data/app/components/avo/fields/country_field/show_component.html.erb +1 -1
  20. data/app/components/avo/fields/date_field/edit_component.html.erb +1 -1
  21. data/app/components/avo/fields/date_field/show_component.html.erb +1 -1
  22. data/app/components/avo/fields/date_time_field/edit_component.html.erb +1 -1
  23. data/app/components/avo/fields/date_time_field/show_component.html.erb +1 -1
  24. data/app/components/avo/fields/edit_component.rb +22 -4
  25. data/app/components/avo/fields/external_image_field/edit_component.html.erb +1 -1
  26. data/app/components/avo/fields/external_image_field/index_component.html.erb +1 -1
  27. data/app/components/avo/fields/external_image_field/show_component.html.erb +1 -1
  28. data/app/components/avo/fields/file_field/edit_component.html.erb +1 -1
  29. data/app/components/avo/fields/file_field/index_component.html.erb +2 -2
  30. data/app/components/avo/fields/file_field/show_component.html.erb +1 -1
  31. data/app/components/avo/fields/files_field/edit_component.html.erb +1 -1
  32. data/app/components/avo/fields/files_field/show_component.html.erb +1 -1
  33. data/app/components/avo/fields/gravatar_field/index_component.html.erb +1 -1
  34. data/app/components/avo/fields/gravatar_field/show_component.html.erb +1 -1
  35. data/app/components/avo/fields/has_one_field/show_component.html.erb +14 -1
  36. data/app/components/avo/fields/has_one_field/show_component.rb +21 -0
  37. data/app/components/avo/fields/id_field/edit_component.html.erb +1 -1
  38. data/app/components/avo/fields/id_field/index_component.html.erb +1 -1
  39. data/app/components/avo/fields/id_field/show_component.html.erb +1 -1
  40. data/app/components/avo/fields/index_component.rb +9 -4
  41. data/app/components/avo/fields/key_value_field/edit_component.html.erb +2 -2
  42. data/app/components/avo/fields/key_value_field/show_component.html.erb +1 -1
  43. data/app/components/avo/fields/markdown_field/edit_component.html.erb +2 -2
  44. data/app/components/avo/fields/markdown_field/show_component.html.erb +1 -1
  45. data/app/components/avo/fields/number_field/edit_component.html.erb +1 -1
  46. data/app/components/avo/fields/number_field/show_component.html.erb +1 -1
  47. data/app/components/avo/fields/password_field/edit_component.html.erb +1 -1
  48. data/app/components/avo/fields/progress_bar_field/edit_component.html.erb +1 -1
  49. data/app/components/avo/fields/progress_bar_field/show_component.html.erb +1 -1
  50. data/app/components/avo/fields/select_field/edit_component.html.erb +1 -2
  51. data/app/components/avo/fields/select_field/show_component.html.erb +1 -1
  52. data/app/components/avo/fields/show_component.rb +36 -1
  53. data/app/components/avo/fields/status_field/edit_component.html.erb +1 -1
  54. data/app/components/avo/fields/status_field/show_component.html.erb +1 -1
  55. data/app/components/avo/fields/tags_field/edit_component.html.erb +1 -5
  56. data/app/components/avo/fields/tags_field/show_component.html.erb +1 -1
  57. data/app/components/avo/fields/text_field/edit_component.html.erb +2 -2
  58. data/app/components/avo/fields/text_field/index_component.html.erb +1 -1
  59. data/app/components/avo/fields/text_field/show_component.html.erb +1 -1
  60. data/app/components/avo/fields/textarea_field/edit_component.html.erb +1 -1
  61. data/app/components/avo/fields/textarea_field/show_component.html.erb +1 -1
  62. data/app/components/avo/fields/trix_field/edit_component.html.erb +13 -13
  63. data/app/components/avo/fields/trix_field/edit_component.rb +19 -1
  64. data/app/components/avo/fields/trix_field/show_component.html.erb +1 -1
  65. data/app/components/avo/index/grid_item_component.html.erb +6 -6
  66. data/app/components/avo/index/grid_item_component.rb +15 -0
  67. data/app/components/avo/index/resource_controls_component.rb +3 -0
  68. data/app/components/avo/index/resource_grid_component.rb +1 -1
  69. data/app/components/avo/resource_component.rb +5 -1
  70. data/app/components/avo/sidebar/item_switcher_component.html.erb +3 -3
  71. data/app/components/avo/sidebar/link_component.html.erb +2 -2
  72. data/app/components/avo/sidebar/link_component.rb +3 -1
  73. data/app/components/avo/views/resource_edit_component.html.erb +47 -28
  74. data/app/components/avo/views/resource_edit_component.rb +26 -9
  75. data/app/components/avo/views/resource_show_component.rb +0 -8
  76. data/app/controllers/avo/actions_controller.rb +7 -5
  77. data/app/controllers/avo/application_controller.rb +22 -3
  78. data/app/controllers/avo/associations_controller.rb +2 -2
  79. data/app/controllers/avo/base_controller.rb +24 -11
  80. data/app/helpers/avo/application_helper.rb +31 -3
  81. data/app/helpers/avo/resources_helper.rb +4 -8
  82. data/app/helpers/avo/url_helpers.rb +8 -0
  83. data/app/javascript/js/controllers/action_controller.js +3 -1
  84. data/app/javascript/js/controllers/fields/date_field_controller.js +21 -1
  85. data/app/javascript/js/controllers/search_controller.js +122 -118
  86. data/app/views/avo/actions/show.html.erb +5 -1
  87. data/avo.gemspec +1 -1
  88. data/config/master.key +1 -0
  89. data/lib/avo/base_action.rb +25 -6
  90. data/lib/avo/base_resource.rb +6 -4
  91. data/lib/avo/base_resource_tool.rb +1 -1
  92. data/lib/avo/concerns/fetches_things.rb +2 -0
  93. data/lib/avo/configuration.rb +2 -0
  94. data/lib/avo/fields/base_field.rb +5 -1
  95. data/lib/avo/fields/belongs_to_field.rb +1 -1
  96. data/lib/avo/fields/has_and_belongs_to_many_field.rb +1 -1
  97. data/lib/avo/fields/has_base_field.rb +5 -1
  98. data/lib/avo/fields/has_many_field.rb +1 -1
  99. data/lib/avo/fields/select_field.rb +1 -0
  100. data/lib/avo/menu/base_item.rb +1 -0
  101. data/lib/avo/menu/builder.rb +4 -2
  102. data/lib/avo/menu/menu.rb +2 -0
  103. data/lib/avo/services/authorization_service.rb +24 -20
  104. data/lib/avo/version.rb +1 -1
  105. data/lib/generators/avo/templates/field/components/edit_component.html.erb.tt +1 -1
  106. data/lib/generators/avo/templates/field/components/show_component.html.erb.tt +1 -1
  107. data/public/avo-assets/avo.base.css +26 -8
  108. data/public/avo-assets/avo.base.js +79 -79
  109. data/public/avo-assets/avo.base.js.map +3 -3
  110. metadata +8 -11
  111. data/app/components/avo/common_field_wrapper_component.html.erb +0 -26
  112. data/app/components/avo/common_field_wrapper_component.rb +0 -46
  113. data/app/components/avo/edit/field_wrapper_component.html.erb +0 -11
  114. data/app/components/avo/edit/field_wrapper_component.rb +0 -21
  115. data/app/components/avo/show/field_wrapper_component.html.erb +0 -9
  116. data/app/components/avo/show/field_wrapper_component.rb +0 -12
@@ -46,7 +46,11 @@ class Avo::ResourceComponent < Avo::BaseComponent
46
46
  end
47
47
 
48
48
  def destroy_path
49
- helpers.resource_path(model: @resource.model, resource: @resource)
49
+ if params[:via_resource_class].present?
50
+ helpers.resource_path(model: @resource.model, resource: @resource, referrer: back_path)
51
+ else
52
+ helpers.resource_path(model: @resource.model, resource: @resource)
53
+ end
50
54
  end
51
55
 
52
56
  def authorize_association_for(policy_method)
@@ -1,11 +1,11 @@
1
1
  <% if item.is_a? Avo::Menu::Link %>
2
- <%= render Avo::Sidebar::LinkComponent.new label: item.name, path: item.path, target: item.target %>
2
+ <%= render Avo::Sidebar::LinkComponent.new label: item.name, path: item.path, target: item.target, data: item.data %>
3
3
  <% end %>
4
4
  <% if item.is_a? Avo::Menu::Resource %>
5
- <%= render Avo::Sidebar::LinkComponent.new label: item.navigation_label, path: helpers.resources_path(resource: resource) %>
5
+ <%= render Avo::Sidebar::LinkComponent.new label: item.navigation_label, path: helpers.resources_path(resource: resource), data: item.data %>
6
6
  <% end %>
7
7
  <% if item.is_a? Avo::Menu::Dashboard %>
8
- <%= render Avo::Sidebar::LinkComponent.new label: item.navigation_label, path: dashboard.navigation_path %>
8
+ <%= render Avo::Sidebar::LinkComponent.new label: item.navigation_label, path: dashboard.navigation_path, data: item.data %>
9
9
  <% end %>
10
10
  <% if item.is_a? Avo::Menu::Section %>
11
11
  <%= render Avo::Sidebar::SectionComponent.new item: item %>
@@ -1,12 +1,12 @@
1
1
  <% if path.present? %>
2
- <%= send link_method, path, class: classes, active: active, target: target do %>
2
+ <%= send link_method, path, class: classes, active: active, target: target, data: data do %>
3
3
  <%= label %>
4
4
  <% if target == :_blank %>
5
5
  <%= helpers.svg('heroicons/outline/external-link', class: 'self-center ml-auto h-3 mr-2') %>
6
6
  <% end %>
7
7
  <% end %>
8
8
  <% else %>
9
- <%= content_tag :div, class: classes, active: active, target: target do %>
9
+ <%= content_tag :div, class: classes, active: active, target: target, data: data do %>
10
10
  <%= label %>
11
11
  <% end %>
12
12
  <% end %>
@@ -5,12 +5,14 @@ class Avo::Sidebar::LinkComponent < ViewComponent::Base
5
5
  attr_reader :target
6
6
  attr_reader :label
7
7
  attr_reader :path
8
+ attr_reader :data
8
9
 
9
- def initialize(label: nil, path: nil, active: :inclusive, target: nil)
10
+ def initialize(label: nil, path: nil, active: :inclusive, target: nil, data: {})
10
11
  @label = label
11
12
  @path = path
12
13
  @active = active
13
14
  @target = target
15
+ @data = data
14
16
  end
15
17
 
16
18
  def is_external?
@@ -15,22 +15,40 @@
15
15
  },
16
16
  multipart: true do |form| %>
17
17
  <%= render Avo::ReferrerParamsComponent.new back_path: back_path %>
18
- <%= render Avo::PanelComponent.new(name: title, description: @resource.resource_description, display_breadcrumbs: @reflection.blank?, index: 0, data: { panel_id: "main" }) do |c| %>
19
- <% c.tools do %>
20
- <%= a_link back_path,
18
+ <%= content_tag :div, class: 'space-y-12' do %>
19
+ <%= render Avo::PanelComponent.new(name: title, description: @resource.resource_description, display_breadcrumbs: @reflection.blank?, index: 0, data: { panel_id: "main" }) do |c| %>
20
+ <% c.tools do %>
21
+ <%= a_link back_path,
21
22
  style: :text,
22
23
  icon: 'arrow-left' do %>
23
24
  <%= t('avo.cancel').capitalize %>
24
25
  <% end %>
26
+ <% if can_see_the_destroy_button? %>
27
+ <%= a_link destroy_path,
28
+ method: :delete,
29
+ local: true,
30
+ style: :text,
31
+ loading: true,
32
+ confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
33
+ color: :red,
34
+ icon: 'trash',
35
+ form_class: 'flex flex-col sm:flex-row sm:inline-flex',
36
+ data: {
37
+ control: :destroy,
38
+ 'resource-id': @resource.model.id,
39
+ } do %>
40
+ <%= t('avo.delete').capitalize %>
41
+ <% end %>
42
+ <% end %>
25
43
  <% if can_see_the_actions_button? %>
26
44
  <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
27
45
  <% end %>
28
46
  <% if can_see_the_save_button? %>
29
47
  <%= a_button color: :primary,
30
- style: :primary,
31
- loading: true,
32
- type: :submit,
33
- icon: 'save' do %>
48
+ style: :primary,
49
+ loading: true,
50
+ type: :submit,
51
+ icon: 'save' do %>
34
52
  <%= t('avo.save').capitalize %>
35
53
  <% end %>
36
54
  <% end %>
@@ -41,39 +59,40 @@
41
59
  <% c.body do %>
42
60
  <div class="divide-y">
43
61
  <% main_panel.items.each_with_index do |field, index| %>
44
- <%= render field.hydrate(resource: @resource, model: @resource.model, user: @resource.user, view: view)
45
- .component_for_view(view)
62
+ <%= render field.hydrate(resource: @resource, model: @resource.model, user: @resource.user, view: view_for(field))
63
+ .component_for_view(view_for field)
46
64
  .new(field: field, resource: @resource, index: index, form: form)
47
65
  %>
48
- <% end %>
49
- </div>
66
+ <% end %>
67
+ </div>
68
+ <% end %>
50
69
  <% end %>
51
- <% end %>
52
- <% if Avo.configuration.buttons_on_form_footers %>
53
- <% c.footer_tools do %>
54
- <div class="mt-4">
55
- <%= a_link back_path,
70
+ <% if Avo.configuration.buttons_on_form_footers %>
71
+ <% c.footer_tools do %>
72
+ <div class="mt-4">
73
+ <%= a_link back_path,
56
74
  style: :text,
57
75
  icon: 'arrow-left' do %>
58
- <%= t('avo.cancel').capitalize %>
59
- <% end %>
60
- <% if can_see_the_save_button? %>
61
- <%= a_button color: :primary,
76
+ <%= t('avo.cancel').capitalize %>
77
+ <% end %>
78
+ <% if can_see_the_save_button? %>
79
+ <%= a_button color: :primary,
62
80
  style: :primary,
63
81
  loading: true,
64
82
  type: :submit,
65
83
  icon: 'save' do %>
66
- <%= t('avo.save').capitalize %>
84
+ <%= t('avo.save').capitalize %>
85
+ <% end %>
67
86
  <% end %>
68
- <% end %>
69
- </div>
87
+ </div>
88
+ <% end %>
70
89
  <% end %>
71
90
  <% end %>
72
- <% end %>
73
- <%= content_tag :div, class: 'space-y-12 mt-12' do %>
74
- <% @resource.get_items.each_with_index do |item, index| %>
75
- <% next if item.nil? %>
76
- <%= render Avo::ItemSwitcherComponent.new resource: @resource, item: item, index: index + 1, view: @view, form: form %>
91
+ <%= content_tag :div, class: 'space-y-12' do %>
92
+ <% @resource.get_items.each_with_index do |item, index| %>
93
+ <% next if item.nil? %>
94
+ <%= render Avo::ItemSwitcherComponent.new resource: @resource, item: item, index: index + 1, view: @view, form: form %>
95
+ <% end %>
77
96
  <% end %>
78
97
  <% end %>
79
98
  <% end %>
@@ -16,16 +16,28 @@ class Avo::Views::ResourceEditComponent < Avo::ResourceComponent
16
16
  end
17
17
 
18
18
  def back_path
19
- if via_resource?
20
- model = params[:via_resource_class] || params[:via_relation_class]
21
- helpers.resource_path(model: model.safe_constantize, resource: relation_resource, resource_id: params[:via_resource_id])
22
- elsif via_index?
23
- helpers.resources_path(resource: @resource)
24
- elsif is_edit? # via resource show page
25
- helpers.resource_path(model: @resource.model, resource: @resource)
26
- else
27
- helpers.resources_path(resource: @resource)
19
+ return resource_view_path if via_resource?
20
+ return resources_path if via_index?
21
+
22
+ if is_edit? && Avo.configuration.resource_default_view == :show # via resource show or edit page
23
+ return helpers.resource_path(model: @resource.model, resource: @resource)
28
24
  end
25
+
26
+ resources_path
27
+ end
28
+
29
+ def resources_path
30
+ helpers.resources_path(resource: @resource)
31
+ end
32
+
33
+ def resource_view_path
34
+ helpers.resource_view_path(model: relation_resource.model, resource: relation_resource)
35
+ end
36
+
37
+ def can_see_the_destroy_button?
38
+ return super if is_edit? && Avo.configuration.resource_default_view == :edit
39
+
40
+ false
29
41
  end
30
42
 
31
43
  # The save button is dependent on the edit? policy method.
@@ -65,4 +77,9 @@ class Avo::Views::ResourceEditComponent < Avo::ResourceComponent
65
77
  )
66
78
  end
67
79
  end
80
+
81
+ # Render :show view for read only trix fields
82
+ def view_for(field)
83
+ (field.is_a? Avo::Fields::TrixField) && field.is_readonly? ? :show : view
84
+ end
68
85
  end
@@ -45,14 +45,6 @@ class Avo::Views::ResourceShowComponent < Avo::ResourceComponent
45
45
  helpers.edit_resource_path(model: @resource.model, resource: @resource, **args)
46
46
  end
47
47
 
48
- def destroy_path
49
- if params[:via_resource_class].present?
50
- helpers.resource_path(model: @resource.model, resource: @resource, referrer: back_path)
51
- else
52
- helpers.resource_path(model: @resource.model, resource: @resource)
53
- end
54
- end
55
-
56
48
  private
57
49
 
58
50
  # In development and test environments we shoudl show the invalid field errors
@@ -4,9 +4,15 @@ module Avo
4
4
  class ActionsController < ApplicationController
5
5
  before_action :set_resource_name
6
6
  before_action :set_resource
7
+ before_action :set_model, only: :show, if: ->(request) do
8
+ # Try to se the model only if the user is on the record page.
9
+ # set_model will fail if it's tried to be used from the Index page.
10
+ request.params[:id].present?
11
+ end
7
12
  before_action :set_action, only: [:show, :handle]
8
13
 
9
14
  def show
15
+ @resource.hydrate(model: @model, view: :show, user: _current_user, params: params)
10
16
  @model = ActionModel.new @action.get_attributes_for_action
11
17
  end
12
18
 
@@ -44,11 +50,7 @@ module Avo
44
50
  def set_action
45
51
  action_class = params[:action_id].gsub("avo_actions_", "").camelize.safe_constantize
46
52
 
47
- if params[:id].present?
48
- model = @resource.class.find_scope.find params[:id]
49
- end
50
-
51
- @action = action_class.new(model: model, resource: resource, user: _current_user, view: :edit)
53
+ @action = action_class.new(model: @model, resource: @resource, user: _current_user, view: :edit)
52
54
  end
53
55
 
54
56
  def respond(response)
@@ -16,6 +16,7 @@ module Avo
16
16
  before_action :set_default_locale, if: -> { params[:set_locale].present? }
17
17
  before_action :init_app
18
18
  before_action :check_avo_license
19
+ before_action :set_resource_name
19
20
  before_action :set_authorization
20
21
  before_action :_authenticate!
21
22
  before_action :set_container_classes
@@ -26,7 +27,7 @@ module Avo
26
27
  rescue_from Pundit::NotAuthorizedError, with: :render_unauthorized
27
28
  rescue_from ActiveRecord::RecordInvalid, with: :exception_logger
28
29
 
29
- helper_method :_current_user, :resources_path, :resource_path, :new_resource_path, :edit_resource_path, :resource_attach_path, :resource_detach_path, :related_resources_path, :turbo_frame_request?
30
+ helper_method :_current_user, :resources_path, :resource_path, :new_resource_path, :edit_resource_path, :resource_attach_path, :resource_detach_path, :related_resources_path, :turbo_frame_request?, :resource_view_path
30
31
  add_flash_types :info, :warning, :success, :error
31
32
 
32
33
  def init_app
@@ -126,7 +127,19 @@ module Avo
126
127
  end
127
128
 
128
129
  def set_model
129
- @model = eager_load_files(@resource, @resource.class.find_scope).find params[:id]
130
+ @model = model_find_scope.find record_id
131
+ end
132
+
133
+ def record_id
134
+ params.permit(:id).dig(:id)
135
+ end
136
+
137
+ def model_find_scope
138
+ eager_load_files(@resource, model_scope)
139
+ end
140
+
141
+ def model_scope
142
+ @resource.class.find_scope
130
143
  end
131
144
 
132
145
  def set_related_model
@@ -257,7 +270,13 @@ module Avo
257
270
  end
258
271
 
259
272
  def set_authorization
260
- @authorization = Services::AuthorizationService.new _current_user
273
+ # We need to set @resource_name for the #resource method to work properly
274
+ set_resource_name
275
+ @authorization = if resource
276
+ resource.authorization(user: _current_user)
277
+ else
278
+ Services::AuthorizationService.new _current_user
279
+ end
261
280
  end
262
281
 
263
282
  def set_container_classes
@@ -65,7 +65,7 @@ module Avo
65
65
 
66
66
  respond_to do |format|
67
67
  if @model.save
68
- format.html { redirect_back fallback_location: resource_path(model: @model, resource: @resource), notice: t("avo.attachment_class_attached", attachment_class: @related_resource.name) }
68
+ format.html { redirect_back fallback_location: resource_view_response_path, notice: t("avo.attachment_class_attached", attachment_class: @related_resource.name) }
69
69
  else
70
70
  format.html { render :new }
71
71
  end
@@ -80,7 +80,7 @@ module Avo
80
80
  end
81
81
 
82
82
  respond_to do |format|
83
- format.html { redirect_to params[:referrer] || resource_path(model: @model, resource: @resource), notice: t("avo.attachment_class_detached", attachment_class: @attachment_class) }
83
+ format.html { redirect_to params[:referrer] || resource_view_response_path, notice: t("avo.attachment_class_detached", attachment_class: @attachment_class) }
84
84
  end
85
85
  end
86
86
 
@@ -84,7 +84,7 @@ module Avo
84
84
 
85
85
  # If we're accessing this resource via another resource add the parent to the breadcrumbs.
86
86
  if params[:via_resource_class].present? && params[:via_resource_id].present?
87
- via_resource = Avo::App.get_resource_by_model_name params[:via_resource_class]
87
+ via_resource = Avo::App.get_resource_by_model_name(params[:via_resource_class]).dup
88
88
  via_model = via_resource.class.find_scope.find params[:via_resource_id]
89
89
  via_resource.hydrate model: via_model
90
90
 
@@ -106,8 +106,8 @@ module Avo
106
106
 
107
107
  @page_title = @resource.default_panel_name.to_s
108
108
 
109
- if params[:via_relation_class].present? && params[:via_resource_id].present?
110
- via_resource = Avo::App.get_resource_by_model_name params[:via_relation_class]
109
+ if is_associated_record?
110
+ via_resource = Avo::App.get_resource_by_model_name(params[:via_relation_class]).dup
111
111
  via_model = via_resource.class.find_scope.find params[:via_resource_id]
112
112
  via_resource.hydrate model: via_model
113
113
 
@@ -139,7 +139,7 @@ module Avo
139
139
  # For when working with has_one, has_one_through, has_many_through, has_and_belongs_to_many, polymorphic
140
140
  if @reflection.is_a? ActiveRecord::Reflection::ThroughReflection
141
141
  # find the record
142
- via_resource = ::Avo::App.get_resource_by_model_name params[:via_relation_class]
142
+ via_resource = ::Avo::App.get_resource_by_model_name(params[:via_relation_class]).dup
143
143
  @related_record = via_resource.model_class.find params[:via_resource_id]
144
144
 
145
145
  @model.send(params[:via_relation]) << @related_record
@@ -370,7 +370,7 @@ module Avo
370
370
  last_crumb_args = {}
371
371
  # If we're accessing this resource via another resource add the parent to the breadcrumbs.
372
372
  if params[:via_resource_class].present? && params[:via_resource_id].present?
373
- via_resource = Avo::App.get_resource_by_model_name params[:via_resource_class]
373
+ via_resource = Avo::App.get_resource_by_model_name(params[:via_resource_class]).dup
374
374
  via_model = via_resource.class.find_scope.find params[:via_resource_id]
375
375
  via_resource.hydrate model: via_model
376
376
 
@@ -412,13 +412,17 @@ module Avo
412
412
 
413
413
  def after_create_path
414
414
  # If this is an associated record return to the association show page
415
- if params[:via_relation_class].present? && params[:via_resource_id].present?
416
- parent_resource = ::Avo::App.get_resource_by_model_name params[:via_relation_class]
415
+ if is_associated_record?
416
+ parent_resource = ::Avo::App.get_resource_by_model_name(params[:via_relation_class]).dup
417
417
 
418
- return resource_path(model: params[:via_relation_class], resource: parent_resource, resource_id: params[:via_resource_id])
418
+ return resource_view_path(
419
+ model: @model.send(params[:via_relation]),
420
+ resource: parent_resource,
421
+ resource_id: params[:via_resource_id]
422
+ )
419
423
  end
420
424
 
421
- redirect_path_from_resource_option(:after_create_path) || resource_path(model: @model, resource: @resource)
425
+ redirect_path_from_resource_option(:after_create_path) || resource_view_response_path
422
426
  end
423
427
 
424
428
  def update_success_action
@@ -445,7 +449,12 @@ module Avo
445
449
  def after_update_path
446
450
  return params[:referrer] if params[:referrer].present?
447
451
 
448
- redirect_path_from_resource_option(:after_update_path) || resource_path(model: @model, resource: @resource)
452
+ redirect_path_from_resource_option(:after_update_path) || resource_view_response_path
453
+ end
454
+
455
+ # Needs a different name, otwherwise, in some places, this can be called instead helpers.resource_view_path
456
+ def resource_view_response_path
457
+ helpers.resource_view_path(model: @model, resource: @resource)
449
458
  end
450
459
 
451
460
  def destroy_success_action
@@ -477,11 +486,15 @@ module Avo
477
486
 
478
487
  if @resource.class.send(action) == :index
479
488
  resources_path(resource: @resource)
480
- elsif @resource.class.send(action) == :edit
489
+ elsif @resource.class.send(action) == :edit || Avo.configuration.resource_default_view == :edit
481
490
  edit_resource_path(resource: @resource, model: @resource.model)
482
491
  else
483
492
  resource_path(model: @model, resource: @resource)
484
493
  end
485
494
  end
495
+
496
+ def is_associated_record?
497
+ params[:via_relation_class].present? && params[:via_resource_id].present?
498
+ end
486
499
  end
487
500
  end
@@ -17,18 +17,18 @@ module Avo
17
17
  end
18
18
 
19
19
  def empty_state(**args)
20
- render Avo::EmptyStateComponent.new **args
20
+ render Avo::EmptyStateComponent.new(**args)
21
21
  end
22
22
 
23
23
  def a_button(**args, &block)
24
24
  render Avo::ButtonComponent.new(is_link: false, **args) do
25
- capture(&block) if block_given?
25
+ capture(&block) if block
26
26
  end
27
27
  end
28
28
 
29
29
  def a_link(path = nil, **args, &block)
30
30
  render Avo::ButtonComponent.new(path, is_link: true, **args) do
31
- capture(&block) if block_given?
31
+ capture(&block) if block
32
32
  end
33
33
  end
34
34
 
@@ -114,5 +114,33 @@ module Avo
114
114
 
115
115
  output
116
116
  end
117
+
118
+ def avo_field(type = nil, id = nil, as: nil, view: :show, form: nil, component_options: {}, **args, &block)
119
+ if as.present?
120
+ id = type
121
+ type = as
122
+ end
123
+ field_klass = "Avo::Fields::#{type.to_s.camelize}Field".safe_constantize
124
+ field = field_klass.new id, form: form, view: view, **args, &block
125
+
126
+ # Add the form record to the field so all fields have access to it.
127
+ field.hydrate(model: form.object)
128
+
129
+ render field.component_for_view(view).new field: field, form: form, **component_options
130
+ end
131
+
132
+ def avo_show_field(id, type = nil, view: :show, **args, &block)
133
+ avo_field(id, type, **args, view: view, &block)
134
+ end
135
+
136
+ def avo_edit_field(id, type = nil, view: :edit, **args, &block)
137
+ avo_field(id, type, **args, view: view, &block)
138
+ end
139
+
140
+ def field_container(**args, &block)
141
+ classes = args[:class] || ""
142
+ classes << "flex flex-col divide-y"
143
+ content_tag :div, **args, class: classes, &block
144
+ end
117
145
  end
118
146
  end
@@ -20,17 +20,13 @@ module Avo
20
20
  end
21
21
  end
22
22
 
23
- def show_field_wrapper(**args, &block)
24
- render Show::FieldWrapperComponent.new(**args) do
25
- capture(&block)
26
- end
27
- end
28
-
29
- def edit_field_wrapper(**args, &block)
30
- render Edit::FieldWrapperComponent.new(**args) do
23
+ def field_wrapper(**args, &block)
24
+ render Avo::FieldWrapperComponent.new(**args) do
31
25
  capture(&block)
32
26
  end
33
27
  end
28
+ alias :edit_field_wrapper :field_wrapper
29
+ alias :show_field_wrapper :field_wrapper
34
30
 
35
31
  def filter_wrapper(name: nil, index: nil, **args, &block)
36
32
  render layout: "layouts/avo/filter_wrapper", locals: {
@@ -76,5 +76,13 @@ module Avo
76
76
 
77
77
  avo.resources_associations_index_path(parent_model.model_name.route_key, record.id, **existing_params, **args)
78
78
  end
79
+
80
+ def resource_view_path(**args)
81
+ if Avo.configuration.resource_default_view == :edit
82
+ edit_resource_path(**args)
83
+ else
84
+ resource_path(**args)
85
+ end
86
+ end
79
87
  end
80
88
  end
@@ -1,5 +1,5 @@
1
- import { Controller } from '@hotwired/stimulus'
2
1
  import { castBoolean } from '../helpers/cast_boolean'
2
+ import { Controller } from '@hotwired/stimulus'
3
3
 
4
4
  export default class extends Controller {
5
5
  static targets = ['controllerDiv', 'resourceIds', 'form', 'selectedAllQuery']
@@ -7,6 +7,8 @@ export default class extends Controller {
7
7
  connect() {
8
8
  this.resourceIdsTarget.value = this.resourceIds
9
9
 
10
+ console.log('something')
11
+
10
12
  // This value is picked up from the DOM so we check true/false as strings
11
13
  if (this.selectionOptions.itemSelectAllSelectedAllValue === 'true') {
12
14
  this.selectedAllQueryTarget.value = this.selectionOptions.itemSelectAllSelectedAllQueryValue
@@ -21,6 +21,10 @@ export default class extends Controller {
21
21
  disableMobile: Boolean,
22
22
  }
23
23
 
24
+ flatpickrInstance;
25
+
26
+ cachedInitialValue;
27
+
24
28
  get browserZone() {
25
29
  const time = DateTime.local()
26
30
 
@@ -59,6 +63,10 @@ export default class extends Controller {
59
63
  }
60
64
 
61
65
  connect() {
66
+ // Cache the initial value so we can fill it back on disconnection.
67
+ // We do that so the JS parser will continue to work when the user hits the back button to return on this page.
68
+ this.cacheInitialValue()
69
+
62
70
  if (this.isOnShow || this.isOnIndex) {
63
71
  this.initShow()
64
72
  } else if (this.isOnEdit) {
@@ -66,6 +74,18 @@ export default class extends Controller {
66
74
  }
67
75
  }
68
76
 
77
+ disconnect() {
78
+ if (this.isOnShow || this.isOnIndex) {
79
+ this.context.element.innerText = this.cachedInitialValue
80
+ } else if (this.isOnEdit) {
81
+ if (this.flatpickrInstance) this.flatpickrInstance.destroy()
82
+ }
83
+ }
84
+
85
+ cacheInitialValue() {
86
+ this.cachedInitialValue = this.initialValue
87
+ }
88
+
69
89
  // Turns the value in the controller wrapper into the timezone of the browser
70
90
  initShow() {
71
91
  let value = this.parsedValue
@@ -115,7 +135,7 @@ export default class extends Controller {
115
135
  options.defaultDate = universalTimestamp(this.initialValue)
116
136
  }
117
137
 
118
- flatpickr(this.fakeInputTarget, options)
138
+ this.flatpickrInstance = flatpickr(this.fakeInputTarget, options)
119
139
 
120
140
  if (this.enableTimeValue) {
121
141
  this.updateRealInput(this.parsedValue.setZone(this.displayTimezone).toISO())