avo 2.18.1 → 2.20.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 +4 -6
- data/Gemfile.lock +76 -77
- data/app/components/avo/actions_component.html.erb +1 -1
- data/app/components/avo/actions_component.rb +4 -4
- data/app/components/avo/base_component.rb +17 -0
- data/app/components/avo/card_component.html.erb +15 -15
- data/app/components/avo/card_component.rb +7 -5
- data/app/components/avo/field_wrapper_component.rb +7 -1
- data/app/components/avo/fields/has_one_field/show_component.rb +1 -2
- data/app/components/avo/fields/index_component.rb +4 -3
- data/app/components/avo/fields/select_field/edit_component.html.erb +1 -1
- data/app/components/avo/filters_component.html.erb +1 -1
- data/app/components/avo/filters_component.rb +2 -2
- data/app/components/avo/index/grid_item_component.rb +2 -2
- data/app/components/avo/index/resource_controls_component.rb +2 -2
- data/app/components/avo/index/table_row_component.html.erb +1 -1
- data/app/components/avo/item_switcher_component.html.erb +1 -1
- data/app/components/avo/panel_component.html.erb +1 -1
- data/app/components/avo/resource_component.rb +1 -1
- data/app/components/avo/resource_sidebar_component.rb +1 -6
- data/app/components/avo/sidebar/group_component.html.erb +18 -12
- data/app/components/avo/sidebar/heading_component.html.erb +17 -10
- data/app/components/avo/sidebar_profile_component.rb +3 -1
- data/app/components/avo/tab_group_component.rb +1 -1
- data/app/components/avo/views/resource_show_component.html.erb +1 -1
- data/app/controllers/avo/actions_controller.rb +27 -5
- data/app/controllers/avo/application_controller.rb +7 -0
- data/app/controllers/avo/base_controller.rb +30 -18
- data/app/controllers/avo/dashboards/cards_controller.rb +37 -0
- data/app/controllers/avo/dashboards_controller.rb +1 -0
- data/app/helpers/avo/application_helper.rb +5 -1
- data/app/javascript/js/controllers/search_controller.js +11 -2
- data/app/views/avo/actions/keep_modal_open.turbo_stream.erb +5 -0
- data/app/views/avo/actions/show.html.erb +2 -1
- data/app/views/avo/{cards → dashboards/cards}/_chartkick_card.html.erb +0 -0
- data/app/views/avo/{cards → dashboards/cards}/_metric_card.html.erb +0 -0
- data/app/views/avo/{cards → dashboards/cards}/chartkick_missing.html.erb +0 -0
- data/app/views/avo/{cards → dashboards/cards}/show.html.erb +0 -0
- data/app/views/avo/partials/_branding.html.erb +1 -0
- data/app/views/layouts/avo/application.html.erb +1 -1
- data/avo.gemspec +1 -2
- data/bin/init +11 -1
- data/bin/test +1 -0
- data/config/routes.rb +2 -2
- data/db/factories.rb +10 -0
- data/lib/avo/app.rb +14 -1
- data/lib/avo/base_action.rb +35 -10
- data/lib/avo/base_card.rb +3 -1
- data/lib/avo/base_resource.rb +21 -10
- data/lib/avo/concerns/breadcrumbs.rb +96 -0
- data/lib/avo/concerns/filters_session_handler.rb +43 -0
- data/lib/avo/concerns/has_fields.rb +2 -0
- data/lib/avo/concerns/has_html_attributes.rb +14 -16
- data/lib/avo/concerns/visible_items.rb +44 -0
- data/lib/avo/configuration/branding.rb +10 -2
- data/lib/avo/configuration.rb +3 -0
- data/lib/avo/dashboards/base_dashboard.rb +7 -1
- data/lib/avo/dynamic_router.rb +16 -15
- data/lib/avo/engine.rb +6 -9
- data/lib/avo/fields/base_field.rb +21 -12
- data/lib/avo/fields/concerns/has_default.rb +17 -0
- data/lib/avo/fields/concerns/is_readonly.rb +1 -1
- data/lib/avo/fields/concerns/is_required.rb +2 -2
- data/lib/avo/fields/has_base_field.rb +2 -0
- data/lib/avo/fields/key_value_field.rb +1 -1
- data/lib/avo/fields/select_field.rb +39 -34
- data/lib/avo/filters/base_filter.rb +24 -2
- data/lib/avo/hosts/resource_view_record_host.rb +7 -0
- data/lib/avo/hosts/visibility_host.rb +13 -0
- data/lib/avo/panel.rb +4 -1
- data/lib/avo/resources/controls/action.rb +1 -3
- data/lib/avo/sidebar.rb +1 -31
- data/lib/avo/tab.rb +5 -22
- data/lib/avo/version.rb +1 -1
- data/lib/avo.rb +9 -0
- data/lib/generators/avo/resource_generator.rb +281 -0
- data/lib/generators/avo/templates/action.tt +3 -0
- data/lib/generators/avo/templates/filters/boolean_filter.tt +3 -0
- data/lib/generators/avo/templates/filters/multiple_select_filter.tt +3 -0
- data/lib/generators/avo/templates/filters/select_filter.tt +3 -0
- data/lib/generators/avo/templates/filters/text_filter.tt +3 -0
- data/lib/generators/avo/templates/initializer/avo.tt +4 -0
- data/lib/generators/avo/templates/resource/controller.tt +1 -1
- data/lib/generators/avo/templates/resource/resource.tt +2 -2
- data/lib/generators/model_generator.rb +10 -0
- data/lib/generators/rails/avo_resource_generator.rb +11 -0
- data/public/avo-assets/avo.base.css +14 -14
- data/public/avo-assets/avo.base.js +1 -1
- data/public/avo-assets/avo.base.js.map +2 -2
- data/public/avo-assets/favicon.ico +0 -0
- data/{app/assets/svgs → public/avo-assets}/placeholder.svg +0 -0
- metadata +20 -25
- data/app/controllers/avo/cards_controller.rb +0 -35
- data/config/master.key +0 -1
@@ -41,7 +41,7 @@ class Avo::Index::ResourceControlsComponent < Avo::ResourceComponent
|
|
41
41
|
}
|
42
42
|
end
|
43
43
|
|
44
|
-
helpers.resource_path(model: @resource.model, resource:
|
44
|
+
helpers.resource_path(model: @resource.model, resource: parent_or_child_resource , **args)
|
45
45
|
end
|
46
46
|
|
47
47
|
def edit_path
|
@@ -55,7 +55,7 @@ class Avo::Index::ResourceControlsComponent < Avo::ResourceComponent
|
|
55
55
|
}
|
56
56
|
end
|
57
57
|
|
58
|
-
helpers.edit_resource_path(model: @resource.model, resource:
|
58
|
+
helpers.edit_resource_path(model: @resource.model, resource: parent_or_child_resource, **args)
|
59
59
|
end
|
60
60
|
|
61
61
|
def singular_resource_name
|
@@ -17,7 +17,7 @@
|
|
17
17
|
</td>
|
18
18
|
<% end %>
|
19
19
|
<% @resource.get_fields(reflection: @reflection, only_root: true).each_with_index do |field, index| %>
|
20
|
-
<%= render field.component_for_view(:index).new(field: field, resource: @resource, index: index, parent_model: @parent_model, parent_resource: @parent_resource) %>
|
20
|
+
<%= render field.component_for_view(:index).new(field: field, resource: @resource, reflection: @reflection, index: index, parent_model: @parent_model, parent_resource: @parent_resource) %>
|
21
21
|
<% end %>
|
22
22
|
<% if Avo.configuration.resource_controls_on_the_right? %>
|
23
23
|
<td class="text-right whitespace-nowrap px-2" data-control="resource-controls">
|
@@ -6,7 +6,7 @@
|
|
6
6
|
<%= render Avo::PanelComponent.new(name: item.name, description: item.description, index: index) do |c| %>
|
7
7
|
<% c.body do %>
|
8
8
|
<div class="divide-y">
|
9
|
-
<% item.
|
9
|
+
<% item.visible_items.each_with_index do |field, index| %>
|
10
10
|
<%= render field
|
11
11
|
.hydrate(resource: @resource, model: @resource.model, user: resource.user, view: view)
|
12
12
|
.component_for_view(view)
|
@@ -4,7 +4,7 @@
|
|
4
4
|
<div class="overflow-hidden flex flex-col">
|
5
5
|
<% if display_breadcrumbs? %>
|
6
6
|
<div class="breadcrumbs truncate mb-2">
|
7
|
-
<%= helpers.
|
7
|
+
<%= helpers.render_avo_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
10
|
<div class="text-2xl tracking-normal font-semibold text-gray-800 truncate items-center flex flex-1" data-target="title">
|
@@ -92,7 +92,7 @@ class Avo::ResourceComponent < Avo::BaseComponent
|
|
92
92
|
end
|
93
93
|
|
94
94
|
def sidebar_component(form: nil)
|
95
|
-
Avo::ResourceSidebarComponent.new resource: @resource, fields: sidebar.
|
95
|
+
Avo::ResourceSidebarComponent.new resource: @resource, fields: sidebar.visible_items, params: params, view: view, form: form
|
96
96
|
end
|
97
97
|
|
98
98
|
def has_reflection_and_is_read_only
|
@@ -5,6 +5,7 @@ class Avo::ResourceSidebarComponent < ViewComponent::Base
|
|
5
5
|
attr_reader :params
|
6
6
|
attr_reader :view
|
7
7
|
attr_reader :form
|
8
|
+
attr_reader :fields
|
8
9
|
|
9
10
|
def initialize(resource: nil, fields: nil, index: nil, params: nil, form: nil, view: nil)
|
10
11
|
@resource = resource
|
@@ -14,12 +15,6 @@ class Avo::ResourceSidebarComponent < ViewComponent::Base
|
|
14
15
|
@form = form
|
15
16
|
end
|
16
17
|
|
17
|
-
def fields
|
18
|
-
@fields.filter do |field|
|
19
|
-
field.visible_on? view
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
18
|
def render?
|
24
19
|
Avo::App.license.has_with_trial(:resource_sidebar)
|
25
20
|
end
|
@@ -7,22 +7,28 @@
|
|
7
7
|
<% end %>
|
8
8
|
>
|
9
9
|
<% if item.name.present? %>
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
<%=
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
10
|
+
<% if collapsable %>
|
11
|
+
<div
|
12
|
+
class="flex justify-between cursor-pointer px-10 pr-2 pt-2 pb-0 text-gray-400"
|
13
|
+
data-action="click->menu#triggerCollapse"
|
14
|
+
data-menu-key-param="<%= key %>"
|
15
|
+
>
|
16
|
+
<div class="flex items-center text-xs uppercase font-semibold leading-none">
|
17
|
+
<%= item.name %>
|
18
|
+
</div>
|
19
|
+
<div class="<%= 'rotate-90' if collapsed %>"
|
19
20
|
data-menu-target="svg"
|
20
|
-
data-menu-key-param="<%= key %>"
|
21
21
|
>
|
22
22
|
<%= helpers.svg 'heroicons/outline/chevron-down', class: "h-4 mr-0.5"%>
|
23
23
|
</div>
|
24
|
-
|
25
|
-
|
24
|
+
</div>
|
25
|
+
<% else %>
|
26
|
+
<div class="flex justify-between px-10 pr-2 pt-2 pb-0 text-gray-400">
|
27
|
+
<div class="flex items-center text-xs uppercase font-semibold leading-none">
|
28
|
+
<%= item.name %>
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
<% end %>
|
26
32
|
<% end %>
|
27
33
|
<div class="w-full space-y-1 <%= 'hidden' if collapsed %>" data-menu-target="items">
|
28
34
|
<% items.each do |item| %>
|
@@ -1,14 +1,21 @@
|
|
1
|
-
|
2
|
-
<div class="flex
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
<div class="
|
7
|
-
|
8
|
-
|
1
|
+
<% if collapsable %>
|
2
|
+
<div class="flex justify-between cursor-pointer px-4 pr-2 py-1 text-gray-500"
|
3
|
+
data-action="click->menu#triggerCollapse"
|
4
|
+
data-menu-key-param="<%= key %>"
|
5
|
+
>
|
6
|
+
<div class="flex items-center text-sm uppercase font-semibold leading-none space-x-1">
|
7
|
+
<span class="min-w-[20px]"><%= icon %></span> <span><%= label %></span>
|
8
|
+
</div>
|
9
|
+
<div class="<%= 'rotate-90' if collapsed %>"
|
9
10
|
data-menu-target="svg"
|
10
11
|
>
|
11
12
|
<%= helpers.svg 'heroicons/outline/chevron-down', class: 'h-5'%>
|
12
13
|
</div>
|
13
|
-
|
14
|
-
|
14
|
+
</div>
|
15
|
+
<% else %>
|
16
|
+
<div class="flex justify-between px-4 pr-2 py-1 text-gray-500">
|
17
|
+
<div class="flex items-center text-sm uppercase font-semibold leading-none space-x-1">
|
18
|
+
<span class="min-w-[20px]"><%= icon %></span> <span><%= label %></span>
|
19
|
+
</div>
|
20
|
+
</div>
|
21
|
+
<% end %>
|
@@ -34,7 +34,9 @@ class Avo::SidebarProfileComponent < ViewComponent::Base
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def destroy_user_session_path
|
37
|
-
|
37
|
+
# If `sign_out_path_name` is configured, use it. Otherwise construct the
|
38
|
+
# path name based on `current_user_resource_name`.
|
39
|
+
(Avo.configuration.sign_out_path_name || "destroy_#{Avo.configuration.current_user_resource_name}_session_path").to_sym
|
38
40
|
end
|
39
41
|
|
40
42
|
def can_destroy_user?
|
@@ -40,7 +40,7 @@
|
|
40
40
|
<% end %>
|
41
41
|
<% end %>
|
42
42
|
<% elsif can_see_the_actions_button? && control.actions_list? %>
|
43
|
-
<%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view, exclude: control.exclude, style: control.style, color: control.color %>
|
43
|
+
<%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view, exclude: control.exclude, style: control.style, color: control.color, label: control.label %>
|
44
44
|
<% elsif control.edit_button? %>
|
45
45
|
<% if @resource.authorization.authorize_action(:edit, raise_exception: false) %>
|
46
46
|
<% end %>
|
@@ -51,7 +51,13 @@ module Avo
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def set_action
|
54
|
-
@action = action_class.new(
|
54
|
+
@action = action_class.new(
|
55
|
+
model: @model,
|
56
|
+
resource: @resource,
|
57
|
+
user: _current_user,
|
58
|
+
view: @view,
|
59
|
+
arguments: @resource.get_action_arguments(action_class)
|
60
|
+
)
|
55
61
|
end
|
56
62
|
|
57
63
|
def action_class
|
@@ -63,8 +69,10 @@ module Avo
|
|
63
69
|
end
|
64
70
|
|
65
71
|
def respond(response)
|
66
|
-
response[:type] ||= :reload
|
67
72
|
messages = get_messages response
|
73
|
+
return keep_modal_open(messages) if response[:keep_modal_open]
|
74
|
+
|
75
|
+
response[:type] ||= :reload
|
68
76
|
|
69
77
|
if response[:type] == :download
|
70
78
|
return send_data response[:path], filename: response[:filename]
|
@@ -73,9 +81,7 @@ module Avo
|
|
73
81
|
respond_to do |format|
|
74
82
|
format.html do
|
75
83
|
# Flash the messages collected from the action
|
76
|
-
messages
|
77
|
-
flash[message[:type]] = message[:body]
|
78
|
-
end
|
84
|
+
flash_messages messages
|
79
85
|
|
80
86
|
if response[:type] == :redirect
|
81
87
|
path = response[:path]
|
@@ -114,5 +120,21 @@ module Avo
|
|
114
120
|
purpose: :select_all
|
115
121
|
)
|
116
122
|
end
|
123
|
+
|
124
|
+
def flash_messages(messages)
|
125
|
+
messages.each do |message|
|
126
|
+
flash[message[:type]] = message[:body]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def keep_modal_open(messages)
|
131
|
+
flash_messages messages
|
132
|
+
|
133
|
+
respond_to do |format|
|
134
|
+
format.turbo_stream do
|
135
|
+
render "keep_modal_open"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
117
139
|
end
|
118
140
|
end
|
@@ -1,8 +1,15 @@
|
|
1
1
|
module Avo
|
2
2
|
class ApplicationController < ::ActionController::Base
|
3
|
+
if defined?(Pundit::Authorization)
|
4
|
+
Avo::ApplicationController.include Pundit::Authorization
|
5
|
+
elsif defined?(Pundit)
|
6
|
+
Avo::ApplicationController.include Pundit
|
7
|
+
end
|
8
|
+
|
3
9
|
include Pagy::Backend
|
4
10
|
include Avo::ApplicationHelper
|
5
11
|
include Avo::UrlHelpers
|
12
|
+
include Avo::Concerns::Breadcrumbs
|
6
13
|
|
7
14
|
protect_from_forgery with: :exception
|
8
15
|
around_action :set_avo_locale
|
@@ -2,6 +2,8 @@ require_dependency "avo/application_controller"
|
|
2
2
|
|
3
3
|
module Avo
|
4
4
|
class BaseController < ApplicationController
|
5
|
+
include Avo::Concerns::FiltersSessionHandler
|
6
|
+
|
5
7
|
before_action :set_resource_name
|
6
8
|
before_action :set_resource
|
7
9
|
before_action :hydrate_resource
|
@@ -57,7 +59,9 @@ module Avo
|
|
57
59
|
|
58
60
|
# Apply filters to the current query
|
59
61
|
filters_to_be_applied.each do |filter_class, filter_value|
|
60
|
-
@query = filter_class.safe_constantize.new
|
62
|
+
@query = filter_class.safe_constantize.new(
|
63
|
+
arguments: @resource.get_filter_arguments(filter_class)
|
64
|
+
).apply_query request, @query, filter_value
|
61
65
|
end
|
62
66
|
|
63
67
|
extra_pagy_params = {}
|
@@ -222,6 +226,9 @@ module Avo
|
|
222
226
|
@errors = Array.wrap(exception.message)
|
223
227
|
end
|
224
228
|
|
229
|
+
# Add the errors from the model
|
230
|
+
@errors = Array.wrap([@errors, @model.errors.full_messages]).compact
|
231
|
+
|
225
232
|
succeeded
|
226
233
|
end
|
227
234
|
|
@@ -302,26 +309,31 @@ module Avo
|
|
302
309
|
end
|
303
310
|
|
304
311
|
def set_filters
|
305
|
-
@filters = @resource
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
312
|
+
@filters = @resource
|
313
|
+
.get_filters
|
314
|
+
.map do |filter|
|
315
|
+
filter[:class].new arguments: filter[:arguments]
|
316
|
+
end
|
317
|
+
.select do |filter|
|
318
|
+
filter.visible_in_view(resource: @resource, parent_model: @parent_model, parent_resource: @parent_resource)
|
319
|
+
end
|
310
320
|
end
|
311
321
|
|
312
322
|
def set_actions
|
313
323
|
@actions = @resource
|
314
324
|
.get_actions
|
315
325
|
.map do |action|
|
316
|
-
action.new(model: @model, resource: @resource, view: @view)
|
326
|
+
action[:class].new(model: @model, resource: @resource, view: @view, arguments: action[:arguments])
|
317
327
|
end
|
318
328
|
.select do |action|
|
319
|
-
action.visible_in_view
|
329
|
+
action.visible_in_view(parent_model: @parent_model, parent_resource: @parent_resource)
|
320
330
|
end
|
321
331
|
end
|
322
332
|
|
323
333
|
def set_applied_filters
|
324
|
-
|
334
|
+
reset_filters if params[:reset_filter]
|
335
|
+
|
336
|
+
@applied_filters = Avo::Filters::BaseFilter.decode_filters(fetch_filters)
|
325
337
|
|
326
338
|
# Some filters react to others and will have to be merged into this
|
327
339
|
@applied_filters = @applied_filters.merge reactive_filters
|
@@ -334,16 +346,16 @@ module Avo
|
|
334
346
|
|
335
347
|
# Go through all filters
|
336
348
|
@resource.get_filters
|
337
|
-
.select do |
|
338
|
-
|
349
|
+
.select do |filter|
|
350
|
+
filter[:class].instance_methods(false).include? :react
|
339
351
|
end
|
340
|
-
.each do |
|
352
|
+
.each do |filter|
|
341
353
|
# Run the react method if it's present
|
342
|
-
reaction =
|
354
|
+
reaction = filter[:class].new(arguments: filter[:arguments]).react
|
343
355
|
|
344
356
|
next if reaction.nil?
|
345
357
|
|
346
|
-
filter_reactions[
|
358
|
+
filter_reactions[filter[:class].to_s] = reaction
|
347
359
|
end
|
348
360
|
|
349
361
|
filter_reactions
|
@@ -353,11 +365,11 @@ module Avo
|
|
353
365
|
def filters_to_be_applied
|
354
366
|
filter_defaults = {}
|
355
367
|
|
356
|
-
@resource.get_filters.each do |
|
357
|
-
filter =
|
368
|
+
@resource.get_filters.each do |filter|
|
369
|
+
filter = filter[:class].new arguments: filter[:arguments]
|
358
370
|
|
359
371
|
unless filter.default.nil?
|
360
|
-
filter_defaults[
|
372
|
+
filter_defaults[filter.class.to_s] = filter.default
|
361
373
|
end
|
362
374
|
end
|
363
375
|
|
@@ -476,7 +488,7 @@ module Avo
|
|
476
488
|
end
|
477
489
|
|
478
490
|
def destroy_fail_message
|
479
|
-
@errors.present? ? @errors.
|
491
|
+
@errors.present? ? @errors.join(". ") : t("avo.failed")
|
480
492
|
end
|
481
493
|
|
482
494
|
def after_destroy_path
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require_dependency "avo/application_controller"
|
2
|
+
|
3
|
+
module Avo
|
4
|
+
module Dashboards
|
5
|
+
class CardsController < ApplicationController
|
6
|
+
before_action :set_dashboard
|
7
|
+
before_action :set_card
|
8
|
+
before_action :detect_chartkick
|
9
|
+
|
10
|
+
def show
|
11
|
+
render(:chartkick_missing) unless @chartkick_installed
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def set_dashboard
|
17
|
+
@dashboard = Avo::App.get_dashboard_by_id params[:dashboard_id]
|
18
|
+
|
19
|
+
raise ActionController::RoutingError.new("Not Found") if @dashboard.nil? || @dashboard.is_hidden?
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_card
|
23
|
+
@card = @dashboard.item_at_index(params[:index].to_i).tap do |card|
|
24
|
+
card.hydrate(dashboard: @dashboard, params: params)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def detect_chartkick
|
29
|
+
@chartkick_installed = if @card.class.ancestors.map(&:to_s).include?("Avo::Dashboards::ChartkickCard")
|
30
|
+
defined?(Chartkick)
|
31
|
+
else
|
32
|
+
true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -102,7 +102,11 @@ module Avo
|
|
102
102
|
end
|
103
103
|
|
104
104
|
def root_path_without_url
|
105
|
-
Avo::App.root_path
|
105
|
+
Avo::App.root_path
|
106
|
+
.to_s
|
107
|
+
.delete_prefix(request.base_url.to_s)
|
108
|
+
.delete_suffix("/")
|
109
|
+
.gsub("/?", "?")
|
106
110
|
rescue
|
107
111
|
Avo.configuration.root_path
|
108
112
|
end
|
@@ -76,7 +76,7 @@ export default class extends Controller {
|
|
76
76
|
// This line fixes a bug where the search box would be duplicated on back navigation.
|
77
77
|
this.autocompleteTarget.innerHTML = ''
|
78
78
|
|
79
|
-
autocomplete({
|
79
|
+
const { destroy } = autocomplete({
|
80
80
|
container: this.autocompleteTarget,
|
81
81
|
placeholder: this.translationKeys.placeholder,
|
82
82
|
translations: {
|
@@ -101,7 +101,7 @@ export default class extends Controller {
|
|
101
101
|
})
|
102
102
|
|
103
103
|
// document.addEventListener('turbo:before-render', destroy)
|
104
|
-
|
104
|
+
this.destroyMethod = destroy
|
105
105
|
|
106
106
|
// When using search for belongs-to
|
107
107
|
if (this.buttonTarget.dataset.shouldBeDisabled !== 'true') {
|
@@ -109,6 +109,15 @@ export default class extends Controller {
|
|
109
109
|
}
|
110
110
|
}
|
111
111
|
|
112
|
+
disconnect() {
|
113
|
+
// Don't leave open autocompletes around when disconnected. Otherwise it will still
|
114
|
+
// be visible when navigating back to this page.
|
115
|
+
if (this.destroyMethod) {
|
116
|
+
this.destroyMethod()
|
117
|
+
this.destroyMethod = null
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
112
121
|
addSource(resourceName, data) {
|
113
122
|
const that = this
|
114
123
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -46,7 +46,7 @@
|
|
46
46
|
<%= turbo_frame_tag 'actions_show' %>
|
47
47
|
<%= turbo_frame_tag 'attach_modal' %>
|
48
48
|
<%= turbo_frame_tag 'destroy_attachment_form' %>
|
49
|
-
<%= 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-
|
49
|
+
<%= 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-[100] pointer-events-none" do %>
|
50
50
|
<%= render Avo::FlashAlertsComponent.new flashes: flash %>
|
51
51
|
<% # In case we have other general error messages %>
|
52
52
|
<% if @errors.present? %>
|
data/avo.gemspec
CHANGED
@@ -35,14 +35,13 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.add_dependency "activerecord", ">= 6.0"
|
36
36
|
spec.add_dependency "actionview", ">= 6.0"
|
37
37
|
spec.add_dependency "pagy"
|
38
|
-
spec.add_dependency "zeitwerk"
|
38
|
+
spec.add_dependency "zeitwerk", ">= 2.6.2"
|
39
39
|
spec.add_dependency "httparty"
|
40
40
|
spec.add_dependency "active_link_to"
|
41
41
|
spec.add_dependency "view_component"
|
42
42
|
spec.add_dependency "turbo-rails"
|
43
43
|
spec.add_dependency "addressable"
|
44
44
|
spec.add_dependency "meta-tags"
|
45
|
-
spec.add_dependency "breadcrumbs_on_rails"
|
46
45
|
spec.add_dependency "dry-initializer"
|
47
46
|
spec.add_dependency "docile"
|
48
47
|
spec.add_dependency "inline_svg"
|
data/bin/init
CHANGED
@@ -9,7 +9,17 @@ app_root do
|
|
9
9
|
)
|
10
10
|
|
11
11
|
header 'Configuring git'
|
12
|
-
|
12
|
+
target_upstream = "https://github.com/avo-hq/avo.git"
|
13
|
+
current_upstream = `git config --get remote.upstream.url`.chomp
|
14
|
+
if current_upstream.nil? || current_upstream.empty?
|
15
|
+
puts "Adding new remote 'upstream' to #{target_upstream}"
|
16
|
+
run! "git remote add upstream #{target_upstream}"
|
17
|
+
elsif current_upstream != target_upstream
|
18
|
+
puts "Updating existing remote 'upstream' to #{target_upstream}"
|
19
|
+
run! "git remote set-url upstream #{target_upstream}"
|
20
|
+
else
|
21
|
+
puts "Remote 'upstream' already points to #{target_upstream}, no change"
|
22
|
+
end
|
13
23
|
|
14
24
|
header 'Installing gems'
|
15
25
|
run! 'bundle install'
|
data/bin/test
CHANGED
data/config/routes.rb
CHANGED
@@ -7,7 +7,7 @@ Avo::Engine.routes.draw do
|
|
7
7
|
post "/rails/active_storage/direct_uploads", to: "/active_storage/direct_uploads#create"
|
8
8
|
|
9
9
|
resources :dashboards do
|
10
|
-
resources :cards
|
10
|
+
resources :cards, controller: "dashboards/cards"
|
11
11
|
end
|
12
12
|
|
13
13
|
scope "avo_api", as: "avo_api" do
|
@@ -33,7 +33,7 @@ Avo::Engine.routes.draw do
|
|
33
33
|
|
34
34
|
# Generate resource routes as below:
|
35
35
|
# resources :posts
|
36
|
-
Avo::DynamicRouter.routes
|
36
|
+
Avo::DynamicRouter.routes
|
37
37
|
|
38
38
|
# Associations
|
39
39
|
get "/:resource_name/:id/:related_name/new", to: "associations#new", as: "associations_new"
|
data/db/factories.rb
CHANGED
@@ -60,6 +60,16 @@ FactoryBot.define do
|
|
60
60
|
type { "Spouse" }
|
61
61
|
end
|
62
62
|
|
63
|
+
factory :sibling do
|
64
|
+
name { "#{Faker::Name.first_name} #{Faker::Name.last_name}" }
|
65
|
+
type { "Sibling" }
|
66
|
+
end
|
67
|
+
|
68
|
+
factory :brother do
|
69
|
+
name { "#{Faker::Name.first_name} #{Faker::Name.last_name}" }
|
70
|
+
type { "Brother" }
|
71
|
+
end
|
72
|
+
|
63
73
|
factory :fish do
|
64
74
|
name { %w[Tilapia Salmon Trout Catfish Pangasius Carp].sample }
|
65
75
|
end
|
data/lib/avo/app.rb
CHANGED
@@ -17,6 +17,17 @@ module Avo
|
|
17
17
|
class_attribute :error_messages
|
18
18
|
|
19
19
|
class << self
|
20
|
+
def eager_load(entity)
|
21
|
+
paths = Avo::ENTITIES.fetch entity
|
22
|
+
|
23
|
+
return unless paths.present?
|
24
|
+
|
25
|
+
pathname = Rails.root.join(*paths)
|
26
|
+
if pathname.directory?
|
27
|
+
Rails.autoloaders.main.eager_load_dir(pathname.to_s)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
20
31
|
def boot
|
21
32
|
init_fields
|
22
33
|
|
@@ -91,7 +102,7 @@ module Avo
|
|
91
102
|
has_model = resource.model_class.present?
|
92
103
|
|
93
104
|
unless has_model
|
94
|
-
possible_model = resource.class.to_s.gsub
|
105
|
+
possible_model = resource.class.to_s.gsub "Resource", ""
|
95
106
|
|
96
107
|
Avo::App.error_messages.push({
|
97
108
|
url: "https://docs.avohq.io/2.0/resources.html#custom-model-class",
|
@@ -119,6 +130,8 @@ module Avo
|
|
119
130
|
end
|
120
131
|
|
121
132
|
def init_dashboards
|
133
|
+
eager_load :dashboards unless Rails.application.config.eager_load
|
134
|
+
|
122
135
|
self.dashboards = Dashboards::BaseDashboard.descendants
|
123
136
|
.select do |dashboard|
|
124
137
|
dashboard != Dashboards::BaseDashboard
|