avo 2.2.0 → 2.3.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 +5 -5
- data/app/assets/svgs/{dashboards-icon.svg → dashboards.svg} +1 -1
- data/app/assets/svgs/{resources-icon.svg → resources.svg} +0 -0
- data/app/assets/svgs/{tools-icon.svg → tools.svg} +0 -0
- data/app/components/avo/index/field_wrapper_component.rb +13 -0
- data/app/components/avo/profile_item_component.html.erb +2 -2
- data/app/components/avo/profile_item_component.rb +6 -0
- data/app/components/avo/sidebar/base_item_component.rb +31 -0
- data/app/components/avo/sidebar/group_component.html.erb +28 -0
- data/app/components/avo/sidebar/group_component.rb +4 -0
- data/app/components/avo/sidebar/heading_component.html.erb +14 -0
- data/app/components/avo/sidebar/heading_component.rb +17 -0
- data/app/components/avo/sidebar/item_switcher_component.html.erb +16 -0
- data/app/components/avo/sidebar/item_switcher_component.rb +15 -0
- data/app/components/avo/sidebar/link_component.html.erb +12 -0
- data/app/components/avo/sidebar/link_component.rb +28 -0
- data/app/components/avo/sidebar/section_component.html.erb +15 -0
- data/app/components/avo/sidebar/section_component.rb +9 -0
- data/app/components/avo/sidebar_component.html.erb +33 -24
- data/app/components/avo/sidebar_component.rb +3 -9
- data/app/components/avo/sidebar_profile_component.html.erb +10 -1
- data/app/controllers/avo/application_controller.rb +1 -2
- data/app/controllers/avo/base_controller.rb +9 -1
- data/app/helpers/avo/application_helper.rb +2 -0
- data/app/javascript/avo.js +13 -0
- data/app/javascript/js/controllers/menu_controller.js +65 -0
- data/app/javascript/js/controllers/search_controller.js +25 -10
- data/app/javascript/js/controllers.js +2 -0
- data/app/views/avo/base/_boolean_filter.html.erb +1 -1
- data/app/views/avo/base/_multiple_select_filter.html.erb +7 -4
- data/app/views/avo/base/_select_filter.html.erb +1 -1
- data/app/views/avo/base/_text_filter.html.erb +1 -1
- data/avo.gemspec +1 -0
- data/lib/avo/app.rb +8 -86
- data/lib/avo/concerns/fetches_things.rb +127 -0
- data/lib/avo/configuration.rb +4 -0
- data/lib/avo/fields/base_field.rb +2 -0
- data/lib/avo/hosts/base_host.rb +20 -0
- data/lib/avo/licensing/pro_license.rb +2 -1
- data/lib/avo/menu/base_item.rb +20 -0
- data/lib/avo/menu/builder.rb +77 -0
- data/lib/avo/menu/dashboard.rb +17 -0
- data/lib/avo/menu/group.rb +2 -0
- data/lib/avo/menu/link.rb +4 -0
- data/lib/avo/menu/menu.rb +2 -0
- data/lib/avo/menu/resource.rb +9 -0
- data/lib/avo/menu/section.rb +2 -0
- data/lib/avo/reloader.rb +10 -2
- data/lib/avo/services/authorization_service.rb +8 -2
- data/lib/avo/version.rb +1 -1
- data/lib/generators/avo/filter_generator.rb +2 -0
- data/lib/generators/avo/templates/filters/boolean_filter.tt +1 -1
- data/lib/generators/avo/templates/filters/multiple_select_filter.tt +11 -0
- data/lib/generators/avo/templates/filters/select_filter.tt +1 -1
- data/lib/generators/avo/templates/filters/text_filter.tt +1 -1
- data/lib/generators/avo/templates/tool/sidebar_item.tt +1 -1
- data/public/avo-assets/avo.css +21 -4
- data/public/avo-assets/avo.js +63 -63
- data/public/avo-assets/avo.js.map +3 -3
- metadata +42 -9
- data/app/components/avo/sidebar_heading_component.html.erb +0 -3
- data/app/components/avo/sidebar_heading_component.rb +0 -11
- data/app/components/avo/sidebar_item_component.html.erb +0 -3
- data/app/components/avo/sidebar_item_component.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7aa88764021f40e6a32625569658172b802aa0c2ca31e0fb282cafa5ccc8ba33
|
4
|
+
data.tar.gz: 6e256e598fa099862691a623edfee9d53d0723d0101e681090686e4edd2ae460
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab132521622ae3dd8dfa75cbf513383b42e6361d64188ced7751560d9808c7b3bb591588ebe831460c992c1d0ee3a6aebed2abfce923d06ccb21da0502373c64
|
7
|
+
data.tar.gz: 3e60dfffdae92341ece77e3bf62236d6104db247399afea1fd6d7a684ad9d1323eff9be12f180ab9ee76f2097036f7cbb48a45720873b66e9dc958b4a0d8fbbf
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
avo (2.
|
4
|
+
avo (2.3.0)
|
5
5
|
active_link_to
|
6
6
|
addressable
|
7
7
|
breadcrumbs_on_rails
|
8
8
|
chartkick
|
9
9
|
countries
|
10
|
+
docile
|
10
11
|
dry-initializer
|
11
12
|
hotwire-rails
|
12
13
|
httparty
|
@@ -89,13 +90,12 @@ GEM
|
|
89
90
|
activerecord (>= 4.2)
|
90
91
|
addressable (2.8.0)
|
91
92
|
public_suffix (>= 2.0.2, < 5.0)
|
92
|
-
ap (0.1.1)
|
93
|
-
httparty (>= 0.7.7)
|
94
93
|
appraisal (2.4.1)
|
95
94
|
bundler
|
96
95
|
rake
|
97
96
|
thor (>= 0.14.0)
|
98
97
|
ast (2.4.2)
|
98
|
+
awesome_print (1.9.2)
|
99
99
|
aws-eventstream (1.2.0)
|
100
100
|
aws-partitions (1.551.0)
|
101
101
|
aws-sdk-core (3.125.5)
|
@@ -242,7 +242,7 @@ GEM
|
|
242
242
|
net-protocol
|
243
243
|
timeout
|
244
244
|
nio4r (2.5.8)
|
245
|
-
nokogiri (1.13.
|
245
|
+
nokogiri (1.13.4)
|
246
246
|
mini_portile2 (~> 2.8.0)
|
247
247
|
racc (~> 1.4)
|
248
248
|
orm_adapter (0.5.0)
|
@@ -418,9 +418,9 @@ DEPENDENCIES
|
|
418
418
|
active_median
|
419
419
|
acts_as_list
|
420
420
|
addressable
|
421
|
-
ap
|
422
421
|
appraisal
|
423
422
|
avo!
|
423
|
+
awesome_print
|
424
424
|
aws-sdk-s3
|
425
425
|
bootsnap (>= 1.4.2)
|
426
426
|
breadcrumbs_on_rails
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<svg
|
1
|
+
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
2
2
|
<path d="M8.4 2H2V8.4H8.4V2Z" stroke="#757D8A" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
3
3
|
<path d="M18 2H11.6V8.4H18V2Z" stroke="#757D8A" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
4
4
|
<path d="M8.4 11.6001H2V18.0001H8.4V11.6001Z" stroke="#757D8A" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
File without changes
|
File without changes
|
@@ -17,6 +17,19 @@ class Avo::Index::FieldWrapperComponent < ViewComponent::Base
|
|
17
17
|
result += " py-3"
|
18
18
|
end
|
19
19
|
|
20
|
+
result += " #{text_align_classes}"
|
21
|
+
|
20
22
|
result
|
21
23
|
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def text_align_classes
|
28
|
+
case @field.index_text_align.to_sym
|
29
|
+
when :right
|
30
|
+
'text-right'
|
31
|
+
when :center
|
32
|
+
'text-center'
|
33
|
+
end
|
34
|
+
end
|
22
35
|
end
|
@@ -1,3 +1,3 @@
|
|
1
|
-
<%= link_to
|
2
|
-
<%=
|
1
|
+
<%= link_to path, class: "flex-1 flex items-center justify-center bg-white text-left cursor-pointer text-gray-800 font-semibold hover:bg-blue-100 block px-4 py-1 w-full py-3 text-center rounded w-full", target: target do %>
|
2
|
+
<%= helpers.svg(icon, class: 'h-4 mr-1') if icon.present? %> <%= label %>
|
3
3
|
<% end %>
|
@@ -1,6 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Avo::ProfileItemComponent < ViewComponent::Base
|
4
|
+
attr_reader :label
|
5
|
+
attr_reader :icon
|
6
|
+
attr_reader :path
|
7
|
+
attr_reader :active
|
8
|
+
attr_reader :target
|
9
|
+
|
4
10
|
def initialize(label: nil, icon: nil, path: nil, active: :inclusive, target: nil)
|
5
11
|
@label = label
|
6
12
|
@icon = icon
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Avo::Sidebar::BaseItemComponent < ViewComponent::Base
|
4
|
+
attr_reader :item
|
5
|
+
|
6
|
+
def initialize(item: nil)
|
7
|
+
@item = item
|
8
|
+
end
|
9
|
+
|
10
|
+
def items
|
11
|
+
item.items
|
12
|
+
end
|
13
|
+
|
14
|
+
def key
|
15
|
+
result = "avo.#{request.host}.main_menu.#{item.name.underscore}"
|
16
|
+
|
17
|
+
if item.icon.present?
|
18
|
+
result += ".#{item.icon.parameterize.underscore}"
|
19
|
+
end
|
20
|
+
|
21
|
+
result
|
22
|
+
end
|
23
|
+
|
24
|
+
def collapsable
|
25
|
+
item.collapsable
|
26
|
+
end
|
27
|
+
|
28
|
+
def collapsed
|
29
|
+
item.collapsed
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<div class="pb-2 space-y-1"
|
2
|
+
<% if collapsable %>
|
3
|
+
data-controller="menu"
|
4
|
+
data-menu-target="self"
|
5
|
+
data-menu-key-param="<%= key %>"
|
6
|
+
data-menu-default-collapsed-state="<%= collapsed ? 'collapsed' : 'expanded' %>"
|
7
|
+
<% end %>
|
8
|
+
>
|
9
|
+
<div class="flex justify-between px-10 pt-2 pb-0 text-gray-600 ">
|
10
|
+
<div class="flex items-center text-xs uppercase font-semibold leading-none">
|
11
|
+
<%= item.name %>
|
12
|
+
</div>
|
13
|
+
<% if collapsable %>
|
14
|
+
<div class="cursor-pointer <%= 'rotate-90' if collapsed %>"
|
15
|
+
data-action="click->menu#triggerCollapse"
|
16
|
+
data-menu-target="svg"
|
17
|
+
data-menu-key-param="<%= key %>"
|
18
|
+
>
|
19
|
+
<%= helpers.svg 'heroicons/outline/chevron-down', class: "h-4"%>
|
20
|
+
</div>
|
21
|
+
<% end %>
|
22
|
+
</div>
|
23
|
+
<div class="w-full space-y-1 <%= 'hidden' if collapsed %>" data-menu-target="items">
|
24
|
+
<% items.each do |item| %>
|
25
|
+
<%= render Avo::Sidebar::ItemSwitcherComponent.new item: item %>
|
26
|
+
<% end %>
|
27
|
+
</div>
|
28
|
+
</div>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<div class="flex justify-between p-4 py-2 text-gray-500">
|
2
|
+
<div class="flex items-center text-sm uppercase font-semibold leading-none space-x-1">
|
3
|
+
<span class="min-w-[20px]"><%= icon %></span> <span><%= label %></span>
|
4
|
+
</div>
|
5
|
+
<% if collapsable %>
|
6
|
+
<div class="cursor-pointer <%= 'rotate-90' if collapsed %>"
|
7
|
+
data-action="click->menu#triggerCollapse"
|
8
|
+
data-menu-key-param="<%= key %>"
|
9
|
+
data-menu-target="svg"
|
10
|
+
>
|
11
|
+
<%= helpers.svg 'heroicons/outline/chevron-down', class: 'h-5'%>
|
12
|
+
</div>
|
13
|
+
<% end %>
|
14
|
+
</div>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Avo::Sidebar::HeadingComponent < ViewComponent::Base
|
4
|
+
attr_reader :collapsable
|
5
|
+
attr_reader :collapsed
|
6
|
+
attr_reader :icon
|
7
|
+
attr_reader :key
|
8
|
+
attr_reader :label
|
9
|
+
|
10
|
+
def initialize(label: nil, icon: nil, collapsable: false, collapsed: false, key: nil)
|
11
|
+
@collapsable = collapsable
|
12
|
+
@collapsed = collapsed
|
13
|
+
@icon = icon
|
14
|
+
@key = key
|
15
|
+
@label = label
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<% if item.is_a? Avo::Menu::Link %>
|
2
|
+
<%= render Avo::Sidebar::LinkComponent.new label: item.name, path: item.path, target: item.target %>
|
3
|
+
<% end %>
|
4
|
+
<% if item.is_a? Avo::Menu::Resource %>
|
5
|
+
<%= render Avo::Sidebar::LinkComponent.new label: resource.navigation_label, path: helpers.resources_path(resource: resource) %>
|
6
|
+
<% end %>
|
7
|
+
<% if item.is_a? Avo::Menu::Dashboard %>
|
8
|
+
<%= render Avo::Sidebar::LinkComponent.new label: dashboard.navigation_label, path: dashboard.navigation_path %>
|
9
|
+
<% end %>
|
10
|
+
<% if item.is_a? Avo::Menu::Section %>
|
11
|
+
<%= render Avo::Sidebar::SectionComponent.new item: item %>
|
12
|
+
<% end %>
|
13
|
+
<% if item.is_a? Avo::Menu::Group %>
|
14
|
+
<%= render Avo::Sidebar::GroupComponent.new item: item %>
|
15
|
+
<% end %>
|
16
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Avo::Sidebar::ItemSwitcherComponent < Avo::Sidebar::BaseItemComponent
|
4
|
+
def resource
|
5
|
+
item.parsed_resource
|
6
|
+
end
|
7
|
+
|
8
|
+
def dashboard
|
9
|
+
item.parsed_dashboard
|
10
|
+
end
|
11
|
+
|
12
|
+
def render?
|
13
|
+
item.visible?
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<% if path.present? %>
|
2
|
+
<%= send link_method, path, class: classes, active: active, target: target do %>
|
3
|
+
<%= label %>
|
4
|
+
<% if target == :_blank %>
|
5
|
+
<%= helpers.svg('heroicons/outline/external-link', class: 'self-center ml-auto h-3') %>
|
6
|
+
<% end %>
|
7
|
+
<% end %>
|
8
|
+
<% else %>
|
9
|
+
<%= content_tag :div, class: classes, active: active, target: target do %>
|
10
|
+
<%= label %>
|
11
|
+
<% end %>
|
12
|
+
<% end %>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Avo::Sidebar::LinkComponent < ViewComponent::Base
|
4
|
+
attr_reader :active
|
5
|
+
attr_reader :target
|
6
|
+
attr_reader :label
|
7
|
+
attr_reader :path
|
8
|
+
|
9
|
+
def initialize(label: nil, path: nil, active: :inclusive, target: nil)
|
10
|
+
@label = label
|
11
|
+
@path = path
|
12
|
+
@active = active
|
13
|
+
@target = target
|
14
|
+
end
|
15
|
+
|
16
|
+
def is_external?
|
17
|
+
URI(path).scheme.present?
|
18
|
+
end
|
19
|
+
|
20
|
+
# For external links active_link_to marks them all as active.
|
21
|
+
def link_method
|
22
|
+
is_external? ? :link_to : :active_link_to
|
23
|
+
end
|
24
|
+
|
25
|
+
def classes
|
26
|
+
"px-4 flex-1 flex mx-6 leading-none py-2 text-black rounded font-medium hover:bg-gray-150"
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<div class="space-y-1"
|
2
|
+
<% if collapsable %>
|
3
|
+
data-controller="menu"
|
4
|
+
data-menu-target="self"
|
5
|
+
data-menu-key-param="<%= key %>"
|
6
|
+
data-menu-default-collapsed-state="<%= collapsed ? 'collapsed' : 'expanded' %>"
|
7
|
+
<% end %>
|
8
|
+
>
|
9
|
+
<%= render Avo::Sidebar::HeadingComponent.new label: item.name, icon: helpers.svg(icon, class: "h-5"), collapsable: item.collapsable, collapsed: collapsed, key: key %>
|
10
|
+
<div class="w-full space-y-1 <%= 'hidden' if collapsed %>" data-menu-target="items">
|
11
|
+
<% items.each do |item| %>
|
12
|
+
<%= render Avo::Sidebar::ItemSwitcherComponent.new item: item %>
|
13
|
+
<% end %>
|
14
|
+
</div>
|
15
|
+
</div>
|
@@ -7,41 +7,50 @@
|
|
7
7
|
</div>
|
8
8
|
</div>
|
9
9
|
<div class="flex-1 flex flex-col justify-between overflow-auto mt-3">
|
10
|
-
<div class="space-y-6">
|
11
|
-
<%= render Avo::
|
10
|
+
<div class="space-y-6 mb-4">
|
11
|
+
<%= render Avo::Sidebar::LinkComponent.new label: 'Get started', path: helpers.avo.root_path, active: :exclusive if Rails.env.development? && Avo.configuration.home_path.nil? %>
|
12
12
|
|
13
|
-
<% if
|
14
|
-
<div>
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
<% dashboards.sort_by { |r| r.navigation_label }.each do |dashboard| %>
|
19
|
-
<%= render Avo::SidebarItemComponent.new label: dashboard.navigation_label, path: dashboard.navigation_path %>
|
20
|
-
<% end %>
|
21
|
-
</div>
|
13
|
+
<% if Avo::App.license.has_with_trial(:menu_editor) && Avo.configuration.main_menu.present? %>
|
14
|
+
<div class="text-black space-y-4">
|
15
|
+
<% Avo::App.main_menu.items.each do |item| %>
|
16
|
+
<%= render Avo::Sidebar::ItemSwitcherComponent.new item: item %>
|
17
|
+
<% end %>
|
22
18
|
</div>
|
23
|
-
<%
|
19
|
+
<% else %>
|
24
20
|
|
25
|
-
|
26
|
-
|
21
|
+
<% if dashboards.present? %>
|
22
|
+
<div>
|
23
|
+
<%= render Avo::Sidebar::HeadingComponent.new label: t('avo.dashboards'), icon: helpers.svg('dashboards', class: 'h-4') %>
|
27
24
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
25
|
+
<div class="w-full space-y-1">
|
26
|
+
<% dashboards.sort_by { |r| r.navigation_label }.each do |dashboard| %>
|
27
|
+
<%= render Avo::Sidebar::LinkComponent.new label: dashboard.navigation_label, path: dashboard.navigation_path %>
|
28
|
+
<% end %>
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
<% end %>
|
34
32
|
|
35
|
-
<% if tools.present? %>
|
36
33
|
<div>
|
37
|
-
<%= render Avo::
|
34
|
+
<%= render Avo::Sidebar::HeadingComponent.new label: t('avo.resources'), icon: helpers.svg('resources', class: 'h-4') %>
|
38
35
|
|
39
36
|
<div class="w-full space-y-1">
|
40
|
-
<%
|
41
|
-
<%= render
|
37
|
+
<% resources.sort_by { |r| r.navigation_label }.each do |resource| %>
|
38
|
+
<%= render Avo::Sidebar::LinkComponent.new label: resource.navigation_label, path: helpers.resources_path(resource: resource) %>
|
42
39
|
<% end %>
|
43
40
|
</div>
|
44
41
|
</div>
|
42
|
+
|
43
|
+
<% if tools.present? %>
|
44
|
+
<div>
|
45
|
+
<%= render Avo::Sidebar::HeadingComponent.new label: t('avo.tools'), icon: helpers.svg('tools', class: 'h-4') %>
|
46
|
+
|
47
|
+
<div class="w-full space-y-1">
|
48
|
+
<% tools.each do |partial| %>
|
49
|
+
<%= render partial: "/avo/sidebar/items/#{partial}" %>
|
50
|
+
<% end %>
|
51
|
+
</div>
|
52
|
+
</div>
|
53
|
+
<% end %>
|
45
54
|
<% end %>
|
46
55
|
|
47
56
|
<%= render partial: "/avo/partials/sidebar_extra" %>
|
@@ -2,20 +2,14 @@
|
|
2
2
|
|
3
3
|
class Avo::SidebarComponent < ViewComponent::Base
|
4
4
|
def dashboards
|
5
|
-
|
6
|
-
|
7
|
-
Avo::App.get_dashboards(helpers._current_user).select do |dashboard|
|
8
|
-
dashboard.is_visible?
|
9
|
-
end
|
5
|
+
Avo::App.dashboards_for_navigation
|
10
6
|
end
|
11
7
|
|
12
8
|
def resources
|
13
|
-
Avo::App.
|
9
|
+
Avo::App.resources_for_navigation
|
14
10
|
end
|
15
11
|
|
16
12
|
def tools
|
17
|
-
|
18
|
-
|
19
|
-
Avo::App.get_sidebar_partials
|
13
|
+
Avo::App.tools_for_navigation
|
20
14
|
end
|
21
15
|
end
|
@@ -25,8 +25,17 @@
|
|
25
25
|
class="hidden absolute flex flex-col inset-auto right-0 -mt-12 bg-white rounded min-w-[200px] shadow-context -translate-y-full"
|
26
26
|
data-toggle-panel-target="panel"
|
27
27
|
>
|
28
|
+
<% if Avo::App.license.has_with_trial(:menu_editor) && Avo.configuration.profile_menu.present? %>
|
29
|
+
<div class="text-black space-y-4">
|
30
|
+
<% Avo::App.profile_menu.items.each do |item| %>
|
31
|
+
<% if item.is_a? Avo::Menu::Link %>
|
32
|
+
<%= render Avo::ProfileItemComponent.new label: item.name, path: item.path, icon: item.icon %>
|
33
|
+
<% end %>
|
34
|
+
<% end %>
|
35
|
+
</div>
|
36
|
+
<% end %>
|
28
37
|
<%# Example link below %>
|
29
|
-
<%#= render Avo::ProfileItemComponent.new label: 'Profile', path: '/profile', icon:
|
38
|
+
<%#= render Avo::ProfileItemComponent.new label: 'Profile', path: '/profile', icon: 'user-circle' %>
|
30
39
|
<%= button_to helpers.main_app.send(destroy_user_session_path),
|
31
40
|
method: :delete,
|
32
41
|
form: { "data-turbo" => "false" },
|
@@ -19,7 +19,6 @@ module Avo
|
|
19
19
|
before_action :set_container_classes
|
20
20
|
before_action :add_initial_breadcrumbs
|
21
21
|
before_action :set_view
|
22
|
-
before_action :set_model_to_fill
|
23
22
|
|
24
23
|
rescue_from Pundit::NotAuthorizedError, with: :render_unauthorized
|
25
24
|
rescue_from ActiveRecord::RecordInvalid, with: :exception_logger
|
@@ -285,7 +284,7 @@ module Avo
|
|
285
284
|
end
|
286
285
|
|
287
286
|
def set_locale
|
288
|
-
I18n.locale = params[:
|
287
|
+
I18n.locale = params[:set_locale] || I18n.default_locale
|
289
288
|
|
290
289
|
I18n.default_locale = I18n.locale
|
291
290
|
end
|
@@ -44,7 +44,15 @@ module Avo
|
|
44
44
|
unless @index_params[:sort_by].eql? :created_at
|
45
45
|
@query = @query.unscope(:order)
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
|
+
# Check if the sortable field option is actually a proc and we need to do a custom sort
|
49
|
+
field_id = @index_params[:sort_by].to_sym
|
50
|
+
field = @resource.get_field_definitions.find { |field| field.id == field_id }
|
51
|
+
if field&.sortable.is_a?(Proc)
|
52
|
+
@query = field.sortable.call(@query, @index_params[:sort_direction])
|
53
|
+
else
|
54
|
+
@query = @query.order("#{@resource.model_class.table_name}.#{@index_params[:sort_by]} #{@index_params[:sort_direction]}")
|
55
|
+
end
|
48
56
|
end
|
49
57
|
|
50
58
|
# Apply filters
|
data/app/javascript/avo.js
CHANGED
@@ -84,3 +84,16 @@ document.addEventListener('turbo:submit-end', () => document.body.classList.remo
|
|
84
84
|
document.addEventListener('turbo:before-cache', () => {
|
85
85
|
document.querySelectorAll('[data-turbo-remove-before-cache]').forEach((element) => element.remove())
|
86
86
|
})
|
87
|
+
|
88
|
+
window.Avo = window.Avo || { configuration: {} }
|
89
|
+
|
90
|
+
window.Avo.menus = {
|
91
|
+
resetCollapsedState() {
|
92
|
+
Array.from(document.querySelectorAll('[data-menu-key-param]'))
|
93
|
+
.map((i) => i.getAttribute('data-menu-key-param'))
|
94
|
+
.filter(Boolean)
|
95
|
+
.forEach((key) => {
|
96
|
+
window.localStorage.removeItem(key)
|
97
|
+
})
|
98
|
+
},
|
99
|
+
}
|
@@ -0,0 +1,65 @@
|
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
|
+
|
3
|
+
export default class extends Controller {
|
4
|
+
static targets = ['svg', 'items', 'self'];
|
5
|
+
|
6
|
+
collapsed = true;
|
7
|
+
|
8
|
+
get key() {
|
9
|
+
return this.selfTarget.getAttribute('data-menu-key-param')
|
10
|
+
}
|
11
|
+
|
12
|
+
get defaultState() {
|
13
|
+
return this.selfTarget.getAttribute('data-menu-default-collapsed-state')
|
14
|
+
}
|
15
|
+
|
16
|
+
get userState() {
|
17
|
+
return window.localStorage.getItem(this.key)
|
18
|
+
}
|
19
|
+
|
20
|
+
set userState(payload) {
|
21
|
+
window.localStorage.setItem(this.key, payload)
|
22
|
+
}
|
23
|
+
|
24
|
+
get initiallyCollapsed() {
|
25
|
+
if (this.userState === 'collapsed' || this.defaultState === 'collapsed') return true
|
26
|
+
if (this.userState === 'expanded' || this.defaultState === 'expanded') return false
|
27
|
+
|
28
|
+
return false
|
29
|
+
}
|
30
|
+
|
31
|
+
connect() {
|
32
|
+
if (this.initiallyCollapsed) {
|
33
|
+
this.collapsed = true
|
34
|
+
this.markCollapsed()
|
35
|
+
} else {
|
36
|
+
this.collapsed = false
|
37
|
+
this.markExpanded()
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
triggerCollapse() {
|
42
|
+
this.collapsed = !this.collapsed
|
43
|
+
this.userState = this.collapsed ? 'collapsed' : 'expanded'
|
44
|
+
|
45
|
+
this.updateDom()
|
46
|
+
}
|
47
|
+
|
48
|
+
updateDom() {
|
49
|
+
if (this.collapsed) {
|
50
|
+
this.markCollapsed()
|
51
|
+
} else {
|
52
|
+
this.markExpanded()
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
markCollapsed() {
|
57
|
+
this.svgTarget.classList.add('rotate-90')
|
58
|
+
this.itemsTarget.classList.add('hidden')
|
59
|
+
}
|
60
|
+
|
61
|
+
markExpanded() {
|
62
|
+
this.svgTarget.classList.remove('rotate-90')
|
63
|
+
this.itemsTarget.classList.remove('hidden')
|
64
|
+
}
|
65
|
+
}
|
@@ -105,7 +105,7 @@ export default class extends Controller {
|
|
105
105
|
return `${data.header.toUpperCase()} ${data.help}`
|
106
106
|
},
|
107
107
|
item({ item, createElement }) {
|
108
|
-
|
108
|
+
const children = []
|
109
109
|
|
110
110
|
if (item._avatar) {
|
111
111
|
let classes
|
@@ -120,22 +120,37 @@ export default class extends Controller {
|
|
120
120
|
break
|
121
121
|
}
|
122
122
|
|
123
|
-
|
123
|
+
children.push(
|
124
|
+
createElement('img', {
|
125
|
+
src: item._avatar,
|
126
|
+
alt: item._label,
|
127
|
+
class: `flex-shrink-0 w-8 h-8 my-[2px] inline mr-2 ${classes}`,
|
128
|
+
}),
|
129
|
+
)
|
124
130
|
}
|
125
|
-
element += `<div>${item._label}`
|
126
131
|
|
132
|
+
const labelChildren = [item._label]
|
127
133
|
if (item._description) {
|
128
|
-
|
134
|
+
labelChildren.push(
|
135
|
+
createElement(
|
136
|
+
'div',
|
137
|
+
{
|
138
|
+
class: 'aa-ItemDescription',
|
139
|
+
},
|
140
|
+
item._description,
|
141
|
+
),
|
142
|
+
)
|
129
143
|
}
|
130
144
|
|
131
|
-
|
145
|
+
children.push(createElement('div', null, labelChildren))
|
132
146
|
|
133
|
-
return createElement(
|
134
|
-
|
135
|
-
|
136
|
-
|
147
|
+
return createElement(
|
148
|
+
'div',
|
149
|
+
{
|
150
|
+
class: 'flex',
|
137
151
|
},
|
138
|
-
|
152
|
+
children,
|
153
|
+
)
|
139
154
|
},
|
140
155
|
noResults() {
|
141
156
|
return that.translationKeys.no_item_found.replace(
|
@@ -15,6 +15,7 @@ import ItemSelectAllController from './controllers/item_select_all_controller'
|
|
15
15
|
import ItemSelectorController from './controllers/item_selector_controller'
|
16
16
|
import KeyValueController from './controllers/fields/key_value_controller'
|
17
17
|
import LoadingButtonController from './controllers/loading_button_controller'
|
18
|
+
import MenuController from './controllers/menu_controller'
|
18
19
|
import MobileController from './controllers/mobile_controller'
|
19
20
|
import ModalController from './controllers/modal_controller'
|
20
21
|
import MultipleSelectFilterController from './controllers/multiple_select_filter_controller'
|
@@ -39,6 +40,7 @@ application.register('hidden-input', HiddenInputController)
|
|
39
40
|
application.register('item-select-all', ItemSelectAllController)
|
40
41
|
application.register('item-selector', ItemSelectorController)
|
41
42
|
application.register('loading-button', LoadingButtonController)
|
43
|
+
application.register('menu', MenuController)
|
42
44
|
application.register('mobile', MobileController)
|
43
45
|
application.register('modal', ModalController)
|
44
46
|
application.register('multiple-select-filter', MultipleSelectFilterController)
|