avo 2.9.2.pre1 → 2.10.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +5 -7
- 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/date_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/date_time_field/edit_component.html.erb +10 -25
- data/app/components/avo/fields/date_time_field/index_component.html.erb +1 -9
- data/app/components/avo/fields/date_time_field/show_component.html.erb +1 -9
- data/app/components/avo/fields/edit_component.rb +5 -0
- data/app/components/avo/fields/show_component.rb +1 -1
- data/app/components/avo/index/ordering/button_component.rb +2 -12
- 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 +1 -1
- 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 +20 -3
- data/app/helpers/avo/application_helper.rb +0 -6
- data/app/helpers/avo/url_helpers.rb +1 -1
- data/app/javascript/avo.js +5 -1
- data/app/javascript/js/controllers/fields/date_field_controller.js +25 -87
- data/app/javascript/js/controllers/loading_button_controller.js +25 -21
- 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 +1 -1
- data/db/migrate/20210421064037_add_color_to_teams.rb +5 -0
- data/db/migrate/20210423075924_add_progress_to_projects.rb +5 -0
- data/db/migrate/20210525143134_add_slug_to_users.rb +6 -0
- data/lib/avo/app.rb +11 -4
- data/lib/avo/base_action.rb +2 -19
- data/lib/avo/base_card.rb +1 -7
- data/lib/avo/base_resource.rb +1 -95
- data/lib/avo/base_resource_tool.rb +3 -1
- data/lib/avo/concerns/handles_field_args.rb +1 -1
- data/lib/avo/concerns/has_fields.rb +247 -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/dashboards/base_dashboard.rb +1 -1
- data/lib/avo/dsl/field_parser.rb +83 -0
- data/lib/avo/fields/base_field.rb +19 -2
- data/lib/avo/fields/date_field.rb +2 -0
- data/lib/avo/fields/date_time_field.rb +9 -21
- data/lib/avo/fields/field_extensions/visible_in_different_views.rb +18 -1
- data/lib/avo/fields/has_base_field.rb +20 -1
- data/lib/avo/fields/has_one_field.rb +4 -1
- data/lib/avo/grid_collector.rb +6 -3
- data/lib/avo/items_holder.rb +68 -0
- data/lib/avo/licensing/h_q.rb +10 -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 +71 -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/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/public/avo-assets/avo.css +27 -3
- data/public/avo-assets/avo.js +77 -77
- data/public/avo-assets/avo.js.map +3 -3
- metadata +28 -13
- 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
@@ -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(
|
@@ -37,7 +37,7 @@
|
|
37
37
|
<%= render partial: 'avo/partials/resource_search', locals: {resource: @resource.model_name.collection} %>
|
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
|
|
@@ -1,105 +1,74 @@
|
|
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
|
-
<% if
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
} do %>
|
23
|
-
<%= t('avo.detach_item', item: title).capitalize %>
|
24
|
-
<% end %>
|
25
|
-
<%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
|
26
|
-
<% end %>
|
27
|
-
<% if can_see_the_edit_button? %>
|
28
|
-
<%= a_link edit_path,
|
29
|
-
color: :primary,
|
30
|
-
style: :primary,
|
31
|
-
icon: 'edit' do %>
|
32
|
-
<%= t('avo.edit').capitalize %>
|
33
|
-
<% end %>
|
34
|
-
<% end %>
|
35
|
-
<% else %>
|
36
|
-
<%= a_link back_path,
|
37
|
-
style: :text,
|
38
|
-
icon: 'arrow-left' do %>
|
39
|
-
<%= t('avo.go_back') %>
|
40
|
-
<% end %>
|
41
|
-
<% if can_see_the_destroy_button? %>
|
42
|
-
<%= a_button url: helpers.resource_path(model: @resource.model, resource: @resource),
|
43
|
-
method: :delete,
|
44
|
-
local: true,
|
45
|
-
style: :text,
|
46
|
-
title: t('avo.delete_item', item: @resource.model.model_name.name.downcase).capitalize,
|
47
|
-
loading: true,
|
48
|
-
confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
|
49
|
-
color: :red,
|
50
|
-
icon: 'trash',
|
51
|
-
form_class: 'flex flex-col sm:flex-row sm:inline-flex',
|
52
|
-
data: {
|
53
|
-
control: :destroy,
|
54
|
-
'resource-id': @resource.model.id,
|
55
|
-
'tippy': 'tooltip',
|
56
|
-
} do %>
|
57
|
-
<%= t('avo.delete').capitalize %>
|
58
|
-
<% end %>
|
59
|
-
<% end %>
|
60
|
-
<%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
|
61
|
-
<% if @resource.authorization.authorize_action(:edit, raise_exception: false) %>
|
62
|
-
<%= a_link edit_path,
|
63
|
-
color: :primary,
|
64
|
-
style: :primary,
|
65
|
-
icon: 'edit' do %>
|
66
|
-
<%= t('avo.edit').capitalize %>
|
67
|
-
<% end %>
|
68
|
-
<% end %>
|
8
|
+
<%= render Avo::PanelComponent.new(title: title, description: @resource.resource_description, display_breadcrumbs: @reflection.blank?, index: 0, data: { panel_id: "main" }) do |c| %>
|
9
|
+
<% c.tools do %>
|
10
|
+
<% if @reflection.present? && @resource.model.present? %>
|
11
|
+
<% if can_detach? %>
|
12
|
+
<%= a_button url: detach_path,
|
13
|
+
icon: 'detach',
|
14
|
+
method: :delete,
|
15
|
+
form_class: 'flex flex-col sm:flex-row sm:inline-flex',
|
16
|
+
style: :text,
|
17
|
+
data: {
|
18
|
+
confirm: "Are you sure you want to detach this #{title}."
|
19
|
+
} do %>
|
20
|
+
<%= t('avo.detach_item', item: title).capitalize %>
|
69
21
|
<% end %>
|
22
|
+
<%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
|
70
23
|
<% end %>
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
24
|
+
<% if can_see_the_edit_button? %>
|
25
|
+
<%= a_link edit_path,
|
26
|
+
color: :primary,
|
27
|
+
style: :primary,
|
28
|
+
icon: 'edit' do %>
|
29
|
+
<%= t('avo.edit').capitalize %>
|
30
|
+
<% end %>
|
31
|
+
<% end %>
|
32
|
+
<% else %>
|
33
|
+
<%= a_link back_path,
|
34
|
+
style: :text,
|
35
|
+
icon: 'arrow-left' do %>
|
36
|
+
<%= t('avo.go_back') %>
|
37
|
+
<% end %>
|
38
|
+
<% if can_see_the_destroy_button? %>
|
39
|
+
<%= a_button url: helpers.resource_path(model: @resource.model, resource: @resource),
|
40
|
+
method: :delete,
|
41
|
+
local: true,
|
42
|
+
style: :text,
|
43
|
+
loading: true,
|
44
|
+
confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
|
45
|
+
color: :red,
|
46
|
+
icon: 'trash',
|
47
|
+
form_class: 'flex flex-col sm:flex-row sm:inline-flex',
|
48
|
+
data: {
|
49
|
+
control: :destroy,
|
50
|
+
'resource-id': @resource.model.id,
|
51
|
+
'tippy': 'tooltip',
|
52
|
+
} do %>
|
53
|
+
<%= t('avo.delete').capitalize %>
|
54
|
+
<% end %>
|
55
|
+
<% end %>
|
56
|
+
<%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
|
57
|
+
<% if @resource.authorization.authorize_action(:edit, raise_exception: false) %>
|
58
|
+
<%= a_link edit_path,
|
59
|
+
color: :primary,
|
60
|
+
style: :primary,
|
61
|
+
icon: 'edit' do %>
|
62
|
+
<%= t('avo.edit').capitalize %>
|
63
|
+
<% end %>
|
79
64
|
<% end %>
|
80
65
|
<% end %>
|
81
66
|
<% end %>
|
82
67
|
<% end %>
|
83
|
-
|
84
|
-
<%
|
85
|
-
<%
|
86
|
-
|
87
|
-
<% end %>
|
88
|
-
<% end %>
|
89
|
-
<% if has_many_panels.present? %>
|
90
|
-
<% has_many_panels.each_with_index do |field, index| %>
|
91
|
-
<%= render field.component_for_view(:show).new(field: field, resource: @resource, index: index) %>
|
92
|
-
<% end %>
|
93
|
-
<% end %>
|
94
|
-
<% if has_as_belongs_to_many_panels.present? %>
|
95
|
-
<% has_as_belongs_to_many_panels.each_with_index do |field, index| %>
|
96
|
-
<%= render field.component_for_view(:show).new(field: field, resource: @resource, index: index) %>
|
97
|
-
<% end %>
|
98
|
-
<% end %>
|
99
|
-
<% if resource_tools.present? %>
|
100
|
-
<% resource_tools.each do |tool, index| %>
|
101
|
-
<%= render tool.partial, tool: tool %>
|
102
|
-
<% end %>
|
68
|
+
<%= content_tag :div, class: 'space-y-12' do %>
|
69
|
+
<% @resource.get_items.each_with_index do |item, index| %>
|
70
|
+
<% next if item.nil? %>
|
71
|
+
<%= render Avo::ItemSwitcherComponent.new resource: @resource, reflection: @reflection, item: item, index: index + 1, view: @view %>
|
103
72
|
<% end %>
|
104
73
|
<% end %>
|
105
74
|
<% if should_display_invalid_fields_errors? %>
|
@@ -19,7 +19,7 @@ class Avo::Views::ResourceShowComponent < Avo::ResourceComponent
|
|
19
19
|
return field.name if has_one_field?
|
20
20
|
reflection_resource.name
|
21
21
|
else
|
22
|
-
@resource.
|
22
|
+
@resource.default_panel_name
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -52,6 +52,6 @@ class Avo::Views::ResourceShowComponent < Avo::ResourceComponent
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def has_one_field?
|
55
|
-
field.present? and field.
|
55
|
+
field.present? and field.instance_of? Avo::Fields::HasOneField
|
56
56
|
end
|
57
57
|
end
|
@@ -42,7 +42,7 @@ module Avo
|
|
42
42
|
model = @resource.class.find_scope.find params[:id]
|
43
43
|
end
|
44
44
|
|
45
|
-
@action = action_class.new(model: model, resource: resource, user: _current_user)
|
45
|
+
@action = action_class.new(model: model, resource: resource, user: _current_user, view: :edit)
|
46
46
|
end
|
47
47
|
|
48
48
|
def respond(response)
|
@@ -13,7 +13,8 @@ module Avo
|
|
13
13
|
protect_from_forgery with: :exception
|
14
14
|
before_action :init_app
|
15
15
|
before_action :check_avo_license
|
16
|
-
before_action :
|
16
|
+
before_action :set_default_locale
|
17
|
+
around_action :set_force_locale, if: -> { params[:force_locale].present? }
|
17
18
|
before_action :set_authorization
|
18
19
|
before_action :_authenticate!
|
19
20
|
before_action :set_container_classes
|
@@ -27,7 +28,7 @@ module Avo
|
|
27
28
|
add_flash_types :info, :warning, :success, :error
|
28
29
|
|
29
30
|
def init_app
|
30
|
-
Avo::App.init request: request, context: context,
|
31
|
+
Avo::App.init request: request, context: context, current_user: _current_user, view_context: view_context, params: params
|
31
32
|
|
32
33
|
@license = Avo::App.license
|
33
34
|
end
|
@@ -287,10 +288,26 @@ module Avo
|
|
287
288
|
@resource.form_scope
|
288
289
|
end
|
289
290
|
|
290
|
-
def
|
291
|
+
def set_default_locale
|
291
292
|
I18n.locale = params[:set_locale] || I18n.default_locale
|
292
293
|
|
293
294
|
I18n.default_locale = I18n.locale
|
294
295
|
end
|
296
|
+
|
297
|
+
# Temporary set the locale and reverting at the end of the request.
|
298
|
+
def set_force_locale
|
299
|
+
initial_locale = I18n.locale.to_s.dup
|
300
|
+
I18n.locale = params[:force_locale]
|
301
|
+
yield
|
302
|
+
I18n.locale = initial_locale
|
303
|
+
end
|
304
|
+
|
305
|
+
def default_url_options
|
306
|
+
if params[:force_locale].present?
|
307
|
+
{ **super, force_locale: params[:force_locale] }
|
308
|
+
else
|
309
|
+
super
|
310
|
+
end
|
311
|
+
end
|
295
312
|
end
|
296
313
|
end
|
@@ -20,12 +20,6 @@ module Avo
|
|
20
20
|
render Avo::EmptyStateComponent.new **args
|
21
21
|
end
|
22
22
|
|
23
|
-
def turbo_frame_wrap(name, &block)
|
24
|
-
render Avo::TurboFrameWrapperComponent.new name do
|
25
|
-
capture(&block)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
23
|
def a_button(**args, &block)
|
30
24
|
render Avo::ButtonComponent.new(is_link: false, **args) do
|
31
25
|
capture(&block) if block_given?
|
@@ -35,7 +35,7 @@ module Avo
|
|
35
35
|
avo.send :"resources_#{resource.singular_route_key}_path", id, **args
|
36
36
|
end
|
37
37
|
|
38
|
-
def new_resource_path(
|
38
|
+
def new_resource_path(resource:, **args)
|
39
39
|
avo.send :"new_resources_#{resource.singular_route_key}_path", **args
|
40
40
|
end
|
41
41
|
|
data/app/javascript/avo.js
CHANGED
@@ -74,7 +74,11 @@ document.addEventListener('turbo:frame-load', () => {
|
|
74
74
|
document.addEventListener('turbo:before-fetch-response', async (e) => {
|
75
75
|
if (e.detail.fetchResponse.response.status === 500) {
|
76
76
|
const { id, src } = e.target
|
77
|
-
|
77
|
+
// Don't try to redirect to failed to load if this is alread a redirection to failed to load and crashed somewhere.
|
78
|
+
// You'll end up with a request loop.
|
79
|
+
if (!e.detail.fetchResponse?.response?.url?.includes('/failed_to_load')) {
|
80
|
+
e.target.src = `${window.Avo.configuration.root_path}/failed_to_load?turbo_frame=${id}&src=${src}`
|
81
|
+
}
|
78
82
|
}
|
79
83
|
})
|
80
84
|
|