avo 2.17.1.pre.3 → 2.17.1.pre.5.stackedlayout
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 +20 -9
- data/Gemfile.lock +78 -79
- data/app/components/avo/field_wrapper_component.html.erb +9 -11
- data/app/components/avo/field_wrapper_component.rb +10 -3
- data/app/components/avo/fields/date_field/edit_component.html.erb +6 -6
- data/app/components/avo/fields/date_time_field/edit_component.html.erb +7 -6
- data/app/components/avo/fields/date_time_field/index_component.html.erb +1 -0
- data/app/components/avo/fields/date_time_field/show_component.html.erb +1 -0
- data/app/components/avo/fields/edit_component.rb +1 -1
- data/app/components/avo/fields/show_component.rb +1 -1
- data/app/components/avo/fields/time_field/edit_component.html.erb +6 -6
- data/app/components/avo/index/resource_table_component.html.erb +1 -1
- data/app/components/avo/item_switcher_component.html.erb +4 -1
- data/app/components/avo/panel_component.html.erb +5 -2
- data/app/components/avo/views/resource_edit_component.html.erb +3 -1
- data/app/components/avo/views/resource_index_component.html.erb +4 -4
- data/app/components/avo/views/resource_show_component.html.erb +5 -2
- data/app/controllers/avo/actions_controller.rb +6 -5
- data/app/controllers/avo/application_controller.rb +9 -17
- data/app/controllers/avo/associations_controller.rb +1 -1
- data/app/controllers/avo/cards_controller.rb +12 -2
- data/app/javascript/js/controllers/fields/date_field_controller.js +34 -21
- data/app/views/avo/actions/show.html.erb +1 -1
- data/app/views/avo/cards/chartkick_missing.html.erb +14 -0
- data/avo.gemspec +2 -5
- data/db/factories.rb +5 -5
- data/lib/avo/base_action.rb +1 -1
- data/lib/avo/base_resource.rb +1 -0
- data/lib/avo/concerns/can_replace_fields.rb +36 -0
- data/lib/avo/configuration.rb +4 -0
- data/lib/avo/engine.rb +10 -1
- data/lib/avo/fields/base_field.rb +2 -0
- data/lib/avo/fields/country_field.rb +5 -1
- data/lib/avo/fields/date_time_field.rb +2 -0
- data/lib/avo/fields/time_field.rb +1 -7
- data/lib/avo/html/builder.rb +14 -0
- data/lib/avo/services/authorization_clients/pundit_client.rb +51 -0
- data/lib/avo/services/authorization_service.rb +43 -61
- data/lib/avo/version.rb +1 -1
- data/lib/avo.rb +4 -0
- data/lib/generators/avo/templates/initializer/avo.tt +2 -0
- data/public/avo-assets/avo.base.css +5 -0
- data/public/avo-assets/avo.base.js +73 -73
- data/public/avo-assets/avo.base.js.map +2 -2
- metadata +11 -50
@@ -25,8 +25,11 @@
|
|
25
25
|
<% end %>
|
26
26
|
<% if body? %>
|
27
27
|
<div class="flex flex-col sm:flex-row space-y-4 sm:space-y-0 sm:gap-4 w-full">
|
28
|
-
<div class="relative flex-1
|
29
|
-
|
28
|
+
<div class="relative flex-1 <% if sidebar? %> w-2/3 <% else %> w-full <% end %>">
|
29
|
+
<% # The body is wrapped inside another div in order to avoid long & tall panels next to sidebars when the sidebar taller. %>
|
30
|
+
<div class="relative <%= white_panel_classes %> <%= @body_classes %>">
|
31
|
+
<%= body %>
|
32
|
+
</div>
|
30
33
|
</div>
|
31
34
|
<% if sidebar? %>
|
32
35
|
<div class="w-full sm:w-1/3 flex-shrink-0 h-full <%= white_panel_classes %>">
|
@@ -1,6 +1,8 @@
|
|
1
1
|
<%= content_tag :div,
|
2
2
|
data: {
|
3
|
-
|
3
|
+
model_name: @resource.model_name.to_s,
|
4
|
+
resource_name: @resource.class.to_s,
|
5
|
+
model_id: @resource.model.id,
|
4
6
|
selected_resources_name: @resource.model_key,
|
5
7
|
selected_resources: [@resource.model.id],
|
6
8
|
**@resource.stimulus_data_attributes
|
@@ -1,5 +1,7 @@
|
|
1
1
|
<%= content_tag :div,
|
2
2
|
data: {
|
3
|
+
model_name: @resource.model_name.to_s,
|
4
|
+
resource_name: @resource.class.to_s,
|
3
5
|
**@resource.stimulus_data_attributes
|
4
6
|
} do %>
|
5
7
|
<%= render Avo::PanelComponent.new(name: title, description: description, data: { component: 'resources-index' }, display_breadcrumbs: @reflection.blank?) do |c| %>
|
@@ -46,10 +48,8 @@
|
|
46
48
|
</div>
|
47
49
|
<% if view_type.to_sym == :table %>
|
48
50
|
<% if @resources.present? %>
|
49
|
-
<div class="w-full
|
50
|
-
|
51
|
-
<%= render(Avo::Index::ResourceTableComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model, parent_resource: @parent_resource, pagy: @pagy, query: @query)) %>
|
52
|
-
</div>
|
51
|
+
<div class="w-full relative flex-1 flex mt-0">
|
52
|
+
<%= render(Avo::Index::ResourceTableComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model, parent_resource: @parent_resource, pagy: @pagy, query: @query)) %>
|
53
53
|
</div>
|
54
54
|
<% else %>
|
55
55
|
<%= helpers.empty_state resource_name: @resource.name.downcase.pluralize, related_name: params[:related_name], view_type: view_type, add_background: true %>
|
@@ -1,6 +1,8 @@
|
|
1
1
|
<%= content_tag :div,
|
2
2
|
data: {
|
3
|
-
|
3
|
+
model_name: @resource.model_name.to_s,
|
4
|
+
resource_name: @resource.class.to_s,
|
5
|
+
model_id: @resource.model.id,
|
4
6
|
selected_resources_name: @resource.model_key,
|
5
7
|
selected_resources: [@resource.model.id],
|
6
8
|
**@resource.stimulus_data_attributes
|
@@ -154,7 +156,8 @@
|
|
154
156
|
<% end %>
|
155
157
|
<% if main_panel.present? %>
|
156
158
|
<% c.body do %>
|
157
|
-
|
159
|
+
<%# the overflow helps with long values %>
|
160
|
+
<div class="divide-y overflow-auto">
|
158
161
|
<% main_panel.items.each_with_index do |field, index| %>
|
159
162
|
<%= render field
|
160
163
|
.hydrate(resource: @resource, model: @resource.model, user: @resource.user, view: view)
|
@@ -12,7 +12,10 @@ module Avo
|
|
12
12
|
before_action :set_action, only: [:show, :handle]
|
13
13
|
|
14
14
|
def show
|
15
|
-
|
15
|
+
# Se the view to :new so the default value gets prefilled
|
16
|
+
@view = :new
|
17
|
+
|
18
|
+
@resource.hydrate(model: @model, view: @view, user: _current_user, params: params)
|
16
19
|
@model = ActionModel.new @action.get_attributes_for_action
|
17
20
|
end
|
18
21
|
|
@@ -48,17 +51,15 @@ module Avo
|
|
48
51
|
end
|
49
52
|
|
50
53
|
def set_action
|
51
|
-
@action = action_class.new(model: @model, resource: @resource, user: _current_user, view:
|
54
|
+
@action = action_class.new(model: @model, resource: @resource, user: _current_user, view: @view)
|
52
55
|
end
|
53
56
|
|
54
57
|
def action_class
|
55
58
|
klass_name = params[:action_id].gsub("avo_actions_", "").camelize
|
56
59
|
|
57
|
-
|
60
|
+
Avo::BaseAction.descendants.find do |action|
|
58
61
|
action.to_s == klass_name
|
59
62
|
end
|
60
|
-
|
61
|
-
valid_klass
|
62
63
|
end
|
63
64
|
|
64
65
|
def respond(response)
|
@@ -1,11 +1,5 @@
|
|
1
1
|
module Avo
|
2
2
|
class ApplicationController < ::ActionController::Base
|
3
|
-
if defined?(Pundit::Authorization)
|
4
|
-
include Pundit::Authorization
|
5
|
-
else
|
6
|
-
include Pundit
|
7
|
-
end
|
8
|
-
|
9
3
|
include Pagy::Backend
|
10
4
|
include Avo::ApplicationHelper
|
11
5
|
include Avo::UrlHelpers
|
@@ -24,7 +18,7 @@ module Avo
|
|
24
18
|
before_action :set_view
|
25
19
|
before_action :set_sidebar_open
|
26
20
|
|
27
|
-
rescue_from
|
21
|
+
rescue_from Avo::NotAuthorizedError, with: :render_unauthorized
|
28
22
|
rescue_from ActiveRecord::RecordInvalid, with: :exception_logger
|
29
23
|
|
30
24
|
helper_method :_current_user, :resources_path, :resource_path, :new_resource_path, :edit_resource_path, :resource_attach_path, :resource_detach_path, :related_resources_path, :turbo_frame_request?, :resource_view_path
|
@@ -257,18 +251,16 @@ module Avo
|
|
257
251
|
instance_eval(&Avo.configuration.authenticate)
|
258
252
|
end
|
259
253
|
|
260
|
-
def render_unauthorized(
|
261
|
-
|
262
|
-
flash.now[:notice] = t "avo.not_authorized"
|
263
|
-
|
264
|
-
redirect_url = if request.referrer.blank? || (request.referrer == request.url)
|
265
|
-
root_url
|
266
|
-
else
|
267
|
-
request.referrer
|
268
|
-
end
|
254
|
+
def render_unauthorized(_exception)
|
255
|
+
flash.now[:notice] = t "avo.not_authorized"
|
269
256
|
|
270
|
-
|
257
|
+
redirect_url = if request.referrer.blank? || (request.referrer == request.url)
|
258
|
+
root_url
|
259
|
+
else
|
260
|
+
request.referrer
|
271
261
|
end
|
262
|
+
|
263
|
+
redirect_to(redirect_url)
|
272
264
|
end
|
273
265
|
|
274
266
|
def set_authorization
|
@@ -157,7 +157,7 @@ module Avo
|
|
157
157
|
private
|
158
158
|
|
159
159
|
def set_related_authorization
|
160
|
-
@
|
160
|
+
@related_authorization = if related_resource
|
161
161
|
related_resource.authorization(user: _current_user)
|
162
162
|
else
|
163
163
|
Services::AuthorizationService.new _current_user
|
@@ -2,10 +2,12 @@ require_dependency "avo/application_controller"
|
|
2
2
|
|
3
3
|
module Avo
|
4
4
|
class CardsController < ApplicationController
|
5
|
-
before_action :set_dashboard
|
6
|
-
before_action :set_card
|
5
|
+
before_action :set_dashboard
|
6
|
+
before_action :set_card
|
7
|
+
before_action :detect_chartkick
|
7
8
|
|
8
9
|
def show
|
10
|
+
render(:chartkick_missing) unless @chartkick_installed
|
9
11
|
end
|
10
12
|
|
11
13
|
private
|
@@ -21,5 +23,13 @@ module Avo
|
|
21
23
|
card.hydrate(dashboard: @dashboard, params: params)
|
22
24
|
end
|
23
25
|
end
|
26
|
+
|
27
|
+
def detect_chartkick
|
28
|
+
@chartkick_installed = if @card.class.ancestors.map(&:to_s).include?("Avo::Dashboards::ChartkickCard")
|
29
|
+
defined?(Chartkick)
|
30
|
+
else
|
31
|
+
true
|
32
|
+
end
|
33
|
+
end
|
24
34
|
end
|
25
35
|
end
|
@@ -60,6 +60,22 @@ export default class extends Controller {
|
|
60
60
|
return this.viewValue === 'show'
|
61
61
|
}
|
62
62
|
|
63
|
+
get fieldIsDate() {
|
64
|
+
return this.fieldTypeValue === 'date'
|
65
|
+
}
|
66
|
+
|
67
|
+
get fieldIsDateTime() {
|
68
|
+
return this.fieldTypeValue === 'dateTime'
|
69
|
+
}
|
70
|
+
|
71
|
+
get fieldIsTime() {
|
72
|
+
return this.fieldTypeValue === 'time'
|
73
|
+
}
|
74
|
+
|
75
|
+
get fieldHasTime() {
|
76
|
+
return this.fieldIsTime || this.fieldIsDateTime
|
77
|
+
}
|
78
|
+
|
63
79
|
// Parse the time as if it were UTC
|
64
80
|
get parsedValue() {
|
65
81
|
return DateTime.fromISO(this.initialValue, { zone: 'UTC' })
|
@@ -98,7 +114,7 @@ export default class extends Controller {
|
|
98
114
|
let value = this.parsedValue
|
99
115
|
|
100
116
|
// Set the zone only if the type of field is date time or relative time.
|
101
|
-
if (this.
|
117
|
+
if (this.fieldHasTime && this.relativeValue) {
|
102
118
|
value = value.setZone(this.displayTimezone)
|
103
119
|
}
|
104
120
|
|
@@ -136,16 +152,22 @@ export default class extends Controller {
|
|
136
152
|
// Hide calendar and only keep time picker.
|
137
153
|
options.noCalendar = this.noCalendarValue
|
138
154
|
|
155
|
+
if (this.fieldHasTime) {
|
156
|
+
options.dateFormat = 'Y-m-d H:i:S'
|
157
|
+
}
|
158
|
+
|
139
159
|
if (this.initialValue) {
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
160
|
+
switch (this.fieldTypeValue) {
|
161
|
+
case 'date':
|
162
|
+
options.defaultDate = universalTimestamp(this.initialValue)
|
163
|
+
break
|
164
|
+
default:
|
165
|
+
case 'time':
|
166
|
+
options.defaultDate = this.parsedValue.setZone(this.displayTimezone, { keepLocalTime: !this.relativeValue }).toISO()
|
167
|
+
break
|
168
|
+
case 'dateTime':
|
169
|
+
options.defaultDate = this.parsedValue.setZone(this.displayTimezone, { keepLocalTime: !this.relativeValue }).toISO()
|
170
|
+
break
|
149
171
|
}
|
150
172
|
}
|
151
173
|
|
@@ -182,27 +204,18 @@ export default class extends Controller {
|
|
182
204
|
return
|
183
205
|
}
|
184
206
|
|
185
|
-
let args = {}
|
186
|
-
|
187
|
-
// For values that involve time we should keep the local time.
|
188
|
-
if (this.timezoneValue || !this.relativeValue) {
|
189
|
-
args = { keepLocalTime: true }
|
190
|
-
} else {
|
191
|
-
args = { keepLocalTime: false }
|
192
|
-
}
|
193
|
-
|
194
207
|
let value
|
195
208
|
switch (this.fieldTypeValue) {
|
196
209
|
case 'time':
|
197
210
|
// For time values, we should maintain the real value and format it to a time-friendly format.
|
198
|
-
value = DateTime.fromISO(selectedDates[0].toISOString()).setZone('UTC',
|
211
|
+
value = DateTime.fromISO(selectedDates[0].toISOString()).setZone('UTC', { keepLocalTime: !this.relativeValue }).toFormat(RAW_TIME_FORMAT)
|
199
212
|
break
|
200
213
|
case 'date':
|
201
214
|
value = DateTime.fromISO(selectedDates[0].toISOString()).setZone('UTC', { keepLocalTime: true }).toFormat(RAW_DATE_FORMAT)
|
202
215
|
break
|
203
216
|
default:
|
204
217
|
case 'dateTime':
|
205
|
-
value = DateTime.fromISO(selectedDates[0].toISOString()).setZone('UTC',
|
218
|
+
value = DateTime.fromISO(selectedDates[0].toISOString()).setZone('UTC', { keepLocalTime: !this.relativeValue }).toISO()
|
206
219
|
break
|
207
220
|
}
|
208
221
|
|
@@ -27,7 +27,7 @@
|
|
27
27
|
<% @action.get_fields.each_with_index do |field, index| %>
|
28
28
|
<%= render field
|
29
29
|
.hydrate(resource: @resource, model: @resource.model, user: @resource.user, view: @view)
|
30
|
-
.component_for_view(
|
30
|
+
.component_for_view(@view)
|
31
31
|
.new(field: field, resource: @resource, index: index, form: form, compact: true)
|
32
32
|
%>
|
33
33
|
<% end %>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<%= render Avo::TurboFrameWrapperComponent.new(params[:turbo_frame]) do %>
|
2
|
+
<div class="w-full h-full flex items-center text-center">
|
3
|
+
<div class="flex-1">
|
4
|
+
Chartkick is missing.
|
5
|
+
<a
|
6
|
+
href="https://docs.avohq.io/2.0/upgrade.html#upgrade-from-2-17-to-2-18"
|
7
|
+
target="_blank"
|
8
|
+
>
|
9
|
+
Manually require it in your
|
10
|
+
<code class="inline">Gemfile</code>
|
11
|
+
</a>.
|
12
|
+
</div>
|
13
|
+
</div>
|
14
|
+
<% end %>
|
data/avo.gemspec
CHANGED
@@ -32,20 +32,17 @@ Gem::Specification.new do |spec|
|
|
32
32
|
|
33
33
|
spec.files = Dir["{bin,app,config,db,lib,public}/**/*", "MIT-LICENSE", "Rakefile", "README.md", "avo.gemspec", "Gemfile", "Gemfile.lock"]
|
34
34
|
|
35
|
-
spec.add_dependency "
|
35
|
+
spec.add_dependency "activerecord", ">= 6.0"
|
36
|
+
spec.add_dependency "actionview", ">= 6.0"
|
36
37
|
spec.add_dependency "pagy"
|
37
38
|
spec.add_dependency "zeitwerk"
|
38
|
-
spec.add_dependency "countries"
|
39
|
-
spec.add_dependency "pundit"
|
40
39
|
spec.add_dependency "httparty"
|
41
40
|
spec.add_dependency "active_link_to"
|
42
|
-
spec.add_dependency "image_processing"
|
43
41
|
spec.add_dependency "view_component"
|
44
42
|
spec.add_dependency "turbo-rails"
|
45
43
|
spec.add_dependency "addressable"
|
46
44
|
spec.add_dependency "meta-tags"
|
47
45
|
spec.add_dependency "breadcrumbs_on_rails"
|
48
|
-
spec.add_dependency "chartkick"
|
49
46
|
spec.add_dependency "dry-initializer"
|
50
47
|
spec.add_dependency "docile"
|
51
48
|
spec.add_dependency "inline_svg"
|
data/db/factories.rb
CHANGED
@@ -90,10 +90,10 @@ FactoryBot.define do
|
|
90
90
|
end
|
91
91
|
|
92
92
|
factory :product do
|
93
|
-
title {
|
94
|
-
description { "
|
95
|
-
price {
|
96
|
-
status { "
|
97
|
-
category {
|
93
|
+
title { Faker::App.name }
|
94
|
+
description { Faker::Lorem.paragraphs(number: rand(1...3)).join("\n") }
|
95
|
+
price { rand(10000..999000) }
|
96
|
+
status { "status" }
|
97
|
+
category { ::Product.categories.values.sample }
|
98
98
|
end
|
99
99
|
end
|
data/lib/avo/base_action.rb
CHANGED
data/lib/avo/base_resource.rb
CHANGED
@@ -4,6 +4,7 @@ module Avo
|
|
4
4
|
|
5
5
|
include ActionView::Helpers::UrlHelper
|
6
6
|
include Avo::Concerns::HasFields
|
7
|
+
include Avo::Concerns::CanReplaceFields
|
7
8
|
include Avo::Concerns::HasEditableControls
|
8
9
|
include Avo::Concerns::HasStimulusControllers
|
9
10
|
include Avo::Concerns::ModelClassConstantized
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Avo
|
2
|
+
module Concerns
|
3
|
+
module CanReplaceFields
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
class_attribute :backup_items_holder
|
8
|
+
end
|
9
|
+
|
10
|
+
class_methods do
|
11
|
+
def with_temporary_items(&block)
|
12
|
+
# back-up the previous items
|
13
|
+
self.backup_items_holder = items_holder
|
14
|
+
|
15
|
+
self.items_holder = Avo::ItemsHolder.new
|
16
|
+
|
17
|
+
instance_eval(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def restore_items_from_backup
|
21
|
+
self.items_holder = backup_items_holder if backup_items_holder.present?
|
22
|
+
end
|
23
|
+
|
24
|
+
def with_new_items(&block)
|
25
|
+
self.items_holder = Avo::ItemsHolder.new
|
26
|
+
|
27
|
+
instance_eval(&block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def with_new_items(&block)
|
32
|
+
self.class.with_new_items(&block)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/avo/configuration.rb
CHANGED
@@ -37,6 +37,8 @@ module Avo
|
|
37
37
|
attr_accessor :model_resource_mapping
|
38
38
|
attr_accessor :tabs_style
|
39
39
|
attr_accessor :resource_default_view
|
40
|
+
attr_accessor :authorization_client
|
41
|
+
attr_accessor :field_wrapper_layout
|
40
42
|
attr_writer :branding
|
41
43
|
|
42
44
|
def initialize
|
@@ -85,6 +87,8 @@ module Avo
|
|
85
87
|
@model_resource_mapping = {}
|
86
88
|
@tabs_style = :tabs
|
87
89
|
@resource_default_view = :show
|
90
|
+
@authorization_client = :pundit
|
91
|
+
@field_wrapper_layout = :inline
|
88
92
|
end
|
89
93
|
|
90
94
|
def current_user_method(&block)
|
data/lib/avo/engine.rb
CHANGED
@@ -1,6 +1,15 @@
|
|
1
1
|
# requires all dependencies
|
2
2
|
Gem.loaded_specs["avo"].dependencies.each do |d|
|
3
|
-
|
3
|
+
case d.name
|
4
|
+
when "activerecord"
|
5
|
+
require "active_record/railtie"
|
6
|
+
when "actionview"
|
7
|
+
require "action_view/railtie"
|
8
|
+
when "activestorage"
|
9
|
+
require "active_storage/engine"
|
10
|
+
else
|
11
|
+
require d.name
|
12
|
+
end
|
4
13
|
end
|
5
14
|
|
6
15
|
# In development we should load the engine so we get the autoload for components
|
@@ -36,6 +36,7 @@ module Avo
|
|
36
36
|
attr_reader :as_avatar
|
37
37
|
attr_reader :as_description
|
38
38
|
attr_reader :index_text_align
|
39
|
+
attr_reader :stacked
|
39
40
|
|
40
41
|
# Private options
|
41
42
|
attr_reader :updatable
|
@@ -78,6 +79,7 @@ module Avo
|
|
78
79
|
@html = args[:html] || nil
|
79
80
|
@view = args[:view] || nil
|
80
81
|
@value = args[:value] || nil
|
82
|
+
@stacked = args[:stacked] || nil
|
81
83
|
|
82
84
|
@args = args
|
83
85
|
|
@@ -11,7 +11,11 @@ module Avo
|
|
11
11
|
|
12
12
|
super(id, **args, &block)
|
13
13
|
|
14
|
-
@countries =
|
14
|
+
@countries = begin
|
15
|
+
ISO3166::Country.translations.sort_by { |code, name| name }.to_h
|
16
|
+
rescue
|
17
|
+
{none: "You need to install the countries gem for this field to work properly"}
|
18
|
+
end
|
15
19
|
@display_code = args[:display_code].present? ? args[:display_code] : false
|
16
20
|
end
|
17
21
|
|
@@ -5,6 +5,7 @@ module Avo
|
|
5
5
|
attr_reader :picker_format
|
6
6
|
attr_reader :time_24hr
|
7
7
|
attr_reader :timezone
|
8
|
+
attr_reader :relative
|
8
9
|
|
9
10
|
def initialize(id, **args, &block)
|
10
11
|
super(id, **args, &block)
|
@@ -13,6 +14,7 @@ module Avo
|
|
13
14
|
add_string_prop args, :picker_format, "Y-m-d H:i:S"
|
14
15
|
add_string_prop args, :format, "yyyy-LL-dd TT"
|
15
16
|
add_string_prop args, :timezone
|
17
|
+
add_boolean_prop args, :relative, true
|
16
18
|
end
|
17
19
|
|
18
20
|
def formatted_value
|
@@ -1,20 +1,14 @@
|
|
1
1
|
module Avo
|
2
2
|
module Fields
|
3
|
-
class TimeField <
|
3
|
+
class TimeField < DateTimeField
|
4
4
|
attr_reader :format
|
5
5
|
attr_reader :picker_format
|
6
|
-
attr_reader :time_24hr
|
7
|
-
attr_reader :timezone
|
8
|
-
attr_reader :relative
|
9
6
|
|
10
7
|
def initialize(id, **args, &block)
|
11
8
|
super(id, **args, &block)
|
12
9
|
|
13
|
-
add_boolean_prop args, :time_24hr
|
14
10
|
add_string_prop args, :picker_format, "H:i:S"
|
15
11
|
add_string_prop args, :format, "TT"
|
16
|
-
add_string_prop args, :timezone
|
17
|
-
add_boolean_prop args, :relative, true
|
18
12
|
end
|
19
13
|
|
20
14
|
def formatted_value
|
data/lib/avo/html/builder.rb
CHANGED
@@ -13,6 +13,8 @@ class Avo::HTML::Builder
|
|
13
13
|
attr_accessor :edit_stack
|
14
14
|
attr_accessor :index_stack
|
15
15
|
attr_accessor :input_stack
|
16
|
+
attr_accessor :label_stack
|
17
|
+
attr_accessor :content_stack
|
16
18
|
|
17
19
|
attr_accessor :record
|
18
20
|
attr_accessor :resource
|
@@ -30,6 +32,8 @@ class Avo::HTML::Builder
|
|
30
32
|
@edit_stack = {}
|
31
33
|
@index_stack = {}
|
32
34
|
@input_stack = {}
|
35
|
+
@label_stack = {}
|
36
|
+
@content_stack = {}
|
33
37
|
|
34
38
|
@record = record
|
35
39
|
@resource = resource
|
@@ -77,6 +81,16 @@ class Avo::HTML::Builder
|
|
77
81
|
capture_block :input, &block
|
78
82
|
end
|
79
83
|
|
84
|
+
# Takes a block
|
85
|
+
def label(&block)
|
86
|
+
capture_block :label, &block
|
87
|
+
end
|
88
|
+
|
89
|
+
# Takes a block
|
90
|
+
def content(&block)
|
91
|
+
capture_block :content, &block
|
92
|
+
end
|
93
|
+
|
80
94
|
# Takes a block
|
81
95
|
def show(&block)
|
82
96
|
capture_block :show, &block
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Avo
|
2
|
+
module Services
|
3
|
+
module AuthorizationClients
|
4
|
+
class PunditClient
|
5
|
+
def authorize(user, record, action, policy_class: nil)
|
6
|
+
Pundit.authorize(user, record, action, policy_class: policy_class)
|
7
|
+
rescue Pundit::NotDefinedError => error
|
8
|
+
raise NoPolicyError.new error.message
|
9
|
+
rescue Pundit::NotAuthorizedError => error
|
10
|
+
raise NotAuthorizedError.new error.message
|
11
|
+
end
|
12
|
+
|
13
|
+
def policy(user, record)
|
14
|
+
Pundit.policy(user, record)
|
15
|
+
end
|
16
|
+
|
17
|
+
def policy!(user, record)
|
18
|
+
Pundit.policy!(user, record)
|
19
|
+
rescue Pundit::NotDefinedError => error
|
20
|
+
raise NoPolicyError.new error.message
|
21
|
+
end
|
22
|
+
|
23
|
+
def apply_policy(user, model, policy_class: nil)
|
24
|
+
# Try and figure out the scope from a given policy or auto-detected one
|
25
|
+
scope_from_policy_class = scope_for_policy_class(policy_class)
|
26
|
+
|
27
|
+
# If we discover one use it.
|
28
|
+
# Else fallback to pundit.
|
29
|
+
if scope_from_policy_class.present?
|
30
|
+
scope_from_policy_class.new(user, model).resolve
|
31
|
+
else
|
32
|
+
Pundit.policy_scope!(user, model)
|
33
|
+
end
|
34
|
+
rescue Pundit::NotDefinedError => error
|
35
|
+
raise NoPolicyError.new error.message
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# Fetches the scope for a given policy
|
41
|
+
def scope_for_policy_class(policy_class = nil)
|
42
|
+
return if policy_class.blank?
|
43
|
+
|
44
|
+
if policy_class.present? && defined?(policy_class::Scope)
|
45
|
+
policy_class::Scope
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|