avo 3.0.1.beta24 → 3.0.2

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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -5
  3. data/Gemfile.lock +164 -128
  4. data/README.md +19 -27
  5. data/app/components/avo/actions_component.rb +2 -2
  6. data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +122 -104
  7. data/app/components/avo/fields/belongs_to_field/edit_component.rb +11 -0
  8. data/app/components/avo/fields/location_field/edit_component.html.erb +12 -10
  9. data/app/components/avo/index/grid_item_component.html.erb +1 -1
  10. data/app/components/avo/index/resource_table_component.html.erb +2 -2
  11. data/app/components/avo/index/resource_table_component.rb +16 -0
  12. data/app/components/avo/index/table_row_component.html.erb +1 -1
  13. data/app/components/avo/items/panel_component.html.erb +25 -0
  14. data/app/components/avo/items/panel_component.rb +43 -0
  15. data/app/components/avo/items/switcher_component.html.erb +17 -0
  16. data/app/components/avo/items/switcher_component.rb +79 -0
  17. data/app/components/avo/items/visible_items_component.html.erb +10 -0
  18. data/app/components/avo/items/visible_items_component.rb +11 -0
  19. data/app/components/avo/modal_component.html.erb +11 -7
  20. data/app/components/avo/modal_component.rb +21 -0
  21. data/app/components/avo/paginator_component.html.erb +29 -40
  22. data/app/components/avo/paginator_component.rb +18 -0
  23. data/app/components/avo/panel_component.html.erb +2 -2
  24. data/app/components/avo/referrer_params_component.html.erb +1 -0
  25. data/app/components/avo/resource_component.rb +8 -15
  26. data/app/components/avo/resource_sidebar_component.html.erb +11 -18
  27. data/app/components/avo/resource_sidebar_component.rb +4 -2
  28. data/app/components/avo/sidebar_profile_component.html.erb +1 -1
  29. data/app/components/avo/tab_group_component.html.erb +1 -1
  30. data/app/components/avo/views/resource_edit_component.html.erb +15 -32
  31. data/app/components/avo/views/resource_edit_component.rb +18 -6
  32. data/app/components/avo/views/resource_index_component.rb +1 -0
  33. data/app/components/avo/views/resource_show_component.html.erb +14 -33
  34. data/app/components/avo/views/resource_show_component.rb +11 -0
  35. data/app/controllers/avo/actions_controller.rb +6 -4
  36. data/app/controllers/avo/application_controller.rb +2 -33
  37. data/app/controllers/avo/base_controller.rb +25 -16
  38. data/app/helpers/avo/application_helper.rb +4 -0
  39. data/app/javascript/js/controllers/fields/reload_belongs_to_field_controller.js +51 -0
  40. data/app/javascript/js/controllers.js +2 -0
  41. data/app/views/avo/actions/show.html.erb +4 -3
  42. data/app/views/avo/base/_new_via_belongs_to.html.erb +12 -0
  43. data/app/views/avo/base/close_modal_and_reload_field.turbo_stream.erb +8 -0
  44. data/app/views/avo/base/create_fail_action.turbo_stream.erb +13 -0
  45. data/app/views/avo/partials/_flash_alerts.turbo_stream.erb +3 -0
  46. data/config/i18n-tasks.yml +1 -1
  47. data/config/initializers/pagy.rb +2 -0
  48. data/config/master.key +1 -0
  49. data/lib/avo/base_action.rb +44 -38
  50. data/lib/avo/base_resource.rb +7 -8
  51. data/lib/avo/concerns/borrow_items_holder.rb +35 -0
  52. data/lib/avo/concerns/has_items.rb +65 -47
  53. data/lib/avo/concerns/hydration.rb +17 -0
  54. data/lib/avo/concerns/is_resource_item.rb +2 -10
  55. data/lib/avo/concerns/pagination.rb +53 -0
  56. data/lib/avo/concerns/visible_items.rb +7 -30
  57. data/lib/avo/dsl/field_parser.rb +1 -1
  58. data/lib/avo/fields/concerns/is_searchable.rb +3 -1
  59. data/lib/avo/fields/location_field.rb +2 -2
  60. data/lib/avo/filters/base_filter.rb +1 -0
  61. data/lib/avo/html/builder.rb +1 -0
  62. data/lib/avo/licensing/h_q.rb +4 -6
  63. data/lib/avo/licensing/license.rb +4 -0
  64. data/lib/avo/plugin.rb +5 -1
  65. data/lib/avo/resources/items/holder.rb +29 -11
  66. data/lib/avo/resources/items/item_group.rb +4 -9
  67. data/lib/avo/resources/items/main_panel.rb +10 -0
  68. data/lib/avo/resources/items/row.rb +4 -16
  69. data/lib/avo/resources/items/sidebar.rb +9 -10
  70. data/lib/avo/resources/items/tab.rb +3 -9
  71. data/lib/avo/resources/items/tab_group.rb +6 -12
  72. data/lib/avo/version.rb +1 -1
  73. data/lib/generators/avo/templates/locales/avo.ar.yml +7 -6
  74. data/lib/generators/avo/templates/locales/avo.en.yml +2 -0
  75. data/lib/generators/avo/templates/locales/avo.es.yml +127 -0
  76. data/lib/generators/avo/templates/locales/avo.fr.yml +2 -0
  77. data/lib/generators/avo/templates/locales/avo.nb.yml +2 -0
  78. data/lib/generators/avo/templates/locales/avo.nn.yml +2 -0
  79. data/lib/generators/avo/templates/locales/avo.pt-BR.yml +2 -0
  80. data/lib/generators/avo/templates/locales/avo.pt.yml +2 -0
  81. data/lib/generators/avo/templates/locales/avo.ro.yml +2 -0
  82. data/lib/generators/avo/templates/locales/avo.tr.yml +2 -0
  83. data/public/avo-assets/avo.base.css +121 -4
  84. data/public/avo-assets/avo.base.js +86 -86
  85. data/public/avo-assets/avo.base.js.map +3 -3
  86. data/public/avo-assets/avo.css +9744 -0
  87. data/public/avo-assets/avo.js +513 -0
  88. data/public/avo-assets/avo.js.map +7 -0
  89. metadata +23 -8
  90. data/app/components/avo/item_switcher_component.html.erb +0 -27
  91. data/app/components/avo/item_switcher_component.rb +0 -48
  92. data/app/views/avo/actions/keep_modal_open.turbo_stream.erb +0 -5
  93. data/lib/avo/action_model.rb +0 -20
@@ -1,47 +1,36 @@
1
- <%
2
- per_page_options = [*Avo.configuration.per_page_steps, Avo.configuration.per_page.to_i, index_params[:per_page].to_i]
3
-
4
- if parent_record.present?
5
- per_page_options.prepend Avo.configuration.via_per_page
6
- end
7
-
8
- per_page_options = per_page_options.sort.uniq
9
- %>
10
- <% unless @pagy.pages <= 1 && discreet_pagination %>
11
- <div class="flex flex-col sm:flex-row items-center justify-between aborder-t aborder-slate-200 rounded-xl space-y-2 sm:space-y-0">
12
- <div class="flex-2 sm:flex sm:items-center sm:justify-between">
13
- <div>
14
- <div class="text-sm leading-5 text-slate-600 flex items-center">
15
- <div data-controller="per-page">
16
- <div class="flex items-center">
17
- <%= select_tag 'per_page',
18
- options_for_select(per_page_options, index_params[:per_page]),
19
- class: 'appearance-none inline-flex bg-white-100 disabled:bg-white-400 disabled:cursor-not-allowed focus:bg-white text-slate-700 disabled:text-slate-600 rounded-md py-1 px-2 leading-tight border border-slate-300 outline-none focus:border-slate-400 outline w-16 mr-1 text-sm',
20
- data: {
21
- 'turbo-frame': turbo_frame,
22
- 'per-page-target': 'selector',
23
- action: 'change->per-page#reload'
24
- }
25
- %> <%= t('avo.per_page').downcase %>
26
- </div>
27
- <% per_page_options.each do |option| %>
28
- <%= link_to "Change to #{option} items per page", change_items_per_page_url(option), class: 'hidden', 'data-per-page-option': option, 'data-turbo-frame': turbo_frame %>
29
- <% end %>
1
+ <div class="flex flex-col sm:flex-row items-center justify-between aborder-t aborder-slate-200 rounded-xl space-y-2 sm:space-y-0">
2
+ <div class="flex-2 sm:flex sm:items-center sm:justify-between">
3
+ <div>
4
+ <div class="text-sm leading-5 text-slate-600 flex items-center">
5
+ <div data-controller="per-page">
6
+ <div class="flex items-center">
7
+ <%= select_tag 'per_page',
8
+ options_for_select(per_page_options, index_params[:per_page]),
9
+ class: 'appearance-none inline-flex bg-white-100 disabled:bg-white-400 disabled:cursor-not-allowed focus:bg-white text-slate-700 disabled:text-slate-600 rounded-md py-1 px-2 leading-tight border border-slate-300 outline-none focus:border-slate-400 outline w-16 mr-1 text-sm',
10
+ data: {
11
+ 'turbo-frame': turbo_frame,
12
+ 'per-page-target': 'selector',
13
+ action: 'change->per-page#reload'
14
+ }
15
+ %> <%= t('avo.per_page').downcase %>
30
16
  </div>
17
+ <% per_page_options.each do |option| %>
18
+ <%= link_to "Change to #{option} items per page", change_items_per_page_url(option), class: 'hidden', 'data-per-page-option': option, 'data-turbo-frame': turbo_frame %>
19
+ <% end %>
31
20
  </div>
32
21
  </div>
33
22
  </div>
34
- <div class="flex">
35
- <div class="flex-2 sm:flex sm:items-center sm:justify-between space-y-2 sm:space-y-0 text-center sm:text-left">
36
- <% if @pagy.count > 0 %>
37
- <div class="text-sm text-slate-600 mr-4"><%== helpers.pagy_info @pagy %></div>
38
- <% end %>
23
+ </div>
24
+ <div class="flex">
25
+ <div class="flex-2 sm:flex sm:items-center sm:justify-between space-y-2 sm:space-y-0 text-center sm:text-left">
26
+ <% if @resource.pagination_type.default? %>
27
+ <div class="text-sm text-slate-600 mr-4"><%== helpers.pagy_info @pagy %></div>
28
+ <% end %>
39
29
 
40
- <% if @pagy.pages > 1 %>
41
- <%# @todo: add first & last page. make the first and last buttons rounded %>
42
- <%== helpers.pagy_nav @pagy %>
43
- <% end %>
44
- </div>
30
+ <% if @pagy.pages > 1 %>
31
+ <%# @todo: add first & last page. make the first and last buttons rounded %>
32
+ <%== helpers.pagy_nav @pagy %>
33
+ <% end %>
45
34
  </div>
46
35
  </div>
47
- <% end %>
36
+ </div>
@@ -24,4 +24,22 @@ class Avo::PaginatorComponent < ViewComponent::Base
24
24
  helpers.resources_path(resource: resource, per_page: option, keep_query_params: true, page: 1)
25
25
  end
26
26
  end
27
+
28
+ def render?
29
+ return false if discreet_pagination && pagy.pages <= 1
30
+
31
+ @pagy.items > 0
32
+ end
33
+
34
+ def per_page_options
35
+ @per_page_options ||= begin
36
+ options = [*Avo.configuration.per_page_steps, Avo.configuration.per_page.to_i, index_params[:per_page].to_i]
37
+
38
+ if parent_record.present?
39
+ options.prepend Avo.configuration.via_per_page
40
+ end
41
+
42
+ options.sort.uniq
43
+ end
44
+ end
27
45
  end
@@ -32,12 +32,12 @@
32
32
  </div>
33
33
  </div>
34
34
  <% if sidebar? %>
35
- <div class="w-full sm:w-1/3 flex-shrink-0 h-full <%= white_panel_classes %>">
35
+ <div class="max-w-full sm:w-1/3 flex-shrink-0 h-full">
36
36
  <%= sidebar %>
37
37
  </div>
38
38
  <% end %>
39
39
  <% if bare_sidebar? %>
40
- <div class="w-full sm:w-1/3 flex-shrink-0 h-full">
40
+ <div class="max-w-full sm:w-1/3 flex-shrink-0 h-full">
41
41
  <%= bare_sidebar %>
42
42
  </div>
43
43
  <% end %>
@@ -3,4 +3,5 @@
3
3
  <%= hidden_field_tag :via_resource_class, params[:via_resource_class] if params[:via_resource_class] %>
4
4
  <%= hidden_field_tag :via_record_id, params[:via_record_id] if params[:via_record_id] %>
5
5
  <%= hidden_field_tag :via_relation, params[:via_relation] if params[:via_relation] %>
6
+ <%= hidden_field_tag :via_belongs_to_resource_class, params[:via_belongs_to_resource_class] if params[:via_belongs_to_resource_class] %>
6
7
  <%= hidden_field_tag :referrer, back_path if params[:via_resource_class] %>
@@ -113,14 +113,15 @@ class Avo::ResourceComponent < Avo::BaseComponent
113
113
  end
114
114
  end
115
115
 
116
- def sidebar
116
+ def sidebars
117
117
  return if Avo.license.lacks_with_trial(:resource_sidebar)
118
118
 
119
- @sidebar ||= search_for_sidebar
120
- end
121
-
122
- def sidebar_component(form: nil)
123
- Avo::ResourceSidebarComponent.new resource: @resource, fields: sidebar.visible_items, params: params, view: view, form: form
119
+ @item.items.select do |item|
120
+ item.is_sidebar?
121
+ end
122
+ .map do |sidebar|
123
+ sidebar.hydrate(view: view, resource: resource)
124
+ end
124
125
  end
125
126
 
126
127
  def has_reflection_and_is_read_only
@@ -155,16 +156,8 @@ class Avo::ResourceComponent < Avo::BaseComponent
155
156
  (params[:via_resource_class].present? || params[:via_relation_class].present?) && params[:via_record_id].present?
156
157
  end
157
158
 
158
- def search_for_sidebar
159
- item = @resource.get_items.find do |item|
160
- item.is_sidebar?
161
- end
162
-
163
- item&.hydrate(view: view)
164
- end
165
-
166
159
  def render_back_button(control)
167
- return if is_a_related_resource?
160
+ return if back_path.blank? || is_a_related_resource?
168
161
 
169
162
  tippy = control.title ? :tooltip : nil
170
163
  a_link back_path,
@@ -1,23 +1,16 @@
1
1
  <div class="resource-sidebar-component divide-y"
2
- data-component-name="<%= self.class.to_s.underscore%>"
2
+ data-component-name="<%= self.class.to_s.underscore %>"
3
+ data-component-index="<%= index %>"
3
4
  data-resource-name="<%= @resource.class.to_s %>"
4
5
  data-record-id="<%= @resource.record.id %>"
5
6
  >
6
- <% fields.each_with_index do |field, index| %>
7
- <%= render field
8
- .hydrate(
9
- resource: resource,
10
- record: resource.record,
11
- user: resource.user,
12
- view: view
13
- ).component_for_view(view)
14
- .new(
15
- field: field,
16
- resource: resource,
17
- form: form,
18
- stacked: true,
19
- index: index
20
- )
21
- %>
22
- <% end %>
7
+ <%= render Avo::Items::VisibleItemsComponent.new(
8
+ resource: @resource,
9
+ item: @sidebar,
10
+ view: @view,
11
+ form: @form,
12
+ field_component_extra_args: {
13
+ stacked: true
14
+ }
15
+ )%>
23
16
  </div>
@@ -6,13 +6,15 @@ class Avo::ResourceSidebarComponent < ViewComponent::Base
6
6
  attr_reader :view
7
7
  attr_reader :form
8
8
  attr_reader :fields
9
+ attr_reader :index
9
10
 
10
- def initialize(resource: nil, fields: nil, index: nil, params: nil, form: nil, view: nil)
11
+ def initialize(resource: nil, sidebar: nil, index: nil, params: nil, form: nil, view: nil)
11
12
  @resource = resource
12
- @fields = fields
13
+ @sidebar = sidebar
13
14
  @params = params
14
15
  @view = view
15
16
  @form = form
17
+ @index = index
16
18
  end
17
19
 
18
20
  def render?
@@ -2,7 +2,7 @@
2
2
  <div class="flex-1 flex space-x-4 w-full">
3
3
  <% if avatar.present? %>
4
4
  <div class="relative aspect-square w-10 h-10 overflow-hidden rounded shrink-0">
5
- <%= image_tag avatar, class: "object-cover min-w-full min-h-full h-full" %>
5
+ <%= image_tag helpers.main_app.url_for(avatar), class: "object-cover min-w-full min-h-full h-full" %>
6
6
  </div>
7
7
  <% end %>
8
8
  <div class="flex flex-col pr-3 min-w-0">
@@ -47,7 +47,7 @@
47
47
  <% if !tab.is_empty? %>
48
48
  <div class="space-y-12">
49
49
  <% tab.visible_items.each do |item| %>
50
- <%= render Avo::ItemSwitcherComponent.new resource: resource, item: item, index: index, form: form, view: @view %>
50
+ <%= render Avo::Items::SwitcherComponent.new resource: resource, item: item, index: index, form: form, view: @view %>
51
51
  <% end %>
52
52
  </div>
53
53
  <% end %>
@@ -1,4 +1,5 @@
1
1
  <%= content_tag :div,
2
+ id: helpers.frame_id(@resource),
2
3
  data: {
3
4
  model_name: @resource.model_name.to_s,
4
5
  resource_name: @resource.class.to_s,
@@ -19,39 +20,21 @@
19
20
  multipart: true do |form| %>
20
21
  <%= render Avo::ReferrerParamsComponent.new back_path: back_path %>
21
22
  <%= content_tag :div, class: 'space-y-12' do %>
22
- <%= render Avo::PanelComponent.new(name: title, description: @resource.description, display_breadcrumbs: @reflection.blank?, index: 0, data: { panel_id: "main" }) do |c| %>
23
- <% c.with_tools do %>
24
- <% @resource.render_edit_controls.each do |control| %>
25
- <%= render_control control %>
26
- <% end %>
27
- <% end %>
28
- <%# Extract the main panel and display the fields here. %>
29
- <%# This way we'll be able to render the footer buttons under the main fields. %>
30
- <% if main_panel.present? %>
31
- <% c.with_body do %>
32
- <div class="divide-y">
33
- <% main_panel.items.each_with_index do |field, index| %>
34
- <%= render field
35
- .hydrate(resource: @resource, record: @resource.record, user: @resource.user, view: view_for(field))
36
- .component_for_view(view_for field)
37
- .new(field: field, resource: @resource, index: index, form: form, compact: sidebar.present?)
38
- %>
39
- <% end %>
40
- </div>
41
- <% end %>
42
- <% end %>
43
- <% if sidebar.present? %>
44
- <% c.with_sidebar do %>
45
- <%= render sidebar_component form: form %>
46
- <% end %>
47
- <% end %>
48
- <% end %>
49
- <%= content_tag :div, class: 'space-y-12' do %>
50
- <% @resource.get_items.each_with_index do |item, index| %>
51
- <% next if item.nil? %>
52
- <%= render Avo::ItemSwitcherComponent.new resource: @resource, item: item, index: index + 1, view: view, form: form %>
53
- <% end %>
23
+ <% @resource.get_items.each_with_index do |item, index| %>
24
+ <%= render Avo::Items::SwitcherComponent.new(
25
+ resource: @resource,
26
+ reflection: @reflection,
27
+ item: item,
28
+ index: index + 1,
29
+ view: @view,
30
+ parent_resource: @parent_resource,
31
+ parent_record: @parent_record,
32
+ form: form,
33
+ parent_component: self,
34
+ actions: @actions
35
+ )%>
54
36
  <% end %>
37
+
55
38
  <% if Avo.configuration.buttons_on_form_footers %>
56
39
  <%= render Avo::PanelComponent.new do |c| %>
57
40
  <% c.with_footer_tools do %>
@@ -3,11 +3,14 @@
3
3
  class Avo::Views::ResourceEditComponent < Avo::ResourceComponent
4
4
  include Avo::ApplicationHelper
5
5
 
6
- def initialize(resource: nil, record: nil, actions: [], view: "edit")
6
+ attr_reader :actions, :display_breadcrumbs
7
+
8
+ def initialize(resource: nil, record: nil, actions: [], view: "edit", display_breadcrumbs: true)
7
9
  @resource = resource
8
10
  @record = record
9
11
  @actions = actions
10
12
  @view = Avo::ViewInquirer.new(view)
13
+ @display_breadcrumbs = @reflection.blank? && display_breadcrumbs
11
14
  end
12
15
 
13
16
  def title
@@ -15,6 +18,7 @@ class Avo::Views::ResourceEditComponent < Avo::ResourceComponent
15
18
  end
16
19
 
17
20
  def back_path
21
+ return if via_belongs_to?
18
22
  return resource_view_path if via_resource?
19
23
  return resources_path if via_index?
20
24
 
@@ -45,12 +49,25 @@ class Avo::Views::ResourceEditComponent < Avo::ResourceComponent
45
49
  @resource.authorization.authorize_action @view, raise_exception: false
46
50
  end
47
51
 
52
+ def controls
53
+ @resource.render_edit_controls
54
+ end
55
+
56
+ # Render :show view for read only trix fields
57
+ def view_for(field)
58
+ field.is_a?(Avo::Fields::TrixField) && field.is_disabled? ? :show : view
59
+ end
60
+
48
61
  private
49
62
 
50
63
  def via_index?
51
64
  params[:via_view] == "index"
52
65
  end
53
66
 
67
+ def via_belongs_to?
68
+ params[:via_belongs_to_resource_class].present?
69
+ end
70
+
54
71
  def is_edit?
55
72
  view.in?(%w[edit update])
56
73
  end
@@ -76,9 +93,4 @@ class Avo::Views::ResourceEditComponent < Avo::ResourceComponent
76
93
  )
77
94
  end
78
95
  end
79
-
80
- # Render :show view for read only trix fields
81
- def view_for(field)
82
- field.is_a?(Avo::Fields::TrixField) && field.is_disabled? ? :show : view
83
- end
84
96
  end
@@ -77,6 +77,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
77
77
 
78
78
  if @reflection.present?
79
79
  args = {
80
+ via_resource_class: @parent_resource.class,
80
81
  via_relation_class: reflection_model_class,
81
82
  via_record_id: @parent_record.to_param
82
83
  }
@@ -7,39 +7,20 @@
7
7
  selected_resources: [@resource.record.to_param],
8
8
  **@resource.stimulus_data_attributes
9
9
  } do %>
10
- <%= render_cards_component %>
11
- <%= render Avo::PanelComponent.new(name: title, description: @resource.description, display_breadcrumbs: @reflection.blank?, index: 0, data: { panel_id: "main" }) do |c| %>
12
- <% c.with_tools do %>
13
- <% @resource.render_show_controls.each do |control| %>
14
- <%= render_control control %>
15
- <% end %>
16
- <% end %>
17
- <% if main_panel.present? %>
18
- <% c.with_body do %>
19
- <%# the overflow helps with long values %>
20
- <div class="divide-y overflow-auto">
21
- <% main_panel.items.each_with_index do |field, index| %>
22
- <%= render field
23
- .hydrate(resource: @resource, record: @resource.record, user: @resource.user, view: view)
24
- .component_for_view(view)
25
- .new(field: field, resource: @resource, index: index, compact: sidebar.present?)
26
- %>
27
- <% end %>
28
- </div>
29
- <% end %>
30
- <% end %>
31
- <% if sidebar.present? %>
32
- <% c.with_sidebar do %>
33
- <%= render sidebar_component %>
34
- <% end %>
35
- <% end %>
36
- <% end %>
37
- <% if @reflection.blank? %>
38
- <%= content_tag :div, class: 'space-y-12 mt-12' do %>
39
- <% @resource.get_items.each_with_index do |item, index| %>
40
- <% next if item.nil? %>
41
- <%= render Avo::ItemSwitcherComponent.new resource: @resource, reflection: @reflection, item: item, index: index + 1, view: @view %>
42
- <% end %>
10
+ <%= content_tag :div, class: 'space-y-12' do %>
11
+ <%= render_cards_component %>
12
+ <% @resource.get_items.each_with_index do |item, index| %>
13
+ <%= render Avo::Items::SwitcherComponent.new(
14
+ resource: @resource,
15
+ reflection: @reflection,
16
+ item: item,
17
+ index: index + 1,
18
+ view: @view,
19
+ parent_resource: @parent_resource,
20
+ parent_record: @parent_record,
21
+ parent_component: self,
22
+ actions: @actions
23
+ )%>
43
24
  <% end %>
44
25
  <% end %>
45
26
  <% if should_display_invalid_fields_errors? %>
@@ -3,6 +3,8 @@
3
3
  class Avo::Views::ResourceShowComponent < Avo::ResourceComponent
4
4
  include Avo::ApplicationHelper
5
5
 
6
+ attr_reader :actions, :display_breadcrumbs
7
+
6
8
  def initialize(resource: nil, reflection: nil, parent_resource: nil, parent_record: nil, resource_panel: nil, actions: [])
7
9
  @resource = resource
8
10
  @reflection = reflection
@@ -11,6 +13,7 @@ class Avo::Views::ResourceShowComponent < Avo::ResourceComponent
11
13
  @parent_record = parent_record
12
14
  @parent_resource = parent_resource
13
15
  @view = Avo::ViewInquirer.new("show")
16
+ @display_breadcrumbs = reflection.blank?
14
17
  end
15
18
 
16
19
  def title
@@ -44,6 +47,14 @@ class Avo::Views::ResourceShowComponent < Avo::ResourceComponent
44
47
  helpers.edit_resource_path(record: @resource.record, resource: @resource, **args)
45
48
  end
46
49
 
50
+ def controls
51
+ @resource.render_show_controls
52
+ end
53
+
54
+ def view_for(field)
55
+ @view
56
+ end
57
+
47
58
  private
48
59
 
49
60
  # In development and test environments we should show the invalid field errors
@@ -10,13 +10,13 @@ module Avo
10
10
  request.params[:id].present?
11
11
  end
12
12
  before_action :set_action, only: [:show, :handle]
13
+ before_action :verify_authorization, only: [:show, :handle]
13
14
 
14
15
  def show
15
16
  # Se the view to :new so the default value gets prefilled
16
17
  @view = Avo::ViewInquirer.new("new")
17
18
 
18
19
  @resource.hydrate(record: @record, view: @view, user: _current_user, params: params)
19
- @record = ActionModel.new @action.get_attributes_for_action
20
20
  end
21
21
 
22
22
  def handle
@@ -83,8 +83,6 @@ module Avo
83
83
  end
84
84
  end
85
85
 
86
- private
87
-
88
86
  def get_messages(response)
89
87
  default_message = {
90
88
  type: :info,
@@ -126,9 +124,13 @@ module Avo
126
124
 
127
125
  respond_to do |format|
128
126
  format.turbo_stream do
129
- render "keep_modal_open"
127
+ render partial: "avo/partials/flash_alerts"
130
128
  end
131
129
  end
132
130
  end
131
+
132
+ def verify_authorization
133
+ raise Avo::NotAuthorizedError.new unless @action.authorized?
134
+ end
133
135
  end
134
136
  end
@@ -10,7 +10,6 @@ module Avo
10
10
  include Avo::ApplicationHelper
11
11
  include Avo::UrlHelpers
12
12
  include Avo::Concerns::Breadcrumbs
13
- include Pagy::Backend
14
13
 
15
14
  protect_from_forgery with: :exception
16
15
  around_action :set_avo_locale
@@ -130,7 +129,7 @@ module Avo
130
129
  end
131
130
 
132
131
  def set_record
133
- @record = @resource.find_record(params[:id], query: model_find_scope, params: params)
132
+ @record = @resource.find_record(params[:id], query: model_scope, params: params)
134
133
  @resource.hydrate(record: @record)
135
134
  end
136
135
 
@@ -139,15 +138,11 @@ module Avo
139
138
  @related_record = if @field.is_a? Avo::Fields::HasOneField
140
139
  @record.send association_name
141
140
  else
142
- @related_resource.find_record params[:related_id], query: eager_load_files(@related_resource, @record.send(association_name)), params: params
141
+ @related_resource.find_record params[:related_id], query: @record.send(association_name), params: params
143
142
  end
144
143
  @related_resource.hydrate(record: @related_record)
145
144
  end
146
145
 
147
- def model_find_scope
148
- eager_load_files(@resource, model_scope)
149
- end
150
-
151
146
  def model_scope
152
147
  # abort @resource.inspect
153
148
  @resource.class.find_scope
@@ -203,32 +198,6 @@ module Avo
203
198
  @authorization.set_record(class_to_authorize).authorize_action action_to_authorize.to_sym
204
199
  end
205
200
 
206
- def eager_load_files(resource, query)
207
- # Get the non-computed file fields and try to eager load them
208
- attachment_fields = resource
209
- .attachment_fields
210
- .reject do |field|
211
- field.computed
212
- end
213
-
214
- if attachment_fields.present?
215
- attachment_fields.map do |field|
216
- attachment = case field.class.to_s
217
- when "Avo::Fields::FileField"
218
- "attachment"
219
- when "Avo::Fields::FilesField"
220
- "attachments"
221
- else
222
- "attachment"
223
- end
224
-
225
- return query.includes "#{field.id}_#{attachment}": :blob
226
- end
227
- end
228
-
229
- query
230
- end
231
-
232
201
  def _authenticate!
233
202
  instance_eval(&Avo.configuration.authenticate)
234
203
  end
@@ -34,9 +34,6 @@ module Avo
34
34
  @query = @query.includes(*@resource.includes)
35
35
  end
36
36
 
37
- # Eager load the active storage attachments
38
- @query = eager_load_files(@resource, @query)
39
-
40
37
  # Sort the items
41
38
  if @index_params[:sort_by].present?
42
39
  unless @index_params[:sort_by].eql? :created_at
@@ -60,17 +57,9 @@ module Avo
60
57
  ).apply_query request, @query, filter_value
61
58
  end
62
59
 
63
- extra_pagy_params = {}
64
-
65
- # Reset open filters when a user navigates to a new page
66
- extra_pagy_params[:keep_filters_panel_open] = if params[:keep_filters_panel_open] == "1"
67
- "0"
68
- end
69
-
70
60
  safe_call :set_and_apply_scopes
71
61
  safe_call :apply_dynamic_filters
72
-
73
- @pagy, @records = pagy(pagy_query, items: @index_params[:per_page], link_extra: "data-turbo-frame=\"#{params[:turbo_frame]}\"", size: [1, 2, 2, 1], params: extra_pagy_params)
62
+ apply_pagination
74
63
 
75
64
  # Create resources for each record
76
65
  @resources = @records.map do |record|
@@ -109,6 +98,11 @@ module Avo
109
98
  @record = @resource.model_class.new
110
99
  @resource = @resource.hydrate(record: @record, view: :new, user: _current_user)
111
100
 
101
+ # Handle special cases when creating a new record via a belongs_to relationship
102
+ if params[:via_belongs_to_resource_class].present?
103
+ return render turbo_stream: turbo_stream.append('attach_modal', partial: 'avo/base/new_via_belongs_to')
104
+ end
105
+
112
106
  set_actions
113
107
 
114
108
  @page_title = @resource.default_panel_name.to_s
@@ -134,7 +128,7 @@ module Avo
134
128
  @resource.hydrate(record: @record, view: :new, user: _current_user)
135
129
 
136
130
  # This means that the record has been created through another parent record and we need to attach it somehow.
137
- if params[:via_record_id].present?
131
+ if params[:via_record_id].present? && params[:via_belongs_to_resource_class].nil?
138
132
  @reflection = @record._reflections[params[:via_relation]]
139
133
  # Figure out what kind of association does the record have with the parent record
140
134
 
@@ -433,15 +427,19 @@ module Avo
433
427
  end
434
428
 
435
429
  def create_success_action
430
+ return render "close_modal_and_reload_field" if params[:via_belongs_to_resource_class].present?
431
+
436
432
  respond_to do |format|
437
433
  format.html { redirect_to after_create_path, notice: create_success_message}
438
434
  end
439
435
  end
440
436
 
441
437
  def create_fail_action
438
+ flash.now[:error] = create_fail_message
439
+
442
440
  respond_to do |format|
443
- flash.now[:error] = create_fail_message
444
441
  format.html { render :new, status: :unprocessable_entity }
442
+ format.turbo_stream { render "create_fail_action" }
445
443
  end
446
444
  end
447
445
 
@@ -456,7 +454,12 @@ module Avo
456
454
  def after_create_path
457
455
  # If this is an associated record return to the association show page
458
456
  if is_associated_record?
459
- parent_resource = Avo.resource_manager.get_resource_by_model_class(params[:via_relation_class])
457
+ parent_resource = if params[:via_resource_class].present?
458
+ Avo.resource_manager.get_resource(params[:via_resource_class])
459
+ else
460
+ Avo.resource_manager.get_resource_by_model_class(params[:via_relation_class])
461
+ end
462
+
460
463
  association_name = BaseResource.valid_association_name(@record, params[:via_relation])
461
464
 
462
465
  return resource_view_path(
@@ -508,8 +511,10 @@ module Avo
508
511
  end
509
512
 
510
513
  def destroy_fail_action
514
+ flash[:error] = destroy_fail_message
515
+
511
516
  respond_to do |format|
512
- format.html { redirect_back fallback_location: params[:referrer] || resources_path(resource: @resource, turbo_frame: params[:turbo_frame], view_type: params[:view_type]), error: destroy_fail_message }
517
+ format.turbo_stream { render partial: "avo/partials/flash_alerts" }
513
518
  end
514
519
  end
515
520
 
@@ -579,5 +584,9 @@ module Avo
579
584
  "That component was fetched from 'self.components' option inside '#{@resource.class}' resource."
580
585
  end
581
586
  end
587
+
588
+ def apply_pagination
589
+ @pagy, @records = @resource.apply_pagination(index_params: @index_params, query: pagy_query)
590
+ end
582
591
  end
583
592
  end