avo 1.4.1 → 1.4.5.pre.1
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 +2 -0
- data/Gemfile.lock +7 -1
- data/README.md +4 -4
- data/app/components/avo/fields/common/status_viewer_component.html.erb +13 -5
- data/app/components/avo/views/resource_index_component.html.erb +3 -3
- data/app/controllers/avo/application_controller.rb +14 -7
- data/app/controllers/avo/relations_controller.rb +1 -1
- data/app/controllers/avo/search_controller.rb +50 -35
- data/app/packs/entrypoints/application.css +2 -1
- data/app/packs/entrypoints/application.js +3 -0
- data/app/packs/js/controllers/search_controller.js +120 -0
- data/app/packs/js/helpers/debounce_promise.js +13 -0
- data/app/packs/stylesheets/components/status.css +31 -20
- data/app/packs/stylesheets/search.css +79 -0
- data/app/packs/svgs/check-circle-sm.svg +3 -0
- data/app/packs/svgs/x-circle-sm.svg +3 -0
- data/app/views/avo/partials/_global_search.html.erb +17 -0
- data/app/views/avo/partials/_resource_search.html.erb +10 -0
- data/app/views/layouts/avo/application.html.erb +2 -4
- data/avo.gemspec +1 -0
- data/config/routes.rb +2 -6
- data/lib/avo/app.rb +3 -1
- data/lib/avo/base_resource.rb +83 -7
- data/lib/avo/configuration.rb +2 -0
- data/lib/avo/fields/base_field.rb +6 -0
- data/lib/avo/fields/external_image_field.rb +1 -0
- data/lib/avo/fields/file_field.rb +4 -0
- data/lib/avo/licensing/license.rb +10 -0
- data/lib/avo/licensing/pro_license.rb +3 -1
- data/lib/avo/services/authorization_service.rb +1 -1
- data/lib/avo/version.rb +1 -1
- data/lib/generators/avo/templates/initializer/avo.tt +1 -0
- data/lib/generators/avo/templates/resource/resource.tt +3 -0
- data/public/avo-packs/css/{application-cb627e0b.css → application-d69fe930.css} +211 -20
- data/public/avo-packs/css/application-d69fe930.css.br +0 -0
- data/public/avo-packs/css/application-d69fe930.css.gz +0 -0
- data/public/avo-packs/css/application-d69fe930.css.map +1 -0
- data/public/avo-packs/css/application-d69fe930.css.map.br +0 -0
- data/public/avo-packs/css/application-d69fe930.css.map.gz +0 -0
- data/public/avo-packs/js/application-7b3d507875f4bc1f6677.js +26 -0
- data/public/avo-packs/js/{application-6a0b9e58526ae6bef242.js.LICENSE.txt → application-7b3d507875f4bc1f6677.js.LICENSE.txt} +0 -0
- data/public/avo-packs/js/application-7b3d507875f4bc1f6677.js.br +0 -0
- data/public/avo-packs/js/application-7b3d507875f4bc1f6677.js.gz +0 -0
- data/public/avo-packs/js/application-7b3d507875f4bc1f6677.js.map +1 -0
- data/public/avo-packs/js/application-7b3d507875f4bc1f6677.js.map.br +0 -0
- data/public/avo-packs/js/application-7b3d507875f4bc1f6677.js.map.gz +0 -0
- data/public/avo-packs/manifest.json +15 -15
- metadata +38 -17
- data/public/avo-packs/css/application-cb627e0b.css.br +0 -0
- data/public/avo-packs/css/application-cb627e0b.css.gz +0 -0
- data/public/avo-packs/css/application-cb627e0b.css.map +0 -1
- data/public/avo-packs/css/application-cb627e0b.css.map.br +0 -0
- data/public/avo-packs/css/application-cb627e0b.css.map.gz +0 -0
- data/public/avo-packs/js/application-6a0b9e58526ae6bef242.js +0 -26
- data/public/avo-packs/js/application-6a0b9e58526ae6bef242.js.br +0 -0
- data/public/avo-packs/js/application-6a0b9e58526ae6bef242.js.gz +0 -0
- data/public/avo-packs/js/application-6a0b9e58526ae6bef242.js.map +0 -1
- data/public/avo-packs/js/application-6a0b9e58526ae6bef242.js.map.br +0 -0
- data/public/avo-packs/js/application-6a0b9e58526ae6bef242.js.map.gz +0 -0
@@ -1,30 +1,41 @@
|
|
1
1
|
.spinner {
|
2
|
+
width: 16px;
|
3
|
+
height: 16px;
|
4
|
+
|
2
5
|
position: relative;
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
6
|
+
}
|
7
|
+
|
8
|
+
|
9
|
+
.double-bounce1, .double-bounce2 {
|
10
|
+
width: 100%;
|
11
|
+
height: 100%;
|
12
|
+
border-radius: 50%;
|
7
13
|
background-color: #333;
|
8
|
-
|
9
|
-
|
10
|
-
|
14
|
+
opacity: 0.6;
|
15
|
+
position: absolute;
|
16
|
+
top: 0;
|
17
|
+
left: 0;
|
18
|
+
|
19
|
+
-webkit-animation: sk-bounce 2.0s infinite ease-in-out;
|
20
|
+
animation: sk-bounce 2.0s infinite ease-in-out;
|
11
21
|
}
|
12
22
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
-webkit-transform: scale(1.0);
|
17
|
-
opacity: 0;
|
18
|
-
}
|
23
|
+
.double-bounce2 {
|
24
|
+
-webkit-animation-delay: -1.0s;
|
25
|
+
animation-delay: -1.0s;
|
19
26
|
}
|
20
27
|
|
21
|
-
|
22
|
-
0% {
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
28
|
+
@-webkit-keyframes sk-bounce {
|
29
|
+
0%, 100% { -webkit-transform: scale(0.0) }
|
30
|
+
50% { -webkit-transform: scale(1.0) }
|
31
|
+
}
|
32
|
+
|
33
|
+
@keyframes sk-bounce {
|
34
|
+
0%, 100% {
|
35
|
+
transform: scale(0.0);
|
36
|
+
-webkit-transform: scale(0.0);
|
37
|
+
} 50% {
|
27
38
|
transform: scale(1.0);
|
28
|
-
|
39
|
+
-webkit-transform: scale(1.0);
|
29
40
|
}
|
30
41
|
}
|
@@ -0,0 +1,79 @@
|
|
1
|
+
:root {
|
2
|
+
--aa-primary-color: --tw-ring-color;
|
3
|
+
--aa-selected-color: --tw-ring-color;
|
4
|
+
--aa-primary-color-rgb: 5, 150, 105;
|
5
|
+
}
|
6
|
+
|
7
|
+
.global-search {
|
8
|
+
.aa-DetachedSearchButton:focus,
|
9
|
+
.aa-DetachedSearchButton {
|
10
|
+
border: none !important;
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
.resource-search {
|
15
|
+
.aa-Autocomplete {
|
16
|
+
@apply w-full;
|
17
|
+
}
|
18
|
+
|
19
|
+
.aa-DetachedSearchButton {
|
20
|
+
@apply rounded-full border-gray-300;
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
.aa-SourceHeader {
|
25
|
+
@apply uppercase text-xs font-semibold;
|
26
|
+
}
|
27
|
+
|
28
|
+
.aa-DetachedFormContainer,
|
29
|
+
.aa-DetachedContainer .aa-Panel {
|
30
|
+
@apply bg-blue-gray-100 border-b-0;
|
31
|
+
}
|
32
|
+
|
33
|
+
.aa-Form {
|
34
|
+
&:focus-within {
|
35
|
+
@apply ring-0 !important;
|
36
|
+
}
|
37
|
+
|
38
|
+
input {
|
39
|
+
@apply focus:ring-0 !important;
|
40
|
+
}
|
41
|
+
&:focus-within {
|
42
|
+
.aa-InputWrapperPrefix{
|
43
|
+
.aa-SubmitButton {
|
44
|
+
@apply ring-0;
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
.aa-Input {
|
50
|
+
@apply focus:ring-green-600;
|
51
|
+
}
|
52
|
+
|
53
|
+
.aa-DetachedContainer {
|
54
|
+
.aa-PanelLayout {
|
55
|
+
@apply pt-0 space-y-3;
|
56
|
+
}
|
57
|
+
|
58
|
+
.aa-Source {
|
59
|
+
.aa-List {
|
60
|
+
@apply space-y-1;
|
61
|
+
|
62
|
+
.aa-Item {
|
63
|
+
@apply bg-white rounded-md px-3 py-4 shadow;
|
64
|
+
|
65
|
+
.aa-ItemDescription {
|
66
|
+
@apply text-gray-500 text-sm;
|
67
|
+
}
|
68
|
+
|
69
|
+
&[aria-selected=true]{
|
70
|
+
@apply bg-blue-700 text-white;
|
71
|
+
|
72
|
+
.aa-ItemDescription {
|
73
|
+
@apply text-white;
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}
|
@@ -0,0 +1,3 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
2
|
+
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
|
3
|
+
</svg>
|
@@ -0,0 +1,3 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
2
|
+
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" />
|
3
|
+
</svg>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<div data-controller="search" class="global-search" data-turbo-remove-before-cache>
|
2
|
+
<div class="inline-block"
|
3
|
+
data-search-target="autocomplete"
|
4
|
+
data-search-resource="global"
|
5
|
+
data-translation-keys='{"no_item_found": "<%= I18n.translate 'avo.no_item_found' %>"}'
|
6
|
+
data-debounce-timeout='<%= Avo.configuration.search_debounce %>'
|
7
|
+
>
|
8
|
+
</div>
|
9
|
+
<div class="relative top-[-5px] inline-flex text-gray-400 text-sm leading-5 py-0.5 px-1.5 border border-gray-300 rounded-md cursor-pointer"
|
10
|
+
data-search-target="button"
|
11
|
+
>
|
12
|
+
<span class="sr-only">Press </span>
|
13
|
+
<kbd class="font-sans"><abbr title="Command" class="no-underline">⌘</abbr></kbd>
|
14
|
+
<span class="sr-only"> and </span>
|
15
|
+
<kbd class="font-sans">K</kbd><span class="sr-only"> to search</span>
|
16
|
+
</div>
|
17
|
+
</div>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<div data-controller="search" class="resource-search flex items-center h-full w-full" data-turbo-remove-before-cache>
|
2
|
+
<div class="w-full"
|
3
|
+
data-search-target="autocomplete"
|
4
|
+
data-search-resource="<%= resource %>"
|
5
|
+
data-translation-keys='{"no_item_found": "<%= I18n.translate 'avo.no_item_found' %>"}'
|
6
|
+
data-debounce-timeout='<%= Avo.configuration.search_debounce %>'
|
7
|
+
>
|
8
|
+
</div>
|
9
|
+
<div class="relative inline-flex text-gray-400 text-sm border border-gray-300 rounded-full cursor-pointer" data-search-target="button"></div>
|
10
|
+
</div>
|
@@ -23,10 +23,8 @@
|
|
23
23
|
<div>
|
24
24
|
<%= render partial: "avo/partials/header" %>
|
25
25
|
</div>
|
26
|
-
<div class="flex-1 flex
|
27
|
-
|
28
|
-
<%# <resources-search :global="true"> %>
|
29
|
-
</div>
|
26
|
+
<div class="flex-1 flex ml-4 pl-4">
|
27
|
+
<%= render partial: "avo/partials/global_search" if ::Avo::App.license.has_with_trial(:global_search) %>
|
30
28
|
</div>
|
31
29
|
<div class="align-end">
|
32
30
|
<%= render partial: "avo/partials/profile_dropdown" %>
|
data/avo.gemspec
CHANGED
data/config/routes.rb
CHANGED
@@ -4,6 +4,8 @@ Avo::Engine.routes.draw do
|
|
4
4
|
get "resources", to: redirect("/avo")
|
5
5
|
|
6
6
|
scope "avo_api", as: "avo_api" do
|
7
|
+
get "/search", to: "search#index"
|
8
|
+
get "/:resource_name/search", to: "search#show"
|
7
9
|
post "/resources/:resource_name/:id/attachments/", to: "attachments#create"
|
8
10
|
end
|
9
11
|
|
@@ -27,10 +29,4 @@ Avo::Engine.routes.draw do
|
|
27
29
|
post "/:resource_name/:id/:related_name", to: "relations#create"
|
28
30
|
delete "/:resource_name/:id/:related_name/:related_id", to: "relations#destroy"
|
29
31
|
end
|
30
|
-
|
31
|
-
# get '/avo-api/search', to: 'search#index'
|
32
|
-
# get '/avo-api/:resource_name/search', to: 'search#resource'
|
33
|
-
|
34
|
-
# Tools
|
35
|
-
# get '/avo-tools/resource-overview', to: 'resource_overview#index'
|
36
32
|
end
|
data/lib/avo/app.rb
CHANGED
@@ -6,6 +6,7 @@ module Avo
|
|
6
6
|
class_attribute :request, default: nil
|
7
7
|
class_attribute :context, default: nil
|
8
8
|
class_attribute :license, default: nil
|
9
|
+
class_attribute :current_user, default: nil
|
9
10
|
|
10
11
|
class << self
|
11
12
|
def boot
|
@@ -20,9 +21,10 @@ module Avo
|
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
23
|
-
def init(request:, context:)
|
24
|
+
def init(request:, context:, current_user:)
|
24
25
|
self.request = request
|
25
26
|
self.context = context
|
27
|
+
self.current_user = current_user
|
26
28
|
|
27
29
|
self.license = Licensing::LicenseManager.new(Licensing::HQ.new(request).response).license
|
28
30
|
|
data/lib/avo/base_resource.rb
CHANGED
@@ -11,7 +11,7 @@ module Avo
|
|
11
11
|
|
12
12
|
class_attribute :id, default: :id
|
13
13
|
class_attribute :title, default: :id
|
14
|
-
class_attribute :
|
14
|
+
class_attribute :search_query, default: nil
|
15
15
|
class_attribute :includes, default: []
|
16
16
|
class_attribute :model_class
|
17
17
|
class_attribute :translation_key
|
@@ -42,6 +42,18 @@ module Avo
|
|
42
42
|
|
43
43
|
self.filters_loader.use filter_class
|
44
44
|
end
|
45
|
+
|
46
|
+
def scope
|
47
|
+
authorization.apply_policy model_class
|
48
|
+
end
|
49
|
+
|
50
|
+
def authorization
|
51
|
+
Avo::Services::AuthorizationService.new Avo::App.current_user
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def initialize
|
56
|
+
self.class.model_class = model_class
|
45
57
|
end
|
46
58
|
|
47
59
|
def hydrate(model: nil, view: nil, user: nil, params: nil)
|
@@ -65,7 +77,7 @@ module Avo
|
|
65
77
|
field.hydrate(resource: self, panel_name: default_panel_name, user: user)
|
66
78
|
end
|
67
79
|
|
68
|
-
if Avo::App.license.
|
80
|
+
if Avo::App.license.has_with_trial(:custom_fields)
|
69
81
|
fields = fields.reject do |field|
|
70
82
|
field.custom?
|
71
83
|
end
|
@@ -96,9 +108,9 @@ module Avo
|
|
96
108
|
end
|
97
109
|
end
|
98
110
|
|
99
|
-
|
100
|
-
|
101
|
-
|
111
|
+
hydrate_fields(model: @model, view: @view)
|
112
|
+
|
113
|
+
fields
|
102
114
|
end
|
103
115
|
|
104
116
|
def get_grid_fields
|
@@ -119,8 +131,16 @@ module Avo
|
|
119
131
|
self.class.actions_loader.bag
|
120
132
|
end
|
121
133
|
|
134
|
+
def hydrate_fields(model: nil, view: nil)
|
135
|
+
fields.map do |field|
|
136
|
+
field.hydrate(model: @model, view: @view, resource: self)
|
137
|
+
end
|
138
|
+
|
139
|
+
self
|
140
|
+
end
|
141
|
+
|
122
142
|
def default_panel_name
|
123
|
-
return @params[:related_name].capitalize if @params[:related_name].present?
|
143
|
+
return @params[:related_name].capitalize if @params.present? && @params[:related_name].present?
|
124
144
|
|
125
145
|
case @view
|
126
146
|
when :show
|
@@ -226,7 +246,11 @@ module Avo
|
|
226
246
|
|
227
247
|
def fill_model(model, params)
|
228
248
|
# Map the received params to their actual fields
|
229
|
-
fields_by_database_id = get_field_definitions
|
249
|
+
fields_by_database_id = get_field_definitions
|
250
|
+
.reject do |field|
|
251
|
+
field.computed
|
252
|
+
end
|
253
|
+
.map { |field| [field.database_id(model).to_s, field] }.to_h
|
230
254
|
|
231
255
|
params.each do |key, value|
|
232
256
|
field = fields_by_database_id[key]
|
@@ -301,5 +325,57 @@ module Avo
|
|
301
325
|
end
|
302
326
|
end
|
303
327
|
end
|
328
|
+
|
329
|
+
def avo_path
|
330
|
+
"#{Avo.configuration.root_path}/resources/#{model_class.model_name.route_key}/#{model.id}"
|
331
|
+
end
|
332
|
+
|
333
|
+
def label_field
|
334
|
+
get_field_definitions.find do |field|
|
335
|
+
field.as_label.present?
|
336
|
+
end
|
337
|
+
rescue
|
338
|
+
nil
|
339
|
+
end
|
340
|
+
|
341
|
+
def label
|
342
|
+
label_field.value || model_title
|
343
|
+
rescue
|
344
|
+
model_title
|
345
|
+
end
|
346
|
+
|
347
|
+
def avatar_field
|
348
|
+
get_field_definitions.find do |field|
|
349
|
+
field.as_avatar.present?
|
350
|
+
end
|
351
|
+
rescue
|
352
|
+
nil
|
353
|
+
end
|
354
|
+
|
355
|
+
def avatar
|
356
|
+
avatar_field.to_image
|
357
|
+
rescue
|
358
|
+
nil
|
359
|
+
end
|
360
|
+
|
361
|
+
def avatar_type
|
362
|
+
avatar_field.as_avatar
|
363
|
+
rescue
|
364
|
+
nil
|
365
|
+
end
|
366
|
+
|
367
|
+
def description_field
|
368
|
+
get_field_definitions.find do |field|
|
369
|
+
field.as_description.present?
|
370
|
+
end
|
371
|
+
rescue
|
372
|
+
nil
|
373
|
+
end
|
374
|
+
|
375
|
+
def description
|
376
|
+
description_field.value
|
377
|
+
rescue
|
378
|
+
nil
|
379
|
+
end
|
304
380
|
end
|
305
381
|
end
|
data/lib/avo/configuration.rb
CHANGED
@@ -22,6 +22,7 @@ module Avo
|
|
22
22
|
attr_accessor :display_breadcrumbs
|
23
23
|
attr_accessor :initial_breadcrumbs
|
24
24
|
attr_accessor :home_path
|
25
|
+
attr_accessor :search_debounce
|
25
26
|
|
26
27
|
def initialize
|
27
28
|
@root_path = "/avo"
|
@@ -56,6 +57,7 @@ module Avo
|
|
56
57
|
}
|
57
58
|
@display_breadcrumbs = true
|
58
59
|
@home_path = nil
|
60
|
+
@search_debounce = 300
|
59
61
|
end
|
60
62
|
|
61
63
|
def locale_tag
|
@@ -19,6 +19,9 @@ module Avo
|
|
19
19
|
attr_reader :help
|
20
20
|
attr_reader :default
|
21
21
|
attr_reader :visible
|
22
|
+
attr_reader :as_label
|
23
|
+
attr_reader :as_avatar
|
24
|
+
attr_reader :as_description
|
22
25
|
|
23
26
|
# Private options
|
24
27
|
attr_reader :updatable
|
@@ -53,6 +56,9 @@ module Avo
|
|
53
56
|
@help = args[:help] || nil
|
54
57
|
@default = args[:default] || nil
|
55
58
|
@visible = args[:visible] || true
|
59
|
+
@as_label = args[:as_label] || false
|
60
|
+
@as_avatar = args[:as_avatar] || false
|
61
|
+
@as_description = args[:as_description] || false
|
56
62
|
|
57
63
|
@updatable = true
|
58
64
|
@computable = true
|
@@ -47,6 +47,16 @@ module Avo
|
|
47
47
|
|
48
48
|
alias_method :has, :can
|
49
49
|
alias_method :lacks, :cant
|
50
|
+
|
51
|
+
# Returns if has ability and if is a valid license or app is in development.
|
52
|
+
def has_with_trial(ability)
|
53
|
+
can(ability) && (valid? || Rails.env.development? || Rails.env.test?)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns if lacks ability and if is a valid license or app is in development.
|
57
|
+
def lacks_with_trial(ability)
|
58
|
+
!can(ability) && (valid? || Rails.env.development? || Rails.env.test?)
|
59
|
+
end
|
50
60
|
end
|
51
61
|
end
|
52
62
|
end
|