avo 2.0.0 → 2.1.2.pre1
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 +1 -1
- data/Gemfile.lock +3 -3
- data/app/assets/builds/avo.css +8810 -0
- data/app/assets/builds/avo.js +423 -0
- data/app/assets/builds/avo.js.map +7 -0
- data/app/assets/stylesheets/avo.css +1 -1
- data/app/assets/svgs/save.svg +8 -1
- data/app/components/avo/actions_component.html.erb +1 -1
- data/app/components/avo/alert_component.html.erb +1 -1
- data/app/components/avo/alert_component.rb +6 -6
- data/app/components/avo/blank_field_component.html.erb +0 -0
- data/app/components/avo/blank_field_component.rb +4 -0
- data/app/components/avo/card_component.html.erb +7 -2
- data/app/components/avo/fields/badge_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/boolean_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/external_image_field/index_component.html.erb +1 -2
- data/app/components/avo/fields/file_field/index_component.html.erb +3 -3
- data/app/components/avo/fields/file_field/index_component.rb +11 -0
- data/app/components/avo/fields/gravatar_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/progress_bar_field/index_component.html.erb +1 -1
- data/app/components/avo/index/field_wrapper_component.html.erb +1 -1
- data/app/components/avo/index/field_wrapper_component.rb +12 -1
- data/app/components/avo/index/resource_controls_component.html.erb +5 -1
- data/app/components/avo/index/resource_table_component.html.erb +1 -1
- data/app/components/avo/panel_component.html.erb +15 -5
- data/app/components/avo/panel_component.rb +9 -0
- data/app/components/avo/referrer_params_component.html.erb +4 -0
- data/app/components/avo/referrer_params_component.rb +9 -0
- data/app/components/avo/sidebar_component.html.erb +2 -0
- data/app/components/avo/sidebar_component.rb +3 -1
- data/app/components/avo/views/resource_edit_component.html.erb +14 -1
- data/app/components/avo/views/resource_new_component.html.erb +13 -0
- data/app/components/avo/views/resource_show_component.html.erb +11 -0
- data/app/components/avo/views/resource_show_component.rb +5 -0
- data/app/controllers/avo/application_controller.rb +1 -1
- data/app/controllers/avo/base_controller.rb +87 -37
- data/app/controllers/avo/dashboards_controller.rb +2 -6
- data/app/controllers/avo/search_controller.rb +5 -1
- data/app/helpers/avo/url_helpers.rb +6 -2
- data/app/javascript/avo.js +4 -3
- data/app/views/avo/actions/show.html.erb +1 -0
- data/app/views/avo/associations/new.html.erb +1 -0
- data/app/views/avo/dashboards/show.html.erb +4 -1
- data/app/views/avo/home/failed_to_load.html.erb +21 -1
- data/app/views/avo/partials/_sidebar_extra.html.erb +0 -0
- data/app/views/layouts/avo/application.html.erb +7 -0
- data/bin/dev +7 -6
- data/lib/avo/app.rb +8 -1
- data/lib/avo/base_action.rb +5 -4
- data/lib/avo/base_card.rb +175 -0
- data/lib/avo/base_resource.rb +34 -8
- data/lib/avo/configuration.rb +2 -0
- data/lib/avo/dashboards/base_dashboard.rb +37 -2
- data/lib/avo/dashboards/base_divider.rb +3 -1
- data/lib/avo/dashboards/chartkick_card.rb +1 -1
- data/lib/avo/dashboards/dashboard_card.rb +6 -0
- data/lib/avo/dashboards/partial_card.rb +1 -1
- data/lib/avo/fields/base_field.rb +19 -6
- data/lib/avo/fields/belongs_to_field.rb +1 -1
- data/lib/avo/fields/date_field.rb +1 -1
- data/lib/avo/fields/external_image_field.rb +2 -2
- data/lib/avo/fields_collector.rb +7 -2
- data/lib/avo/hosts/dashboard_card.rb +1 -0
- data/lib/avo/hosts/dashboard_visibility.rb +19 -0
- data/lib/avo/licensing/pro_license.rb +1 -0
- data/lib/avo/version.rb +1 -1
- data/lib/generators/avo/templates/dashboards/dashboard.tt +4 -1
- data/public/avo-assets/avo.css +55 -34
- data/public/avo-assets/avo.js +166 -165
- data/public/avo-assets/avo.js.map +3 -3
- metadata +15 -6
- data/app/views/avo/partials/_failed_state.html.erb +0 -16
- data/lib/avo/dashboards/base_card.rb +0 -151
data/app/assets/svgs/save.svg
CHANGED
@@ -1 +1,8 @@
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0
|
1
|
+
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 515 450" style="enable-background:new 0 0 515 450;" xml:space="preserve">
|
2
|
+
<path d="M438.4,116.4l-72.3-72.3c-7.8-7.8-18.3-12.1-29.2-12.1h-231C83,32,64.5,50.5,64.5,73.4v303.3c0,22.8,18.5,41.4,41.4,41.4
|
3
|
+
h303.3c22.8,0,41.4-18.5,41.4-41.4v-231C450.5,134.7,446.1,124.1,438.4,116.4L438.4,116.4z M298.9,73.4v68.9H188.6V73.4H298.9z
|
4
|
+
M404,376.6H111c-2.9,0-5.2-2.3-5.2-5.2V78.5c0-2.9,2.3-5.2,5.2-5.2h36.2V163c0,11.4,9.3,20.7,20.7,20.7h151.6
|
5
|
+
c11.4,0,20.7-9.3,20.7-20.7V76.7l67.4,67.4c1,1,1.5,2.3,1.5,3.7v223.7C409.1,374.3,406.8,376.6,404,376.6L404,376.6z M257.5,204.3
|
6
|
+
c-41.8,0-75.8,34-75.8,75.8s34,75.8,75.8,75.8s75.8-34,75.8-75.8S299.3,204.3,257.5,204.3z M257.5,314.6c-19,0-34.5-15.5-34.5-34.5
|
7
|
+
s15.5-34.5,34.5-34.5s34.5,15.5,34.5,34.5S276.5,314.6,257.5,314.6z"/>
|
8
|
+
</svg>
|
@@ -12,7 +12,7 @@
|
|
12
12
|
<%= t 'avo.actions' %>
|
13
13
|
<% end %>
|
14
14
|
<div
|
15
|
-
class="absolute flex inset-auto right-0 top-full bg-white w-full sm:w-auto sm:min-w-[300px] mt-2 z-20 shadow-modal rounded overflow-hidden hidden"
|
15
|
+
class="absolute flex inset-auto xl:right-0 top-full bg-white w-full sm:w-auto sm:min-w-[300px] mt-2 z-20 shadow-modal rounded overflow-hidden hidden"
|
16
16
|
data-toggle-panel-target="panel"
|
17
17
|
>
|
18
18
|
<div class="w-full space divide-y">
|
@@ -12,18 +12,18 @@ class Avo::AlertComponent < ViewComponent::Base
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def icon
|
15
|
-
return
|
15
|
+
return "x-circle" if is_error?
|
16
16
|
|
17
|
-
|
17
|
+
"check-circle"
|
18
18
|
end
|
19
19
|
|
20
20
|
def classes
|
21
|
-
result = "max-w-
|
21
|
+
result = "max-w-lg w-full shadow-lg rounded px-4 py-3 rounded relative border text-white pointer-events-auto"
|
22
22
|
|
23
|
-
if is_error?
|
24
|
-
|
23
|
+
result += if is_error?
|
24
|
+
" bg-red-400 border-red-700"
|
25
25
|
else
|
26
|
-
|
26
|
+
" bg-green-400 border-green-700"
|
27
27
|
end
|
28
28
|
|
29
29
|
result
|
File without changes
|
@@ -1,4 +1,9 @@
|
|
1
|
-
<div class="relative flex-1 flex flex-col justify-between h-full"
|
1
|
+
<div class="relative flex-1 flex flex-col justify-between h-full"
|
2
|
+
data-controller="dashboard-card"
|
3
|
+
data-dashboard-card-target="card"
|
4
|
+
data-refresh-every="<%= @card.refresh_every %>"
|
5
|
+
data-card-id="<%= @card.id %>"
|
6
|
+
data-card-index="<%= @card.index %>">
|
2
7
|
<% if @card.class.display_header %>
|
3
8
|
<div class="px-4 pt-4">
|
4
9
|
<div class="flex justify-between items-center min-h-6">
|
@@ -7,7 +12,7 @@
|
|
7
12
|
</div>
|
8
13
|
<div data-controller="select">
|
9
14
|
<% if @card.type == :metric && @card.parsed_ranges.present? %>
|
10
|
-
<%= select_tag "#{@card.id}_range", options_for_select(@card.parsed_ranges, @card.range),
|
15
|
+
<%= select_tag "#{@card.id}_#{@card.index}_range", options_for_select(@card.parsed_ranges, @card.range),
|
11
16
|
class: 'appearance-none inline-flex bg-blue-gray-100 disabled:bg-blue-gray-300 disabled:cursor-not-allowed focus:bg-white text-sm text-blue-gray-700 disabled:text-blue-gray-700 leading-none rounded-md py-px px-2 leading-tight border outline-none outline w-24',
|
12
17
|
data: {
|
13
18
|
target: 'select',
|
@@ -1,3 +1,3 @@
|
|
1
|
-
<%= index_field_wrapper field: @field, dash_if_blank: false, center_content: true do %>
|
1
|
+
<%= index_field_wrapper field: @field, dash_if_blank: false, center_content: true, flush: true do %>
|
2
2
|
<%= render Avo::Fields::Common::BooleanCheckComponent.new checked: @field.value %>
|
3
3
|
<% end %>
|
@@ -1,8 +1,7 @@
|
|
1
|
-
<%= index_field_wrapper field: @field do %>
|
1
|
+
<%= index_field_wrapper field: @field, flush: true do %>
|
2
2
|
<% if @field.value.present? %>
|
3
3
|
<%= image_tag @field.value,
|
4
4
|
height: @field.height,
|
5
|
-
width: @field.width,
|
6
5
|
style: "border-radius: #{@field.radius}px; max-height: #{@field.height}#{@field.height.to_s&.ends_with?('px') ? '' : 'px'};"
|
7
6
|
%>
|
8
7
|
<% end %>
|
@@ -1,9 +1,9 @@
|
|
1
|
-
<%= index_field_wrapper field: @field do %>
|
1
|
+
<%= index_field_wrapper field: @field, flush: flush? do %>
|
2
2
|
<% if @field.value.present? %>
|
3
3
|
<% if @field.value.attached? && @field.value.representable? && @field.is_image %>
|
4
|
-
<%= link_to_if @field.link_to_resource, image_tag(helpers.main_app.url_for(@field.value), class: '
|
4
|
+
<%= link_to_if @field.link_to_resource, image_tag(helpers.main_app.url_for(@field.value), class: 'h-10'), resource_path, class: 'block' %>
|
5
5
|
<% elsif @field.value.attached? && @field.is_audio %>
|
6
|
-
<%= link_to_if @field.link_to_resource, audio_tag(helpers.main_app.url_for(@field.value), controls: true, preload: false, class: 'max-h-full'), resource_path, class: 'block h-8' %>
|
6
|
+
<%= link_to_if @field.link_to_resource, audio_tag(helpers.main_app.url_for(@field.value), controls: true, preload: false, class: 'max-h-full h-10'), resource_path, class: 'block h-8' %>
|
7
7
|
<% else %>
|
8
8
|
<%= @field.value.filename %>
|
9
9
|
<% end %>
|
@@ -1,4 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Avo::Fields::FileField::IndexComponent < Avo::Fields::IndexComponent
|
4
|
+
def flush?
|
5
|
+
has_image_tag? || has_audio_tag?
|
6
|
+
end
|
7
|
+
|
8
|
+
def has_image_tag?
|
9
|
+
@field.value.attached? && @field.value.representable? && @field.is_image
|
10
|
+
end
|
11
|
+
|
12
|
+
def has_audio_tag?
|
13
|
+
@field.value.attached? && @field.is_audio
|
14
|
+
end
|
4
15
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<%= index_field_wrapper field: @field do %>
|
1
|
+
<%= index_field_wrapper field: @field, flush: true do %>
|
2
2
|
<% if @field.display_value %>
|
3
3
|
<div class="text-center text-sm font-semibold w-full leading-none mb-1">
|
4
4
|
<%= @field.value %><%= @field.value_suffix if @field.value_suffix.present? %>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<td class="min-h-[3rem] px-
|
1
|
+
<td class="min-h-[3rem] px-3 leading-tight whitespace-nowrap h-full text-slate-800 <%= classes %>" data-field-id="<%= @field.id %>" data-field-type="<%= @field.type %>">
|
2
2
|
<% if @field.value.blank? && @dash_if_blank %>
|
3
3
|
—
|
4
4
|
<% else %>
|
@@ -1,11 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Avo::Index::FieldWrapperComponent < ViewComponent::Base
|
4
|
-
def initialize(field: nil, dash_if_blank: true, center_content: false, **args)
|
4
|
+
def initialize(field: nil, dash_if_blank: true, center_content: false, flush: false, **args)
|
5
5
|
@field = field
|
6
6
|
@dash_if_blank = dash_if_blank
|
7
7
|
@center_content = center_content
|
8
8
|
@classes = args[:class].present? ? args[:class] : ""
|
9
9
|
@args = args
|
10
|
+
@flush = flush
|
11
|
+
end
|
12
|
+
|
13
|
+
def classes
|
14
|
+
result = @classes
|
15
|
+
|
16
|
+
unless @flush
|
17
|
+
result += " py-3"
|
18
|
+
end
|
19
|
+
|
20
|
+
result
|
10
21
|
end
|
11
22
|
end
|
@@ -28,7 +28,10 @@
|
|
28
28
|
<% end %>
|
29
29
|
|
30
30
|
<% if can_detach? %>
|
31
|
-
<%= form_with url: helpers.resource_detach_path(params[:resource_name], params[:id], params[:related_name], @resource.model.id),
|
31
|
+
<%= form_with url: helpers.resource_detach_path(params[:resource_name], params[:id], params[:related_name], @resource.model.id),
|
32
|
+
method: :delete,
|
33
|
+
local: true,
|
34
|
+
html: {
|
32
35
|
'data-turbo-frame': params[:turbo_frame]
|
33
36
|
} do |form| %>
|
34
37
|
<%= form.button helpers.svg('detach', class: button_classes),
|
@@ -51,6 +54,7 @@
|
|
51
54
|
<%= form_with url: helpers.resource_path(model: @resource.model, resource: @resource),
|
52
55
|
method: :delete,
|
53
56
|
class: 'flex items-center',
|
57
|
+
local: true,
|
54
58
|
html: {
|
55
59
|
'data-turbo-frame': params[:turbo_frame]
|
56
60
|
} do |form| %>
|
@@ -3,7 +3,7 @@
|
|
3
3
|
<%= render partial: 'avo/partials/table_header', locals: {fields: @resource.get_fields(reflection: @reflection)} %>
|
4
4
|
<tbody class="divide-y">
|
5
5
|
<% @resources.each_with_index do |resource, index| %>
|
6
|
-
<% cache_if Avo.configuration.cache_resources_on_index_view, resource.cache_hash(@parent_model) do %>
|
6
|
+
<% cache_if Avo.configuration.cache_resources_on_index_view, resource.cache_hash(@parent_model), expires_in: 1.day do %>
|
7
7
|
<%= render Avo::Index::TableRowComponent.new(resource: resource, reflection: @reflection, parent_model: @parent_model) %>
|
8
8
|
<% end %>
|
9
9
|
<% end %>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<div <%== data_attributes %>>
|
2
2
|
<% if render_header? %>
|
3
|
-
<div class="
|
3
|
+
<div class="<%= white_panel_classes %> p-4 flex-1 flex flex-col xl:flex-row justify-between mb-6">
|
4
4
|
<div class="overflow-hidden mr-4">
|
5
5
|
<% if display_breadcrumbs? %>
|
6
6
|
<div class="breadcrumbs truncate mb-2">
|
@@ -19,13 +19,15 @@
|
|
19
19
|
<% end %>
|
20
20
|
</div>
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
<% if tools.present? %>
|
23
|
+
<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
|
+
<%= tools %>
|
25
|
+
</div>
|
26
|
+
<% end %>
|
25
27
|
</div>
|
26
28
|
<% end %>
|
27
29
|
|
28
|
-
<div class="relative
|
30
|
+
<div class="relative <%= white_panel_classes %> <%= @body_classes %>">
|
29
31
|
<%= body %>
|
30
32
|
</div>
|
31
33
|
|
@@ -33,6 +35,14 @@
|
|
33
35
|
<%= bare_content %>
|
34
36
|
</div>
|
35
37
|
|
38
|
+
<% if footer_tools.present? %>
|
39
|
+
<div class="<%= white_panel_classes %> p-4 flex-1 flex flex-col xl:flex-row justify-between mt-6">
|
40
|
+
<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
|
+
<%= footer_tools %>
|
42
|
+
</div>
|
43
|
+
</div>
|
44
|
+
<% end %>
|
45
|
+
|
36
46
|
<div class="flex justify-end w-full">
|
37
47
|
<div>
|
38
48
|
<%= footer %>
|
@@ -6,6 +6,7 @@ class Avo::PanelComponent < ViewComponent::Base
|
|
6
6
|
renders_one :tools
|
7
7
|
renders_one :body
|
8
8
|
renders_one :bare_content
|
9
|
+
renders_one :footer_tools
|
9
10
|
renders_one :footer
|
10
11
|
|
11
12
|
def initialize(title: nil, description: nil, body_classes: nil, data: {}, display_breadcrumbs: false, index: nil)
|
@@ -19,6 +20,10 @@ class Avo::PanelComponent < ViewComponent::Base
|
|
19
20
|
|
20
21
|
private
|
21
22
|
|
23
|
+
def white_panel_classes
|
24
|
+
'bg-white rounded shadow'
|
25
|
+
end
|
26
|
+
|
22
27
|
def data_attributes
|
23
28
|
@data.merge({'panel-index': @index}).map do |key, value|
|
24
29
|
" data-#{key}=\"#{value}\""
|
@@ -38,4 +43,8 @@ class Avo::PanelComponent < ViewComponent::Base
|
|
38
43
|
def render_header?
|
39
44
|
@title.present? || description.present? || tools.present? || display_breadcrumbs?
|
40
45
|
end
|
46
|
+
|
47
|
+
def render_footer_tools?
|
48
|
+
footer_tools.present?
|
49
|
+
end
|
41
50
|
end
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<%= hidden_field_tag :via_resource_class, params[:via_resource_class] if params[:via_resource_class] %>
|
2
|
+
<%= hidden_field_tag :via_resource_id, params[:via_resource_id] if params[:via_resource_id] %>
|
3
|
+
<%= hidden_field_tag :via_relation, params[:via_relation] if params[:via_relation] %>
|
4
|
+
<%= hidden_field_tag :referrer, back_path if params[:via_resource_class] %>
|
@@ -4,7 +4,9 @@ class Avo::SidebarComponent < ViewComponent::Base
|
|
4
4
|
def dashboards
|
5
5
|
return [] if Avo::App.license.lacks_with_trial(:dashboards)
|
6
6
|
|
7
|
-
Avo::App.get_dashboards(helpers._current_user)
|
7
|
+
Avo::App.get_dashboards(helpers._current_user).select do |dashboard|
|
8
|
+
dashboard.is_visible?
|
9
|
+
end
|
8
10
|
end
|
9
11
|
|
10
12
|
def resources
|
@@ -4,8 +4,9 @@
|
|
4
4
|
scope: @resource.form_scope,
|
5
5
|
url: helpers.resource_path(model: @resource.model, resource: @resource),
|
6
6
|
method: :put,
|
7
|
+
local: true,
|
7
8
|
multipart: true do |form| %>
|
8
|
-
<%=
|
9
|
+
<%= render Avo::ReferrerParamsComponent.new back_path: back_path %>
|
9
10
|
<%= render Avo::PanelComponent.new(title: resource_panel[:name], description: @resource.resource_description, display_breadcrumbs: true) do |c| %>
|
10
11
|
<% c.tools do %>
|
11
12
|
<%= a_link back_path, icon: 'arrow-left' do %>
|
@@ -17,6 +18,18 @@
|
|
17
18
|
<% end %>
|
18
19
|
<% end %>
|
19
20
|
<% end %>
|
21
|
+
<% if Avo.configuration.buttons_on_form_footers %>
|
22
|
+
<% c.footer_tools do %>
|
23
|
+
<%= a_link back_path, icon: 'arrow-left' do %>
|
24
|
+
<%= t('avo.cancel').capitalize %>
|
25
|
+
<% end %>
|
26
|
+
<% if can_see_the_save_button? %>
|
27
|
+
<%= a_button color: :green, spinner: true, type: :submit, icon: 'save' do %>
|
28
|
+
<%= t('avo.save').capitalize %>
|
29
|
+
<% end %>
|
30
|
+
<% end %>
|
31
|
+
<% end %>
|
32
|
+
<% end %>
|
20
33
|
<% c.body do %>
|
21
34
|
<div class="divide-y">
|
22
35
|
<% @resource.get_fields.each_with_index do |field, index| %>
|
@@ -10,6 +10,7 @@
|
|
10
10
|
),
|
11
11
|
local: true,
|
12
12
|
multipart: true do |form| %>
|
13
|
+
<%= render Avo::ReferrerParamsComponent.new back_path: back_path %>
|
13
14
|
<%= render Avo::PanelComponent.new(title: resource_panel[:name], description: @resource.resource_description, display_breadcrumbs: true) do |c| %>
|
14
15
|
<% c.tools do %>
|
15
16
|
<div class="flex justify-end space-x-2">
|
@@ -23,6 +24,18 @@
|
|
23
24
|
<% end %>
|
24
25
|
</div>
|
25
26
|
<% end %>
|
27
|
+
<% if Avo.configuration.buttons_on_form_footers %>
|
28
|
+
<% c.footer_tools do %>
|
29
|
+
<%= a_link back_path, icon: 'arrow-left' do %>
|
30
|
+
<%= t('avo.cancel').capitalize %>
|
31
|
+
<% end %>
|
32
|
+
<% if can_see_the_save_button? %>
|
33
|
+
<%= a_button color: :green, spinner: true, type: :submit, icon: 'save' do %>
|
34
|
+
<%= t('avo.save').capitalize %>
|
35
|
+
<% end %>
|
36
|
+
<% end %>
|
37
|
+
<% end %>
|
38
|
+
<% end %>
|
26
39
|
<% c.body do %>
|
27
40
|
<div class="divide-y">
|
28
41
|
<% @resource.get_fields.each_with_index do |field, index| %>
|
@@ -33,6 +33,7 @@
|
|
33
33
|
<% if can_see_the_destroy_button? %>
|
34
34
|
<%= a_button url: helpers.resource_path(model: @resource.model, resource: @resource),
|
35
35
|
method: :delete,
|
36
|
+
local: true,
|
36
37
|
title: t('avo.delete_item', item: @resource.model.model_name.name.downcase).capitalize,
|
37
38
|
spinner: true,
|
38
39
|
color: :red,
|
@@ -83,4 +84,14 @@
|
|
83
84
|
<% end %>
|
84
85
|
<% end %>
|
85
86
|
<% end %>
|
87
|
+
|
88
|
+
<% if should_display_invalid_fields_errors? %>
|
89
|
+
<turbo-stream action="append" target="alerts">
|
90
|
+
<template>
|
91
|
+
<% @resource.invalid_fields.each do |error| %>
|
92
|
+
<%= render Avo::AlertComponent.new :error, error[:message] %>
|
93
|
+
<% end %>
|
94
|
+
</template>
|
95
|
+
</turbo-stream>
|
96
|
+
<% end %>
|
86
97
|
</div>
|
@@ -90,4 +90,9 @@ class Avo::Views::ResourceShowComponent < Avo::ResourceComponent
|
|
90
90
|
end
|
91
91
|
end
|
92
92
|
end
|
93
|
+
|
94
|
+
# In development and test environments we shoudl show the invalid field errors
|
95
|
+
def should_display_invalid_fields_errors?
|
96
|
+
(Rails.env.development? || Rails.env.test?) && @resource.invalid_fields.present?
|
97
|
+
end
|
93
98
|
end
|
@@ -28,7 +28,7 @@ module Avo
|
|
28
28
|
add_flash_types :info, :warning, :success, :error
|
29
29
|
|
30
30
|
def init_app
|
31
|
-
Avo::App.init request: request, context: context, root_path: avo.root_path.delete_suffix("/"), current_user: _current_user, view_context: view_context
|
31
|
+
Avo::App.init request: request, context: context, root_path: avo.root_path.delete_suffix("/"), current_user: _current_user, view_context: view_context, params: params
|
32
32
|
|
33
33
|
@license = Avo::App.license
|
34
34
|
end
|
@@ -7,6 +7,7 @@ module Avo
|
|
7
7
|
before_action :hydrate_resource
|
8
8
|
before_action :set_model, only: [:show, :edit, :destroy, :update, :order]
|
9
9
|
before_action :set_model_to_fill
|
10
|
+
before_action :set_edit_title_and_breadcrumbs, only: [:edit, :update]
|
10
11
|
before_action :fill_model, only: [:create, :update]
|
11
12
|
before_action :authorize_action
|
12
13
|
before_action :reset_pagination_if_filters_changed, only: :index
|
@@ -43,7 +44,7 @@ module Avo
|
|
43
44
|
unless @index_params[:sort_by].eql? :created_at
|
44
45
|
@query = @query.unscope(:order)
|
45
46
|
end
|
46
|
-
@query = @query.order("#{@resource.model_class.table_name}.#{@index_params[:sort_by]} #{@index_params[:sort_direction]}")
|
47
|
+
@query = @query.order(Arel.sql("#{@resource.model_class.table_name}.#{@index_params[:sort_by]} #{@index_params[:sort_direction]}"))
|
47
48
|
end
|
48
49
|
|
49
50
|
# Apply filters
|
@@ -91,30 +92,9 @@ module Avo
|
|
91
92
|
add_breadcrumb t("avo.new").humanize
|
92
93
|
end
|
93
94
|
|
94
|
-
def edit
|
95
|
-
@resource = @resource.hydrate(model: @model, view: :edit, user: _current_user)
|
96
|
-
|
97
|
-
@page_title = @resource.default_panel_name.to_s
|
98
|
-
|
99
|
-
# If we're accessing this resource via another resource add the parent to the breadcrumbs.
|
100
|
-
if params[:via_resource_class].present? && params[:via_resource_id].present?
|
101
|
-
via_resource = Avo::App.get_resource_by_model_name params[:via_resource_class]
|
102
|
-
via_model = via_resource.class.find_scope.find params[:via_resource_id]
|
103
|
-
via_resource.hydrate model: via_model
|
104
|
-
|
105
|
-
add_breadcrumb via_resource.plural_name, resources_path(resource: @resource)
|
106
|
-
add_breadcrumb via_resource.model_title, resource_path(model: via_model, resource: via_resource)
|
107
|
-
else
|
108
|
-
add_breadcrumb @resource.plural_name.humanize, resources_path(resource: @resource)
|
109
|
-
end
|
110
|
-
|
111
|
-
add_breadcrumb @resource.model_title, resource_path(model: @resource.model, resource: @resource)
|
112
|
-
add_breadcrumb t("avo.edit").humanize
|
113
|
-
end
|
114
|
-
|
115
95
|
def create
|
116
96
|
# model gets instantiated and filled in the fill_model method
|
117
|
-
saved =
|
97
|
+
saved = save_model
|
118
98
|
@resource.hydrate(model: @model, view: :new, user: _current_user)
|
119
99
|
|
120
100
|
# This means that the record has been created through another parent record and we need to attach it somehow.
|
@@ -148,14 +128,7 @@ module Avo
|
|
148
128
|
|
149
129
|
respond_to do |format|
|
150
130
|
if saved
|
151
|
-
|
152
|
-
|
153
|
-
if params[:via_relation_class].present? && params[:via_resource_id].present?
|
154
|
-
parent_resource = ::Avo::App.get_resource_by_model_name params[:via_relation_class].safe_constantize
|
155
|
-
redirect_path = resource_path(model: params[:via_relation_class].safe_constantize, resource: parent_resource, resource_id: params[:via_resource_id])
|
156
|
-
end
|
157
|
-
|
158
|
-
format.html { redirect_to redirect_path, notice: "#{@model.class.name} #{t("avo.was_successfully_created")}." }
|
131
|
+
format.html { redirect_to after_create_path, notice: "#{@model.class.name} #{t("avo.was_successfully_created")}." }
|
159
132
|
else
|
160
133
|
flash.now[:error] = t "avo.you_missed_something_check_form"
|
161
134
|
format.html { render :new, status: :unprocessable_entity }
|
@@ -163,14 +136,17 @@ module Avo
|
|
163
136
|
end
|
164
137
|
end
|
165
138
|
|
139
|
+
def edit
|
140
|
+
end
|
141
|
+
|
166
142
|
def update
|
167
143
|
# model gets instantiated and filled in the fill_model method
|
168
|
-
saved =
|
144
|
+
saved = save_model
|
169
145
|
@resource = @resource.hydrate(model: @model, view: :edit, user: _current_user)
|
170
146
|
|
171
147
|
respond_to do |format|
|
172
148
|
if saved
|
173
|
-
format.html { redirect_to
|
149
|
+
format.html { redirect_to after_update_path, notice: "#{@model.class.name} #{t("avo.was_successfully_updated")}." }
|
174
150
|
else
|
175
151
|
flash.now[:error] = t "avo.you_missed_something_check_form"
|
176
152
|
format.html { render :edit, status: :unprocessable_entity }
|
@@ -179,11 +155,14 @@ module Avo
|
|
179
155
|
end
|
180
156
|
|
181
157
|
def destroy
|
182
|
-
@model.destroy!
|
183
|
-
|
184
158
|
respond_to do |format|
|
185
|
-
|
186
|
-
|
159
|
+
if destroy_model
|
160
|
+
format.html { redirect_to params[:referrer] || resources_path(resource: @resource, turbo_frame: params[:turbo_frame], view_type: params[:view_type]), notice: t("avo.resource_destroyed", attachment_class: @attachment_class) }
|
161
|
+
else
|
162
|
+
error_message = @errors.present? ? @errors.first : t("avo.failed")
|
163
|
+
|
164
|
+
format.html { redirect_back fallback_location: params[:referrer] || resources_path(resource: @resource, turbo_frame: params[:turbo_frame], view_type: params[:view_type]), error: error_message }
|
165
|
+
end
|
187
166
|
end
|
188
167
|
end
|
189
168
|
|
@@ -204,6 +183,31 @@ module Avo
|
|
204
183
|
|
205
184
|
private
|
206
185
|
|
186
|
+
def save_model
|
187
|
+
perform_action_and_record_errors do
|
188
|
+
@model.save!
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def destroy_model
|
193
|
+
perform_action_and_record_errors do
|
194
|
+
@model.destroy!
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def perform_action_and_record_errors(&block)
|
199
|
+
begin
|
200
|
+
succeeded = block.call
|
201
|
+
rescue => exception
|
202
|
+
# In case there's an error somewhere else than the model
|
203
|
+
# Example: When you save a license that should create a user for it and creating that user throws and error.
|
204
|
+
# Example: When you Try to delete a record and has a foreign key constraint.
|
205
|
+
@errors = Array.wrap(exception.message)
|
206
|
+
end
|
207
|
+
|
208
|
+
succeeded
|
209
|
+
end
|
210
|
+
|
207
211
|
def model_params
|
208
212
|
request_params = params.require(model_param_key).permit(permitted_params)
|
209
213
|
|
@@ -327,5 +331,51 @@ module Avo
|
|
327
331
|
def applied_filters_cache_key
|
328
332
|
"avo.base_controller.#{@resource.model_key}.applied_filters"
|
329
333
|
end
|
334
|
+
|
335
|
+
def set_edit_title_and_breadcrumbs
|
336
|
+
@resource = @resource.hydrate(model: @model, view: :edit, user: _current_user)
|
337
|
+
@page_title = @resource.default_panel_name.to_s
|
338
|
+
# If we're accessing this resource via another resource add the parent to the breadcrumbs.
|
339
|
+
if params[:via_resource_class].present? && params[:via_resource_id].present?
|
340
|
+
via_resource = Avo::App.get_resource_by_model_name params[:via_resource_class]
|
341
|
+
via_model = via_resource.class.find_scope.find params[:via_resource_id]
|
342
|
+
via_resource.hydrate model: via_model
|
343
|
+
|
344
|
+
add_breadcrumb via_resource.plural_name, resources_path(resource: @resource)
|
345
|
+
add_breadcrumb via_resource.model_title, resource_path(model: via_model, resource: via_resource)
|
346
|
+
else
|
347
|
+
add_breadcrumb @resource.plural_name.humanize, resources_path(resource: @resource)
|
348
|
+
end
|
349
|
+
|
350
|
+
add_breadcrumb @resource.model_title, resource_path(model: @resource.model, resource: @resource)
|
351
|
+
add_breadcrumb t("avo.edit").humanize
|
352
|
+
end
|
353
|
+
|
354
|
+
def after_create_path
|
355
|
+
# If this is an associated record return to the association show page
|
356
|
+
if params[:via_relation_class].present? && params[:via_resource_id].present?
|
357
|
+
parent_resource = ::Avo::App.get_resource_by_model_name params[:via_relation_class].safe_constantize
|
358
|
+
|
359
|
+
return resource_path(model: params[:via_relation_class].safe_constantize, resource: parent_resource, resource_id: params[:via_resource_id])
|
360
|
+
end
|
361
|
+
|
362
|
+
redirect_path_from_resource_option || resource_path(model: @model, resource: @resource)
|
363
|
+
end
|
364
|
+
|
365
|
+
def after_update_path
|
366
|
+
return params[:referrer] if params[:referrer].present?
|
367
|
+
|
368
|
+
redirect_path_from_resource_option || resource_path(model: @model, resource: @resource)
|
369
|
+
end
|
370
|
+
|
371
|
+
def redirect_path_from_resource_option
|
372
|
+
return nil if @resource.class.after_update_path.blank?
|
373
|
+
|
374
|
+
if @resource.class.after_create_path == :index
|
375
|
+
resources_path(resource: @resource)
|
376
|
+
else
|
377
|
+
resource_path(model: @model, resource: @resource)
|
378
|
+
end
|
379
|
+
end
|
330
380
|
end
|
331
381
|
end
|
@@ -8,11 +8,7 @@ module Avo
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def card
|
11
|
-
@card = @dashboard.
|
12
|
-
next unless item.is_card?
|
13
|
-
|
14
|
-
item.id.to_s == params[:card_id]
|
15
|
-
end.tap do |card|
|
11
|
+
@card = @dashboard.item_at_index(params[:index].to_i).tap do |card|
|
16
12
|
card.hydrate(dashboard: @dashboard, params: params)
|
17
13
|
end
|
18
14
|
end
|
@@ -22,7 +18,7 @@ module Avo
|
|
22
18
|
def set_dashboard
|
23
19
|
@dashboard = Avo::App.get_dashboard_by_id params[:dashboard_id]
|
24
20
|
|
25
|
-
raise ActionController::RoutingError.new("Not Found") if @dashboard.nil?
|
21
|
+
raise ActionController::RoutingError.new("Not Found") if @dashboard.nil? || @dashboard.is_hidden?
|
26
22
|
end
|
27
23
|
end
|
28
24
|
end
|