avo 2.1.2.pre2 → 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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -2
  3. data/Gemfile.lock +11 -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/button_component.rb +6 -2
  8. data/app/components/avo/fields/belongs_to_field/autocomplete_component.html.erb +1 -0
  9. data/app/components/avo/fields/belongs_to_field/edit_component.rb +5 -2
  10. data/app/components/avo/index/field_wrapper_component.rb +13 -0
  11. data/app/components/avo/index/grid_item_component.html.erb +3 -1
  12. data/app/components/avo/index/table_row_component.html.erb +7 -5
  13. data/app/components/avo/panel_component.html.erb +4 -4
  14. data/app/components/avo/profile_item_component.html.erb +2 -2
  15. data/app/components/avo/profile_item_component.rb +6 -0
  16. data/app/components/avo/sidebar/base_item_component.rb +31 -0
  17. data/app/components/avo/sidebar/group_component.html.erb +28 -0
  18. data/app/components/avo/sidebar/group_component.rb +4 -0
  19. data/app/components/avo/sidebar/heading_component.html.erb +14 -0
  20. data/app/components/avo/sidebar/heading_component.rb +15 -0
  21. data/app/components/avo/sidebar/item_switcher_component.html.erb +16 -0
  22. data/app/components/avo/sidebar/item_switcher_component.rb +15 -0
  23. data/app/components/avo/sidebar/link_component.html.erb +12 -0
  24. data/app/components/avo/sidebar/link_component.rb +28 -0
  25. data/app/components/avo/sidebar/section_component.html.erb +15 -0
  26. data/app/components/avo/sidebar/section_component.rb +9 -0
  27. data/app/components/avo/sidebar_component.html.erb +33 -24
  28. data/app/components/avo/sidebar_component.rb +3 -9
  29. data/app/components/avo/sidebar_profile_component.html.erb +10 -1
  30. data/app/components/avo/views/resource_edit_component.html.erb +2 -2
  31. data/app/components/avo/views/resource_new_component.html.erb +2 -2
  32. data/app/components/avo/views/resource_show_component.html.erb +2 -2
  33. data/app/controllers/avo/application_controller.rb +1 -2
  34. data/app/controllers/avo/base_controller.rb +1 -1
  35. data/app/helpers/avo/application_helper.rb +2 -0
  36. data/app/javascript/js/controllers/loading_button_controller.js +47 -10
  37. data/app/javascript/js/controllers/menu_controller.js +60 -0
  38. data/app/javascript/js/controllers/search_controller.js +28 -10
  39. data/app/javascript/js/controllers.js +2 -0
  40. data/app/views/avo/base/_boolean_filter.html.erb +1 -1
  41. data/app/views/avo/base/_multiple_select_filter.html.erb +7 -4
  42. data/app/views/avo/base/_select_filter.html.erb +1 -1
  43. data/app/views/avo/base/_text_filter.html.erb +1 -1
  44. data/app/views/avo/partials/_table_header.html.erb +12 -13
  45. data/app/views/layouts/avo/application.html.erb +3 -0
  46. data/avo.gemspec +1 -0
  47. data/bin/helpers.rb +7 -1
  48. data/bin/init +2 -2
  49. data/lib/avo/app.rb +8 -86
  50. data/lib/avo/base_resource.rb +1 -3
  51. data/lib/avo/concerns/fetches_things.rb +127 -0
  52. data/lib/avo/configuration.rb +4 -0
  53. data/lib/avo/dynamic_router.rb +1 -1
  54. data/lib/avo/engine.rb +0 -1
  55. data/lib/avo/fields/base_field.rb +2 -0
  56. data/lib/avo/fields/belongs_to_field.rb +2 -0
  57. data/lib/avo/hosts/base_host.rb +20 -0
  58. data/lib/avo/licensing/pro_license.rb +2 -1
  59. data/lib/avo/menu/base_item.rb +20 -0
  60. data/lib/avo/menu/builder.rb +77 -0
  61. data/lib/avo/menu/dashboard.rb +17 -0
  62. data/lib/avo/menu/group.rb +2 -0
  63. data/lib/avo/menu/link.rb +4 -0
  64. data/lib/avo/menu/menu.rb +2 -0
  65. data/lib/avo/menu/resource.rb +9 -0
  66. data/lib/avo/menu/section.rb +2 -0
  67. data/lib/avo/reloader.rb +15 -7
  68. data/lib/avo/version.rb +1 -1
  69. data/lib/generators/avo/filter_generator.rb +2 -0
  70. data/lib/generators/avo/templates/filters/boolean_filter.tt +1 -1
  71. data/lib/generators/avo/templates/filters/multiple_select_filter.tt +11 -0
  72. data/lib/generators/avo/templates/filters/select_filter.tt +1 -1
  73. data/lib/generators/avo/templates/filters/text_filter.tt +1 -1
  74. data/lib/generators/avo/templates/tool/sidebar_item.tt +1 -1
  75. data/public/avo-assets/avo.css +23 -6
  76. data/public/avo-assets/avo.js +63 -63
  77. data/public/avo-assets/avo.js.map +3 -3
  78. metadata +44 -14
  79. data/app/assets/builds/avo.css +0 -8810
  80. data/app/assets/builds/avo.js +0 -423
  81. data/app/assets/builds/avo.js.map +0 -7
  82. data/app/components/avo/sidebar_heading_component.html.erb +0 -3
  83. data/app/components/avo/sidebar_heading_component.rb +0 -11
  84. data/app/components/avo/sidebar_item_component.html.erb +0 -3
  85. 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: bde8997aaf953104f34a221e6be3c93b6c7f20bc1b9f125615c0ff994cc6791f
4
- data.tar.gz: ca3a39976e8046d165cdb66a8aad6260e98d869981e73eba1d6d121bb57a7580
3
+ metadata.gz: 35ab86df7a30aa58a644902eea79236c3b46f3f77eb86fc791e100dbdfc4c278
4
+ data.tar.gz: a1c038e4cfd7101b35361638152c60f1ec06d456364909860cb9296ffa1aa99a
5
5
  SHA512:
6
- metadata.gz: 50c30c580b89ad850a34c0125ad0079d34a1af72eefbb99193644f605692ea5f3e2bb54e1a0032ef04e219ba84888171cfcf6b69c6da045475f21afc50747680
7
- data.tar.gz: 0ce0f8be40b683c2c1ef5b8e963bbbb0d8282e4e0b7d193f4acedee530d9618481a036a0c3955214d4c024876a374009c82df85a788708aebf603943595218c1
6
+ metadata.gz: 9976990e8b22f579579f2e983e1990a058fe8f91e27e40972b8ee745a879d3200eb134a9583fb7c7c7f8991e6e44dd18ba5d832914025b8faa881336a5da2168
7
+ data.tar.gz: 7f16c6e613a17e130a7c2352ac343da1c29b95be680f697dc51f8f95ffbb779751b7fd73ece5f905d020ca2a275cce4c61c07ebdda97a95321efb87f08a0979e
data/Gemfile CHANGED
@@ -34,7 +34,7 @@ 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
37
- # gem 'redis', '~> 4.0'
37
+ gem 'redis', '~> 4.0'
38
38
  # Use Active Model has_secure_password
39
39
  # gem 'bcrypt', '~> 3.1.7'
40
40
 
@@ -79,10 +79,12 @@ group :development do
79
79
  # gem 'pry-rails'
80
80
 
81
81
  gem 'htmlbeautifier'
82
+
83
+ gem "hotwire-livereload", "~> 1.1"
82
84
  end
83
85
 
84
86
  group :development, :test do
85
- gem 'ap'
87
+ gem "awesome_print"
86
88
  gem "faker", require: false
87
89
  end
88
90
 
data/Gemfile.lock CHANGED
@@ -1,12 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avo (2.1.2.pre2)
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)
@@ -183,6 +183,9 @@ GEM
183
183
  hashdiff (1.0.1)
184
184
  hightop (0.3.0)
185
185
  activesupport (>= 5.2)
186
+ hotwire-livereload (1.1.0)
187
+ listen (>= 3.0.0)
188
+ rails (>= 6.0.0)
186
189
  hotwire-rails (0.1.3)
187
190
  rails (>= 6.0.0)
188
191
  stimulus-rails
@@ -239,7 +242,7 @@ GEM
239
242
  net-protocol
240
243
  timeout
241
244
  nio4r (2.5.8)
242
- nokogiri (1.13.3)
245
+ nokogiri (1.13.4)
243
246
  mini_portile2 (~> 2.8.0)
244
247
  racc (~> 1.4)
245
248
  orm_adapter (0.5.0)
@@ -297,6 +300,7 @@ GEM
297
300
  rb-fsevent (0.11.0)
298
301
  rb-inotify (0.10.1)
299
302
  ffi (~> 1.0)
303
+ redis (4.6.0)
300
304
  regexp_parser (2.2.0)
301
305
  responders (3.0.1)
302
306
  actionpack (>= 5.0)
@@ -414,9 +418,9 @@ DEPENDENCIES
414
418
  active_median
415
419
  acts_as_list
416
420
  addressable
417
- ap
418
421
  appraisal
419
422
  avo!
423
+ awesome_print
420
424
  aws-sdk-s3
421
425
  bootsnap (>= 1.4.2)
422
426
  breadcrumbs_on_rails
@@ -435,6 +439,7 @@ DEPENDENCIES
435
439
  gem-release
436
440
  groupdate
437
441
  hightop
442
+ hotwire-livereload (~> 1.1)
438
443
  hotwire-rails
439
444
  htmlbeautifier
440
445
  httparty
@@ -452,6 +457,7 @@ DEPENDENCIES
452
457
  rails (~> 6.1.0)
453
458
  rails-controller-testing
454
459
  ransack
460
+ redis (~> 4.0)
455
461
  rspec-rails (~> 4.0.0)
456
462
  rubocop
457
463
  rubocop-shopify
@@ -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
@@ -24,8 +24,12 @@ class Avo::ButtonComponent < ViewComponent::Base
24
24
  end
25
25
 
26
26
  def args
27
- if @args[:spinner]
27
+ if @args[:loading]
28
28
  @args[:"data-controller"] = "loading-button"
29
+
30
+ if @args[:confirm]
31
+ @args[:"data-avo-confirm"] = @args.delete(:confirm)
32
+ end
29
33
  end
30
34
 
31
35
  @args[:class] = button_classes
@@ -34,7 +38,7 @@ class Avo::ButtonComponent < ViewComponent::Base
34
38
  end
35
39
 
36
40
  def button_classes
37
- classes = "button-component inline-flex flex-grow-0 items-center text-sm font-semibold leading-6 fill-current whitespace-nowrap transition duration-100 transform transition duration-100 cursor-pointer disabled:cursor-not-allowed disabled:opacity-30 border justify-center active:outline active:outline-1 #{@class}"
41
+ classes = "button-component inline-flex flex-grow-0 items-center text-sm font-semibold leading-6 fill-current whitespace-nowrap transition duration-100 transform transition duration-100 cursor-pointer disabled:cursor-not-allowed disabled:opacity-70 border justify-center active:outline active:outline-1 #{@class}"
38
42
 
39
43
  classes += " rounded" if @rounded.present?
40
44
 
@@ -7,6 +7,7 @@
7
7
  ></div>
8
8
  <div class="relative w-full" autocomplete="off">
9
9
  <%= @form.text_field @foreign_key,
10
+ type: :text,
10
11
  value: field_label,
11
12
  class: helpers.input_classes('w-full', has_error: @field.model_errors.include?(@field.id)),
12
13
  placeholder: @field.placeholder,
@@ -9,8 +9,11 @@ class Avo::Fields::BelongsToField::EditComponent < Avo::Fields::EditComponent
9
9
 
10
10
  def disabled
11
11
  return true if @field.readonly
12
- return true if @field.target_resource.present? && @field.target_resource.model_class.name == params[:via_resource_class]
13
- return true if @field.id.to_s == params[:via_relation].to_s
12
+
13
+ # When visiting the record through it's association we keep the field disabled by default
14
+ # We make an exception when the user deliberately instructs Avo to allow detaching in this scenario
15
+ return !@field.allow_via_detaching if @field.target_resource.present? && @field.target_resource.model_class.name == params[:via_resource_class]
16
+ return !@field.allow_via_detaching if @field.id.to_s == params[:via_relation].to_s
14
17
 
15
18
  false
16
19
  end
@@ -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
@@ -3,7 +3,9 @@
3
3
  <%== item_selector_init @resource %>
4
4
  >
5
5
  <div class="relative w-full pb-3/4 rounded-t overflow-hidden">
6
- <%== item_selector_input floating: true, size: :lg %>
6
+ <% if @resource.record_selector %>
7
+ <%== item_selector_input floating: true, size: :lg %>
8
+ <% end %>
7
9
  <% if cover.blank? %>
8
10
  <%= link_to cover.link_to_resource do %>
9
11
  <%= render Avo::Index::GridCoverEmptyStateComponent.new %>
@@ -2,11 +2,13 @@
2
2
  class="bg-white hover:bg-blue-50 hover:shadow-row hover:z-[21] relative z-20 border-b"
3
3
  <%== item_selector_init @resource %>
4
4
  >
5
- <td class="w-10">
6
- <div class="flex justify-center h-full">
7
- <%== item_selector_input floating: false %>
8
- </div>
9
- </td>
5
+ <% if @resource.record_selector %>
6
+ <td class="w-10">
7
+ <div class="flex justify-center h-full">
8
+ <%== item_selector_input floating: false %>
9
+ </div>
10
+ </td>
11
+ <% end %>
10
12
  <% @resource.get_fields(reflection: @reflection).each_with_index do |field, index| %>
11
13
  <%= render field.component_for_view(:index).new(field: field, resource: @resource, index: index, parent_model: @parent_model) %>
12
14
  <% end %>
@@ -1,19 +1,19 @@
1
1
  <div <%== data_attributes %>>
2
2
  <% if render_header? %>
3
3
  <div class="<%= white_panel_classes %> p-4 flex-1 flex flex-col xl:flex-row justify-between mb-6">
4
- <div class="overflow-hidden mr-4">
4
+ <div class="overflow-hidden mr-4 flex flex-col">
5
5
  <% if display_breadcrumbs? %>
6
6
  <div class="breadcrumbs truncate mb-2">
7
7
  <%= helpers.render_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
 
11
- <div class="text-2xl tracking-normal font-semibold text-gray-800 truncate" data-target="title">
12
- <%= @title %>
11
+ <div class="text-2xl tracking-normal font-semibold text-gray-800 truncate items-center flex flex-1" data-target="title">
12
+ <span><%= @title %></span>
13
13
  </div>
14
14
 
15
15
  <% if description.present? %>
16
- <div class="text-base tracking-normal font-medium text-gray-600 truncate" data-target="description">
16
+ <div class="text-base tracking-normal font-medium text-gray-600" data-target="description">
17
17
  <%== description %>
18
18
  </div>
19
19
  <% 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" },
@@ -13,7 +13,7 @@
13
13
  <%= t('avo.cancel').capitalize %>
14
14
  <% end %>
15
15
  <% if can_see_the_save_button? %>
16
- <%= a_button color: :green, spinner: true, type: :submit, icon: 'save' do %>
16
+ <%= a_button color: :green, loading: true, type: :submit, icon: 'save' do %>
17
17
  <%= t('avo.save').capitalize %>
18
18
  <% end %>
19
19
  <% end %>
@@ -24,7 +24,7 @@
24
24
  <%= t('avo.cancel').capitalize %>
25
25
  <% end %>
26
26
  <% if can_see_the_save_button? %>
27
- <%= a_button color: :green, spinner: true, type: :submit, icon: 'save' do %>
27
+ <%= a_button color: :green, loading: true, type: :submit, icon: 'save' do %>
28
28
  <%= t('avo.save').capitalize %>
29
29
  <% end %>
30
30
  <% end %>
@@ -18,7 +18,7 @@
18
18
  <%= t('avo.cancel').capitalize %>
19
19
  <% end %>
20
20
  <% if can_see_the_save_button? %>
21
- <%= a_button color: 'green', spinner: true, type: :submit, icon: 'save' do %>
21
+ <%= a_button color: 'green', loading: true, type: :submit, icon: 'save' do %>
22
22
  <%= t('avo.save').capitalize %>
23
23
  <% end %>
24
24
  <% end %>
@@ -30,7 +30,7 @@
30
30
  <%= t('avo.cancel').capitalize %>
31
31
  <% end %>
32
32
  <% if can_see_the_save_button? %>
33
- <%= a_button color: :green, spinner: true, type: :submit, icon: 'save' do %>
33
+ <%= a_button color: :green, loading: true, type: :submit, icon: 'save' do %>
34
34
  <%= t('avo.save').capitalize %>
35
35
  <% end %>
36
36
  <% end %>