avo 2.9.1.pre3 → 2.9.1.pre4
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.lock +3 -1
- data/app/assets/builds/avo.js +63 -63
- data/app/assets/builds/avo.js.map +2 -2
- data/app/components/avo/actions_component.rb +6 -2
- data/app/components/avo/base_component.rb +2 -0
- data/app/components/avo/fields/common/single_file_viewer_component.rb +1 -1
- data/app/components/avo/fields/date_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/date_time_field/edit_component.html.erb +9 -11
- data/app/components/avo/fields/date_time_field/index_component.html.erb +1 -9
- data/app/components/avo/fields/date_time_field/show_component.html.erb +1 -9
- data/app/components/avo/index/ordering/button_component.rb +3 -13
- data/app/components/avo/views/resource_edit_component.rb +1 -1
- data/app/components/avo/views/resource_index_component.rb +2 -2
- data/app/controllers/avo/application_controller.rb +24 -3
- data/app/javascript/avo.js +5 -1
- data/app/javascript/js/controllers/fields/date_field_controller.js +24 -68
- data/app/views/avo/partials/_javascript.html.erb +1 -1
- data/config/routes.rb +1 -1
- data/lib/avo/app.rb +6 -2
- data/lib/avo/base_card.rb +1 -7
- data/lib/avo/base_resource.rb +1 -1
- data/lib/avo/concerns/handles_field_args.rb +1 -1
- data/lib/avo/concerns/model_class_constantized.rb +23 -0
- data/lib/avo/dashboards/base_dashboard.rb +1 -1
- data/lib/avo/fields/date_field.rb +2 -0
- data/lib/avo/fields/date_time_field.rb +9 -13
- data/lib/avo/fields/has_base_field.rb +3 -1
- data/lib/avo/fields/has_one_field.rb +4 -1
- data/lib/avo/menu/builder.rb +3 -7
- data/lib/avo/services/uri_service.rb +41 -0
- data/lib/avo/version.rb +1 -1
- data/lib/avo.rb +1 -0
- data/public/avo-assets/avo.js +63 -63
- data/public/avo-assets/avo.js.map +2 -2
- metadata +4 -2
@@ -43,10 +43,14 @@ class Avo::ActionsComponent < ViewComponent::Base
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def single_record_path(id)
|
46
|
-
|
46
|
+
Avo::Services::URIService.parse(@resource.record_path)
|
47
|
+
.append_paths("actions", id)
|
48
|
+
.to_s
|
47
49
|
end
|
48
50
|
|
49
51
|
def many_records_path(id)
|
50
|
-
|
52
|
+
Avo::Services::URIService.parse(@resource.records_path)
|
53
|
+
.append_paths("actions", id)
|
54
|
+
.to_s
|
51
55
|
end
|
52
56
|
end
|
@@ -10,7 +10,7 @@ class Avo::Fields::Common::SingleFileViewerComponent < ViewComponent::Base
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def destroy_path
|
13
|
-
|
13
|
+
Avo::Services::URIService.parse(@resource.record_path).append_paths("active_storage_attachments", id, file.id).to_s
|
14
14
|
end
|
15
15
|
|
16
16
|
def id
|
@@ -1,18 +1,16 @@
|
|
1
1
|
<%= edit_field_wrapper field: @field, index: @index, form: @form, resource: @resource, displayed_in_modal: @displayed_in_modal do %>
|
2
|
-
|
3
|
-
controller: "date-field",
|
4
|
-
date_field_view_value: @view,
|
5
|
-
date_field_enable_time_value: true,
|
6
|
-
date_field_picker_format_value: @field.picker_format,
|
7
|
-
date_field_first_day_of_week_value: @field.first_day_of_week,
|
8
|
-
date_field_time24_hr_value: @field.time_24hr,
|
9
|
-
date_field_timezone_value: @field.timezone,
|
10
|
-
} do %>
|
2
|
+
<div data-controller="date-field">
|
11
3
|
<%= @form.datetime_field @field.id,
|
12
|
-
value: @field.edit_formatted_value,
|
13
4
|
class: classes("w-full"),
|
14
5
|
data: {
|
15
6
|
'date-field-target': 'input',
|
7
|
+
'first-day-of-week': @field.first_day_of_week,
|
8
|
+
'picker-format': @field.picker_format,
|
9
|
+
'disable-mobile': @field.disable_mobile,
|
10
|
+
'enable-time': true,
|
11
|
+
time24hr: @field.time_24hr,
|
12
|
+
timezone: @field.timezone,
|
13
|
+
format: @field.format,
|
16
14
|
placeholder: @field.placeholder,
|
17
15
|
relative: @field.relative,
|
18
16
|
**@field.get_html(:data, view: view, element: :input)
|
@@ -21,5 +19,5 @@
|
|
21
19
|
placeholder: @field.placeholder,
|
22
20
|
style: @field.get_html(:style, view: view, element: :input)
|
23
21
|
%>
|
24
|
-
|
22
|
+
</div>
|
25
23
|
<% end %>
|
@@ -1,11 +1,3 @@
|
|
1
1
|
<%= index_field_wrapper field: @field, resource: @resource do %>
|
2
|
-
|
3
|
-
controller: "date-field",
|
4
|
-
date_field_view_value: @view,
|
5
|
-
date_field_format_value: @field.format,
|
6
|
-
date_field_timezone_value: @field.timezone,
|
7
|
-
date_field_picker_format_value: @field.picker_format,
|
8
|
-
} do %>
|
9
|
-
<%= @field.formatted_value %>
|
10
|
-
<% end %>
|
2
|
+
<%= @field.formatted_value %>
|
11
3
|
<% end %>
|
@@ -1,11 +1,3 @@
|
|
1
1
|
<%= show_field_wrapper field: @field, resource: @resource, index: @index do %>
|
2
|
-
<%=
|
3
|
-
controller: "date-field",
|
4
|
-
date_field_view_value: @view,
|
5
|
-
date_field_format_value: @field.format,
|
6
|
-
date_field_timezone_value: @field.timezone,
|
7
|
-
date_field_picker_format_value: @field.picker_format,
|
8
|
-
} do %>
|
9
|
-
<%= @field.formatted_value %>
|
10
|
-
<% end %>
|
2
|
+
<%= @field.formatted_value %>
|
11
3
|
<% end %>
|
@@ -18,20 +18,10 @@ class Avo::Index::Ordering::ButtonComponent < Avo::Index::Ordering::BaseComponen
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def order_path(args)
|
21
|
-
|
22
|
-
|
21
|
+
if reflection.present?
|
22
|
+
view_context.avo.associations_order_path(reflection_parent_resource.route_key, params[:id], field.id, resource.model.id, **args)
|
23
23
|
else
|
24
|
-
|
24
|
+
view_context.avo.resources_order_path(resource.route_key, resource.model.id, **args)
|
25
25
|
end
|
26
|
-
|
27
|
-
if args.present?
|
28
|
-
string_args = args.map do |key, value|
|
29
|
-
"#{key}=#{value}"
|
30
|
-
end.join('&')
|
31
|
-
|
32
|
-
path = "#{path}?#{string_args}"
|
33
|
-
end
|
34
|
-
|
35
|
-
path
|
36
26
|
end
|
37
27
|
end
|
@@ -32,7 +32,7 @@ class Avo::Views::ResourceEditComponent < Avo::ResourceComponent
|
|
32
32
|
# The save button is dependent on the edit? policy method.
|
33
33
|
# The update? method should be called only when the user clicks the Save button so the developer gets access to the params from the form.
|
34
34
|
def can_see_the_save_button?
|
35
|
-
@resource.authorization.authorize_action
|
35
|
+
@resource.authorization.authorize_action @view, raise_exception: false
|
36
36
|
end
|
37
37
|
|
38
38
|
private
|
@@ -117,7 +117,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
|
|
117
117
|
end
|
118
118
|
|
119
119
|
def attach_path
|
120
|
-
|
120
|
+
Avo::App.root_path(paths: [request.env["PATH_INFO"], "new"])
|
121
121
|
end
|
122
122
|
|
123
123
|
def singular_resource_name
|
@@ -145,7 +145,7 @@ class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent
|
|
145
145
|
@reflection.active_record.to_s
|
146
146
|
end
|
147
147
|
|
148
|
-
def name
|
148
|
+
def name
|
149
149
|
field.custom_name? ? field.name : field.plural_name
|
150
150
|
end
|
151
151
|
|
@@ -13,7 +13,8 @@ module Avo
|
|
13
13
|
protect_from_forgery with: :exception
|
14
14
|
before_action :init_app
|
15
15
|
before_action :check_avo_license
|
16
|
-
before_action :
|
16
|
+
before_action :set_default_locale
|
17
|
+
around_action :set_force_locale
|
17
18
|
before_action :set_authorization
|
18
19
|
before_action :_authenticate!
|
19
20
|
before_action :set_container_classes
|
@@ -27,7 +28,7 @@ module Avo
|
|
27
28
|
add_flash_types :info, :warning, :success, :error
|
28
29
|
|
29
30
|
def init_app
|
30
|
-
Avo::App.init request: request, context: context,
|
31
|
+
Avo::App.init request: request, context: context, current_user: _current_user, view_context: view_context, params: params
|
31
32
|
|
32
33
|
@license = Avo::App.license
|
33
34
|
end
|
@@ -287,10 +288,30 @@ module Avo
|
|
287
288
|
@resource.form_scope
|
288
289
|
end
|
289
290
|
|
290
|
-
def
|
291
|
+
def set_default_locale
|
291
292
|
I18n.locale = params[:set_locale] || I18n.default_locale
|
292
293
|
|
293
294
|
I18n.default_locale = I18n.locale
|
294
295
|
end
|
296
|
+
|
297
|
+
# Temporary set the locale
|
298
|
+
def set_force_locale
|
299
|
+
if params[:force_locale].present?
|
300
|
+
initial_locale = I18n.locale.to_s.dup
|
301
|
+
I18n.locale = params[:force_locale]
|
302
|
+
yield
|
303
|
+
I18n.locale = initial_locale
|
304
|
+
else
|
305
|
+
yield
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def default_url_options
|
310
|
+
if params[:force_locale].present?
|
311
|
+
{ **super, force_locale: params[:force_locale] }
|
312
|
+
else
|
313
|
+
super
|
314
|
+
end
|
315
|
+
end
|
295
316
|
end
|
296
317
|
end
|
data/app/javascript/avo.js
CHANGED
@@ -74,7 +74,11 @@ document.addEventListener('turbo:frame-load', () => {
|
|
74
74
|
document.addEventListener('turbo:before-fetch-response', async (e) => {
|
75
75
|
if (e.detail.fetchResponse.response.status === 500) {
|
76
76
|
const { id, src } = e.target
|
77
|
-
|
77
|
+
// Don't try to redirect to failed to load if this is alread a redirection to failed to load and crashed somewhere.
|
78
|
+
// You'll end up with a request loop.
|
79
|
+
if (!e.detail.fetchResponse?.response?.url?.includes('/failed_to_load')) {
|
80
|
+
e.target.src = `${window.Avo.configuration.root_path}/failed_to_load?turbo_frame=${id}&src=${src}`
|
81
|
+
}
|
78
82
|
}
|
79
83
|
})
|
80
84
|
|
@@ -2,6 +2,8 @@ import { Controller } from '@hotwired/stimulus'
|
|
2
2
|
import { DateTime } from 'luxon'
|
3
3
|
import flatpickr from 'flatpickr'
|
4
4
|
|
5
|
+
import { castBoolean } from '../../helpers/cast_boolean'
|
6
|
+
|
5
7
|
// Get the DateTime with the TZ offset applied.
|
6
8
|
function universalTimestamp(timestampStr) {
|
7
9
|
return new Date(new Date(timestampStr).getTime() + (new Date(timestampStr).getTimezoneOffset() * 60 * 1000))
|
@@ -10,99 +12,53 @@ function universalTimestamp(timestampStr) {
|
|
10
12
|
export default class extends Controller {
|
11
13
|
static targets = ['input']
|
12
14
|
|
13
|
-
static values = {
|
14
|
-
view: String,
|
15
|
-
timezone: String,
|
16
|
-
format: String,
|
17
|
-
enableTime: Boolean,
|
18
|
-
pickerFormat: String,
|
19
|
-
firstDayOfWeek: Number,
|
20
|
-
time24Hr: Boolean,
|
21
|
-
}
|
22
|
-
|
23
|
-
get browserZone() {
|
24
|
-
const time = DateTime.local()
|
25
|
-
|
26
|
-
return time.zoneName
|
27
|
-
}
|
28
|
-
|
29
|
-
get initialValue() {
|
30
|
-
if (this.isOnShow || this.isOnIndex) {
|
31
|
-
return this.context.element.innerText
|
32
|
-
} if (this.isOnEdit) {
|
33
|
-
return this.inputTarget.value
|
34
|
-
}
|
35
|
-
|
36
|
-
return null
|
37
|
-
}
|
38
|
-
|
39
|
-
get isOnIndex() {
|
40
|
-
return this.viewValue === 'index'
|
41
|
-
}
|
42
|
-
|
43
|
-
get isOnEdit() {
|
44
|
-
return this.viewValue === 'edit'
|
45
|
-
}
|
46
|
-
|
47
|
-
get isOnShow() {
|
48
|
-
return this.viewValue === 'show'
|
49
|
-
}
|
50
|
-
|
51
|
-
// Parse the time as if it were UTC
|
52
|
-
get parsedValue() {
|
53
|
-
return DateTime.fromISO(this.initialValue, { zone: 'UTC' })
|
54
|
-
}
|
55
|
-
|
56
|
-
get displayTimezone() {
|
57
|
-
return this.timezoneValue || this.browserZone
|
58
|
-
}
|
59
|
-
|
60
15
|
connect() {
|
61
|
-
if (this.isOnShow || this.isOnIndex) {
|
62
|
-
this.initShow()
|
63
|
-
} else if (this.isOnEdit) {
|
64
|
-
this.initEdit()
|
65
|
-
}
|
66
|
-
}
|
67
|
-
|
68
|
-
// Turns the value in the controller wrapper into the timezone of the browser
|
69
|
-
initShow() {
|
70
|
-
this.context.element.innerText = this.parsedValue.setZone(this.displayTimezone).toFormat(this.formatValue)
|
71
|
-
}
|
72
|
-
|
73
|
-
initEdit() {
|
74
16
|
const options = {
|
75
17
|
enableTime: false,
|
76
18
|
enableSeconds: false,
|
77
19
|
// eslint-disable-next-line camelcase
|
78
|
-
time_24hr:
|
20
|
+
time_24hr: false,
|
79
21
|
locale: {
|
80
22
|
firstDayOfWeek: 0,
|
81
23
|
},
|
82
24
|
altInput: true,
|
83
25
|
}
|
26
|
+
const enableTime = castBoolean(this.inputTarget.dataset.enableTime)
|
84
27
|
|
85
28
|
// Set the format of the displayed input field.
|
86
|
-
options.altFormat = this.
|
29
|
+
options.altFormat = this.inputTarget.dataset.pickerFormat
|
30
|
+
|
31
|
+
// Disable native input in mobile browsers
|
32
|
+
options.disableMobile = this.inputTarget.dataset.disableMobile
|
87
33
|
|
88
34
|
// Set first day of the week.
|
89
|
-
options.locale.firstDayOfWeek = this.
|
35
|
+
options.locale.firstDayOfWeek = this.inputTarget.dataset.firstDayOfWeek
|
90
36
|
|
91
37
|
// Enable time if needed.
|
92
|
-
options.enableTime =
|
93
|
-
options.enableSeconds =
|
38
|
+
options.enableTime = enableTime
|
39
|
+
options.enableSeconds = enableTime
|
40
|
+
|
41
|
+
let currentValue
|
94
42
|
|
95
43
|
// enable timezone display
|
96
|
-
if (
|
97
|
-
|
44
|
+
if (enableTime) {
|
45
|
+
currentValue = DateTime.fromISO(this.inputTarget.value, { zone: window.Avo.configuration.timezone })
|
46
|
+
currentValue = currentValue.setZone(this.inputTarget.dataset.timezone)
|
47
|
+
currentValue = currentValue.toISO()
|
98
48
|
|
99
49
|
options.dateFormat = 'Y-m-d H:i:S'
|
50
|
+
// eslint-disable-next-line camelcase
|
51
|
+
options.time_24hr = castBoolean(this.inputTarget.dataset.time24hr)
|
52
|
+
// this.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone
|
53
|
+
options.appTimezone = this.inputTarget.dataset.timezone
|
100
54
|
} else {
|
101
55
|
// Because the browser treats the date like a timestamp and updates it ot 00:00 hour, when on a western timezone the date will be converted with one day offset.
|
102
56
|
// Ex: 2022-01-30 will render as 2022-01-29 on an American timezone
|
103
|
-
|
57
|
+
currentValue = universalTimestamp(this.inputTarget.value)
|
104
58
|
}
|
105
59
|
|
60
|
+
options.defaultDate = currentValue
|
61
|
+
|
106
62
|
flatpickr(this.inputTarget, options)
|
107
63
|
}
|
108
64
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<%= javascript_tag nonce: true do %>
|
2
2
|
window.Avo = window.Avo || { configuration: {} }
|
3
3
|
Avo.configuration.timezone = '<%= Avo.configuration.timezone %>'
|
4
|
-
Avo.configuration.root_path = '<%= Avo
|
4
|
+
Avo.configuration.root_path = '<%= Avo.configuration.root_path %>'
|
5
5
|
Avo.configuration.search_debounce = '<%= Avo.configuration.search_debounce %>'
|
6
6
|
<% end %>
|
data/config/routes.rb
CHANGED
@@ -23,7 +23,7 @@ Avo::Engine.routes.draw do
|
|
23
23
|
delete "/:resource_name/:id/active_storage_attachments/:attachment_name/:attachment_id", to: "attachments#destroy"
|
24
24
|
|
25
25
|
# Ordering
|
26
|
-
patch "/:resource_name/:id/order", to: "resources#order"
|
26
|
+
patch "/:resource_name/:id/order", to: "resources#order", as: "order"
|
27
27
|
patch "/:resource_name/:id/:related_name/:related_id/order", to: "associations#order", as: "associations_order"
|
28
28
|
|
29
29
|
# Actions
|
data/lib/avo/app.rb
CHANGED
@@ -29,12 +29,16 @@ module Avo
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
|
32
|
+
# Renerate a dynamic root path using the URIService
|
33
|
+
def root_path(paths: [], **args)
|
34
|
+
Avo::Services::URIService.parse(view_context.avo.root_url.to_s).append_paths(paths).to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
def init(request:, context:, current_user:, view_context:, params:)
|
33
38
|
self.error_messages = []
|
34
39
|
self.request = request
|
35
40
|
self.context = context
|
36
41
|
self.current_user = current_user
|
37
|
-
self.root_path = root_path
|
38
42
|
self.view_context = view_context
|
39
43
|
self.params = params
|
40
44
|
|
data/lib/avo/base_card.rb
CHANGED
@@ -59,13 +59,7 @@ module Avo
|
|
59
59
|
def frame_url(enforced_range: nil, params: {})
|
60
60
|
enforced_range ||= initial_range || ranges.first
|
61
61
|
|
62
|
-
|
63
|
-
begin
|
64
|
-
other_params = "&#{params.permit!.to_h.map { |k, v| "#{k}=#{v}" }.join("&")}"
|
65
|
-
rescue
|
66
|
-
end
|
67
|
-
|
68
|
-
"#{Avo::App.root_path}/dashboards/#{dashboard.id}/cards/#{id}?turbo_frame=#{turbo_frame}&index=#{index}&range=#{enforced_range}#{other_params}"
|
62
|
+
Avo::App.view_context.avo.dashboard_card_path(dashboard.id, id, turbo_frame: turbo_frame, index: index, range: enforced_range, **params.permit!)
|
69
63
|
end
|
70
64
|
|
71
65
|
def card_classes
|
data/lib/avo/base_resource.rb
CHANGED
@@ -8,6 +8,7 @@ module Avo
|
|
8
8
|
include Avo::Concerns::HasModel
|
9
9
|
include Avo::Concerns::HasFields
|
10
10
|
include Avo::Concerns::HasStimulusControllers
|
11
|
+
include Avo::Concerns::ModelClassConstantized
|
11
12
|
|
12
13
|
delegate :view_context, to: ::Avo::App
|
13
14
|
delegate :simple_format, :content_tag, to: :view_context
|
@@ -29,7 +30,6 @@ module Avo
|
|
29
30
|
class_attribute :search_query, default: nil
|
30
31
|
class_attribute :search_query_help, default: ""
|
31
32
|
class_attribute :includes, default: []
|
32
|
-
class_attribute :model_class
|
33
33
|
class_attribute :translation_key
|
34
34
|
class_attribute :default_view_type, default: :table
|
35
35
|
class_attribute :devise_password_optional, default: false
|
@@ -28,7 +28,7 @@ module Avo
|
|
28
28
|
add_prop_from_args args, name: name, default: default, type: :array
|
29
29
|
end
|
30
30
|
|
31
|
-
def add_string_prop(args, name, default =
|
31
|
+
def add_string_prop(args, name, default = [])
|
32
32
|
add_prop_from_args args, name: name, default: default, type: :string
|
33
33
|
end
|
34
34
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Avo
|
2
|
+
module Concerns
|
3
|
+
module ModelClassConstantized
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
class_methods do
|
7
|
+
attr_reader :model_class
|
8
|
+
|
9
|
+
# Cast the model class to a constantized version and memoize it like that
|
10
|
+
def model_class=(value)
|
11
|
+
@model_class = case value
|
12
|
+
when Class
|
13
|
+
value
|
14
|
+
when String, Symbol
|
15
|
+
value.to_s.safe_constantize
|
16
|
+
else
|
17
|
+
raise ArgumentError.new "Failed to find a proper model class for #{self.to_s}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -3,6 +3,7 @@ module Avo
|
|
3
3
|
class DateField < TextField
|
4
4
|
attr_reader :first_day_of_week
|
5
5
|
attr_reader :picker_format
|
6
|
+
attr_reader :disable_mobile
|
6
7
|
attr_reader :format
|
7
8
|
attr_reader :relative
|
8
9
|
|
@@ -13,6 +14,7 @@ module Avo
|
|
13
14
|
@picker_format = args[:picker_format].present? ? args[:picker_format] : "Y-m-d"
|
14
15
|
@format = args[:format].present? ? args[:format] : :long
|
15
16
|
@relative = args[:relative].present? ? args[:relative] : false
|
17
|
+
@disable_mobile = args[:disable_mobile].present? ? args[:disable_mobile] : false
|
16
18
|
end
|
17
19
|
|
18
20
|
def formatted_value
|
@@ -2,29 +2,25 @@ module Avo
|
|
2
2
|
module Fields
|
3
3
|
class DateTimeField < DateField
|
4
4
|
attr_reader :format
|
5
|
-
attr_reader :picker_format
|
6
5
|
attr_reader :time_24hr
|
7
6
|
attr_reader :timezone
|
8
7
|
|
9
8
|
def initialize(id, **args, &block)
|
10
9
|
super(id, **args, &block)
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
add_string_prop args, :timezone
|
11
|
+
@picker_format = args[:picker_format].present? ? args[:picker_format] : "Y-m-d H:i:S"
|
12
|
+
@time_24hr = args[:time_24hr].present? ? args[:time_24hr] : false
|
13
|
+
@timezone = args[:timezone].present? ? args[:timezone] : Rails.application.config.time_zone
|
16
14
|
end
|
17
15
|
|
18
16
|
def formatted_value
|
19
17
|
return nil if value.nil?
|
20
18
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
value.utc.to_formatted_s(:db)
|
19
|
+
if @format.is_a?(Symbol)
|
20
|
+
value.to_time.in_time_zone(timezone).to_formatted_s(@format)
|
21
|
+
else
|
22
|
+
value.to_time.in_time_zone(timezone).strftime(@format)
|
23
|
+
end
|
28
24
|
end
|
29
25
|
|
30
26
|
def fill_field(model, key, value, params)
|
@@ -36,7 +32,7 @@ module Avo
|
|
36
32
|
|
37
33
|
return model if value.blank?
|
38
34
|
|
39
|
-
model[id] = value.in_time_zone(
|
35
|
+
model[id] = value.to_time.in_time_zone(Rails.application.config.time_zone)
|
40
36
|
|
41
37
|
model
|
42
38
|
end
|
@@ -29,7 +29,9 @@ module Avo
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def frame_url
|
32
|
-
|
32
|
+
Avo::Services::URIService.parse(@resource.record_path)
|
33
|
+
.append_path(id.to_s)
|
34
|
+
.append_query("turbo_frame=#{turbo_frame.to_s}").to_s
|
33
35
|
end
|
34
36
|
|
35
37
|
# The value
|
@@ -22,7 +22,10 @@ module Avo
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def frame_url
|
25
|
-
|
25
|
+
Avo::Services::URIService.parse(@resource.record_path)
|
26
|
+
.append_paths(id, value.id)
|
27
|
+
.append_query("turbo_frame=#{turbo_frame}")
|
28
|
+
.to_s
|
26
29
|
end
|
27
30
|
|
28
31
|
def fill_field(model, key, value, params)
|
data/lib/avo/menu/builder.rb
CHANGED
@@ -5,6 +5,8 @@ class Avo::Menu::Builder
|
|
5
5
|
end
|
6
6
|
end
|
7
7
|
|
8
|
+
delegate :root_path, to: Avo::App
|
9
|
+
|
8
10
|
def initialize(name: nil, items: [])
|
9
11
|
@menu = Avo::Menu::Menu.new
|
10
12
|
|
@@ -60,7 +62,7 @@ class Avo::Menu::Builder
|
|
60
62
|
# Add all the tools
|
61
63
|
def all_tools(**args)
|
62
64
|
Avo::App.tools_for_navigation.each do |tool|
|
63
|
-
link tool.humanize, path:
|
65
|
+
link tool.humanize, path: root_path(paths: [tool])
|
64
66
|
end
|
65
67
|
end
|
66
68
|
|
@@ -68,10 +70,4 @@ class Avo::Menu::Builder
|
|
68
70
|
def build
|
69
71
|
@menu
|
70
72
|
end
|
71
|
-
|
72
|
-
protected
|
73
|
-
|
74
|
-
def root_path
|
75
|
-
Avo::App.root_path
|
76
|
-
end
|
77
73
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Avo
|
2
|
+
module Services
|
3
|
+
class URIService
|
4
|
+
class << self
|
5
|
+
def parse(path)
|
6
|
+
self.new path
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader = :uri
|
11
|
+
|
12
|
+
def initialize(path = '')
|
13
|
+
@uri = Addressable::URI.parse(path)
|
14
|
+
end
|
15
|
+
|
16
|
+
def append_paths(*paths)
|
17
|
+
paths = Array.wrap(paths)
|
18
|
+
|
19
|
+
# abort 11.inspect
|
20
|
+
|
21
|
+
return self if paths.blank?
|
22
|
+
# abort 12.inspect
|
23
|
+
|
24
|
+
@uri.merge!(path: @uri.path.concat("/#{paths.join("/")}"))
|
25
|
+
self
|
26
|
+
end
|
27
|
+
alias_method :append_path, :append_paths
|
28
|
+
|
29
|
+
def append_query(*params)
|
30
|
+
params = Array.wrap(params)
|
31
|
+
|
32
|
+
@uri.merge!(query: [@uri.query, *params].join("&"))
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
@uri.to_s
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/avo/version.rb
CHANGED
data/lib/avo.rb
CHANGED