avo 2.0.0 → 2.1.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 +1 -1
- data/Gemfile.lock +3 -3
- data/app/assets/svgs/save.svg +8 -1
- data/app/components/avo/actions_component.html.erb +1 -1
- data/app/components/avo/alert_component.rb +5 -5
- 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/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 +10 -2
- 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.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 +1 -0
- data/app/controllers/avo/application_controller.rb +1 -1
- data/app/controllers/avo/base_controller.rb +57 -27
- data/app/controllers/avo/dashboards_controller.rb +1 -1
- data/app/controllers/avo/search_controller.rb +5 -1
- 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/home/failed_to_load.html.erb +21 -1
- 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 +4 -4
- data/lib/avo/base_resource.rb +26 -7
- data/lib/avo/configuration.rb +2 -0
- data/lib/avo/dashboards/base_dashboard.rb +17 -0
- data/lib/avo/dashboards/chartkick_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/external_image_field.rb +2 -2
- 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 +37 -21
- data/public/avo-assets/avo.js +166 -165
- data/public/avo-assets/avo.js.map +3 -3
- metadata +7 -3
- data/app/views/avo/partials/_failed_state.html.erb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 633ca9db11d83d470c185235c921f4c6d5d8c76929443fa459d64f3e10ac6ba3
|
4
|
+
data.tar.gz: 81a6fe46847a7829f88362f39f5a732dce6953a9bc1197e7bdcfae7c80eb644d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f6135bc849ee84b9d637fd9495ff5836fad0c58fc4d1b65504ba7d6eb6b95afd8b7a1724b287ca4857de32920b251d1c749901fc4c28e7cf1f9e6cf2b65a389
|
7
|
+
data.tar.gz: 59e3248675295cbb521f71b7a66e0f80b3433ebe022d6ad05b48138cd93c4907b96a3672e5bfe6d661412ff1f0c7ea52c957445ba16896d63e425a17d734c1b7
|
data/Gemfile
CHANGED
@@ -30,7 +30,7 @@ gem "rails", "~> 6.1.0"
|
|
30
30
|
# Use postgresql as the database for Active Record
|
31
31
|
gem "pg", ">= 0.18", "< 2.0"
|
32
32
|
# Use Puma as the app server
|
33
|
-
gem "puma", "~> 5.6.
|
33
|
+
gem "puma", "~> 5.6.4"
|
34
34
|
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
|
35
35
|
# gem "jbuilder", "~> 2.7"
|
36
36
|
# Use Redis adapter to run Action Cable in production
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
avo (2.
|
4
|
+
avo (2.1.0)
|
5
5
|
active_link_to
|
6
6
|
addressable
|
7
7
|
breadcrumbs_on_rails
|
@@ -250,7 +250,7 @@ GEM
|
|
250
250
|
ast (~> 2.4.1)
|
251
251
|
pg (1.3.1)
|
252
252
|
public_suffix (4.0.6)
|
253
|
-
puma (5.6.
|
253
|
+
puma (5.6.4)
|
254
254
|
nio4r (~> 2.0)
|
255
255
|
pundit (2.2.0)
|
256
256
|
activesupport (>= 3.0.0)
|
@@ -447,7 +447,7 @@ DEPENDENCIES
|
|
447
447
|
meta-tags
|
448
448
|
net-smtp
|
449
449
|
pg (>= 0.18, < 2.0)
|
450
|
-
puma (~> 5.6.
|
450
|
+
puma (~> 5.6.4)
|
451
451
|
pundit
|
452
452
|
rails (~> 6.1.0)
|
453
453
|
rails-controller-testing
|
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
21
|
result = "max-w-sm 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,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">
|
@@ -25,7 +25,7 @@
|
|
25
25
|
</div>
|
26
26
|
<% end %>
|
27
27
|
|
28
|
-
<div class="relative
|
28
|
+
<div class="relative <%= white_panel_classes %> <%= @body_classes %>">
|
29
29
|
<%= body %>
|
30
30
|
</div>
|
31
31
|
|
@@ -33,6 +33,14 @@
|
|
33
33
|
<%= bare_content %>
|
34
34
|
</div>
|
35
35
|
|
36
|
+
<% if footer_tools.present? %>
|
37
|
+
<div class="<%= white_panel_classes %> p-4 flex-1 flex flex-col xl:flex-row justify-between mt-6">
|
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">
|
39
|
+
<%= footer_tools %>
|
40
|
+
</div>
|
41
|
+
</div>
|
42
|
+
<% end %>
|
43
|
+
|
36
44
|
<div class="flex justify-end w-full">
|
37
45
|
<div>
|
38
46
|
<%= 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,
|
@@ -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
|
@@ -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.
|
@@ -163,9 +143,12 @@ module Avo
|
|
163
143
|
end
|
164
144
|
end
|
165
145
|
|
146
|
+
def edit
|
147
|
+
end
|
148
|
+
|
166
149
|
def update
|
167
150
|
# model gets instantiated and filled in the fill_model method
|
168
|
-
saved =
|
151
|
+
saved = save_model
|
169
152
|
@resource = @resource.hydrate(model: @model, view: :edit, user: _current_user)
|
170
153
|
|
171
154
|
respond_to do |format|
|
@@ -179,11 +162,14 @@ module Avo
|
|
179
162
|
end
|
180
163
|
|
181
164
|
def destroy
|
182
|
-
@model.destroy!
|
183
|
-
|
184
165
|
respond_to do |format|
|
185
|
-
|
186
|
-
|
166
|
+
if destroy_model
|
167
|
+
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) }
|
168
|
+
else
|
169
|
+
error_message = @errors.present? ? @errors.first : t("avo.failed")
|
170
|
+
|
171
|
+
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 }
|
172
|
+
end
|
187
173
|
end
|
188
174
|
end
|
189
175
|
|
@@ -204,6 +190,31 @@ module Avo
|
|
204
190
|
|
205
191
|
private
|
206
192
|
|
193
|
+
def save_model
|
194
|
+
perform_action_and_record_errors do
|
195
|
+
@model.save!
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def destroy_model
|
200
|
+
perform_action_and_record_errors do
|
201
|
+
@model.destroy!
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def perform_action_and_record_errors(&block)
|
206
|
+
begin
|
207
|
+
succeeded = block.call
|
208
|
+
rescue => exception
|
209
|
+
# In case there's an error somewhere else than the model
|
210
|
+
# Example: When you save a license that should create a user for it and creating that user throws and error.
|
211
|
+
# Example: When you Try to delete a record and has a foreign key constraint.
|
212
|
+
@errors = Array.wrap(exception.message)
|
213
|
+
end
|
214
|
+
|
215
|
+
succeeded
|
216
|
+
end
|
217
|
+
|
207
218
|
def model_params
|
208
219
|
request_params = params.require(model_param_key).permit(permitted_params)
|
209
220
|
|
@@ -327,5 +338,24 @@ module Avo
|
|
327
338
|
def applied_filters_cache_key
|
328
339
|
"avo.base_controller.#{@resource.model_key}.applied_filters"
|
329
340
|
end
|
341
|
+
|
342
|
+
def set_edit_title_and_breadcrumbs
|
343
|
+
@resource = @resource.hydrate(model: @model, view: :edit, user: _current_user)
|
344
|
+
@page_title = @resource.default_panel_name.to_s
|
345
|
+
# If we're accessing this resource via another resource add the parent to the breadcrumbs.
|
346
|
+
if params[:via_resource_class].present? && params[:via_resource_id].present?
|
347
|
+
via_resource = Avo::App.get_resource_by_model_name params[:via_resource_class]
|
348
|
+
via_model = via_resource.class.find_scope.find params[:via_resource_id]
|
349
|
+
via_resource.hydrate model: via_model
|
350
|
+
|
351
|
+
add_breadcrumb via_resource.plural_name, resources_path(resource: @resource)
|
352
|
+
add_breadcrumb via_resource.model_title, resource_path(model: via_model, resource: via_resource)
|
353
|
+
else
|
354
|
+
add_breadcrumb @resource.plural_name.humanize, resources_path(resource: @resource)
|
355
|
+
end
|
356
|
+
|
357
|
+
add_breadcrumb @resource.model_title, resource_path(model: @resource.model, resource: @resource)
|
358
|
+
add_breadcrumb t("avo.edit").humanize
|
359
|
+
end
|
330
360
|
end
|
331
361
|
end
|
@@ -22,7 +22,7 @@ module Avo
|
|
22
22
|
def set_dashboard
|
23
23
|
@dashboard = Avo::App.get_dashboard_by_id params[:dashboard_id]
|
24
24
|
|
25
|
-
raise ActionController::RoutingError.new("Not Found") if @dashboard.nil?
|
25
|
+
raise ActionController::RoutingError.new("Not Found") if @dashboard.nil? || @dashboard.is_hidden?
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
@@ -10,7 +10,11 @@ module Avo
|
|
10
10
|
def index
|
11
11
|
raise ActionController::BadRequest.new("This feature requires the pro license https://avohq.io/purchase/pro") if App.license.lacks_with_trial(:global_search)
|
12
12
|
|
13
|
-
|
13
|
+
resources = Avo::App.resources.reject do |resource|
|
14
|
+
resource.class.search_hide_from_global_search
|
15
|
+
end
|
16
|
+
|
17
|
+
render json: search_resources(resources)
|
14
18
|
end
|
15
19
|
|
16
20
|
def show
|
data/app/javascript/avo.js
CHANGED
@@ -71,12 +71,13 @@ document.addEventListener('turbo:frame-load', () => {
|
|
71
71
|
initTippy()
|
72
72
|
})
|
73
73
|
|
74
|
-
document.addEventListener('turbo:before-fetch-response', (e) => {
|
74
|
+
document.addEventListener('turbo:before-fetch-response', async (e) => {
|
75
75
|
if (e.detail.fetchResponse.response.status === 500) {
|
76
|
-
const id = e.
|
77
|
-
e.
|
76
|
+
const { id, src } = e.target
|
77
|
+
e.target.src = `${window.Avo.configuration.root_path}/failed_to_load?turbo_frame=${id}&src=${src}`
|
78
78
|
}
|
79
79
|
})
|
80
|
+
|
80
81
|
document.addEventListener('turbo:visit', () => document.body.classList.add('turbo-loading'))
|
81
82
|
document.addEventListener('turbo:submit-start', () => document.body.classList.add('turbo-loading'))
|
82
83
|
document.addEventListener('turbo:submit-end', () => document.body.classList.remove('turbo-loading'))
|
@@ -1,3 +1,23 @@
|
|
1
1
|
<%= turbo_frame_wrap(params[:turbo_frame]) do %>
|
2
|
-
|
2
|
+
<%
|
3
|
+
classes = 'absolute inset-auto left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2'
|
4
|
+
label = t 'avo.failed_to_load'
|
5
|
+
%>
|
6
|
+
<div class="relative flex-1 py-12">
|
7
|
+
<div class="relative block text-gray-300 h-40 w-full">
|
8
|
+
<%= svg 'avocado', class: "#{classes} h-20 text-gray-400" %>
|
9
|
+
<%= svg 'code', class: "#{classes} h-8 -ml-20 -mt-12" %>
|
10
|
+
<%= svg 'fire', class: "#{classes} h-8 -ml-10 -mt-24" %>
|
11
|
+
<%= svg 'color-swatch', class: "#{classes} h-8 ml-8 -mt-24" %>
|
12
|
+
<%= svg 'globe', class: "#{classes} h-8 ml-20 -mt-12" %>
|
13
|
+
<%= svg 'library', class: "#{classes} h-8 -ml-20 mt-4" %>
|
14
|
+
<%= svg 'photograph', class: "#{classes} h-8 ml-20 mt-4" %>
|
15
|
+
</div>
|
16
|
+
<div class="relative block text-center text-lg text-gray-400 font-semibold -mt-10"><%= label %> <span class="border-b-2 border-dashed"><%= params[:turbo_frame].to_s.humanize.downcase if params[:turbo_frame].present? %></span> frame</div>
|
17
|
+
</div>
|
18
|
+
<% if Rails.env.development? %>
|
19
|
+
<div class="text-center text-sm w-full">
|
20
|
+
This is not an issue with Avo. Click <%= link_to 'this link', params[:src], target: :_blank %> to see why this frame failed to load.
|
21
|
+
</div>
|
22
|
+
<% end %>
|
3
23
|
<% end %>
|
@@ -42,6 +42,13 @@
|
|
42
42
|
|
43
43
|
<%= turbo_frame_tag 'alerts', class: "fixed inset-0 bottom-0 flex flex-col space-y-4 items-end justify-right px-4 py-6 sm:p-6 justify-end z-50 pointer-events-none" do %>
|
44
44
|
<%= render Avo::FlashAlertsComponent.new flashes: flash %>
|
45
|
+
|
46
|
+
<% # In case we have other general error messages %>
|
47
|
+
<% if @errors.present? %>
|
48
|
+
<% @errors.each do |message| %>
|
49
|
+
<%= render Avo::AlertComponent.new :error, message %>
|
50
|
+
<% end %>
|
51
|
+
<% end %>
|
45
52
|
<% end %>
|
46
53
|
|
47
54
|
<%= render partial: "avo/partials/scripts" %>
|