avo 2.15.3 → 2.16.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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/app/components/avo/fields/belongs_to_field/index_component.html.erb +2 -1
  4. data/app/components/avo/fields/belongs_to_field/show_component.html.erb +1 -1
  5. data/app/components/avo/fields/belongs_to_field/show_component.rb +8 -0
  6. data/app/components/avo/fields/external_image_field/index_component.html.erb +1 -1
  7. data/app/components/avo/fields/file_field/index_component.html.erb +2 -2
  8. data/app/components/avo/fields/gravatar_field/index_component.html.erb +1 -1
  9. data/app/components/avo/fields/has_one_field/show_component.html.erb +14 -1
  10. data/app/components/avo/fields/has_one_field/show_component.rb +21 -0
  11. data/app/components/avo/fields/id_field/index_component.html.erb +1 -1
  12. data/app/components/avo/fields/index_component.rb +9 -4
  13. data/app/components/avo/fields/text_field/index_component.html.erb +1 -1
  14. data/app/components/avo/fields/trix_field/edit_component.html.erb +13 -13
  15. data/app/components/avo/index/grid_item_component.html.erb +6 -6
  16. data/app/components/avo/index/grid_item_component.rb +15 -0
  17. data/app/components/avo/index/resource_controls_component.rb +2 -0
  18. data/app/components/avo/index/resource_grid_component.rb +1 -1
  19. data/app/components/avo/resource_component.rb +5 -1
  20. data/app/components/avo/sidebar/item_switcher_component.html.erb +3 -3
  21. data/app/components/avo/sidebar/link_component.html.erb +2 -2
  22. data/app/components/avo/sidebar/link_component.rb +3 -1
  23. data/app/components/avo/views/resource_edit_component.html.erb +19 -2
  24. data/app/components/avo/views/resource_edit_component.rb +26 -9
  25. data/app/components/avo/views/resource_show_component.rb +0 -8
  26. data/app/controllers/avo/actions_controller.rb +7 -5
  27. data/app/controllers/avo/application_controller.rb +14 -2
  28. data/app/controllers/avo/associations_controller.rb +2 -2
  29. data/app/controllers/avo/base_controller.rb +19 -6
  30. data/app/helpers/avo/url_helpers.rb +8 -0
  31. data/app/views/avo/actions/show.html.erb +5 -1
  32. data/lib/avo/base_action.rb +25 -6
  33. data/lib/avo/base_resource.rb +1 -1
  34. data/lib/avo/base_resource_tool.rb +1 -1
  35. data/lib/avo/configuration.rb +2 -0
  36. data/lib/avo/fields/base_field.rb +1 -1
  37. data/lib/avo/fields/belongs_to_field.rb +1 -1
  38. data/lib/avo/fields/has_and_belongs_to_many_field.rb +1 -1
  39. data/lib/avo/fields/has_base_field.rb +5 -1
  40. data/lib/avo/fields/has_many_field.rb +1 -1
  41. data/lib/avo/menu/base_item.rb +1 -0
  42. data/lib/avo/menu/builder.rb +4 -2
  43. data/lib/avo/version.rb +1 -1
  44. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68cfd9efb2f52f774b347c404afe6b68e8e0e21102500e234184a11a4b8dd104
4
- data.tar.gz: b8f9fc9d7a24fc30a453f0643aeae48c2e4bb9ecce27b59679e246bd55054fa3
3
+ metadata.gz: 8ca4190d675e166dedf5f47c9c68f3b7fa57e29c9e7510262a4033f1c0cbb00d
4
+ data.tar.gz: 6f4f3c3f1a39fbb7b9d3566ff679cd3992b684576b1e4c1451b7d4fdd39c173f
5
5
  SHA512:
6
- metadata.gz: c80aedbf84f25b6b53e99d51c6ba3e603eaa619e9963ae988b4f76469f3f14c92e9e5f8045234bb7746cbed3008b9656d598effc0d49c742665acbbd4d35390a
7
- data.tar.gz: c116b5296b79976867bd3f3342d334d355e7a5acb012b5bbb7e2965b65d98794f08b6f747d07e1598b144ff78c5c1fcfcf0e978ab681166ea67ca8a86abf9b4c
6
+ metadata.gz: c2dfc8a393554111f16a4c95ed94ef1180e9b448327d182071ebef301773e37436db614411121744107bae9252e40a5432d828ebb2661abef2148883e0675c08
7
+ data.tar.gz: 3914b51410ba770dd7f8a396bddfb6bb1be58d694aebb159f23b3de1e3c841186fa85d62bf0d982ef475a5a07c80bd9f24a4cf41d0b22a874e4df073dc11da25
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avo (2.15.3)
4
+ avo (2.16.0)
5
5
  active_link_to
6
6
  addressable
7
7
  breadcrumbs_on_rails
@@ -1,3 +1,4 @@
1
1
  <%= index_field_wrapper field: @field, resource: @resource do %>
2
- <%= link_to @field.label, helpers.resource_path(model: @field.value, resource: @field.target_resource) %>
2
+ <%= link_to @field.label, helpers.resource_view_path(model: @field.value, resource: @field.target_resource)
3
+ %>
3
4
  <% end %>
@@ -1,3 +1,3 @@
1
1
  <%= show_field_wrapper field: @field, resource: @resource, index: @index do %>
2
- <%= link_to @field.label, helpers.resource_path(model: @field.value, resource: @field.target_resource, via_resource_class: @resource.model_class, via_resource_id: @resource.model.id) %>
2
+ <%= link_to @field.label, resource_view_path %>
3
3
  <% end %>
@@ -1,4 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Avo::Fields::BelongsToField::ShowComponent < Avo::Fields::ShowComponent
4
+ def resource_view_path
5
+ helpers.resource_view_path(
6
+ model: @field.value,
7
+ resource: @field.target_resource,
8
+ via_resource_class: @resource.model_class,
9
+ via_resource_id: @resource.model.id
10
+ )
11
+ end
4
12
  end
@@ -4,7 +4,7 @@
4
4
  image_tag(@field.value,
5
5
  height: @field.height,
6
6
  style: "border-radius: #{@field.radius}px; max-height: #{@field.height}#{@field.height.to_s&.ends_with?('px') ? '' : 'px'};"),
7
- resource_path
7
+ resource_view_path
8
8
  %>
9
9
  <% end %>
10
10
  <% end %>
@@ -1,9 +1,9 @@
1
1
  <%= index_field_wrapper field: @field, resource: @resource, flush: flush? do %>
2
2
  <% if @field.value.present? %>
3
3
  <% if @field.value.attached? && @field.value.representable? && @field.is_image %>
4
- <%= link_to_if @field.link_to_resource, image_tag(helpers.main_app.url_for(@field.value), class: 'h-10'), resource_path, class: 'block' %>
4
+ <%= link_to_if @field.link_to_resource, image_tag(helpers.main_app.url_for(@field.value), class: 'h-10'), resource_view_path, class: 'block' %>
5
5
  <% elsif @field.value.attached? && @field.is_audio %>
6
- <%= link_to_if @field.link_to_resource, audio_tag(helpers.main_app.url_for(@field.value), controls: true, preload: false, class: 'max-h-full h-10'), resource_path, class: 'block h-8' %>
6
+ <%= link_to_if @field.link_to_resource, audio_tag(helpers.main_app.url_for(@field.value), controls: true, preload: false, class: 'max-h-full h-10'), resource_view_path, class: 'block h-8' %>
7
7
  <% else %>
8
8
  <%= @field.value.filename %>
9
9
  <% end %>
@@ -5,7 +5,7 @@
5
5
  size: @field.size,
6
6
  rounded: @field.rounded,
7
7
  link_to_resource: @field.link_to_resource,
8
- link: resource_path,
8
+ link: resource_view_path,
9
9
  title: t('avo.view_item', item: @resource.name).humanize
10
10
  )
11
11
  %>
@@ -6,10 +6,23 @@
6
6
  <%= render Avo::PanelComponent.new(name: @field.name) do |c| %>
7
7
  <% c.tools do %>
8
8
  <% if !@field.is_readonly? && can_attach? %>
9
- <%= a_link attach_path, icon: 'heroicons/outline/link', color: :primary, 'data-turbo-frame': 'attach_modal' do %>
9
+ <%= a_link attach_path,
10
+ icon: 'heroicons/outline/link',
11
+ color: :primary,
12
+ 'data-turbo-frame': 'attach_modal' do %>
10
13
  <%= t('avo.attach_item', item: @field.name.downcase) %>
11
14
  <% end %>
12
15
  <% end %>
16
+ <% if !@field.is_readonly? && can_see_the_create_button? %>
17
+ <%= a_link create_path,
18
+ icon: 'heroicons/outline/plus',
19
+ 'data-target': 'create',
20
+ 'data-turbo-frame': '_top',
21
+ style: :primary,
22
+ color: :primary do %>
23
+ <%= t('avo.create_new_item', item: @field.name.downcase ) %>
24
+ <% end %>
25
+ <% end %>
13
26
  <% end %>
14
27
 
15
28
  <% c.body do %>
@@ -23,4 +23,25 @@ class Avo::Fields::HasOneField::ShowComponent < Avo::Fields::ShowComponent
23
23
  def attach_path
24
24
  helpers.avo.resources_associations_new_path(@resource.singular_model_key, @resource.model.id, @field.id)
25
25
  end
26
+
27
+ def can_see_the_create_button?
28
+ create = "create_#{@field.id.to_s}?"
29
+
30
+ authorization_service = @resource.authorization
31
+
32
+ # By default return true if the create method is not defined for this field
33
+ return true unless authorization_service.has_method?(create, raise_exception: false)
34
+
35
+ authorization_service.authorize_action(create, raise_exception: false)
36
+ end
37
+
38
+ def create_path
39
+ args = {
40
+ via_relation: @resource.singular_model_key,
41
+ via_relation_class: @resource.name,
42
+ via_resource_id: @resource.model.id
43
+ }
44
+
45
+ helpers.new_resource_path(resource: @field.target_resource, **args)
46
+ end
26
47
  end
@@ -1,3 +1,3 @@
1
1
  <%= index_field_wrapper field: @field, resource: @resource, class: 'whitespace-no-wrap w-[1%]' do %>
2
- <% link_to_if (@field.link_to_resource or Avo.configuration.id_links_to_resource), @field.value, resource_path, title: t('avo.view_item', item: @resource.name).humanize %>
2
+ <% link_to_if (@field.link_to_resource or Avo.configuration.id_links_to_resource), @field.value, resource_view_path, title: t('avo.view_item', item: @resource.name).humanize %>
3
3
  <% end %>
@@ -13,11 +13,16 @@ class Avo::Fields::IndexComponent < ViewComponent::Base
13
13
  @view = :index
14
14
  end
15
15
 
16
- def resource_path
16
+ def resource_view_path
17
+ args = {}
18
+
17
19
  if @parent_model.present?
18
- helpers.resource_path(model: @resource.model, resource: @resource, via_resource_class: @parent_model.class, via_resource_id: @parent_model.id)
19
- else
20
- helpers.resource_path(model: @resource.model, resource: @resource)
20
+ args = {
21
+ via_resource_class: @parent_model.class,
22
+ via_resource_id: @parent_model.id
23
+ }
21
24
  end
25
+
26
+ helpers.resource_view_path(model: @resource.model, resource: @resource, **args)
22
27
  end
23
28
  end
@@ -4,6 +4,6 @@
4
4
  <% elsif @field.protocol.present? %>
5
5
  <%= link_to @field.value, "#{@field.protocol}:#{@field.value}" %>
6
6
  <% else %>
7
- <%= link_to_if @field.link_to_resource, @field.value, resource_path %>
7
+ <%= link_to_if @field.link_to_resource, @field.value, resource_view_path %>
8
8
  <% end %>
9
9
  <% end %>
@@ -1,16 +1,16 @@
1
1
  <%= edit_field_wrapper field: @field, index: @index, form: @form, resource: @resource, displayed_in_modal: @displayed_in_modal, full_width: true do %>
2
- <div
3
- data-controller="trix-field"
4
- data-trix-field-target="controller"
5
- data-resource-name="<%= @resource.model_key %>"
6
- data-resource-id="<%= @resource.model.id %>"
7
- data-attachments-disabled="<%= @field.attachments_disabled %>"
8
- data-attachment-key="<%= @field.attachment_key %>"
9
- data-hide-attachment-filename="<%= @field.hide_attachment_filename %>"
10
- data-hide-attachment-filesize="<%= @field.hide_attachment_filesize %>"
11
- data-hide-attachment-url="<%= @field.hide_attachment_url %>"
12
- class="relative block overflow-x-auto max-w-full"
13
- >
2
+ <%= content_tag :div, class: "relative block overflow-x-auto max-w-full",
3
+ data: {
4
+ controller: "trix-field",
5
+ trix_field_target: "controller",
6
+ resource_name: @resource.model_key,
7
+ resource_id: @resource.model.methods.include?(:id) ? @resource.model&.id : nil,
8
+ attachments_disabled: @field.attachments_disabled,
9
+ attachment_key: @field.attachment_key,
10
+ hide_attachment_filename: @field.hide_attachment_filename,
11
+ hide_attachment_filesize: @field.hide_attachment_filesize,
12
+ hide_attachment_url: @field.hide_attachment_url,
13
+ } do %>
14
14
  <%= content_tag 'trix-editor',
15
15
  class: 'trix-content',
16
16
  data: {
@@ -29,5 +29,5 @@
29
29
  placeholder: @field.placeholder,
30
30
  style: @field.get_html(:style, view: view, element: :input)
31
31
  %>
32
- </div>
32
+ <% end %>
33
33
  <% end %>
@@ -7,23 +7,23 @@
7
7
  <%== item_selector_input floating: true, size: :lg %>
8
8
  <% end %>
9
9
  <% if cover.blank? %>
10
- <%= link_to cover.link_to_resource do %>
10
+ <%= link_to resource_view_path do %>
11
11
  <%= render Avo::Index::GridCoverEmptyStateComponent.new %>
12
12
  <% end %>
13
13
  <% elsif cover.respond_to?(:to_image) && cover.to_image.present? %>
14
- <%= link_to_if cover.link_to_resource, image_tag(cover.to_image, class: 'absolute h-full w-full object-cover'), helpers.resource_path(model: @resource.model, resource: @resource), class: 'absolute h-full w-full object-cover', title: title.value %>
14
+ <%= link_to_if cover.link_to_resource, image_tag(cover.to_image, class: 'absolute h-full w-full object-cover'), resource_view_path, class: 'absolute h-full w-full object-cover', title: title.value %>
15
15
  <% elsif cover.type == 'file' %>
16
16
  <% if cover.value.attached? && cover.value.representable? %>
17
- <%= link_to_if cover.link_to_resource, image_tag(helpers.main_app.url_for(cover.value.variant(resize_to_limit: [480, 480])), class: 'absolute h-full w-full object-cover'), helpers.resource_path(model: @resource.model, resource: @resource), class: 'absolute h-full w-full object-cover', title: title.value %>
17
+ <%= link_to_if cover.link_to_resource, image_tag(helpers.main_app.url_for(cover.value.variant(resize_to_limit: [480, 480])), class: 'absolute h-full w-full object-cover'), resource_view_path, class: 'absolute h-full w-full object-cover', title: title.value %>
18
18
  <% else %>
19
- <%= link_to @resource.record_path do %>
19
+ <%= link_to resource_view_path do %>
20
20
  <div class="absolute bg-gray-100 w-full h-full">
21
21
  <%= helpers.svg 'avocado', class: 'relative transform -translate-x-1/2 -translate-y-1/2 h-20 text-gray-400 inset-auto top-1/2 left-1/2' %>
22
22
  </div>
23
23
  <% end %>
24
24
  <% end %>
25
25
  <% elsif cover.value.present? %>
26
- <%= link_to_if cover.link_to_resource, image_tag(cover.value, class: 'absolute h-full w-full object-cover'), helpers.resource_path(model: @resource.model, resource: @resource), class: 'absolute h-full w-full object-cover', title: title.value %>
26
+ <%= link_to_if cover.link_to_resource, image_tag(cover.value, class: 'absolute h-full w-full object-cover'), resource_view_path, class: 'absolute h-full w-full object-cover', title: title.value %>
27
27
  <% else %>
28
28
  <%= render Avo::Index::GridCoverEmptyStateComponent.new %>
29
29
  <% end %>
@@ -31,7 +31,7 @@
31
31
  <div class="grid grid-cols-1 place-content-between p-4 h-full">
32
32
  <div class="mb-4 h-full flex flex-col space-between">
33
33
  <div class="grid font-semibold leading-tight text-lg mb-2">
34
- <%= link_to_if title.link_to_resource, title.value, helpers.resource_path(model: @resource.model, resource: @resource) if title.present? %>
34
+ <%= link_to_if title.link_to_resource, title.value, resource_view_path if title.present? %>
35
35
  </div>
36
36
  <div class="text-sm break-words text-gray-500">
37
37
  <%= body.value if body.present? %>
@@ -3,6 +3,8 @@
3
3
  class Avo::Index::GridItemComponent < ViewComponent::Base
4
4
  include Avo::ResourcesHelper
5
5
 
6
+ attr_reader :parent_resource
7
+
6
8
  def initialize(resource: nil, reflection: nil, parent_model: nil, parent_resource: nil)
7
9
  @resource = resource
8
10
  @reflection = reflection
@@ -24,4 +26,17 @@ class Avo::Index::GridItemComponent < ViewComponent::Base
24
26
  def body
25
27
  @grid_fields.body_field
26
28
  end
29
+
30
+ def resource_view_path
31
+ args = {}
32
+
33
+ if @parent_model.present?
34
+ args = {
35
+ via_resource_class: parent_resource.model_class,
36
+ via_resource_id: @parent_model.id
37
+ }
38
+ end
39
+
40
+ helpers.resource_view_path(model: @resource.model, resource: @resource, **args)
41
+ end
27
42
  end
@@ -23,6 +23,8 @@ class Avo::Index::ResourceControlsComponent < Avo::ResourceComponent
23
23
  end
24
24
 
25
25
  def can_view?
26
+ return false if Avo.configuration.resource_default_view == :edit
27
+
26
28
  return authorize_association_for(:show) if @reflection.present?
27
29
 
28
30
  # Even if there's a @reflection object present, for show we're going to fallback to the original policy.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Avo::Index::ResourceGridComponent < ViewComponent::Base
4
- def initialize(resources: nil, resource: nil, reflection: nil, parent_model: nil, parent_resource: @parent_resource)
4
+ def initialize(resources: nil, resource: nil, reflection: nil, parent_model: nil, parent_resource: nil)
5
5
  @resources = resources
6
6
  @resource = resource
7
7
  @reflection = reflection
@@ -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?
@@ -22,6 +22,23 @@
22
22
  icon: 'arrow-left' do %>
23
23
  <%= t('avo.cancel').capitalize %>
24
24
  <% end %>
25
+ <% if can_see_the_destroy_button? %>
26
+ <%= a_link destroy_path,
27
+ method: :delete,
28
+ local: true,
29
+ style: :text,
30
+ loading: true,
31
+ confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
32
+ color: :red,
33
+ icon: 'trash',
34
+ form_class: 'flex flex-col sm:flex-row sm:inline-flex',
35
+ data: {
36
+ control: :destroy,
37
+ 'resource-id': @resource.model.id,
38
+ } do %>
39
+ <%= t('avo.delete').capitalize %>
40
+ <% end %>
41
+ <% end %>
25
42
  <% if can_see_the_actions_button? %>
26
43
  <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
27
44
  <% end %>
@@ -41,8 +58,8 @@
41
58
  <% c.body do %>
42
59
  <div class="divide-y">
43
60
  <% 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)
61
+ <%= render field.hydrate(resource: @resource, model: @resource.model, user: @resource.user, view: view_for(field))
62
+ .component_for_view(view_for field)
46
63
  .new(field: field, resource: @resource, index: index, form: form)
47
64
  %>
48
65
  <% 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)
@@ -26,7 +26,7 @@ module Avo
26
26
  rescue_from Pundit::NotAuthorizedError, with: :render_unauthorized
27
27
  rescue_from ActiveRecord::RecordInvalid, with: :exception_logger
28
28
 
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?
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?, :resource_view_path
30
30
  add_flash_types :info, :warning, :success, :error
31
31
 
32
32
  def init_app
@@ -126,7 +126,19 @@ module Avo
126
126
  end
127
127
 
128
128
  def set_model
129
- @model = eager_load_files(@resource, @resource.class.find_scope).find params[:id]
129
+ @model = model_find_scope.find record_id
130
+ end
131
+
132
+ def record_id
133
+ params.permit(:id).dig(:id)
134
+ end
135
+
136
+ def model_find_scope
137
+ eager_load_files(@resource, model_scope)
138
+ end
139
+
140
+ def model_scope
141
+ @resource.class.find_scope
130
142
  end
131
143
 
132
144
  def set_related_model
@@ -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
 
@@ -106,7 +106,7 @@ 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?
109
+ if is_associated_record?
110
110
  via_resource = Avo::App.get_resource_by_model_name params[:via_relation_class]
111
111
  via_model = via_resource.class.find_scope.find params[:via_resource_id]
112
112
  via_resource.hydrate model: via_model
@@ -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?
415
+ if is_associated_record?
416
416
  parent_resource = ::Avo::App.get_resource_by_model_name params[:via_relation_class]
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
@@ -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
@@ -25,7 +25,11 @@
25
25
  <% if @action.get_fields.present? %>
26
26
  <div class="mt-4">
27
27
  <% @action.get_fields.each_with_index do |field, index| %>
28
- <%= render field.component_for_view(:edit).new field: field, resource: @resource, index: index, form: form, displayed_in_modal: true %>
28
+ <%= render field
29
+ .hydrate(resource: @resource, model: @resource.model, user: @resource.user, view: @view)
30
+ .component_for_view(:edit)
31
+ .new(field: field, resource: @resource, index: index, form: form, displayed_in_modal: true)
32
+ %>
29
33
  <% end %>
30
34
  </div>
31
35
  <% end %>
@@ -73,26 +73,36 @@ module Avo
73
73
  def get_attributes_for_action
74
74
  get_fields.map do |field|
75
75
  [field.id, field.value]
76
- end
77
- .to_h
76
+ end.to_h
78
77
  end
79
78
 
80
79
  def handle_action(**args)
81
80
  models, fields, current_user, resource = args.values_at(:models, :fields, :current_user, :resource)
82
- avo_fields = get_fields.map { |field| [field.id, field] }.to_h
81
+ # 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.
82
+ action_fields = get_field_definitions.map { |field| [field.id, field] }.to_h
83
+
84
+ # For some fields, like belongs_to, the id and database_id differ (user vs user_id).
85
+ # That's why we need to fetch the database_id for when we process the action.
86
+ action_fields_by_database_id = action_fields.map do |id, value|
87
+ [value.database_id.to_sym, value]
88
+ end.to_h
83
89
 
84
90
  if fields.present?
85
91
  processed_fields = fields.to_unsafe_h.map do |name, value|
86
- [name, avo_fields[name.to_sym].resolve_attribute(value)]
92
+ field = action_fields_by_database_id[name.to_sym]
93
+
94
+ next if field.blank?
95
+
96
+ [name, field.resolve_attribute(value)]
87
97
  end
88
98
 
89
- processed_fields = processed_fields.to_h
99
+ processed_fields = processed_fields.reject(&:blank?).to_h
90
100
  else
91
101
  processed_fields = {}
92
102
  end
93
103
 
94
104
  args = {
95
- fields: processed_fields,
105
+ fields: processed_fields.with_indifferent_access,
96
106
  current_user: current_user,
97
107
  resource: resource
98
108
  }
@@ -175,6 +185,15 @@ module Avo
175
185
  self
176
186
  end
177
187
 
188
+ # We're overriding this method to hydrate with the proper resource attribute.
189
+ def hydrate_fields(model: nil, view: nil)
190
+ fields.map do |field|
191
+ field.hydrate(model: @model, view: @view, resource: resource)
192
+ end
193
+
194
+ self
195
+ end
196
+
178
197
  private
179
198
 
180
199
  def add_message(body, type = :info)
@@ -263,7 +263,7 @@ module Avo
263
263
  field.computed
264
264
  end
265
265
  .map do |field|
266
- [field.database_id(model).to_s, field]
266
+ [field.database_id.to_s, field]
267
267
  end
268
268
  .to_h
269
269
 
@@ -13,7 +13,7 @@ module Avo
13
13
 
14
14
  def initialize(**args)
15
15
  # Set the visibility
16
- show_on :show
16
+ show_on Avo.configuration.resource_default_view
17
17
 
18
18
  show_on args[:show_on] if args[:show_on].present?
19
19
  hide_on args[:hide_on] if args[:hide_on].present?
@@ -36,6 +36,7 @@ module Avo
36
36
  attr_accessor :profile_menu
37
37
  attr_accessor :model_resource_mapping
38
38
  attr_accessor :tabs_style
39
+ attr_accessor :resource_default_view
39
40
  attr_writer :branding
40
41
 
41
42
  def initialize
@@ -83,6 +84,7 @@ module Avo
83
84
  @profile_menu = nil
84
85
  @model_resource_mapping = {}
85
86
  @tabs_style = :tabs
87
+ @resource_default_view = :show
86
88
  end
87
89
 
88
90
  def current_user_method(&block)
@@ -191,7 +191,7 @@ module Avo
191
191
  end
192
192
 
193
193
  # Try to see if the field has a different database ID than it's name
194
- def database_id(model)
194
+ def database_id
195
195
  foreign_key
196
196
  rescue
197
197
  id
@@ -210,7 +210,7 @@ module Avo
210
210
  model
211
211
  end
212
212
 
213
- def database_id(model)
213
+ def database_id
214
214
  # If the field is a polymorphic value, return the polymorphic_type as key and pre-fill the _id in fill_field.
215
215
  return "#{polymorphic_as}_type" if polymorphic_as.present?
216
216
 
@@ -5,7 +5,7 @@ module Avo
5
5
  args[:updatable] = false
6
6
 
7
7
  hide_on :all
8
- show_on :show
8
+ show_on Avo.configuration.resource_default_view
9
9
 
10
10
  super(id, **args, &block)
11
11
  end
@@ -30,7 +30,7 @@ module Avo
30
30
  end
31
31
 
32
32
  def resource
33
- Avo::App.get_resource_by_model_name @model.class
33
+ @resource || Avo::App.get_resource_by_model_name(@model.class)
34
34
  end
35
35
 
36
36
  def turbo_frame
@@ -108,6 +108,10 @@ module Avo
108
108
  def frame_id
109
109
  use_resource.present? ? use_resource.route_key.to_sym : @id
110
110
  end
111
+
112
+ def default_view
113
+ Avo.configuration.skip_show_view ? :edit : :show
114
+ end
111
115
  end
112
116
  end
113
117
  end
@@ -5,7 +5,7 @@ module Avo
5
5
  args[:updatable] = false
6
6
 
7
7
  hide_on :all
8
- show_on :show
8
+ show_on Avo.configuration.resource_default_view
9
9
 
10
10
  super(id, **args, &block)
11
11
  end
@@ -9,6 +9,7 @@ class Avo::Menu::BaseItem
9
9
  option :items, default: proc { [] }
10
10
  option :name, default: proc { "" }
11
11
  option :visible, default: proc { true }
12
+ option :data, default: proc { {} }
12
13
 
13
14
  def visible?
14
15
  return visible if visible.in? [true, false]
@@ -22,9 +22,11 @@ class Avo::Menu::Builder
22
22
  end
23
23
 
24
24
  # Adds a link
25
- def link(name, **args)
26
- @menu.items << Avo::Menu::Link.new(name: name, **args)
25
+ def link(name, path = nil, **args)
26
+ path ||= args[:path]
27
+ @menu.items << Avo::Menu::Link.new(name: name, path: path, **args)
27
28
  end
29
+ alias_method :link_to, :link
28
30
 
29
31
  # Validates and adds a resource
30
32
  def resource(name, **args)
data/lib/avo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Avo
2
- VERSION = "2.15.3" unless const_defined?(:VERSION)
2
+ VERSION = "2.16.0" unless const_defined?(:VERSION)
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: avo
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.15.3
4
+ version: 2.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adrian Marin
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-09-15 00:00:00.000000000 Z
12
+ date: 2022-09-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails