avo 2.9.1.pre7 → 2.9.2.pre1
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 +1 -1
- data/app/assets/builds/action_cable.js +2 -0
- data/app/assets/builds/action_cable.js.map +7 -0
- data/app/assets/builds/application.js +2 -0
- data/app/assets/builds/application.js.map +7 -0
- data/app/assets/builds/avo.css +9028 -0
- data/app/assets/builds/avo.js +512 -0
- data/app/assets/builds/avo.js.map +7 -0
- data/app/assets/builds/avo_custom.js +6 -0
- data/app/assets/builds/avo_custom.js.map +7 -0
- data/app/components/avo/actions_component.rb +2 -6
- data/app/components/avo/fields/common/key_value_component.html.erb +2 -2
- data/app/components/avo/fields/common/single_file_viewer_component.rb +1 -1
- data/app/components/avo/fields/date_field/edit_component.html.erb +0 -1
- data/app/components/avo/fields/date_time_field/edit_component.html.erb +25 -10
- data/app/components/avo/fields/date_time_field/index_component.html.erb +9 -1
- data/app/components/avo/fields/date_time_field/show_component.html.erb +9 -1
- data/app/components/avo/index/ordering/button_component.rb +13 -5
- data/app/components/avo/index/resource_controls_component.html.erb +2 -2
- data/app/components/avo/index/resource_controls_component.rb +1 -5
- 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 +3 -24
- data/app/javascript/avo.js +1 -5
- data/app/javascript/js/controllers/fields/date_field_controller.js +87 -25
- data/app/views/avo/partials/_javascript.html.erb +1 -1
- data/config/routes.rb +1 -1
- data/lib/avo/app.rb +4 -11
- data/lib/avo/base_card.rb +7 -1
- data/lib/avo/base_resource.rb +1 -1
- data/lib/avo/concerns/handles_field_args.rb +1 -1
- data/lib/avo/dashboards/base_dashboard.rb +1 -1
- data/lib/avo/fields/date_field.rb +0 -2
- data/lib/avo/fields/date_time_field.rb +21 -9
- data/lib/avo/fields/has_base_field.rb +1 -3
- data/lib/avo/fields/has_one_field.rb +1 -4
- data/lib/avo/menu/builder.rb +7 -8
- data/lib/avo/version.rb +1 -1
- data/lib/avo.rb +0 -1
- data/public/avo-assets/avo.js +68 -68
- data/public/avo-assets/avo.js.map +2 -2
- metadata +11 -9
- data/app/javascript/js/controllers/tabs_controller.js +0 -80
- data/db/migrate/20210421064037_add_color_to_teams.rb +0 -5
- data/db/migrate/20210423075924_add_progress_to_projects.rb +0 -5
- data/db/migrate/20210525143134_add_slug_to_users.rb +0 -6
- data/lib/avo/concerns/model_class_constantized.rb +0 -23
- data/lib/avo/services/uri_service.rb +0 -71
- data/lib/generators/avo/templates/locales/avo.fr.yml +0 -115
@@ -13,8 +13,7 @@ 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 :
|
17
|
-
around_action :set_force_locale
|
16
|
+
before_action :set_locale
|
18
17
|
before_action :set_authorization
|
19
18
|
before_action :_authenticate!
|
20
19
|
before_action :set_container_classes
|
@@ -28,7 +27,7 @@ module Avo
|
|
28
27
|
add_flash_types :info, :warning, :success, :error
|
29
28
|
|
30
29
|
def init_app
|
31
|
-
Avo::App.init request: request, context: context, current_user: _current_user, view_context: view_context, params: params
|
30
|
+
Avo::App.init request: request, context: context, root_path: avo.root_path.delete_suffix("/"), current_user: _current_user, view_context: view_context, params: params
|
32
31
|
|
33
32
|
@license = Avo::App.license
|
34
33
|
end
|
@@ -288,30 +287,10 @@ module Avo
|
|
288
287
|
@resource.form_scope
|
289
288
|
end
|
290
289
|
|
291
|
-
def
|
290
|
+
def set_locale
|
292
291
|
I18n.locale = params[:set_locale] || I18n.default_locale
|
293
292
|
|
294
293
|
I18n.default_locale = I18n.locale
|
295
294
|
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
|
316
295
|
end
|
317
296
|
end
|
data/app/javascript/avo.js
CHANGED
@@ -74,11 +74,7 @@ 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
|
-
|
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
|
-
}
|
77
|
+
e.target.src = `${window.Avo.configuration.root_path}/failed_to_load?turbo_frame=${id}&src=${src}`
|
82
78
|
}
|
83
79
|
})
|
84
80
|
|
@@ -2,63 +2,125 @@ 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
|
-
|
7
5
|
// Get the DateTime with the TZ offset applied.
|
8
6
|
function universalTimestamp(timestampStr) {
|
9
7
|
return new Date(new Date(timestampStr).getTime() + (new Date(timestampStr).getTimezoneOffset() * 60 * 1000))
|
10
8
|
}
|
11
9
|
|
12
10
|
export default class extends Controller {
|
13
|
-
static targets = ['input']
|
11
|
+
static targets = ['input', 'fakeInput']
|
12
|
+
|
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
|
+
}
|
14
59
|
|
15
60
|
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() {
|
16
74
|
const options = {
|
17
75
|
enableTime: false,
|
18
76
|
enableSeconds: false,
|
19
77
|
// eslint-disable-next-line camelcase
|
20
|
-
time_24hr:
|
78
|
+
time_24hr: this.time24HrValue,
|
21
79
|
locale: {
|
22
80
|
firstDayOfWeek: 0,
|
23
81
|
},
|
24
82
|
altInput: true,
|
83
|
+
onChange: this.onChange.bind(this),
|
25
84
|
}
|
26
|
-
const enableTime = castBoolean(this.inputTarget.dataset.enableTime)
|
27
85
|
|
28
86
|
// Set the format of the displayed input field.
|
29
|
-
options.altFormat = this.
|
30
|
-
|
31
|
-
// Disable native input in mobile browsers
|
32
|
-
options.disableMobile = this.inputTarget.dataset.disableMobile
|
87
|
+
options.altFormat = this.pickerFormatValue
|
33
88
|
|
34
89
|
// Set first day of the week.
|
35
|
-
options.locale.firstDayOfWeek = this.
|
90
|
+
options.locale.firstDayOfWeek = this.firstDayOfWeekValue
|
36
91
|
|
37
92
|
// Enable time if needed.
|
38
|
-
options.enableTime =
|
39
|
-
options.enableSeconds =
|
40
|
-
|
41
|
-
let currentValue
|
93
|
+
options.enableTime = this.enableTimeValue
|
94
|
+
options.enableSeconds = this.enableTimeValue
|
42
95
|
|
43
96
|
// enable timezone display
|
44
|
-
if (
|
45
|
-
|
46
|
-
currentValue = currentValue.setZone(this.inputTarget.dataset.timezone)
|
47
|
-
currentValue = currentValue.toISO()
|
97
|
+
if (this.enableTimeValue) {
|
98
|
+
options.defaultDate = this.parsedValue.setZone(this.displayTimezone).toISO()
|
48
99
|
|
49
100
|
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
|
54
101
|
} else {
|
55
102
|
// 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.
|
56
103
|
// Ex: 2022-01-30 will render as 2022-01-29 on an American timezone
|
57
|
-
|
104
|
+
options.defaultDate = universalTimestamp(this.initialValue)
|
58
105
|
}
|
59
106
|
|
60
|
-
|
107
|
+
flatpickr(this.fakeInputTarget, options)
|
108
|
+
|
109
|
+
this.updateRealInput(this.parsedValue.setZone(this.displayTimezone).toISO())
|
110
|
+
}
|
111
|
+
|
112
|
+
onChange(selectedDates) {
|
113
|
+
let time
|
114
|
+
|
115
|
+
if (this.timezoneValue) {
|
116
|
+
time = DateTime.fromISO(selectedDates[0].toISOString()).setZone('UTC', { keepLocalTime: true })
|
117
|
+
} else {
|
118
|
+
time = DateTime.fromISO(selectedDates[0].toISOString()).setZone('UTC', { keepLocalTime: false })
|
119
|
+
}
|
120
|
+
this.updateRealInput(time)
|
121
|
+
}
|
61
122
|
|
62
|
-
|
123
|
+
updateRealInput(value) {
|
124
|
+
this.inputTarget.value = value
|
63
125
|
}
|
64
126
|
}
|
@@ -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::App.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"
|
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,21 +29,14 @@ module Avo
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
|
33
|
-
def root_path(paths: [], query: {}, **args)
|
34
|
-
Avo::Services::URIService.parse(view_context.avo.root_url.to_s)
|
35
|
-
.append_paths(paths)
|
36
|
-
.append_query(query)
|
37
|
-
.to_s
|
38
|
-
end
|
39
|
-
|
40
|
-
def init(request:, context:, current_user:, view_context:, params:)
|
32
|
+
def init(request:, context:, current_user:, root_path:, view_context:, params:)
|
41
33
|
self.error_messages = []
|
34
|
+
self.request = request
|
42
35
|
self.context = context
|
43
36
|
self.current_user = current_user
|
44
|
-
self.
|
45
|
-
self.request = request
|
37
|
+
self.root_path = root_path
|
46
38
|
self.view_context = view_context
|
39
|
+
self.params = params
|
47
40
|
|
48
41
|
self.license = Licensing::LicenseManager.new(Licensing::HQ.new(request).response).license
|
49
42
|
self.translation_enabled = license.has(:localization)
|
data/lib/avo/base_card.rb
CHANGED
@@ -59,7 +59,13 @@ module Avo
|
|
59
59
|
def frame_url(enforced_range: nil, params: {})
|
60
60
|
enforced_range ||= initial_range || ranges.first
|
61
61
|
|
62
|
-
|
62
|
+
# append the parent params to the card request
|
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}"
|
63
69
|
end
|
64
70
|
|
65
71
|
def card_classes
|
data/lib/avo/base_resource.rb
CHANGED
@@ -8,7 +8,6 @@ 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
|
12
11
|
|
13
12
|
delegate :view_context, to: ::Avo::App
|
14
13
|
delegate :simple_format, :content_tag, to: :view_context
|
@@ -30,6 +29,7 @@ module Avo
|
|
30
29
|
class_attribute :search_query, default: nil
|
31
30
|
class_attribute :search_query_help, default: ""
|
32
31
|
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 = nil)
|
32
32
|
add_prop_from_args args, name: name, default: default, type: :string
|
33
33
|
end
|
34
34
|
end
|
@@ -3,7 +3,6 @@ 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
|
7
6
|
attr_reader :format
|
8
7
|
attr_reader :relative
|
9
8
|
|
@@ -14,7 +13,6 @@ module Avo
|
|
14
13
|
@picker_format = args[:picker_format].present? ? args[:picker_format] : "Y-m-d"
|
15
14
|
@format = args[:format].present? ? args[:format] : :long
|
16
15
|
@relative = args[:relative].present? ? args[:relative] : false
|
17
|
-
@disable_mobile = args[:disable_mobile].present? ? args[:disable_mobile] : false
|
18
16
|
end
|
19
17
|
|
20
18
|
def formatted_value
|
@@ -2,25 +2,29 @@ module Avo
|
|
2
2
|
module Fields
|
3
3
|
class DateTimeField < DateField
|
4
4
|
attr_reader :format
|
5
|
+
attr_reader :picker_format
|
5
6
|
attr_reader :time_24hr
|
6
7
|
attr_reader :timezone
|
7
8
|
|
8
9
|
def initialize(id, **args, &block)
|
9
10
|
super(id, **args, &block)
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
12
|
+
add_boolean_prop args, :time_24hr
|
13
|
+
add_string_prop args, :picker_format, "Y-m-d H:i:S"
|
14
|
+
add_string_prop args, :format, "yyyy-LL-dd TT"
|
15
|
+
add_string_prop args, :timezone
|
14
16
|
end
|
15
17
|
|
16
18
|
def formatted_value
|
17
19
|
return nil if value.nil?
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
value.utc.to_time.iso8601
|
22
|
+
end
|
23
|
+
|
24
|
+
def edit_formatted_value
|
25
|
+
return nil if value.nil?
|
26
|
+
|
27
|
+
value.utc.iso8601
|
24
28
|
end
|
25
29
|
|
26
30
|
def fill_field(model, key, value, params)
|
@@ -32,10 +36,18 @@ module Avo
|
|
32
36
|
|
33
37
|
return model if value.blank?
|
34
38
|
|
35
|
-
model[id] = value
|
39
|
+
model[id] = utc_time(value)
|
36
40
|
|
37
41
|
model
|
38
42
|
end
|
43
|
+
|
44
|
+
def utc_time(value)
|
45
|
+
if timezone.present?
|
46
|
+
ActiveSupport::TimeZone.new(timezone).local_to_utc(Time.parse(value))
|
47
|
+
else
|
48
|
+
value
|
49
|
+
end
|
50
|
+
end
|
39
51
|
end
|
40
52
|
end
|
41
53
|
end
|
@@ -29,9 +29,7 @@ module Avo
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def frame_url
|
32
|
-
|
33
|
-
.append_path(id.to_s)
|
34
|
-
.append_query(turbo_frame: turbo_frame.to_s).to_s
|
32
|
+
"#{@resource.record_path}/#{id}?turbo_frame=#{turbo_frame}"
|
35
33
|
end
|
36
34
|
|
37
35
|
# The value
|
@@ -22,10 +22,7 @@ module Avo
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def frame_url
|
25
|
-
|
26
|
-
.append_paths(id, value.id)
|
27
|
-
.append_query(turbo_frame: turbo_frame)
|
28
|
-
.to_s
|
25
|
+
"#{@resource.record_path}/#{id}/#{value.id}?turbo_frame=#{turbo_frame}"
|
29
26
|
end
|
30
27
|
|
31
28
|
def fill_field(model, key, value, params)
|
data/lib/avo/menu/builder.rb
CHANGED
@@ -5,13 +5,6 @@ class Avo::Menu::Builder
|
|
5
5
|
end
|
6
6
|
end
|
7
7
|
|
8
|
-
delegate :context, to: Avo::App
|
9
|
-
delegate :current_user, to: Avo::App
|
10
|
-
delegate :params, to: Avo::App
|
11
|
-
delegate :request, to: Avo::App
|
12
|
-
delegate :root_path, to: Avo::App
|
13
|
-
delegate :view_context, to: Avo::App
|
14
|
-
|
15
8
|
def initialize(name: nil, items: [])
|
16
9
|
@menu = Avo::Menu::Menu.new
|
17
10
|
|
@@ -67,7 +60,7 @@ class Avo::Menu::Builder
|
|
67
60
|
# Add all the tools
|
68
61
|
def all_tools(**args)
|
69
62
|
Avo::App.tools_for_navigation.each do |tool|
|
70
|
-
link tool.humanize, path: root_path
|
63
|
+
link tool.humanize, path: "#{root_path}/#{tool}"
|
71
64
|
end
|
72
65
|
end
|
73
66
|
|
@@ -75,4 +68,10 @@ class Avo::Menu::Builder
|
|
75
68
|
def build
|
76
69
|
@menu
|
77
70
|
end
|
71
|
+
|
72
|
+
protected
|
73
|
+
|
74
|
+
def root_path
|
75
|
+
Avo::App.root_path
|
76
|
+
end
|
78
77
|
end
|
data/lib/avo/version.rb
CHANGED
data/lib/avo.rb
CHANGED