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
@@ -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
|
-
|
5
|
-
|
6
|
-
|
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
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
|
-
|
106
|
-
|
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
|
-
|
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
|
163
|
-
|
164
|
-
end
|
113
|
+
def profile_menu
|
114
|
+
return nil if Avo::App.license.lacks_with_trial(:menu_builder)
|
165
115
|
|
166
|
-
|
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
|
data/lib/avo/configuration.rb
CHANGED
@@ -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
|
@@ -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
|
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
|
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
|
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
@@ -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::TextFilter
|
2
|
-
self.name =
|
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::
|
1
|
+
<%%= render Avo::Sidebar::LinkComponent.new label: '<%= human_name %>', path: "#{avo.root_path}<%= file_name %>" %>
|
data/public/avo-assets/avo.css
CHANGED
@@ -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-
|
8027
|
+
.hover\:bg-blue-50:hover{
|
8011
8028
|
--tw-bg-opacity:1;
|
8012
|
-
background-color:rgb(
|
8029
|
+
background-color:rgb(251 253 255 / var(--tw-bg-opacity))
|
8013
8030
|
}
|
8014
8031
|
|
8015
|
-
.hover\:bg-
|
8032
|
+
.hover\:bg-gray-150:hover{
|
8016
8033
|
--tw-bg-opacity:1;
|
8017
|
-
background-color:rgb(
|
8034
|
+
background-color:rgb(233 234 236 / var(--tw-bg-opacity))
|
8018
8035
|
}
|
8019
8036
|
|
8020
8037
|
.hover\:text-gray-500:hover{
|