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.
- checksums.yaml +4 -4
- data/Gemfile.lock +69 -69
- data/README.md +4 -0
- data/app/assets/stylesheets/css/buttons.css +4 -1
- data/app/components/avo/actions_component.rb +6 -2
- data/app/components/avo/base_component.rb +2 -0
- data/app/components/avo/button_component.rb +3 -1
- data/app/components/avo/fields/common/key_value_component.html.erb +2 -2
- data/app/components/avo/fields/common/single_file_viewer_component.rb +1 -1
- data/app/components/avo/fields/country_field/edit_component.html.erb +9 -3
- data/app/components/avo/fields/date_field/edit_component.html.erb +26 -7
- data/app/components/avo/fields/date_field/index_component.html.erb +7 -1
- data/app/components/avo/fields/date_field/show_component.html.erb +7 -1
- data/app/components/avo/fields/date_time_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/edit_component.rb +5 -0
- data/app/components/avo/fields/file_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/files_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/select_field/edit_component.html.erb +14 -10
- data/app/components/avo/fields/show_component.rb +1 -1
- data/app/components/avo/index/ordering/button_component.rb +1 -15
- data/app/components/avo/index/resource_controls_component.html.erb +2 -2
- data/app/components/avo/index/resource_controls_component.rb +5 -1
- data/app/components/avo/index/resource_table_component.html.erb +1 -1
- data/app/components/avo/index/table_row_component.html.erb +1 -1
- data/app/components/avo/item_switcher_component.html.erb +19 -0
- data/app/components/avo/item_switcher_component.rb +45 -0
- data/app/components/avo/panel_component.html.erb +23 -24
- data/app/components/avo/panel_component.rb +8 -5
- data/app/components/avo/tab_group_component.html.erb +53 -0
- data/app/components/avo/tab_group_component.rb +51 -0
- data/app/components/avo/tab_switcher_component.html.erb +21 -0
- data/app/components/avo/tab_switcher_component.rb +86 -0
- data/app/components/avo/views/resource_edit_component.html.erb +34 -56
- data/app/components/avo/views/resource_edit_component.rb +11 -1
- data/app/components/avo/views/resource_index_component.html.erb +2 -2
- data/app/components/avo/views/resource_index_component.rb +3 -3
- data/app/components/avo/views/resource_show_component.html.erb +58 -89
- data/app/components/avo/views/resource_show_component.rb +2 -2
- data/app/controllers/avo/actions_controller.rb +1 -1
- data/app/controllers/avo/application_controller.rb +33 -10
- data/app/controllers/avo/base_controller.rb +11 -3
- data/app/controllers/avo/reorder_controller.rb +25 -0
- data/app/helpers/avo/application_helper.rb +6 -6
- data/app/helpers/avo/url_helpers.rb +1 -5
- data/app/javascript/avo.js +5 -1
- data/app/javascript/js/controllers/fields/date_field_controller.js +15 -3
- data/app/javascript/js/controllers/loading_button_controller.js +25 -21
- data/app/javascript/js/controllers/search_controller.js +3 -0
- data/app/javascript/js/controllers/tabs_controller.js +86 -0
- data/app/javascript/js/controllers.js +2 -0
- data/app/views/avo/base/index.html.erb +1 -1
- data/app/views/avo/base/show.html.erb +1 -1
- data/app/views/avo/cards/show.html.erb +1 -1
- data/app/views/avo/debug/index.html.erb +1 -1
- data/app/views/avo/home/_actions.html.erb +1 -1
- data/app/views/avo/home/_dashboards.html.erb +19 -0
- data/app/views/avo/home/_filters.html.erb +1 -1
- data/app/views/avo/home/_resources.html.erb +1 -1
- data/app/views/avo/home/failed_to_load.html.erb +1 -1
- data/app/views/avo/home/index.html.erb +14 -2
- data/app/views/avo/partials/_javascript.html.erb +1 -1
- data/app/views/avo/partials/_tabs_toggle.html.erb +20 -0
- data/app/views/avo/private/design.html.erb +1 -1
- data/config/routes.rb +5 -4
- data/db/factories.rb +1 -0
- data/lib/avo/app.rb +12 -7
- data/lib/avo/base_action.rb +2 -19
- data/lib/avo/base_card.rb +1 -7
- data/lib/avo/base_resource.rb +6 -98
- data/lib/avo/base_resource_tool.rb +3 -1
- data/lib/avo/concerns/has_fields.rb +249 -50
- data/lib/avo/concerns/has_html_attributes.rb +1 -1
- data/lib/avo/concerns/is_resource_item.rb +36 -0
- data/lib/avo/concerns/model_class_constantized.rb +23 -0
- data/lib/avo/configuration.rb +2 -12
- data/lib/avo/dashboards/base_dashboard.rb +1 -1
- data/lib/avo/dsl/field_parser.rb +83 -0
- data/lib/avo/fields/base_field.rb +21 -2
- data/lib/avo/fields/country_field.rb +2 -0
- data/lib/avo/fields/date_field.rb +13 -9
- data/lib/avo/fields/field_extensions/has_include_blank.rb +17 -0
- data/lib/avo/fields/field_extensions/visible_in_different_views.rb +18 -1
- data/lib/avo/fields/file_field.rb +2 -0
- data/lib/avo/fields/files_field.rb +2 -0
- data/lib/avo/fields/has_base_field.rb +20 -1
- data/lib/avo/fields/has_one_field.rb +4 -1
- data/lib/avo/fields/key_value_field.rb +4 -4
- data/lib/avo/fields/select_field.rb +2 -0
- data/lib/avo/grid_collector.rb +6 -3
- data/lib/avo/items_holder.rb +68 -0
- data/lib/avo/licensing/h_q.rb +12 -0
- data/lib/avo/main_panel.rb +3 -0
- data/lib/avo/menu/builder.rb +8 -7
- data/lib/avo/panel.rb +25 -0
- data/lib/avo/panel_builder.rb +23 -0
- data/lib/avo/services/uri_service.rb +75 -0
- data/lib/avo/tab.rb +78 -0
- data/lib/avo/tab_builder.rb +25 -0
- data/lib/avo/tab_group.rb +40 -0
- data/lib/avo/tab_group_builder.rb +43 -0
- data/lib/avo/version.rb +1 -1
- data/lib/avo.rb +1 -0
- data/lib/generators/avo/action_generator.rb +3 -2
- data/lib/generators/avo/base_generator.rb +14 -0
- data/lib/generators/avo/card/chartkick_generator.rb +18 -0
- data/lib/generators/avo/card/metric_generator.rb +18 -0
- data/lib/generators/avo/card/partial_generator.rb +19 -0
- data/lib/generators/avo/controller_generator.rb +9 -3
- data/lib/generators/avo/dashboard_generator.rb +2 -2
- data/lib/generators/avo/eject_generator.rb +2 -3
- data/lib/generators/avo/field_generator.rb +2 -2
- data/lib/generators/avo/filter_generator.rb +3 -2
- data/lib/generators/avo/install_generator.rb +2 -2
- data/lib/generators/avo/locales_generator.rb +2 -2
- data/lib/generators/avo/named_base_generator.rb +14 -0
- data/lib/generators/avo/resource_generator.rb +2 -2
- data/lib/generators/avo/resource_tool_generator.rb +4 -4
- data/lib/generators/avo/templates/locales/avo.fr.yml +115 -0
- data/lib/generators/avo/templates/resource/controller.tt +2 -0
- data/lib/generators/avo/templates/resource_tools/partial.tt +1 -1
- data/lib/generators/avo/templates/tool/view.tt +1 -1
- data/lib/generators/avo/tool_generator.rb +4 -4
- data/lib/generators/avo/version_generator.rb +23 -0
- data/public/avo-assets/avo.css +31 -3
- data/public/avo-assets/avo.js +72 -72
- data/public/avo-assets/avo.js.map +3 -3
- metadata +32 -16
- data/app/assets/builds/action_cable.js +0 -2
- data/app/assets/builds/action_cable.js.map +0 -7
- data/app/assets/builds/application.js +0 -2
- data/app/assets/builds/application.js.map +0 -7
- data/app/assets/builds/avo.css +0 -9028
- data/app/assets/builds/avo.js +0 -512
- data/app/assets/builds/avo.js.map +0 -7
- data/app/assets/builds/avo_custom.js +0 -6
- data/app/assets/builds/avo_custom.js.map +0 -7
- data/lib/avo/concerns/has_tools.rb +0 -47
- data/lib/avo/fields/currency_field.rb +0 -15
- data/lib/generators/avo/chartkick_card_generator.rb +0 -16
- data/lib/generators/avo/metric_card_generator.rb +0 -16
- 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
|
-
|
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><%= @
|
11
|
+
<span><%= @name %></span>
|
13
12
|
</div>
|
14
|
-
|
15
13
|
<% if description.present? %>
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
<%
|
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
|
-
|
47
|
-
|
48
|
-
|
43
|
+
<% if footer? %>
|
44
|
+
<div class="flex justify-end w-full">
|
45
|
+
<div>
|
46
|
+
<%= footer %>
|
47
|
+
</div>
|
49
48
|
</div>
|
50
|
-
|
51
|
-
|
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
|
-
@
|
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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
31
|
-
<% end %>
|
32
|
+
<%= t('avo.save').capitalize %>
|
32
33
|
<% end %>
|
33
34
|
<% end %>
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
45
|
+
<% end %>
|
52
46
|
<% end %>
|
53
47
|
<% end %>
|
54
48
|
<% end %>
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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
|
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.
|
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
|
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(
|
116
|
+
helpers.new_resource_path(resource: @resource, **args)
|
117
117
|
end
|
118
118
|
|
119
119
|
def attach_path
|
120
|
-
|
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
|
|