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.

Files changed (66) 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 +17 -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/controllers/avo/base_controller.rb +9 -1
  26. data/app/helpers/avo/application_helper.rb +2 -0
  27. data/app/javascript/avo.js +13 -0
  28. data/app/javascript/js/controllers/menu_controller.js +65 -0
  29. data/app/javascript/js/controllers/search_controller.js +25 -10
  30. data/app/javascript/js/controllers.js +2 -0
  31. data/app/views/avo/base/_boolean_filter.html.erb +1 -1
  32. data/app/views/avo/base/_multiple_select_filter.html.erb +7 -4
  33. data/app/views/avo/base/_select_filter.html.erb +1 -1
  34. data/app/views/avo/base/_text_filter.html.erb +1 -1
  35. data/avo.gemspec +1 -0
  36. data/lib/avo/app.rb +8 -86
  37. data/lib/avo/concerns/fetches_things.rb +127 -0
  38. data/lib/avo/configuration.rb +4 -0
  39. data/lib/avo/fields/base_field.rb +2 -0
  40. data/lib/avo/hosts/base_host.rb +20 -0
  41. data/lib/avo/licensing/pro_license.rb +2 -1
  42. data/lib/avo/menu/base_item.rb +20 -0
  43. data/lib/avo/menu/builder.rb +77 -0
  44. data/lib/avo/menu/dashboard.rb +17 -0
  45. data/lib/avo/menu/group.rb +2 -0
  46. data/lib/avo/menu/link.rb +4 -0
  47. data/lib/avo/menu/menu.rb +2 -0
  48. data/lib/avo/menu/resource.rb +9 -0
  49. data/lib/avo/menu/section.rb +2 -0
  50. data/lib/avo/reloader.rb +10 -2
  51. data/lib/avo/services/authorization_service.rb +8 -2
  52. data/lib/avo/version.rb +1 -1
  53. data/lib/generators/avo/filter_generator.rb +2 -0
  54. data/lib/generators/avo/templates/filters/boolean_filter.tt +1 -1
  55. data/lib/generators/avo/templates/filters/multiple_select_filter.tt +11 -0
  56. data/lib/generators/avo/templates/filters/select_filter.tt +1 -1
  57. data/lib/generators/avo/templates/filters/text_filter.tt +1 -1
  58. data/lib/generators/avo/templates/tool/sidebar_item.tt +1 -1
  59. data/public/avo-assets/avo.css +21 -4
  60. data/public/avo-assets/avo.js +63 -63
  61. data/public/avo-assets/avo.js.map +3 -3
  62. metadata +42 -9
  63. data/app/components/avo/sidebar_heading_component.html.erb +0 -3
  64. data/app/components/avo/sidebar_heading_component.rb +0 -11
  65. data/app/components/avo/sidebar_item_component.html.erb +0 -3
  66. data/app/components/avo/sidebar_item_component.rb +0 -10
@@ -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
data/lib/avo/app.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  module Avo
2
2
  class App
3
+ include Avo::Concerns::FetchesThings
4
+
3
5
  class_attribute :resources, default: []
4
6
  class_attribute :dashboards, default: []
5
7
  class_attribute :cache_store, default: nil
@@ -102,96 +104,16 @@ module Avo
102
104
  end
103
105
  end
104
106
 
105
- # Returns the Avo dashboard by id
106
- def get_dashboard_by_id(id)
107
- dashboards.find do |dashboard|
108
- dashboard.id == id
109
- end
110
- end
111
-
112
- # Returns the Avo resource by camelized name
113
- #
114
- # get_resource_by_name('User') => UserResource
115
- def get_resource(resource)
116
- resources.find do |available_resource|
117
- "#{resource}Resource".safe_constantize == available_resource.class
118
- end
119
- end
120
-
121
- # Returns the Avo resource by singular snake_cased name
122
- #
123
- # get_resource_by_name('user') => UserResource
124
- def get_resource_by_name(name)
125
- get_resource name.singularize.camelize
126
- end
127
-
128
- # Returns the Avo resource by singular snake_cased name
129
- #
130
- # get_resource_by_name('User') => UserResource
131
- # get_resource_by_name(User) => UserResource
132
- def get_resource_by_model_name(name)
133
- resources.find do |resource|
134
- resource.model_class.model_name.name == name.to_s
135
- end
136
- end
137
-
138
- # Returns the Avo resource by singular snake_cased name
139
- #
140
- # get_resource_by_controller_name('delayed_backend_active_record_jobs') => DelayedJobResource
141
- # get_resource_by_controller_name('users') => UserResource
142
- def get_resource_by_controller_name(name)
143
- resources.find do |resource|
144
- resource.model_class.to_s.pluralize.underscore.tr("/", "_") == name.to_s
145
- end
146
- end
147
-
148
- # Returns the Rails model class by singular snake_cased name
149
- #
150
- # get_model_class_by_name('user') => User
151
- def get_model_class_by_name(name)
152
- name.to_s.camelize.singularize
153
- end
107
+ def main_menu
108
+ return nil if Avo::App.license.lacks_with_trial(:menu_builder)
154
109
 
155
- def get_available_resources(user = nil)
156
- resources.select do |resource|
157
- Services::AuthorizationService.authorize user, resource.model_class, Avo.configuration.authorization_methods.stringify_keys["index"], raise_exception: false
158
- end
159
- .sort_by { |r| r.name }
110
+ Avo::Menu::Builder.parse_menu(&Avo.configuration.main_menu)
160
111
  end
161
112
 
162
- def get_available_dashboards(user = nil)
163
- dashboards.sort_by { |r| r.name }
164
- end
113
+ def profile_menu
114
+ return nil if Avo::App.license.lacks_with_trial(:menu_builder)
165
115
 
166
- def resources_navigation(user = nil)
167
- get_available_resources(user)
168
- .select do |resource|
169
- resource.model_class.present?
170
- end
171
- .select do |resource|
172
- resource.visible_on_sidebar
173
- end
174
- end
175
-
176
- def get_dashboards(user = nil)
177
- return [] unless App.license.has_with_trial(:resource_ordering)
178
-
179
- get_available_dashboards(user)
180
- end
181
-
182
- # Insert any partials that we find in app/views/avo/sidebar/items.
183
- def get_sidebar_partials
184
- Dir.glob(Rails.root.join("app", "views", "avo", "sidebar", "items", "*.html.erb"))
185
- .map do |path|
186
- File.basename path
187
- end
188
- .map do |filename|
189
- # remove the leading underscore (_)
190
- filename[0] = ""
191
- # remove the extension
192
- filename.gsub!(".html.erb", "")
193
- filename
194
- end
116
+ Avo::Menu::Builder.parse_menu(&Avo.configuration.profile_menu)
195
117
  end
196
118
  end
197
119
  end
@@ -0,0 +1,127 @@
1
+ module Avo
2
+ module Concerns
3
+ module FetchesThings
4
+ extend ActiveSupport::Concern
5
+
6
+ class_methods do
7
+ # Returns the Avo dashboard by id
8
+ #
9
+ # get_dashboard_by_id(:dashy) -> Dashy
10
+ def get_dashboard_by_id(id)
11
+ dashboards.find do |dashboard|
12
+ dashboard.id == id
13
+ end
14
+ end
15
+
16
+ # Returns the Avo dashboard by name
17
+ #
18
+ # get_dashboard_by_name(:dashy) -> Dashy
19
+ def get_dashboard_by_name(name)
20
+ dashboards.find do |dashboard|
21
+ dashboard.name == name
22
+ end
23
+ end
24
+
25
+ # Returns the Avo resource by camelized name
26
+ #
27
+ # get_resource_by_name('User') => UserResource
28
+ def get_resource(resource)
29
+ possible_resource = "#{resource}Resource".gsub "ResourceResource", "Resource"
30
+
31
+ resources.find do |available_resource|
32
+ possible_resource.safe_constantize == available_resource.class
33
+ end
34
+ end
35
+
36
+ # Returns the Avo resource by singular snake_cased name
37
+ #
38
+ # get_resource_by_name('user') => UserResource
39
+ def get_resource_by_name(name)
40
+ get_resource name.singularize.camelize
41
+ end
42
+
43
+ # Returns the Avo resource by singular snake_cased name
44
+ #
45
+ # get_resource_by_name('User') => UserResource
46
+ # get_resource_by_name(User) => UserResource
47
+ def get_resource_by_model_name(name)
48
+ resources.find do |resource|
49
+ resource.model_class.model_name.name == name.to_s
50
+ end
51
+ end
52
+
53
+ # Returns the Avo resource by singular snake_cased name
54
+ #
55
+ # get_resource_by_controller_name('delayed_backend_active_record_jobs') => DelayedJobResource
56
+ # get_resource_by_controller_name('users') => UserResource
57
+ def get_resource_by_controller_name(name)
58
+ resources.find do |resource|
59
+ resource.model_class.to_s.pluralize.underscore.tr("/", "_") == name.to_s
60
+ end
61
+ end
62
+
63
+ # Returns the Avo resource by some name
64
+ def guess_resource(name)
65
+ get_resource_by_name(name.to_s) || get_resource_by_model_name(name)
66
+ end
67
+
68
+ # Returns the Rails model class by singular snake_cased name
69
+ #
70
+ # get_model_class_by_name('user') => User
71
+ def get_model_class_by_name(name)
72
+ name.to_s.camelize.singularize
73
+ end
74
+
75
+ def get_available_resources(user = nil)
76
+ resources.select do |resource|
77
+ Services::AuthorizationService.authorize user, resource.model_class, Avo.configuration.authorization_methods.stringify_keys["index"], raise_exception: false
78
+ end
79
+ .sort_by { |r| r.name }
80
+ end
81
+
82
+ def get_available_dashboards(user = nil)
83
+ dashboards.sort_by { |r| r.name }
84
+ end
85
+
86
+ def resources_for_navigation(user = nil)
87
+ get_available_resources(current_user)
88
+ .select do |resource|
89
+ resource.model_class.present?
90
+ end
91
+ .select do |resource|
92
+ resource.visible_on_sidebar
93
+ end
94
+ end
95
+
96
+ def dashboards_for_navigation(user = nil)
97
+ return [] if App.license.lacks_with_trial(:resource_ordering)
98
+
99
+ get_available_dashboards(user).select do |dashboard|
100
+ dashboard.is_visible?
101
+ end
102
+ end
103
+
104
+ # Insert any partials that we find in app/views/avo/sidebar/items.
105
+ def get_sidebar_partials
106
+ Dir.glob(Rails.root.join("app", "views", "avo", "sidebar", "items", "*.html.erb"))
107
+ .map do |path|
108
+ File.basename path
109
+ end
110
+ .map do |filename|
111
+ # remove the leading underscore (_)
112
+ filename[0] = ""
113
+ # remove the extension
114
+ filename.gsub!(".html.erb", "")
115
+ filename
116
+ end
117
+ end
118
+
119
+ def tools_for_navigation
120
+ return [] if Avo::App.license.lacks_with_trial(:custom_tools)
121
+
122
+ get_sidebar_partials
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -29,6 +29,8 @@ module Avo
29
29
  attr_accessor :raise_error_on_missing_policy
30
30
  attr_accessor :disabled_features
31
31
  attr_accessor :buttons_on_form_footers
32
+ attr_accessor :main_menu
33
+ attr_accessor :profile_menu
32
34
 
33
35
  def initialize
34
36
  @root_path = "/avo"
@@ -70,6 +72,8 @@ module Avo
70
72
  @raise_error_on_missing_policy = false
71
73
  @disabled_features = []
72
74
  @buttons_on_form_footers = false
75
+ @main_menu = nil
76
+ @profile_menu = nil
73
77
  end
74
78
 
75
79
  def locale_tag
@@ -26,6 +26,7 @@ module Avo
26
26
  attr_reader :as_label
27
27
  attr_reader :as_avatar
28
28
  attr_reader :as_description
29
+ attr_reader :index_text_align
29
30
 
30
31
  # Private options
31
32
  attr_reader :updatable
@@ -64,6 +65,7 @@ module Avo
64
65
  @as_label = args[:as_label] || false
65
66
  @as_avatar = args[:as_avatar] || false
66
67
  @as_description = args[:as_description] || false
68
+ @index_text_align = args[:index_text_align] || :left
67
69
 
68
70
  @updatable = true
69
71
  @computable = true
@@ -0,0 +1,20 @@
1
+ require "dry-initializer"
2
+
3
+ # This object holds some data tha is usually needed to compute blocks around the app.
4
+ module Avo
5
+ module Hosts
6
+ class BaseHost
7
+ extend Dry::Initializer
8
+
9
+ option :context, default: proc { Avo::App.context }
10
+ option :params, default: proc { Avo::App.params }
11
+ option :view_context, default: proc { Avo::App.view_context }
12
+ option :current_user, default: proc { Avo::App.current_user }
13
+ option :block, optional: true
14
+
15
+ def handle
16
+ instance_exec(&block)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -11,7 +11,8 @@ module Avo
11
11
  :enhanced_search_results,
12
12
  :searchable_associations,
13
13
  :resource_ordering,
14
- :dashboards
14
+ :dashboards,
15
+ :menu_editor
15
16
  ]
16
17
  end
17
18
  end
@@ -0,0 +1,20 @@
1
+ require "dry-initializer"
2
+
3
+ class Avo::Menu::BaseItem
4
+ extend Dry::Initializer
5
+
6
+ option :collapsable, default: proc { false }
7
+ option :collapsed, default: proc { false }
8
+ option :icon, optional: true
9
+ option :items, default: proc { [] }
10
+ option :name, default: proc { "" }
11
+ option :visible, default: proc { true }
12
+
13
+ def visible?
14
+ return visible if visible.in? [true, false]
15
+
16
+ if visible.respond_to? :call
17
+ Avo::Hosts::BaseHost.new(block: visible).handle
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,77 @@
1
+ class Avo::Menu::Builder
2
+ class << self
3
+ def parse_menu(&block)
4
+ Docile.dsl_eval(Avo::Menu::Builder.new, &block).build
5
+ end
6
+ end
7
+
8
+ def initialize(name: nil, items: [])
9
+ @menu = Avo::Menu::Menu.new
10
+
11
+ @menu.name = name
12
+ @menu.items = items
13
+ end
14
+
15
+ # Adds a link
16
+ def link(name, **args)
17
+ @menu.items << Avo::Menu::Link.new(name: name, **args)
18
+ end
19
+
20
+ # Validates and adds a resource
21
+ def resource(name, **args)
22
+ name = name.to_s.singularize
23
+ res = Avo::App.guess_resource(name)
24
+
25
+ if res.present?
26
+ @menu.items << Avo::Menu::Resource.new(resource: name, **args)
27
+ end
28
+ end
29
+ alias_method :resources, :resource
30
+
31
+ # Adds a dashboard
32
+ def dashboard(dashboard, **args)
33
+ @menu.items << Avo::Menu::Dashboard.new(dashboard: dashboard, **args)
34
+ end
35
+
36
+ # Adds a section
37
+ def section(name = nil, **args, &block)
38
+ @menu.items << Avo::Menu::Section.new(name: name, **args, items: self.class.parse_menu(&block).items)
39
+ end
40
+
41
+ # Adds a group
42
+ def group(name = nil, **args, &block)
43
+ @menu.items << Avo::Menu::Group.new(name: name, **args, items: self.class.parse_menu(&block).items)
44
+ end
45
+
46
+ # Add all the resources
47
+ def all_resources(**args)
48
+ Avo::App.resources_for_navigation.each do |res|
49
+ resource res.model_class, **args
50
+ end
51
+ end
52
+
53
+ # Add all the dashboards
54
+ def all_dashboards(**args)
55
+ Avo::App.dashboards_for_navigation.each do |dash|
56
+ dashboard dash.id, **args
57
+ end
58
+ end
59
+
60
+ # Add all the tools
61
+ def all_tools(**args)
62
+ Avo::App.tools_for_navigation.each do |tool|
63
+ link tool.humanize, path: "#{root_path}/#{tool}"
64
+ end
65
+ end
66
+
67
+ # Fetch the menu
68
+ def build
69
+ @menu
70
+ end
71
+
72
+ protected
73
+
74
+ def root_path
75
+ Avo::App.root_path
76
+ end
77
+ end
@@ -0,0 +1,17 @@
1
+ class Avo::Menu::Dashboard < Avo::Menu::BaseItem
2
+ extend Dry::Initializer
3
+
4
+ option :dashboard
5
+
6
+ def parsed_dashboard
7
+ dashboard_by_id || dashboard_by_name
8
+ end
9
+
10
+ def dashboard_by_name
11
+ Avo::App.get_dashboard_by_name dashboard.to_s
12
+ end
13
+
14
+ def dashboard_by_id
15
+ Avo::App.get_dashboard_by_id dashboard.to_s
16
+ end
17
+ end
@@ -0,0 +1,2 @@
1
+ class Avo::Menu::Group < Avo::Menu::BaseItem
2
+ end
@@ -0,0 +1,4 @@
1
+ class Avo::Menu::Link < Avo::Menu::BaseItem
2
+ option :path, default: proc { "" }
3
+ option :target, optional: true
4
+ end
@@ -0,0 +1,2 @@
1
+ class Avo::Menu::Menu < OpenStruct
2
+ end
@@ -0,0 +1,9 @@
1
+ class Avo::Menu::Resource < Avo::Menu::BaseItem
2
+ extend Dry::Initializer
3
+
4
+ option :resource
5
+
6
+ def parsed_resource
7
+ Avo::App.guess_resource resource.to_s
8
+ end
9
+ end
@@ -0,0 +1,2 @@
1
+ class Avo::Menu::Section < Avo::Menu::BaseItem
2
+ end
data/lib/avo/reloader.rb CHANGED
@@ -3,11 +3,19 @@ class Avo::Reloader
3
3
 
4
4
  def reload!
5
5
  # reload all files declared in paths
6
- files.each { |file| load file }
6
+ files.each do |file|
7
+ if File.exist? file
8
+ load file
9
+ end
10
+ end
7
11
 
8
12
  # reload all files declared in each directory
9
13
  directories.keys.each do |dir|
10
- Dir.glob("#{dir}/**/*.rb".to_s).each { |file| load file }
14
+ Dir.glob("#{dir}/**/*.rb".to_s).each do |file|
15
+ if File.exist? file
16
+ load file
17
+ end
18
+ end
11
19
  end
12
20
  end
13
21
 
@@ -68,11 +68,17 @@ module Avo
68
68
  def authorize_action(user, record, action, **args)
69
69
  action = Avo.configuration.authorization_methods.stringify_keys[action.to_s] || action
70
70
 
71
+ # If no action passed we should raise error if the user wants that.
72
+ # If not, just allow it.
73
+ if action.nil?
74
+ raise Pundit::NotDefinedError.new 'Policy method is missing' if Avo.configuration.raise_error_on_missing_policy
75
+
76
+ return true
77
+ end
78
+
71
79
  # Add the question mark if it's missing
72
80
  action = "#{action}?" unless action.end_with? '?'
73
81
 
74
- return true if action.nil?
75
-
76
82
  authorize user, record, action, **args
77
83
  end
78
84
 
data/lib/avo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Avo
2
- VERSION = "2.2.0"
2
+ VERSION = "2.3.0"
3
3
  end
@@ -4,6 +4,7 @@ module Generators
4
4
  module Avo
5
5
  class FilterGenerator < ::Rails::Generators::NamedBase
6
6
  source_root File.expand_path("templates", __dir__)
7
+ class_option :multiple_select, type: :boolean
7
8
  class_option :select, type: :boolean
8
9
  class_option :text, type: :boolean
9
10
 
@@ -12,6 +13,7 @@ module Generators
12
13
  def create_resource_file
13
14
  type = "boolean"
14
15
 
16
+ type = "multiple_select" if options[:multiple_select]
15
17
  type = "select" if options[:select]
16
18
  type = "text" if options[:text]
17
19
 
@@ -1,5 +1,5 @@
1
1
  class <%= class_name.camelize %> < Avo::Filters::BooleanFilter
2
- self.name = '<%= name.underscore.humanize %>'
2
+ self.name = "<%= name.underscore.humanize %>"
3
3
 
4
4
  def apply(request, query, values)
5
5
  query
@@ -0,0 +1,11 @@
1
+ class <%= class_name.camelize %> < Avo::Filters::MultipleSelectFilter
2
+ self.name = "<%= name.underscore.humanize %>"
3
+
4
+ def apply(request, query, value)
5
+ query
6
+ end
7
+
8
+ def options
9
+ {}
10
+ end
11
+ end
@@ -1,5 +1,5 @@
1
1
  class <%= class_name.camelize %> < Avo::Filters::SelectFilter
2
- self.name = '<%= name.underscore.humanize %>'
2
+ self.name = "<%= name.underscore.humanize %>"
3
3
 
4
4
  def apply(request, query, value)
5
5
  query
@@ -1,5 +1,5 @@
1
1
  class <%= class_name.camelize %> < Avo::Filters::TextFilter
2
- self.name = '<%= name.underscore.humanize %>'
2
+ self.name = "<%= name.underscore.humanize %>"
3
3
  self.button_label = 'Filter by <%= class_name.underscore.humanize.downcase.gsub(' filter', '') %>'
4
4
 
5
5
  def apply(request, query, value)
@@ -1 +1 @@
1
- <%%= render Avo::SidebarItemComponent.new label: '<%= human_name %>', path: "#{avo.root_path}<%= file_name %>" %>
1
+ <%%= render Avo::Sidebar::LinkComponent.new label: '<%= human_name %>', path: "#{avo.root_path}<%= file_name %>" %>
@@ -6449,6 +6449,10 @@ progress[value]::-moz-progress-bar{
6449
6449
  margin-left:50%
6450
6450
  }
6451
6451
 
6452
+ .ml-auto{
6453
+ margin-left:auto
6454
+ }
6455
+
6452
6456
  .-mb-2{
6453
6457
  margin-bottom:-0.5rem
6454
6458
  }
@@ -6677,6 +6681,10 @@ progress[value]::-moz-progress-bar{
6677
6681
  min-width:200px
6678
6682
  }
6679
6683
 
6684
+ .min-w-\[20px\]{
6685
+ min-width:20px
6686
+ }
6687
+
6680
6688
  .max-w-168{
6681
6689
  max-width:42rem
6682
6690
  }
@@ -7381,6 +7389,11 @@ progress[value]::-moz-progress-bar{
7381
7389
  padding-bottom:6rem
7382
7390
  }
7383
7391
 
7392
+ .px-10{
7393
+ padding-left:2.5rem;
7394
+ padding-right:2.5rem
7395
+ }
7396
+
7384
7397
  .py-8{
7385
7398
  padding-top:2rem;
7386
7399
  padding-bottom:2rem
@@ -7418,6 +7431,10 @@ progress[value]::-moz-progress-bar{
7418
7431
  padding-bottom:75%
7419
7432
  }
7420
7433
 
7434
+ .pt-2{
7435
+ padding-top:0.5rem
7436
+ }
7437
+
7421
7438
  .text-left{
7422
7439
  text-align:left
7423
7440
  }
@@ -8007,14 +8024,14 @@ trix-editor {
8007
8024
  background-color:rgb(6 95 158 / var(--tw-bg-opacity))
8008
8025
  }
8009
8026
 
8010
- .hover\:bg-gray-150:hover{
8027
+ .hover\:bg-blue-50:hover{
8011
8028
  --tw-bg-opacity:1;
8012
- background-color:rgb(233 234 236 / var(--tw-bg-opacity))
8029
+ background-color:rgb(251 253 255 / var(--tw-bg-opacity))
8013
8030
  }
8014
8031
 
8015
- .hover\:bg-blue-50:hover{
8032
+ .hover\:bg-gray-150:hover{
8016
8033
  --tw-bg-opacity:1;
8017
- background-color:rgb(251 253 255 / var(--tw-bg-opacity))
8034
+ background-color:rgb(233 234 236 / var(--tw-bg-opacity))
8018
8035
  }
8019
8036
 
8020
8037
  .hover\:text-gray-500:hover{