avo 2.2.1 → 2.2.2

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.

Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +5 -5
  4. data/app/assets/svgs/{dashboards-icon.svg → dashboards.svg} +1 -1
  5. data/app/assets/svgs/{resources-icon.svg → resources.svg} +0 -0
  6. data/app/assets/svgs/{tools-icon.svg → tools.svg} +0 -0
  7. data/app/components/avo/index/field_wrapper_component.rb +13 -0
  8. data/app/components/avo/profile_item_component.html.erb +2 -2
  9. data/app/components/avo/profile_item_component.rb +6 -0
  10. data/app/components/avo/sidebar/base_item_component.rb +31 -0
  11. data/app/components/avo/sidebar/group_component.html.erb +28 -0
  12. data/app/components/avo/sidebar/group_component.rb +4 -0
  13. data/app/components/avo/sidebar/heading_component.html.erb +14 -0
  14. data/app/components/avo/sidebar/heading_component.rb +15 -0
  15. data/app/components/avo/sidebar/item_switcher_component.html.erb +16 -0
  16. data/app/components/avo/sidebar/item_switcher_component.rb +15 -0
  17. data/app/components/avo/sidebar/link_component.html.erb +12 -0
  18. data/app/components/avo/sidebar/link_component.rb +28 -0
  19. data/app/components/avo/sidebar/section_component.html.erb +15 -0
  20. data/app/components/avo/sidebar/section_component.rb +9 -0
  21. data/app/components/avo/sidebar_component.html.erb +33 -24
  22. data/app/components/avo/sidebar_component.rb +3 -9
  23. data/app/components/avo/sidebar_profile_component.html.erb +10 -1
  24. data/app/controllers/avo/application_controller.rb +1 -2
  25. data/app/helpers/avo/application_helper.rb +2 -0
  26. data/app/javascript/js/controllers/menu_controller.js +60 -0
  27. data/app/javascript/js/controllers.js +2 -0
  28. data/app/views/avo/base/_boolean_filter.html.erb +1 -1
  29. data/app/views/avo/base/_multiple_select_filter.html.erb +7 -4
  30. data/app/views/avo/base/_select_filter.html.erb +1 -1
  31. data/app/views/avo/base/_text_filter.html.erb +1 -1
  32. data/avo.gemspec +1 -0
  33. data/lib/avo/app.rb +8 -86
  34. data/lib/avo/concerns/fetches_things.rb +127 -0
  35. data/lib/avo/configuration.rb +4 -0
  36. data/lib/avo/fields/base_field.rb +2 -0
  37. data/lib/avo/hosts/base_host.rb +20 -0
  38. data/lib/avo/licensing/pro_license.rb +2 -1
  39. data/lib/avo/menu/base_item.rb +20 -0
  40. data/lib/avo/menu/builder.rb +77 -0
  41. data/lib/avo/menu/dashboard.rb +17 -0
  42. data/lib/avo/menu/group.rb +2 -0
  43. data/lib/avo/menu/link.rb +4 -0
  44. data/lib/avo/menu/menu.rb +2 -0
  45. data/lib/avo/menu/resource.rb +9 -0
  46. data/lib/avo/menu/section.rb +2 -0
  47. data/lib/avo/reloader.rb +10 -2
  48. data/lib/avo/version.rb +1 -1
  49. data/lib/generators/avo/filter_generator.rb +2 -0
  50. data/lib/generators/avo/templates/filters/boolean_filter.tt +1 -1
  51. data/lib/generators/avo/templates/filters/multiple_select_filter.tt +11 -0
  52. data/lib/generators/avo/templates/filters/select_filter.tt +1 -1
  53. data/lib/generators/avo/templates/filters/text_filter.tt +1 -1
  54. data/lib/generators/avo/templates/tool/sidebar_item.tt +1 -1
  55. data/public/avo-assets/avo.css +21 -4
  56. data/public/avo-assets/avo.js +63 -63
  57. data/public/avo-assets/avo.js.map +3 -3
  58. metadata +42 -9
  59. data/app/components/avo/sidebar_heading_component.html.erb +0 -3
  60. data/app/components/avo/sidebar_heading_component.rb +0 -11
  61. data/app/components/avo/sidebar_item_component.html.erb +0 -3
  62. 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: 1ed006aa7c57368aa03156290f54f757484daff2434ad0f235fa1cdabd0489e4
4
- data.tar.gz: 5596ead68c48c161977b477ad5b689be6228957b56f818d0a2ba015f3bf250be
3
+ metadata.gz: 35ab86df7a30aa58a644902eea79236c3b46f3f77eb86fc791e100dbdfc4c278
4
+ data.tar.gz: a1c038e4cfd7101b35361638152c60f1ec06d456364909860cb9296ffa1aa99a
5
5
  SHA512:
6
- metadata.gz: 68a9010fd5eec2c2c45527cc3bb46c751eefbde06894d4e8857f9d86c8417fdc13d835422479efd5361e16c677ecfa57a3ae0a375b4cd84598d5e88bd85dd2bd
7
- data.tar.gz: e2adc97bfcac2b881d9780d60bdc323186362f76c3139f03b0282ac1275f64cba2555c46ad6617aab3fff886c12e1322debbd1e7b38cd107f082129a6f392900
6
+ metadata.gz: 9976990e8b22f579579f2e983e1990a058fe8f91e27e40972b8ee745a879d3200eb134a9583fb7c7c7f8991e6e44dd18ba5d832914025b8faa881336a5da2168
7
+ data.tar.gz: 7f16c6e613a17e130a7c2352ac343da1c29b95be680f697dc51f8f95ffbb779751b7fd73ece5f905d020ca2a275cce4c61c07ebdda97a95321efb87f08a0979e
data/Gemfile CHANGED
@@ -84,7 +84,7 @@ group :development do
84
84
  end
85
85
 
86
86
  group :development, :test do
87
- gem 'ap'
87
+ gem "awesome_print"
88
88
  gem "faker", require: false
89
89
  end
90
90
 
data/Gemfile.lock CHANGED
@@ -1,12 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avo (2.2.1)
4
+ avo (2.2.2)
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.3)
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 width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/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
@@ -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 @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" do %>
2
- <%= @icon if @icon.present? %> <%= @label %>
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-collapsed-param="<%= 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"
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" 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,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::Sidebar::GroupComponent < Avo::Sidebar::BaseItemComponent
4
+ end
@@ -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"
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,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::Sidebar::HeadingComponent < ViewComponent::Base
4
+ attr_reader :collapsable
5
+ attr_reader :icon
6
+ attr_reader :key
7
+ attr_reader :label
8
+
9
+ def initialize(label: nil, icon: nil, collapsable: false, key: nil)
10
+ @collapsable = collapsable
11
+ @icon = icon
12
+ @key = key
13
+ @label = label
14
+ end
15
+ 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-collapsed-param="<%= 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, key: key %>
10
+ <div class="w-full space-y-1" data-menu-target="items">
11
+ <% items.each do |item| %>
12
+ <%= render Avo::Sidebar::ItemSwitcherComponent.new item: item %>
13
+ <% end %>
14
+ </div>
15
+ </div>
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::Sidebar::SectionComponent < Avo::Sidebar::BaseItemComponent
4
+ def icon
5
+ return nil if item.icon.nil?
6
+
7
+ item.icon
8
+ end
9
+ end
@@ -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::SidebarItemComponent.new label: 'Get started', path: helpers.avo.root_path, active: :exclusive if Rails.env.development? && Avo.configuration.home_path.nil? %>
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 dashboards.present? %>
14
- <div>
15
- <%= render Avo::SidebarHeadingComponent.new label: t('avo.dashboards'), icon: helpers.svg('dashboards-icon', class: 'h-4') %>
16
-
17
- <div class="w-full space-y-1">
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
- <% end %>
19
+ <% else %>
24
20
 
25
- <div>
26
- <%= render Avo::SidebarHeadingComponent.new label: t('avo.resources'), icon: helpers.svg('resources-icon', class: 'h-4') %>
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
- <div class="w-full space-y-1">
29
- <% resources.sort_by { |r| r.navigation_label }.each do |resource| %>
30
- <%= render Avo::SidebarItemComponent.new label: resource.navigation_label, path: helpers.resources_path(resource: resource) %>
31
- <% end %>
32
- </div>
33
- </div>
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::SidebarHeadingComponent.new label: t('avo.tools'), icon: helpers.svg('tools-icon', class: 'h-4') %>
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
- <% tools.each do |partial| %>
41
- <%= render partial: "/avo/sidebar/items/#{partial}" %>
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
- return [] if Avo::App.license.lacks_with_trial(:dashboards)
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.resources_navigation(helpers._current_user)
9
+ Avo::App.resources_for_navigation
14
10
  end
15
11
 
16
12
  def tools
17
- return [] if Avo::App.license.lacks_with_trial(:custom_tools)
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: helpers.svg('user-circle', class: 'h-4 mr-1') %>
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[:locale] || I18n.default_locale
287
+ I18n.locale = params[:set_locale] || I18n.default_locale
289
288
 
290
289
  I18n.default_locale = I18n.locale
291
290
  end
@@ -71,6 +71,8 @@ module Avo
71
71
  end
72
72
 
73
73
  def svg(file_name, **args)
74
+ return if file_name.nil?
75
+
74
76
  options = {}
75
77
  options[:class] = args[:class].present? ? args[:class] : ""
76
78
  options[:class] += args[:extra_class].present? ? " #{args[:extra_class]}" : ""
@@ -0,0 +1,60 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+ import isNull from 'lodash/isNull'
3
+
4
+ export default class extends Controller {
5
+ static targets = ['svg', 'items', 'self'];
6
+
7
+ collapsed = false;
8
+
9
+ get key() {
10
+ return this.selfTarget.getAttribute('data-menu-key-param')
11
+ }
12
+
13
+ defaultState() {
14
+ return this.selfTarget.getAttribute('data-menu-collapsed-param') === 'collapsed'
15
+ }
16
+
17
+ connect() {
18
+ if (this.getState() === 'collapsed') {
19
+ this.collapsed = true
20
+ this.markCollapsed()
21
+ } else if (isNull(this.getState()) && this.defaultState()) {
22
+ this.collapsed = true
23
+ this.markCollapsed()
24
+ }
25
+ }
26
+
27
+ triggerCollapse() {
28
+ this.collapsed = !this.collapsed
29
+
30
+ this.updateDom()
31
+ }
32
+
33
+ updateDom() {
34
+ if (this.collapsed) {
35
+ this.markCollapsed()
36
+ } else {
37
+ this.markExpanded()
38
+ }
39
+ }
40
+
41
+ markCollapsed() {
42
+ this.svgTarget.classList.add('rotate-90')
43
+ this.itemsTarget.classList.add('hidden')
44
+ this.storeState('collapsed')
45
+ }
46
+
47
+ markExpanded() {
48
+ this.svgTarget.classList.remove('rotate-90')
49
+ this.itemsTarget.classList.remove('hidden')
50
+ this.storeState('expanded')
51
+ }
52
+
53
+ getState() {
54
+ return window.localStorage.getItem(this.key)
55
+ }
56
+
57
+ storeState(payload) {
58
+ window.localStorage.setItem(this.key, payload)
59
+ }
60
+ }
@@ -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)
@@ -11,7 +11,7 @@
11
11
  end
12
12
  set_value = {} if set_value.nil?
13
13
  %>
14
- <div data-controller="boolean-filter">
14
+ <div data-controller="boolean-filter" data-filter-name="<%= filter.name %>">
15
15
  <%= filter_wrapper name: filter.name do %>
16
16
  <div class="flex items-center">
17
17
  <div class="space-y-2">
@@ -1,12 +1,15 @@
1
1
  <%
2
+ set_value = filter.default.present? ? filter.default.select { |key, value| value }.keys.map(&:to_sym) : {}
3
+
2
4
  begin
3
5
  decoded_filters_param = JSON.parse(Base64.decode64(params[:filters]))
4
- set_value = decoded_filters_param[filter.class.to_s]
5
- rescue => exception
6
- set_value = filter.options.keys
6
+ if decoded_filters_param[filter.class.to_s].present?
7
+ set_value = decoded_filters_param[filter.class.to_s]
8
+ end
9
+ rescue
7
10
  end
8
11
  %>
9
- <div data-controller="multiple-select-filter">
12
+ <div data-controller="multiple-select-filter" data-filter-name="<%= filter.name %>">
10
13
  <%= filter_wrapper name: filter.name do %>
11
14
  <%= select_tag filter.id, options_for_select(filter.options.invert, set_value),
12
15
  class: input_classes('w-full mb-0'),
@@ -6,7 +6,7 @@
6
6
  set_value = filter.default
7
7
  end
8
8
  %>
9
- <div data-controller="select-filter">
9
+ <div data-controller="select-filter" data-filter-name="<%= filter.name %>">
10
10
  <%= filter_wrapper name: filter.name do %>
11
11
  <%= select_tag filter.id, options_for_select(filter.options.invert, set_value),
12
12
  class: input_classes('w-full mb-0'),
@@ -6,7 +6,7 @@
6
6
  set_value = filter.default
7
7
  end
8
8
  %>
9
- <div data-controller="text-filter">
9
+ <div data-controller="text-filter" data-filter-name="<%= filter.name %>">
10
10
  <%= filter_wrapper name: filter.name do %>
11
11
  <%= text_field_tag filter.id, set_value,
12
12
  class: input_classes('w-full mb-0'),
data/avo.gemspec CHANGED
@@ -47,4 +47,5 @@ Gem::Specification.new do |spec|
47
47
  spec.add_dependency "breadcrumbs_on_rails"
48
48
  spec.add_dependency "chartkick"
49
49
  spec.add_dependency "dry-initializer"
50
+ spec.add_dependency "docile"
50
51
  end