avo 2.9.2.pre1 → 2.10.3.pre.1

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 (141) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +69 -69
  3. data/README.md +4 -0
  4. data/app/assets/stylesheets/css/buttons.css +4 -1
  5. data/app/components/avo/actions_component.rb +6 -2
  6. data/app/components/avo/base_component.rb +2 -0
  7. data/app/components/avo/button_component.rb +3 -1
  8. data/app/components/avo/fields/common/key_value_component.html.erb +2 -2
  9. data/app/components/avo/fields/common/single_file_viewer_component.rb +1 -1
  10. data/app/components/avo/fields/country_field/edit_component.html.erb +9 -3
  11. data/app/components/avo/fields/date_field/edit_component.html.erb +26 -7
  12. data/app/components/avo/fields/date_field/index_component.html.erb +7 -1
  13. data/app/components/avo/fields/date_field/show_component.html.erb +7 -1
  14. data/app/components/avo/fields/date_time_field/edit_component.html.erb +1 -0
  15. data/app/components/avo/fields/edit_component.rb +5 -0
  16. data/app/components/avo/fields/file_field/edit_component.html.erb +1 -0
  17. data/app/components/avo/fields/files_field/edit_component.html.erb +1 -0
  18. data/app/components/avo/fields/select_field/edit_component.html.erb +14 -10
  19. data/app/components/avo/fields/show_component.rb +1 -1
  20. data/app/components/avo/index/ordering/button_component.rb +1 -15
  21. data/app/components/avo/index/resource_controls_component.html.erb +2 -2
  22. data/app/components/avo/index/resource_controls_component.rb +5 -1
  23. data/app/components/avo/index/resource_table_component.html.erb +1 -1
  24. data/app/components/avo/index/table_row_component.html.erb +1 -1
  25. data/app/components/avo/item_switcher_component.html.erb +19 -0
  26. data/app/components/avo/item_switcher_component.rb +45 -0
  27. data/app/components/avo/panel_component.html.erb +23 -24
  28. data/app/components/avo/panel_component.rb +8 -5
  29. data/app/components/avo/tab_group_component.html.erb +53 -0
  30. data/app/components/avo/tab_group_component.rb +51 -0
  31. data/app/components/avo/tab_switcher_component.html.erb +21 -0
  32. data/app/components/avo/tab_switcher_component.rb +86 -0
  33. data/app/components/avo/views/resource_edit_component.html.erb +34 -56
  34. data/app/components/avo/views/resource_edit_component.rb +11 -1
  35. data/app/components/avo/views/resource_index_component.html.erb +2 -2
  36. data/app/components/avo/views/resource_index_component.rb +3 -3
  37. data/app/components/avo/views/resource_show_component.html.erb +58 -89
  38. data/app/components/avo/views/resource_show_component.rb +2 -2
  39. data/app/controllers/avo/actions_controller.rb +1 -1
  40. data/app/controllers/avo/application_controller.rb +33 -10
  41. data/app/controllers/avo/base_controller.rb +11 -3
  42. data/app/controllers/avo/reorder_controller.rb +25 -0
  43. data/app/helpers/avo/application_helper.rb +6 -6
  44. data/app/helpers/avo/url_helpers.rb +1 -5
  45. data/app/javascript/avo.js +5 -1
  46. data/app/javascript/js/controllers/fields/date_field_controller.js +15 -3
  47. data/app/javascript/js/controllers/loading_button_controller.js +25 -21
  48. data/app/javascript/js/controllers/search_controller.js +3 -0
  49. data/app/javascript/js/controllers/tabs_controller.js +86 -0
  50. data/app/javascript/js/controllers.js +2 -0
  51. data/app/views/avo/base/index.html.erb +1 -1
  52. data/app/views/avo/base/show.html.erb +1 -1
  53. data/app/views/avo/cards/show.html.erb +1 -1
  54. data/app/views/avo/debug/index.html.erb +1 -1
  55. data/app/views/avo/home/_actions.html.erb +1 -1
  56. data/app/views/avo/home/_dashboards.html.erb +19 -0
  57. data/app/views/avo/home/_filters.html.erb +1 -1
  58. data/app/views/avo/home/_resources.html.erb +1 -1
  59. data/app/views/avo/home/failed_to_load.html.erb +1 -1
  60. data/app/views/avo/home/index.html.erb +14 -2
  61. data/app/views/avo/partials/_javascript.html.erb +1 -1
  62. data/app/views/avo/partials/_tabs_toggle.html.erb +20 -0
  63. data/app/views/avo/private/design.html.erb +1 -1
  64. data/config/routes.rb +5 -4
  65. data/db/factories.rb +1 -0
  66. data/lib/avo/app.rb +12 -7
  67. data/lib/avo/base_action.rb +2 -19
  68. data/lib/avo/base_card.rb +1 -7
  69. data/lib/avo/base_resource.rb +6 -98
  70. data/lib/avo/base_resource_tool.rb +3 -1
  71. data/lib/avo/concerns/has_fields.rb +249 -50
  72. data/lib/avo/concerns/has_html_attributes.rb +1 -1
  73. data/lib/avo/concerns/is_resource_item.rb +36 -0
  74. data/lib/avo/concerns/model_class_constantized.rb +23 -0
  75. data/lib/avo/configuration.rb +2 -12
  76. data/lib/avo/dashboards/base_dashboard.rb +1 -1
  77. data/lib/avo/dsl/field_parser.rb +83 -0
  78. data/lib/avo/fields/base_field.rb +21 -2
  79. data/lib/avo/fields/country_field.rb +2 -0
  80. data/lib/avo/fields/date_field.rb +13 -9
  81. data/lib/avo/fields/field_extensions/has_include_blank.rb +17 -0
  82. data/lib/avo/fields/field_extensions/visible_in_different_views.rb +18 -1
  83. data/lib/avo/fields/file_field.rb +2 -0
  84. data/lib/avo/fields/files_field.rb +2 -0
  85. data/lib/avo/fields/has_base_field.rb +20 -1
  86. data/lib/avo/fields/has_one_field.rb +4 -1
  87. data/lib/avo/fields/key_value_field.rb +4 -4
  88. data/lib/avo/fields/select_field.rb +2 -0
  89. data/lib/avo/grid_collector.rb +6 -3
  90. data/lib/avo/items_holder.rb +68 -0
  91. data/lib/avo/licensing/h_q.rb +12 -0
  92. data/lib/avo/main_panel.rb +3 -0
  93. data/lib/avo/menu/builder.rb +8 -7
  94. data/lib/avo/panel.rb +25 -0
  95. data/lib/avo/panel_builder.rb +23 -0
  96. data/lib/avo/services/uri_service.rb +75 -0
  97. data/lib/avo/tab.rb +78 -0
  98. data/lib/avo/tab_builder.rb +25 -0
  99. data/lib/avo/tab_group.rb +40 -0
  100. data/lib/avo/tab_group_builder.rb +43 -0
  101. data/lib/avo/version.rb +1 -1
  102. data/lib/avo.rb +1 -0
  103. data/lib/generators/avo/action_generator.rb +3 -2
  104. data/lib/generators/avo/base_generator.rb +14 -0
  105. data/lib/generators/avo/card/chartkick_generator.rb +18 -0
  106. data/lib/generators/avo/card/metric_generator.rb +18 -0
  107. data/lib/generators/avo/card/partial_generator.rb +19 -0
  108. data/lib/generators/avo/controller_generator.rb +9 -3
  109. data/lib/generators/avo/dashboard_generator.rb +2 -2
  110. data/lib/generators/avo/eject_generator.rb +2 -3
  111. data/lib/generators/avo/field_generator.rb +2 -2
  112. data/lib/generators/avo/filter_generator.rb +3 -2
  113. data/lib/generators/avo/install_generator.rb +2 -2
  114. data/lib/generators/avo/locales_generator.rb +2 -2
  115. data/lib/generators/avo/named_base_generator.rb +14 -0
  116. data/lib/generators/avo/resource_generator.rb +2 -2
  117. data/lib/generators/avo/resource_tool_generator.rb +4 -4
  118. data/lib/generators/avo/templates/locales/avo.fr.yml +115 -0
  119. data/lib/generators/avo/templates/resource/controller.tt +2 -0
  120. data/lib/generators/avo/templates/resource_tools/partial.tt +1 -1
  121. data/lib/generators/avo/templates/tool/view.tt +1 -1
  122. data/lib/generators/avo/tool_generator.rb +4 -4
  123. data/lib/generators/avo/version_generator.rb +23 -0
  124. data/public/avo-assets/avo.css +31 -3
  125. data/public/avo-assets/avo.js +72 -72
  126. data/public/avo-assets/avo.js.map +3 -3
  127. metadata +32 -16
  128. data/app/assets/builds/action_cable.js +0 -2
  129. data/app/assets/builds/action_cable.js.map +0 -7
  130. data/app/assets/builds/application.js +0 -2
  131. data/app/assets/builds/application.js.map +0 -7
  132. data/app/assets/builds/avo.css +0 -9028
  133. data/app/assets/builds/avo.js +0 -512
  134. data/app/assets/builds/avo.js.map +0 -7
  135. data/app/assets/builds/avo_custom.js +0 -6
  136. data/app/assets/builds/avo_custom.js.map +0 -7
  137. data/lib/avo/concerns/has_tools.rb +0 -47
  138. data/lib/avo/fields/currency_field.rb +0 -15
  139. data/lib/generators/avo/chartkick_card_generator.rb +0 -16
  140. data/lib/generators/avo/metric_card_generator.rb +0 -16
  141. data/lib/generators/avo/partial_card_generator.rb +0 -17
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::ItemSwitcherComponent < Avo::BaseComponent
4
+ include Turbo::FramesHelper
5
+
6
+ attr_reader :resource
7
+ attr_reader :reflection
8
+ attr_reader :index
9
+ attr_reader :item
10
+ attr_reader :view
11
+
12
+ def initialize(resource: nil, reflection: nil, item: nil, index: nil, view: nil, form: nil)
13
+ @resource = resource
14
+ @reflection = reflection
15
+ @form = form
16
+ @index = index
17
+ @item = item
18
+ @view = view
19
+ end
20
+
21
+ def form
22
+ @form || nil
23
+ end
24
+
25
+ def render?
26
+ # Stops rendering if the field should be hidden in reflections
27
+ if item.is_field?
28
+ return false if in_reflection? && item.hidden_in_reflection?
29
+ end
30
+
31
+ true
32
+ end
33
+
34
+ def in_reflection?
35
+ @reflection.present?
36
+ end
37
+
38
+ def tab_group_component
39
+ Avo::TabGroupComponent.new resource: @resource, group: item.hydrate(view: view), index: index, params: params, form: form, view: view
40
+ end
41
+
42
+ def field_component
43
+ item.component_for_view(@view).new(field: item.hydrate(resource: @resource, view: @view, model: @resource.model), resource: @resource, index: index, form: form)
44
+ end
45
+ end
@@ -1,4 +1,4 @@
1
- <div <%== data_attributes %>>
1
+ <%= content_tag :div, data: data_attributes, class: classes do %>
2
2
  <% if render_header? %>
3
3
  <div class="flex-1 flex flex-col xl:flex-row justify-between mb-4">
4
4
  <div class="overflow-hidden flex flex-col">
@@ -7,18 +7,15 @@
7
7
  <%= helpers.render_breadcrumbs(separator: helpers.svg('chevron-right', class: 'inline-block h-3 stroke-current relative top-[-1px] ml-1' )) if Avo.configuration.display_breadcrumbs %>
8
8
  </div>
9
9
  <% end %>
10
-
11
10
  <div class="text-2xl tracking-normal font-semibold text-gray-800 truncate items-center flex flex-1" data-target="title">
12
- <span><%= @title %></span>
11
+ <span><%= @name %></span>
13
12
  </div>
14
-
15
13
  <% if description.present? %>
16
- <div class="text-sm tracking-normal font-medium text-gray-600" data-target="description">
17
- <%== description %>
18
- </div>
14
+ <div class="text-sm tracking-normal font-medium text-gray-600" data-target="description">
15
+ <%== description %>
16
+ </div>
19
17
  <% end %>
20
18
  </div>
21
-
22
19
  <% if tools.present? %>
23
20
  <div class="flex-1 w-full flex flex-col sm:flex-row xl:justify-end sm:items-end space-y-2 sm:space-y-0 sm:space-x-2 mt-4 xl:mt-0">
24
21
  <%= tools %>
@@ -26,26 +23,28 @@
26
23
  <% end %>
27
24
  </div>
28
25
  <% end %>
29
-
30
- <div class="relative <%= white_panel_classes %> <%= @body_classes %>">
31
- <%= body %>
32
- </div>
33
-
34
- <div class="relative">
35
- <%= bare_content %>
36
- </div>
37
-
38
- <% if footer_tools.present? %>
26
+ <% if body? %>
27
+ <div class="relative <%= white_panel_classes %> <%= @body_classes %>">
28
+ <%= body %>
29
+ </div>
30
+ <% end %>
31
+ <% if bare_content? %>
32
+ <div class="relative">
33
+ <%= bare_content %>
34
+ </div>
35
+ <% end %>
36
+ <% if footer_tools? %>
39
37
  <div class="<%= white_panel_classes %> p-4 flex-1 flex flex-col xl:flex-row justify-between mt-6">
40
38
  <div class="flex-1 w-full flex flex-col sm:flex-row xl:justify-end sm:items-end space-y-2 sm:space-y-0 sm:space-x-2 mt-4 xl:mt-0">
41
39
  <%= footer_tools %>
42
40
  </div>
43
41
  </div>
44
42
  <% end %>
45
-
46
- <div class="flex justify-end w-full">
47
- <div>
48
- <%= footer %>
43
+ <% if footer? %>
44
+ <div class="flex justify-end w-full">
45
+ <div>
46
+ <%= footer %>
47
+ </div>
49
48
  </div>
50
- </div>
51
- </div>
49
+ <% end %>
50
+ <% end %>
@@ -2,6 +2,8 @@
2
2
 
3
3
  class Avo::PanelComponent < ViewComponent::Base
4
4
  attr_reader :title
5
+ attr_reader :name
6
+ attr_reader :classes
5
7
 
6
8
  renders_one :tools
7
9
  renders_one :body
@@ -9,13 +11,17 @@ class Avo::PanelComponent < ViewComponent::Base
9
11
  renders_one :footer_tools
10
12
  renders_one :footer
11
13
 
12
- def initialize(title: nil, description: nil, body_classes: nil, data: {}, display_breadcrumbs: false, index: nil)
14
+ def initialize(title: nil, name: nil, description: nil, body_classes: nil, data: {}, display_breadcrumbs: false, index: nil, classes: nil, view: nil)
15
+ # deprecating title in favor of name
13
16
  @title = title
17
+ @name = name || title
14
18
  @description = description
19
+ @classes = classes
15
20
  @body_classes = body_classes
16
21
  @data = data
17
22
  @display_breadcrumbs = display_breadcrumbs
18
23
  @index = index
24
+ @view = view
19
25
  end
20
26
 
21
27
  private
@@ -26,9 +32,6 @@ class Avo::PanelComponent < ViewComponent::Base
26
32
 
27
33
  def data_attributes
28
34
  @data.merge({"panel-index": @index})
29
- .map do |key, value|
30
- " data-#{key}=\"#{value}\""
31
- end.join
32
35
  end
33
36
 
34
37
  def display_breadcrumbs?
@@ -42,7 +45,7 @@ class Avo::PanelComponent < ViewComponent::Base
42
45
  end
43
46
 
44
47
  def render_header?
45
- @title.present? || description.present? || tools.present? || display_breadcrumbs?
48
+ @name.present? || description.present? || tools.present? || display_breadcrumbs?
46
49
  end
47
50
 
48
51
  def render_footer_tools?
@@ -0,0 +1,53 @@
1
+ <%= content_tag :div,
2
+ data: {
3
+ target: "tab-group",
4
+ index: index,
5
+ controller: "tabs",
6
+ tabs_view_value: view,
7
+ tabs_active_tab_value: active_tab_name
8
+ },
9
+ class: 'space-y-12' do %>
10
+ <% visible_tabs.each_with_index do |tab, index| %>
11
+ <%
12
+ args = {
13
+ # Hide the turbo frames that aren't in the current tab
14
+ # This way we can lazy load the un-selected tabs on the show view
15
+ class: "block #{'hidden' unless tab.name == active_tab_name}",
16
+ data: {
17
+ # Add a marker to know if we already loaded a turbo frame
18
+ loaded: tab.name == active_tab_name,
19
+ tabs_target: :tab,
20
+ tab_id: tab.name,
21
+ }
22
+ }
23
+
24
+ is_current_tab = active_tab_name.to_s == tab.name.to_s
25
+
26
+ # On edit screens we want to load each tab because we wnst the DOM to have the fields present on form submission.
27
+ # If you have a field which is in the second tab and it's required, the form submission will fail because the required field is not in view, and we don't want that.
28
+ # We also want to load the current tab
29
+ should_lazy_load = if @view.to_s.in?(['edit', 'new'])
30
+ false
31
+ else
32
+ !is_current_tab
33
+ end
34
+
35
+ if should_lazy_load
36
+ args[:src] = helpers.resource_path(resource: @resource, model: @resource.model, keep_query_params: true, active_tab_name: tab.name, tab_turbo_frame: group.turbo_frame_id)
37
+ args[:loading] = :lazy
38
+ end
39
+ %>
40
+ <%= turbo_frame_tag tab.turbo_frame_id(parent: @group), **args do %>
41
+ <div class="border rounded-lg p-2 -mx-2 -my-2 lg:p-4 lg:-mx-4 lg:-my-4 space-y-4">
42
+ <%= render Avo::TabSwitcherComponent.new resource: @resource, current_tab: tab, group: group, active_tab_name: active_tab_name, view: view %>
43
+ <% if !should_lazy_load && !tab.empty? %>
44
+ <div class="space-y-12">
45
+ <% tab.visible_items.each do |item| %>
46
+ <%= render Avo::ItemSwitcherComponent.new resource: @resource, item: item, index: index, form: form, view: @view %>
47
+ <% end %>
48
+ </div>
49
+ <% end %>
50
+ </div>
51
+ <% end %>
52
+ <% end %>
53
+ <% end %>
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::TabGroupComponent < Avo::BaseComponent
4
+ attr_reader :group
5
+ attr_reader :index
6
+ attr_reader :view
7
+ attr_reader :form
8
+
9
+ def initialize(resource:, group:, index:, form:, params:, view:)
10
+ @resource = resource
11
+ @group = group
12
+ @index = index
13
+ @form = form
14
+ @params = params
15
+ @view = view
16
+
17
+ @group.index = index
18
+ end
19
+
20
+ def render?
21
+ tabs_have_content? && visible_tabs.present?
22
+ end
23
+
24
+ def tabs_have_content?
25
+ visible_tabs.present?
26
+ end
27
+
28
+ def active_tab_name
29
+ params[:active_tab_name] || group.visible_items&.first&.name
30
+ end
31
+
32
+ def tabs
33
+ @group.items.map do |tab|
34
+ tab.hydrate(view: view)
35
+ end
36
+ end
37
+
38
+ def visible_tabs
39
+ tabs.select do |tab|
40
+ !tab.empty?
41
+ end
42
+ end
43
+
44
+ def active_tab
45
+ return if group.visible_items.blank?
46
+
47
+ group.visible_items.find do |tab|
48
+ tab.name.to_s == active_tab_name.to_s
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,21 @@
1
+ <div class="flex" data-target="tab-switcher">
2
+ <div class="button-group">
3
+ <% visible_items.each do |tab| %>
4
+ <%= a_link tab_path(tab),
5
+ color: selected?(tab) ? :gray : :primary,
6
+ rounded: false,
7
+ size: :sm,
8
+ class: selected?(tab) ? ' bg-gray-100 border-gray-300' : ' z-20',
9
+ title: tab.description,
10
+ data: {
11
+ tippy: tab.description.present? ? 'tooltip' : '',
12
+ control: "view-type-toggle-#{tab.name}",
13
+ selected: selected?(tab),
14
+ action: 'click->tabs#changeTab',
15
+ tabs_id_param: tab.name
16
+ } do %>
17
+ <%= tab.name %>
18
+ <% end %>
19
+ <% end %>
20
+ </div>
21
+ </div>
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::TabSwitcherComponent < Avo::BaseComponent
4
+ include Avo::UrlHelpers
5
+ include Avo::ApplicationHelper
6
+
7
+ attr_reader :active_tab_name
8
+ attr_reader :group
9
+ attr_reader :current_tab
10
+ attr_reader :tabs
11
+ attr_reader :view
12
+
13
+ def initialize(resource:, group:, current_tab:, active_tab_name:, view:)
14
+ @active_tab_name = active_tab_name
15
+ @resource = resource
16
+ @group = group
17
+ @current_tab = current_tab
18
+ @tabs = group.items
19
+ @view = view
20
+ end
21
+
22
+ def tab_path(tab)
23
+ if is_edit?
24
+ helpers.edit_resource_path(resource: @resource, model: @resource.model, keep_query_params: true, active_tab_name: tab.name, tab_turbo_frame: group.turbo_frame_id)
25
+ elsif is_new?
26
+ helpers.new_resource_path(resource: @resource, keep_query_params: true, active_tab_name: tab.name, tab_turbo_frame: group.turbo_frame_id)
27
+ else
28
+ helpers.resource_path(resource: @resource, model: @resource.model, keep_query_params: true, active_tab_name: tab.name, tab_turbo_frame: group.turbo_frame_id)
29
+ end
30
+ end
31
+
32
+ def is_edit?
33
+ @view == :edit
34
+ end
35
+
36
+ def is_new?
37
+ @view == :new
38
+ end
39
+
40
+ def is_initial_load?
41
+ params[:active_tab_name].blank?
42
+ end
43
+
44
+ # On initial load we want that each tab button to be the selected one.
45
+ # We do that so we don't get the wrongly selected item for a quick brief when first switching from one panel to another.
46
+ def selected?(tab)
47
+ if is_initial_load?
48
+ current_tab.name.to_s == tab.name.to_s
49
+ else
50
+ tab.name.to_s == active_tab_name.to_s
51
+ end
52
+ end
53
+
54
+ # Goes through all items and removes the ones that are not supposed to be visible.
55
+ # Example below:
56
+ # tabs do
57
+ # field :comments, as: :has_many
58
+ # end
59
+ # Because the developer hasn't specified that it should be visible on edit views (with the show_on: :edit option),
60
+ # the field should not be visible in the item switcher either.
61
+ def visible_items
62
+ tabs.select do |item|
63
+ visible = true
64
+
65
+ if item.items.blank?
66
+ visible = false
67
+ end
68
+
69
+ first_item = item.items.first
70
+ if item.items.count == 1 && first_item.is_field? && first_item.has_own_panel? && !first_item.visible_on?(view)
71
+ # Return nil if tab contians a has_many type of fields and it's hidden in current view
72
+ visible = false
73
+ end
74
+
75
+ if item.respond_to?(:visible_on?)
76
+ visible = item.visible_on? view
77
+ end
78
+
79
+ if item.respond_to?(:visible?)
80
+ visible = item.visible?
81
+ end
82
+
83
+ visible
84
+ end
85
+ end
86
+ end
@@ -1,77 +1,55 @@
1
1
  <%= content_tag :div,
2
- class: "space-y-12",
3
2
  data: {
4
3
  'model-id': @resource.model.id,
5
4
  selected_resources_name: @resource.model_key,
6
5
  selected_resources: [@resource.model.id],
7
6
  **@resource.stimulus_data_attributes
8
7
  } do %>
9
- <% @resource.panels.each_with_index do |resource_panel, index| %>
10
- <%= form_with model: @resource.model,
11
- scope: @resource.form_scope,
12
- url: form_url,
13
- local: true,
14
- multipart: true do |form| %>
15
- <%= render Avo::ReferrerParamsComponent.new back_path: back_path %>
16
- <%= render Avo::PanelComponent.new(title: resource_panel[:name], description: @resource.resource_description, display_breadcrumbs: true, index: index) do |c| %>
17
- <% c.tools do %>
18
- <%= a_link back_path,
19
- style: :text,
20
- icon: 'arrow-left' do %>
21
- <%= t('avo.cancel').capitalize %>
22
- <% end %>
23
- <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
24
- <% if can_see_the_save_button? %>
25
- <%= a_button color: :primary,
8
+ <%= form_with model: @resource.model,
9
+ scope: @resource.form_scope,
10
+ url: form_url,
11
+ method: form_method,
12
+ local: true,
13
+ html: {
14
+ novalidate: true
15
+ },
16
+ multipart: true do |form| %>
17
+ <%= render Avo::ReferrerParamsComponent.new back_path: back_path %>
18
+ <%= render Avo::PanelComponent.new(title: 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,
21
+ style: :text,
22
+ icon: 'arrow-left' do %>
23
+ <%= t('avo.cancel').capitalize %>
24
+ <% end %>
25
+ <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
26
+ <% if can_see_the_save_button? %>
27
+ <%= a_button color: :primary,
26
28
  style: :primary,
27
29
  loading: true,
28
30
  type: :submit,
29
31
  icon: 'save' do %>
30
- <%= t('avo.save').capitalize %>
31
- <% end %>
32
+ <%= t('avo.save').capitalize %>
32
33
  <% end %>
33
34
  <% end %>
34
- <% if Avo.configuration.buttons_on_form_footers %>
35
- <% c.footer_tools do %>
36
- <%= a_link back_path, icon: 'arrow-left' do %>
37
- <%= t('avo.cancel').capitalize %>
38
- <% end %>
39
- <% if can_see_the_save_button? %>
40
- <%= a_button color: :green, loading: true, type: :submit, icon: 'save' do %>
41
- <%= t('avo.save').capitalize %>
42
- <% end %>
43
- <% end %>
35
+ <% end %>
36
+ <% if Avo.configuration.buttons_on_form_footers %>
37
+ <% c.footer_tools do %>
38
+ <%= a_link back_path, icon: 'arrow-left' do %>
39
+ <%= t('avo.cancel').capitalize %>
44
40
  <% end %>
45
- <% end %>
46
- <% c.body do %>
47
- <div class="divide-y">
48
- <% @resource.get_fields.each_with_index do |field, index| %>
49
- <%= render field.component_for_view(:edit).new(field: field, resource: @resource, index: index, form: form) unless field.computed %>
41
+ <% if can_see_the_save_button? %>
42
+ <%= a_button color: :green, loading: true, type: :submit, icon: 'save' do %>
43
+ <%= t('avo.save').capitalize %>
50
44
  <% end %>
51
- </div>
45
+ <% end %>
52
46
  <% end %>
53
47
  <% end %>
54
48
  <% end %>
55
- <% end %>
56
- <% if @reflection.blank? %>
57
- <% if has_one_panels.present? %>
58
- <% has_one_panels.each_with_index do |field, index| %>
59
- <%= render field.component_for_view(:show).new(field: field, resource: @resource, index: index) %>
60
- <% end %>
61
- <% end %>
62
- <% if has_many_panels.present? %>
63
- <% has_many_panels.each_with_index do |field, index| %>
64
- <%= render field.component_for_view(:show).new(field: field, resource: @resource, index: index) %>
65
- <% end %>
66
- <% end %>
67
- <% if has_as_belongs_to_many_panels.present? %>
68
- <% has_as_belongs_to_many_panels.each_with_index do |field, index| %>
69
- <%= render field.component_for_view(:show).new(field: field, resource: @resource, index: index) %>
70
- <% end %>
71
- <% end %>
72
- <% if resource_tools.present? %>
73
- <% resource_tools.each do |tool, index| %>
74
- <%= render tool.partial, tool: tool %>
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 %>
75
53
  <% end %>
76
54
  <% end %>
77
55
  <% end %>
@@ -15,6 +15,10 @@ class Avo::Views::ResourceEditComponent < Avo::ResourceComponent
15
15
  split_panel_fields
16
16
  end
17
17
 
18
+ def title
19
+ @resource.default_panel_name
20
+ end
21
+
18
22
  def back_path
19
23
  if via_resource?
20
24
  helpers.resource_path(model: params[:via_resource_class].safe_constantize, resource: relation_resource, resource_id: params[:via_resource_id])
@@ -32,7 +36,7 @@ class Avo::Views::ResourceEditComponent < Avo::ResourceComponent
32
36
  # The save button is dependent on the edit? policy method.
33
37
  # The update? method should be called only when the user clicks the Save button so the developer gets access to the params from the form.
34
38
  def can_see_the_save_button?
35
- @resource.authorization.authorize_action :edit, raise_exception: false
39
+ @resource.authorization.authorize_action @view, raise_exception: false
36
40
  end
37
41
 
38
42
  private
@@ -45,6 +49,12 @@ class Avo::Views::ResourceEditComponent < Avo::ResourceComponent
45
49
  view == :edit
46
50
  end
47
51
 
52
+ def form_method
53
+ return :put if is_edit?
54
+
55
+ :post
56
+ end
57
+
48
58
  def form_url
49
59
  if is_edit?
50
60
  helpers.resource_path(
@@ -34,10 +34,10 @@
34
34
  >
35
35
  <% if @resource.search_query.present? %>
36
36
  <div class="flex items-center px-4 w-64">
37
- <%= render partial: 'avo/partials/resource_search', locals: {resource: @resource.model_name.collection} %>
37
+ <%= render partial: 'avo/partials/resource_search', locals: {resource: @resource.route_key} %>
38
38
  </div>
39
39
  <% else %>
40
- <%# Offset for the space-y-2 property when the serach is missing %>
40
+ <%# Offset for the space-y-2 property when the search is missing %>
41
41
  <div class="-mb-2"></div>
42
42
  <% end %>
43
43
  <% if @filters.present? || available_view_types.count > 1 %>
@@ -113,11 +113,11 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
113
113
  end
114
114
  end
115
115
 
116
- helpers.new_resource_path(model: @resource.model_class, resource: @resource, **args)
116
+ helpers.new_resource_path(resource: @resource, **args)
117
117
  end
118
118
 
119
119
  def attach_path
120
- "#{Avo::App.root_path}#{request.env["PATH_INFO"]}/new"
120
+ Avo::App.root_path(paths: [request.env["PATH_INFO"], "new"])
121
121
  end
122
122
 
123
123
  def singular_resource_name
@@ -145,7 +145,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
145
145
  @reflection.active_record.to_s
146
146
  end
147
147
 
148
- def name
148
+ def name
149
149
  field.custom_name? ? field.name : field.plural_name
150
150
  end
151
151