avo 2.16.0 → 2.16.1.pre.1.nativefields
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 +0 -2
- data/Gemfile.lock +78 -86
- data/app/components/avo/base_component.rb +7 -1
- data/app/components/avo/field_wrapper_component.html.erb +40 -0
- data/app/components/avo/field_wrapper_component.rb +102 -0
- data/app/components/avo/fields/badge_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +3 -3
- data/app/components/avo/fields/belongs_to_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/boolean_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/boolean_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/boolean_group_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/boolean_group_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/code_field/edit_component.html.erb +2 -2
- data/app/components/avo/fields/code_field/show_component.html.erb +2 -2
- data/app/components/avo/fields/country_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/country_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/date_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/date_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/date_time_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/date_time_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/edit_component.rb +22 -4
- data/app/components/avo/fields/external_image_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/external_image_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/file_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/file_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/files_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/files_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/gravatar_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/id_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/id_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/key_value_field/edit_component.html.erb +2 -2
- data/app/components/avo/fields/key_value_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/markdown_field/edit_component.html.erb +2 -2
- data/app/components/avo/fields/markdown_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/number_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/number_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/password_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/progress_bar_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/progress_bar_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/select_field/edit_component.html.erb +1 -2
- data/app/components/avo/fields/select_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/show_component.rb +36 -1
- data/app/components/avo/fields/status_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/status_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/tags_field/edit_component.html.erb +1 -5
- data/app/components/avo/fields/tags_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/text_field/edit_component.html.erb +2 -2
- data/app/components/avo/fields/text_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/textarea_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/textarea_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/trix_field/edit_component.html.erb +2 -2
- data/app/components/avo/fields/trix_field/edit_component.rb +19 -1
- data/app/components/avo/fields/trix_field/show_component.html.erb +1 -1
- data/app/components/avo/index/resource_controls_component.rb +1 -0
- data/app/components/avo/views/resource_edit_component.html.erb +28 -26
- data/app/controllers/avo/application_controller.rb +8 -1
- data/app/controllers/avo/base_controller.rb +5 -5
- data/app/helpers/avo/application_helper.rb +31 -3
- data/app/helpers/avo/resources_helper.rb +4 -8
- data/app/javascript/js/controllers/action_controller.js +3 -1
- data/app/javascript/js/controllers/fields/date_field_controller.js +21 -1
- data/app/javascript/js/controllers/search_controller.js +122 -118
- data/avo.gemspec +1 -1
- data/config/master.key +1 -0
- data/lib/avo/base_resource.rb +5 -3
- data/lib/avo/concerns/fetches_things.rb +2 -0
- data/lib/avo/fields/base_field.rb +4 -0
- data/lib/avo/fields/select_field.rb +1 -0
- data/lib/avo/menu/menu.rb +2 -0
- data/lib/avo/services/authorization_service.rb +24 -20
- data/lib/avo/version.rb +1 -1
- data/lib/generators/avo/templates/field/components/edit_component.html.erb.tt +1 -1
- data/lib/generators/avo/templates/field/components/show_component.html.erb.tt +1 -1
- data/public/avo-assets/avo.base.css +26 -8
- data/public/avo-assets/avo.base.js +79 -79
- data/public/avo-assets/avo.base.js.map +3 -3
- metadata +8 -11
- data/app/components/avo/common_field_wrapper_component.html.erb +0 -26
- data/app/components/avo/common_field_wrapper_component.rb +0 -46
- data/app/components/avo/edit/field_wrapper_component.html.erb +0 -11
- data/app/components/avo/edit/field_wrapper_component.rb +0 -21
- data/app/components/avo/show/field_wrapper_component.html.erb +0 -9
- data/app/components/avo/show/field_wrapper_component.rb +0 -12
@@ -21,6 +21,10 @@ export default class extends Controller {
|
|
21
21
|
disableMobile: Boolean,
|
22
22
|
}
|
23
23
|
|
24
|
+
flatpickrInstance;
|
25
|
+
|
26
|
+
cachedInitialValue;
|
27
|
+
|
24
28
|
get browserZone() {
|
25
29
|
const time = DateTime.local()
|
26
30
|
|
@@ -59,6 +63,10 @@ export default class extends Controller {
|
|
59
63
|
}
|
60
64
|
|
61
65
|
connect() {
|
66
|
+
// Cache the initial value so we can fill it back on disconnection.
|
67
|
+
// We do that so the JS parser will continue to work when the user hits the back button to return on this page.
|
68
|
+
this.cacheInitialValue()
|
69
|
+
|
62
70
|
if (this.isOnShow || this.isOnIndex) {
|
63
71
|
this.initShow()
|
64
72
|
} else if (this.isOnEdit) {
|
@@ -66,6 +74,18 @@ export default class extends Controller {
|
|
66
74
|
}
|
67
75
|
}
|
68
76
|
|
77
|
+
disconnect() {
|
78
|
+
if (this.isOnShow || this.isOnIndex) {
|
79
|
+
this.context.element.innerText = this.cachedInitialValue
|
80
|
+
} else if (this.isOnEdit) {
|
81
|
+
if (this.flatpickrInstance) this.flatpickrInstance.destroy()
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
cacheInitialValue() {
|
86
|
+
this.cachedInitialValue = this.initialValue
|
87
|
+
}
|
88
|
+
|
69
89
|
// Turns the value in the controller wrapper into the timezone of the browser
|
70
90
|
initShow() {
|
71
91
|
let value = this.parsedValue
|
@@ -115,7 +135,7 @@ export default class extends Controller {
|
|
115
135
|
options.defaultDate = universalTimestamp(this.initialValue)
|
116
136
|
}
|
117
137
|
|
118
|
-
flatpickr(this.fakeInputTarget, options)
|
138
|
+
this.flatpickrInstance = flatpickr(this.fakeInputTarget, options)
|
119
139
|
|
120
140
|
if (this.enableTimeValue) {
|
121
141
|
this.updateRealInput(this.parsedValue.setZone(this.displayTimezone).toISO())
|
@@ -25,6 +25,8 @@ export default class extends Controller {
|
|
25
25
|
|
26
26
|
debouncedFetch = debouncePromise(fetch, this.searchDebounce);
|
27
27
|
|
28
|
+
destroyMethod;
|
29
|
+
|
28
30
|
get dataset() {
|
29
31
|
return this.autocompleteTarget.dataset
|
30
32
|
}
|
@@ -56,97 +58,52 @@ export default class extends Controller {
|
|
56
58
|
return this.dataset.searchResource === 'global'
|
57
59
|
}
|
58
60
|
|
59
|
-
|
60
|
-
const
|
61
|
-
|
62
|
-
return url.segment(this.searchSegments()).search(this.searchParams(query)).toString()
|
63
|
-
}
|
64
|
-
|
65
|
-
searchSegments() {
|
66
|
-
let segments = [
|
67
|
-
window.Avo.configuration.root_path,
|
68
|
-
'avo_api',
|
69
|
-
this.dataset.searchResource,
|
70
|
-
'search',
|
71
|
-
]
|
72
|
-
|
73
|
-
if (this.isGlobalSearch) {
|
74
|
-
segments = [window.Avo.configuration.root_path, 'avo_api', 'search']
|
75
|
-
}
|
76
|
-
|
77
|
-
return segments
|
78
|
-
}
|
79
|
-
|
80
|
-
searchParams(query) {
|
81
|
-
let params = {
|
82
|
-
q: query,
|
83
|
-
global: false,
|
84
|
-
}
|
85
|
-
|
86
|
-
if (this.isGlobalSearch) {
|
87
|
-
params.global = true
|
88
|
-
}
|
61
|
+
connect() {
|
62
|
+
const that = this
|
89
63
|
|
90
|
-
|
91
|
-
params = this.addAssociationParams(params)
|
92
|
-
params = this.addReflectionParams(params)
|
64
|
+
this.buttonTarget.onclick = () => this.showSearchPanel()
|
93
65
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
// eslint-disable-next-line camelcase
|
98
|
-
via_parent_resource_id: this.dataset.viaParentResourceId,
|
99
|
-
// eslint-disable-next-line camelcase
|
100
|
-
via_parent_resource_class: this.dataset.viaParentResourceClass,
|
101
|
-
// eslint-disable-next-line camelcase
|
102
|
-
via_relation: this.dataset.viaRelation,
|
103
|
-
}
|
66
|
+
this.clearValueTargets.forEach((target) => {
|
67
|
+
if (target.getAttribute('value') && this.hasClearButtonTarget) {
|
68
|
+
this.clearButtonTarget.classList.remove('hidden')
|
104
69
|
}
|
105
|
-
}
|
106
|
-
|
107
|
-
return params
|
108
|
-
}
|
70
|
+
})
|
109
71
|
|
110
|
-
|
111
|
-
|
112
|
-
...params,
|
113
|
-
// eslint-disable-next-line camelcase
|
114
|
-
via_association: this.dataset.viaAssociation,
|
115
|
-
// eslint-disable-next-line camelcase
|
116
|
-
via_association_id: this.dataset.viaAssociationId,
|
72
|
+
if (this.isGlobalSearch) {
|
73
|
+
Mousetrap.bind(['command+k', 'ctrl+k'], () => this.showSearchPanel())
|
117
74
|
}
|
118
75
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
76
|
+
autocomplete({
|
77
|
+
container: this.autocompleteTarget,
|
78
|
+
placeholder: this.translationKeys.placeholder,
|
79
|
+
translations: {
|
80
|
+
detachedCancelButtonText: this.translationKeys.cancel_button,
|
81
|
+
},
|
82
|
+
autoFocus: true,
|
83
|
+
openOnFocus: true,
|
84
|
+
detachedMediaQuery: '',
|
85
|
+
getSources: ({ query }) => {
|
86
|
+
document.body.classList.add('search-loading')
|
87
|
+
const endpoint = that.searchUrl(query)
|
130
88
|
|
131
|
-
|
132
|
-
|
89
|
+
return that
|
90
|
+
.debouncedFetch(endpoint)
|
91
|
+
.then((response) => {
|
92
|
+
document.body.classList.remove('search-loading')
|
133
93
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
94
|
+
return response.json()
|
95
|
+
})
|
96
|
+
.then((data) => Object.keys(data).map((resourceName) => that.addSource(resourceName, data[resourceName])))
|
97
|
+
},
|
98
|
+
})
|
138
99
|
|
139
|
-
|
100
|
+
// document.addEventListener('turbo:before-render', destroy)
|
101
|
+
// this.destroyMethod = destroy
|
140
102
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
} else {
|
145
|
-
Turbo.visit(item._url, { action: 'advance' })
|
103
|
+
// When using search for belongs-to
|
104
|
+
if (this.buttonTarget.dataset.shouldBeDisabled !== 'true') {
|
105
|
+
this.buttonTarget.removeAttribute('disabled')
|
146
106
|
}
|
147
|
-
|
148
|
-
// On searchable belongs to the class `aa-Detached` remains on the body making it unscrollable
|
149
|
-
document.body.classList.remove('aa-Detached')
|
150
107
|
}
|
151
108
|
|
152
109
|
addSource(resourceName, data) {
|
@@ -221,59 +178,106 @@ export default class extends Controller {
|
|
221
178
|
}
|
222
179
|
}
|
223
180
|
|
224
|
-
|
225
|
-
this.
|
181
|
+
handleOnSelect({ item }) {
|
182
|
+
if (this.isBelongsToSearch) {
|
183
|
+
this.updateFieldAttribute(this.hiddenIdTarget, 'value', item._id)
|
184
|
+
this.updateFieldAttribute(this.buttonTarget, 'value', item._label)
|
185
|
+
|
186
|
+
document.querySelector('.aa-DetachedOverlay').remove()
|
187
|
+
|
188
|
+
if (this.hasClearButtonTarget) {
|
189
|
+
this.clearButtonTarget.classList.remove('hidden')
|
190
|
+
}
|
191
|
+
} else {
|
192
|
+
Turbo.visit(item._url, { action: 'advance' })
|
193
|
+
}
|
194
|
+
|
195
|
+
// On searchable belongs to the class `aa-Detached` remains on the body making it unscrollable
|
196
|
+
document.body.classList.remove('aa-Detached')
|
226
197
|
}
|
227
198
|
|
228
|
-
|
229
|
-
|
230
|
-
|
199
|
+
searchUrl(query) {
|
200
|
+
const url = URI()
|
201
|
+
|
202
|
+
return url.segment(this.searchSegments()).search(this.searchParams(query)).toString()
|
231
203
|
}
|
232
204
|
|
233
|
-
|
234
|
-
|
205
|
+
searchSegments() {
|
206
|
+
let segments = [
|
207
|
+
window.Avo.configuration.root_path,
|
208
|
+
'avo_api',
|
209
|
+
this.dataset.searchResource,
|
210
|
+
'search',
|
211
|
+
]
|
235
212
|
|
236
|
-
|
213
|
+
if (this.isGlobalSearch) {
|
214
|
+
segments = [window.Avo.configuration.root_path, 'avo_api', 'search']
|
215
|
+
}
|
237
216
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
217
|
+
return segments
|
218
|
+
}
|
219
|
+
|
220
|
+
searchParams(query) {
|
221
|
+
let params = {
|
222
|
+
q: query,
|
223
|
+
global: false,
|
224
|
+
}
|
243
225
|
|
244
226
|
if (this.isGlobalSearch) {
|
245
|
-
|
227
|
+
params.global = true
|
246
228
|
}
|
247
229
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
translations: {
|
252
|
-
detachedCancelButtonText: this.translationKeys.cancel_button,
|
253
|
-
},
|
254
|
-
openOnFocus: true,
|
255
|
-
detachedMediaQuery: '',
|
256
|
-
getSources: ({ query }) => {
|
257
|
-
document.body.classList.add('search-loading')
|
258
|
-
const endpoint = that.searchUrl(query)
|
230
|
+
if (this.isBelongsToSearch || this.isHasManySearch) {
|
231
|
+
params = this.addAssociationParams(params)
|
232
|
+
params = this.addReflectionParams(params)
|
259
233
|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
234
|
+
if (this.isBelongsToSearch) {
|
235
|
+
params = {
|
236
|
+
...params,
|
237
|
+
// eslint-disable-next-line camelcase
|
238
|
+
via_parent_resource_id: this.dataset.viaParentResourceId,
|
239
|
+
// eslint-disable-next-line camelcase
|
240
|
+
via_parent_resource_class: this.dataset.viaParentResourceClass,
|
241
|
+
// eslint-disable-next-line camelcase
|
242
|
+
via_relation: this.dataset.viaRelation,
|
243
|
+
}
|
244
|
+
}
|
245
|
+
}
|
264
246
|
|
265
|
-
|
266
|
-
|
267
|
-
.then((data) => Object.keys(data).map((resourceName) => that.addSource(resourceName, data[resourceName])))
|
268
|
-
},
|
269
|
-
})
|
247
|
+
return params
|
248
|
+
}
|
270
249
|
|
271
|
-
|
250
|
+
addAssociationParams(params) {
|
251
|
+
params = {
|
252
|
+
...params,
|
253
|
+
// eslint-disable-next-line camelcase
|
254
|
+
via_association: this.dataset.viaAssociation,
|
255
|
+
// eslint-disable-next-line camelcase
|
256
|
+
via_association_id: this.dataset.viaAssociationId,
|
257
|
+
}
|
272
258
|
|
273
|
-
|
274
|
-
|
275
|
-
|
259
|
+
return params
|
260
|
+
}
|
261
|
+
|
262
|
+
addReflectionParams(params) {
|
263
|
+
params = {
|
264
|
+
...params,
|
265
|
+
// eslint-disable-next-line camelcase
|
266
|
+
via_reflection_class: this.dataset.viaReflectionClass,
|
267
|
+
// eslint-disable-next-line camelcase
|
268
|
+
via_reflection_id: this.dataset.viaReflectionId,
|
276
269
|
}
|
270
|
+
|
271
|
+
return params
|
272
|
+
}
|
273
|
+
|
274
|
+
showSearchPanel() {
|
275
|
+
this.autocompleteTarget.querySelector('button').click()
|
276
|
+
}
|
277
|
+
|
278
|
+
clearValue() {
|
279
|
+
this.clearValueTargets.map((target) => this.updateFieldAttribute(target, 'value', ''))
|
280
|
+
this.clearButtonTarget.classList.add('hidden')
|
277
281
|
}
|
278
282
|
|
279
283
|
// Private
|
data/avo.gemspec
CHANGED
@@ -41,7 +41,7 @@ Gem::Specification.new do |spec|
|
|
41
41
|
spec.add_dependency "active_link_to"
|
42
42
|
spec.add_dependency "image_processing"
|
43
43
|
spec.add_dependency "view_component", "2.60"
|
44
|
-
spec.add_dependency "
|
44
|
+
spec.add_dependency "turbo-rails"
|
45
45
|
spec.add_dependency "addressable"
|
46
46
|
spec.add_dependency "meta-tags"
|
47
47
|
spec.add_dependency "breadcrumbs_on_rails"
|
data/config/master.key
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2aeb23d82b909d9c6b5abb62f7058c2a
|
data/lib/avo/base_resource.rb
CHANGED
@@ -30,6 +30,7 @@ module Avo
|
|
30
30
|
class_attribute :search_query, default: nil
|
31
31
|
class_attribute :search_query_help, default: ""
|
32
32
|
class_attribute :includes, default: []
|
33
|
+
class_attribute :authorization_policy
|
33
34
|
class_attribute :translation_key
|
34
35
|
class_attribute :default_view_type, default: :table
|
35
36
|
class_attribute :devise_password_optional, default: false
|
@@ -92,7 +93,7 @@ module Avo
|
|
92
93
|
end
|
93
94
|
|
94
95
|
def authorization
|
95
|
-
Avo::Services::AuthorizationService.new Avo::App.current_user
|
96
|
+
Avo::Services::AuthorizationService.new Avo::App.current_user, model_class, policy_class: authorization_policy
|
96
97
|
end
|
97
98
|
|
98
99
|
def order_actions
|
@@ -285,8 +286,9 @@ module Avo
|
|
285
286
|
model
|
286
287
|
end
|
287
288
|
|
288
|
-
def authorization
|
289
|
-
|
289
|
+
def authorization(user: nil)
|
290
|
+
current_user = user || Avo::App.current_user
|
291
|
+
Avo::Services::AuthorizationService.new(current_user, model || model_class, policy_class: authorization_policy)
|
290
292
|
end
|
291
293
|
|
292
294
|
def file_hash
|
@@ -48,9 +48,11 @@ module Avo
|
|
48
48
|
end
|
49
49
|
|
50
50
|
# Returns the Avo resource by singular snake_cased name
|
51
|
+
# From all the resources that use the same model_class, it will fetch the first one in alphabetical order
|
51
52
|
#
|
52
53
|
# get_resource_by_name('User') => UserResource
|
53
54
|
# get_resource_by_name(User) => UserResource
|
55
|
+
|
54
56
|
def get_resource_by_model_name(klass)
|
55
57
|
# Fetch the mappings imposed by the user.
|
56
58
|
# If they are present, use those ones.
|
@@ -76,6 +76,8 @@ module Avo
|
|
76
76
|
@as_description = args[:as_description] || false
|
77
77
|
@index_text_align = args[:index_text_align] || :left
|
78
78
|
@html = args[:html] || nil
|
79
|
+
@view = args[:view] || nil
|
80
|
+
@value = args[:value] || nil
|
79
81
|
|
80
82
|
@args = args
|
81
83
|
|
@@ -155,6 +157,8 @@ module Avo
|
|
155
157
|
end
|
156
158
|
|
157
159
|
def value(property = nil)
|
160
|
+
return @value if @value.present?
|
161
|
+
|
158
162
|
property ||= id
|
159
163
|
|
160
164
|
# Get model value
|
data/lib/avo/menu/menu.rb
CHANGED
@@ -5,13 +5,14 @@ module Avo
|
|
5
5
|
attr_accessor :record
|
6
6
|
|
7
7
|
class << self
|
8
|
-
def authorize(user, record, action, **args)
|
8
|
+
def authorize(user, record, action, policy_class: nil, **args)
|
9
9
|
return true if skip_authorization
|
10
10
|
return true if user.nil?
|
11
11
|
|
12
|
+
policy_class ||= Pundit.policy(user, record)&.class
|
12
13
|
begin
|
13
|
-
if
|
14
|
-
Pundit.authorize user, record, action
|
14
|
+
if policy_class&.new(user, record)
|
15
|
+
Pundit.authorize user, record, action, policy_class: policy_class
|
15
16
|
end
|
16
17
|
|
17
18
|
true
|
@@ -28,7 +29,7 @@ module Avo
|
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
31
|
-
def authorize_action(user, record, action, **args)
|
32
|
+
def authorize_action(user, record, action, policy_class: nil, **args)
|
32
33
|
action = Avo.configuration.authorization_methods.stringify_keys[action.to_s] || action
|
33
34
|
|
34
35
|
# If no action passed we should raise error if the user wants that.
|
@@ -41,16 +42,18 @@ module Avo
|
|
41
42
|
|
42
43
|
# Add the question mark if it's missing
|
43
44
|
action = "#{action}?" unless action.end_with? "?"
|
44
|
-
|
45
|
-
authorize user, record, action, **args
|
45
|
+
authorize(user, record, action, policy_class: policy_class, **args)
|
46
46
|
end
|
47
47
|
|
48
|
-
def apply_policy(user, model)
|
49
|
-
return model if skip_authorization
|
50
|
-
return model if user.nil?
|
48
|
+
def apply_policy(user, model, policy_class: nil)
|
49
|
+
return model if skip_authorization || user.nil?
|
51
50
|
|
52
51
|
begin
|
53
|
-
|
52
|
+
if policy_class
|
53
|
+
policy_class::Scope.new(user, model).resolve
|
54
|
+
else
|
55
|
+
Pundit.policy_scope! user, model
|
56
|
+
end
|
54
57
|
rescue Pundit::NotDefinedError => e
|
55
58
|
return model unless Avo.configuration.raise_error_on_missing_policy
|
56
59
|
|
@@ -68,12 +71,12 @@ module Avo
|
|
68
71
|
end.to_h
|
69
72
|
end
|
70
73
|
|
71
|
-
def
|
72
|
-
Pundit.policy
|
73
|
-
end
|
74
|
+
def defined_methods(user, record, policy_class: nil, **args)
|
75
|
+
return Pundit.policy!(user, record).methods if policy_class.nil?
|
74
76
|
|
75
|
-
|
76
|
-
|
77
|
+
# I'm aware this will not raise a Pundit error.
|
78
|
+
# Should the policy not exist, it will however raise an uninitialized constant error, which is probably what we want when specifying a custom policy
|
79
|
+
policy_class.new(user, record).methods
|
77
80
|
rescue Pundit::NotDefinedError => e
|
78
81
|
return [] unless Avo.configuration.raise_error_on_missing_policy
|
79
82
|
|
@@ -87,13 +90,14 @@ module Avo
|
|
87
90
|
end
|
88
91
|
end
|
89
92
|
|
90
|
-
def initialize(user = nil, record = nil)
|
93
|
+
def initialize(user = nil, record = nil, policy_class: nil)
|
91
94
|
@user = user
|
92
95
|
@record = record
|
96
|
+
@policy_class = policy_class || Pundit.policy(user, record)&.class
|
93
97
|
end
|
94
98
|
|
95
99
|
def authorize(action, **args)
|
96
|
-
self.class.authorize(user, record, action, **args)
|
100
|
+
self.class.authorize(user, record, action, policy_class: @policy_class, **args)
|
97
101
|
end
|
98
102
|
|
99
103
|
def set_record(record)
|
@@ -109,15 +113,15 @@ module Avo
|
|
109
113
|
end
|
110
114
|
|
111
115
|
def authorize_action(action, **args)
|
112
|
-
self.class.authorize_action(user, record, action, **args)
|
116
|
+
self.class.authorize_action(user, record, action, policy_class: @policy_class, **args)
|
113
117
|
end
|
114
118
|
|
115
119
|
def apply_policy(model)
|
116
|
-
self.class.apply_policy(user, model)
|
120
|
+
self.class.apply_policy(user, model, policy_class: @policy_class)
|
117
121
|
end
|
118
122
|
|
119
123
|
def defined_methods(model, **args)
|
120
|
-
self.class.defined_methods(user, model, **args)
|
124
|
+
self.class.defined_methods(user, model, policy_class: @policy_class, **args)
|
121
125
|
end
|
122
126
|
|
123
127
|
def has_method?(method, **args)
|
data/lib/avo/version.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
<%%=
|
1
|
+
<%%= field_wrapper **field_wrapper_args do %>
|
2
2
|
<%%= @form.text_field @field.id,
|
3
3
|
class: classes("w-full"),
|
4
4
|
placeholder: @field.placeholder,
|
@@ -6445,6 +6445,11 @@ trix-toolbar .trix-button-group:not(:first-child){
|
|
6445
6445
|
margin-right:1.5rem
|
6446
6446
|
}
|
6447
6447
|
|
6448
|
+
.-mx-4{
|
6449
|
+
margin-left:-1rem;
|
6450
|
+
margin-right:-1rem
|
6451
|
+
}
|
6452
|
+
|
6448
6453
|
.mt-3{
|
6449
6454
|
margin-top:0.75rem
|
6450
6455
|
}
|
@@ -6573,10 +6578,6 @@ trix-toolbar .trix-button-group:not(:first-child){
|
|
6573
6578
|
margin-left:auto
|
6574
6579
|
}
|
6575
6580
|
|
6576
|
-
.mt-12{
|
6577
|
-
margin-top:3rem
|
6578
|
-
}
|
6579
|
-
|
6580
6581
|
.-mb-2{
|
6581
6582
|
margin-bottom:-0.5rem
|
6582
6583
|
}
|
@@ -6585,6 +6586,10 @@ trix-toolbar .trix-button-group:not(:first-child){
|
|
6585
6586
|
margin-top:1.5rem
|
6586
6587
|
}
|
6587
6588
|
|
6589
|
+
.mt-12{
|
6590
|
+
margin-top:3rem
|
6591
|
+
}
|
6592
|
+
|
6588
6593
|
.mr-px{
|
6589
6594
|
margin-right:1px
|
6590
6595
|
}
|
@@ -6865,6 +6870,10 @@ trix-toolbar .trix-button-group:not(:first-child){
|
|
6865
6870
|
flex-grow:0
|
6866
6871
|
}
|
6867
6872
|
|
6873
|
+
.flex-grow{
|
6874
|
+
flex-grow:1
|
6875
|
+
}
|
6876
|
+
|
6868
6877
|
.-translate-x-1\/2{
|
6869
6878
|
--tw-translate-x:-50%;
|
6870
6879
|
transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))
|
@@ -8076,6 +8085,10 @@ trix-toolbar .trix-button-group:not(:first-child){
|
|
8076
8085
|
opacity:1
|
8077
8086
|
}
|
8078
8087
|
|
8088
|
+
.opacity-80{
|
8089
|
+
opacity:0.8
|
8090
|
+
}
|
8091
|
+
|
8079
8092
|
.shadow-panel{
|
8080
8093
|
--tw-shadow:0px 4px 8px rgba(0, 0, 0, 0.04), 0px 0px 2px rgba(0, 0, 0, 0.06), 0px 0px 1px rgba(0, 0, 0, 0.04);
|
8081
8094
|
--tw-shadow-colored:0px 4px 8px var(--tw-shadow-color), 0px 0px 2px var(--tw-shadow-color), 0px 0px 1px var(--tw-shadow-color);
|
@@ -8120,6 +8133,11 @@ trix-toolbar .trix-button-group:not(:first-child){
|
|
8120
8133
|
filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)
|
8121
8134
|
}
|
8122
8135
|
|
8136
|
+
.sepia{
|
8137
|
+
--tw-sepia:sepia(100%);
|
8138
|
+
filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)
|
8139
|
+
}
|
8140
|
+
|
8123
8141
|
.filter{
|
8124
8142
|
filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)
|
8125
8143
|
}
|
@@ -9580,13 +9598,13 @@ trix-editor {
|
|
9580
9598
|
padding-right:1.5rem
|
9581
9599
|
}
|
9582
9600
|
|
9583
|
-
.md\:pb-0{
|
9584
|
-
padding-bottom:0px
|
9585
|
-
}
|
9586
|
-
|
9587
9601
|
.md\:pt-0{
|
9588
9602
|
padding-top:0px
|
9589
9603
|
}
|
9604
|
+
|
9605
|
+
.md\:pb-0{
|
9606
|
+
padding-bottom:0px
|
9607
|
+
}
|
9590
9608
|
}
|
9591
9609
|
|
9592
9610
|
@media (min-width: 1024px){
|