avo 2.17.1.pre.2.customauthorizationclients → 2.17.1.pre.4.issue.1342
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 +6 -5
- data/app/components/avo/button_component.rb +2 -2
- data/app/components/avo/fields/common/single_file_viewer_component.html.erb +3 -3
- data/app/components/avo/fields/date_field/edit_component.html.erb +2 -0
- data/app/components/avo/fields/date_field/index_component.html.erb +1 -0
- data/app/components/avo/fields/date_field/show_component.html.erb +1 -0
- data/app/components/avo/fields/date_time_field/edit_component.html.erb +3 -0
- data/app/components/avo/fields/date_time_field/index_component.html.erb +2 -0
- data/app/components/avo/fields/date_time_field/show_component.html.erb +2 -0
- data/app/components/avo/fields/time_field/edit_component.html.erb +40 -0
- data/app/components/avo/fields/time_field/edit_component.rb +4 -0
- data/app/components/avo/fields/time_field/index_component.html.erb +15 -0
- data/app/components/avo/fields/time_field/index_component.rb +4 -0
- data/app/components/avo/fields/time_field/show_component.html.erb +15 -0
- data/app/components/avo/fields/time_field/show_component.rb +4 -0
- data/app/components/avo/index/resource_controls_component.html.erb +2 -2
- data/app/components/avo/panel_component.html.erb +2 -4
- data/app/components/avo/panel_component.rb +2 -4
- data/app/components/avo/sidebar_profile_component.html.erb +4 -1
- data/app/components/avo/tab_switcher_component.html.erb +1 -1
- data/app/components/avo/tab_switcher_component.rb +2 -0
- data/app/components/avo/views/resource_edit_component.html.erb +10 -12
- data/app/components/avo/views/resource_index_component.html.erb +2 -4
- data/app/components/avo/views/resource_show_component.html.erb +21 -25
- data/app/helpers/avo/application_helper.rb +4 -0
- data/app/javascript/js/controllers/fields/date_field_controller.js +73 -21
- data/app/javascript/js/controllers/search_controller.js +3 -0
- data/avo.gemspec +1 -1
- data/db/factories.rb +1 -0
- data/lib/avo/concerns/handles_field_args.rb +4 -0
- data/lib/avo/concerns/has_fields.rb +25 -0
- data/lib/avo/fields/base_field.rb +5 -1
- data/lib/avo/fields/date_field.rb +2 -0
- data/lib/avo/fields/date_time_field.rb +2 -0
- data/lib/avo/fields/time_field.rb +49 -0
- data/lib/avo/version.rb +1 -1
- data/lib/generators/avo/templates/locales/avo.nb.yml +1 -1
- data/lib/generators/avo/templates/locales/avo.nn.yml +7 -7
- data/public/avo-assets/avo.base.css +12 -6
- data/public/avo-assets/avo.base.js +88 -88
- data/public/avo-assets/avo.base.js.map +2 -2
- metadata +13 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0cb67ed800f6808830e072dfeaf5acb53a9c8960d7ca1b1fc01a5ac27ab478b4
|
4
|
+
data.tar.gz: 861965614539773f8c6242e211bb7e3449b8393ad2306cf3aa1bcbb030a36212
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a2d565a8a5839e25f23cd4bdac2308c07a5b89dacadd090b8ddcaf5180b58fa4d7f844ebafbd02c167d60d9f0f5193c6b7cd2790c61f538fc8aadfa50e6f32b
|
7
|
+
data.tar.gz: e1a6e356003227ff73440bd51a8aecdce3f4522be2c4cb0829fbd35a88d9916ffcb860638428f19296d66e054396f8683f759852282c22559b6f76fd415a8d81
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
avo (2.17.1.pre.
|
4
|
+
avo (2.17.1.pre.4.issue.1342)
|
5
5
|
active_link_to
|
6
6
|
addressable
|
7
7
|
breadcrumbs_on_rails
|
@@ -17,7 +17,7 @@ PATH
|
|
17
17
|
pundit
|
18
18
|
rails (>= 6.0)
|
19
19
|
turbo-rails
|
20
|
-
view_component
|
20
|
+
view_component
|
21
21
|
zeitwerk
|
22
22
|
|
23
23
|
GEM
|
@@ -265,7 +265,7 @@ GEM
|
|
265
265
|
net-protocol
|
266
266
|
timeout
|
267
267
|
nio4r (2.5.8)
|
268
|
-
nokogiri (1.13.
|
268
|
+
nokogiri (1.13.9)
|
269
269
|
mini_portile2 (~> 2.8.0)
|
270
270
|
racc (~> 1.4)
|
271
271
|
orm_adapter (0.5.0)
|
@@ -413,8 +413,9 @@ GEM
|
|
413
413
|
tzinfo (2.0.5)
|
414
414
|
concurrent-ruby (~> 1.0)
|
415
415
|
unicode-display_width (2.2.0)
|
416
|
-
view_component (2.
|
416
|
+
view_component (2.74.1)
|
417
417
|
activesupport (>= 5.0.0, < 8.0)
|
418
|
+
concurrent-ruby (~> 1.0)
|
418
419
|
method_source (~> 1.0)
|
419
420
|
warden (1.2.9)
|
420
421
|
rack (>= 2.0.9)
|
@@ -437,7 +438,7 @@ GEM
|
|
437
438
|
websocket-extensions (0.1.5)
|
438
439
|
xpath (3.2.0)
|
439
440
|
nokogiri (~> 1.8)
|
440
|
-
zeitwerk (2.6.
|
441
|
+
zeitwerk (2.6.1)
|
441
442
|
|
442
443
|
PLATFORMS
|
443
444
|
ruby
|
@@ -88,8 +88,8 @@ class Avo::ButtonComponent < ViewComponent::Base
|
|
88
88
|
end
|
89
89
|
|
90
90
|
def output_button
|
91
|
-
if
|
92
|
-
button_to
|
91
|
+
if args.dig(:method).present? || args.dig(:data, :turbo_method).present?
|
92
|
+
button_to args[:url], **args do
|
93
93
|
full_content
|
94
94
|
end
|
95
95
|
else
|
@@ -36,15 +36,15 @@
|
|
36
36
|
<% if @resource.authorization.authorize_action(:delete_attachments?, raise_exception: false) %>
|
37
37
|
<%= a_link destroy_path,
|
38
38
|
icon: 'heroicons/outline/trash',
|
39
|
-
method: :delete,
|
40
39
|
color: :red,
|
41
40
|
compact: true,
|
42
41
|
size: :xs,
|
43
42
|
class: 'text-center',
|
44
43
|
title: t('avo.delete_file', item: file.filename),
|
45
44
|
data: {
|
46
|
-
|
47
|
-
|
45
|
+
turbo_method: :delete,
|
46
|
+
turbo_frame: 'destroy_attachment_form',
|
47
|
+
turbo_confirm: t('avo.are_you_sure'),
|
48
48
|
tippy: :tooltip
|
49
49
|
} %>
|
50
50
|
<% end %>
|
@@ -7,6 +7,8 @@
|
|
7
7
|
date_field_picker_format_value: @field.picker_format,
|
8
8
|
date_field_first_day_of_week_value: @field.first_day_of_week,
|
9
9
|
date_field_disable_mobile_value: @field.disable_mobile,
|
10
|
+
date_field_field_type_value: "date",
|
11
|
+
date_field_picker_options_value: @field.picker_options,
|
10
12
|
} do %>
|
11
13
|
<%= datetime_field "fake_#{@field.id}", "fake",
|
12
14
|
value: @field.edit_formatted_value,
|
@@ -8,6 +8,9 @@
|
|
8
8
|
date_field_disable_mobile_value: @field.disable_mobile,
|
9
9
|
date_field_time24_hr_value: @field.time_24hr,
|
10
10
|
date_field_timezone_value: @field.timezone,
|
11
|
+
date_field_relative_value: @field.relative,
|
12
|
+
date_field_field_type_value: "dateTime",
|
13
|
+
date_field_picker_options_value: @field.picker_options,
|
11
14
|
} do %>
|
12
15
|
<%= datetime_field "fake_#{@field.id}", "fake",
|
13
16
|
value: @field.edit_formatted_value,
|
@@ -5,7 +5,9 @@
|
|
5
5
|
date_field_enable_time_value: true,
|
6
6
|
date_field_format_value: @field.format,
|
7
7
|
date_field_timezone_value: @field.timezone,
|
8
|
+
date_field_relative_value: @field.relative,
|
8
9
|
date_field_picker_format_value: @field.picker_format,
|
10
|
+
date_field_field_type_value: "dateTime",
|
9
11
|
} do %>
|
10
12
|
<%= @field.formatted_value %>
|
11
13
|
<% end %>
|
@@ -5,7 +5,9 @@
|
|
5
5
|
date_field_enable_time_value: true,
|
6
6
|
date_field_format_value: @field.format,
|
7
7
|
date_field_timezone_value: @field.timezone,
|
8
|
+
date_field_relative_value: @field.relative,
|
8
9
|
date_field_picker_format_value: @field.picker_format,
|
10
|
+
date_field_field_type_value: "dateTime",
|
9
11
|
} do %>
|
10
12
|
<%= @field.formatted_value %>
|
11
13
|
<% end %>
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<%= field_wrapper **field_wrapper_args do %>
|
2
|
+
<%= content_tag :div, data: {
|
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_disable_mobile_value: @field.disable_mobile,
|
8
|
+
date_field_time24_hr_value: @field.time_24hr,
|
9
|
+
date_field_no_calendar_value: true,
|
10
|
+
date_field_timezone_value: @field.timezone,
|
11
|
+
date_field_relative_value: @field.relative,
|
12
|
+
date_field_field_type_value: "time",
|
13
|
+
date_field_picker_options_value: @field.picker_options,
|
14
|
+
} do %>
|
15
|
+
<%= datetime_field "fake_#{@field.id}", "fake",
|
16
|
+
value: @field.edit_formatted_value,
|
17
|
+
class: classes("w-full"),
|
18
|
+
data: {
|
19
|
+
'date-field-target': 'fakeInput',
|
20
|
+
placeholder: @field.placeholder,
|
21
|
+
**@field.get_html(:data, view: view, element: :input)
|
22
|
+
},
|
23
|
+
disabled: @field.is_readonly?,
|
24
|
+
placeholder: @field.placeholder,
|
25
|
+
style: @field.get_html(:style, view: view, element: :input)
|
26
|
+
%>
|
27
|
+
<%= @form.text_field @field.id,
|
28
|
+
value: @field.edit_formatted_value,
|
29
|
+
class: classes("w-full hidden"),
|
30
|
+
data: {
|
31
|
+
'date-field-target': 'input',
|
32
|
+
placeholder: @field.placeholder,
|
33
|
+
**@field.get_html(:data, view: view, element: :input)
|
34
|
+
},
|
35
|
+
disabled: @field.is_readonly?,
|
36
|
+
placeholder: @field.placeholder,
|
37
|
+
style: @field.get_html(:style, view: view, element: :input)
|
38
|
+
%>
|
39
|
+
<% end %>
|
40
|
+
<% end %>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<%= index_field_wrapper **field_wrapper_args do %>
|
2
|
+
<%= content_tag :div, data: {
|
3
|
+
controller: "date-field",
|
4
|
+
date_field_view_value: @view,
|
5
|
+
date_field_enable_time_value: true,
|
6
|
+
date_field_format_value: @field.format,
|
7
|
+
date_field_timezone_value: @field.timezone,
|
8
|
+
date_field_picker_format_value: @field.picker_format,
|
9
|
+
date_field_no_calendar_value: true,
|
10
|
+
date_field_relative_value: @field.relative,
|
11
|
+
date_field_field_type_value: "time",
|
12
|
+
} do %>
|
13
|
+
<%= @field.formatted_value %>
|
14
|
+
<% end %>
|
15
|
+
<% end %>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<%= field_wrapper **field_wrapper_args do %>
|
2
|
+
<%= content_tag :div, data: {
|
3
|
+
controller: "date-field",
|
4
|
+
date_field_view_value: @view,
|
5
|
+
date_field_enable_time_value: true,
|
6
|
+
date_field_format_value: @field.format,
|
7
|
+
date_field_timezone_value: @field.timezone,
|
8
|
+
date_field_picker_format_value: @field.picker_format,
|
9
|
+
date_field_no_calendar_value: true,
|
10
|
+
date_field_relative_value: @field.relative,
|
11
|
+
date_field_field_type_value: "time",
|
12
|
+
} do %>
|
13
|
+
<%= @field.formatted_value %>
|
14
|
+
<% end %>
|
15
|
+
<% end %>
|
@@ -42,7 +42,7 @@
|
|
42
42
|
type: :submit,
|
43
43
|
data: {
|
44
44
|
target: 'control:detach',
|
45
|
-
|
45
|
+
turbo_confirm: t('avo.are_you_sure_detach_item', item: singular_resource_name),
|
46
46
|
control: :detach,
|
47
47
|
'resource-id': @resource.model.id,
|
48
48
|
'tippy': 'tooltip',
|
@@ -66,7 +66,7 @@
|
|
66
66
|
type: :submit,
|
67
67
|
data: {
|
68
68
|
target: 'control:destroy',
|
69
|
-
|
69
|
+
turbo_confirm: t('avo.are_you_sure', item: singular_resource_name),
|
70
70
|
control: :destroy,
|
71
71
|
'resource-id': @resource.model.id,
|
72
72
|
'tippy': 'tooltip',
|
@@ -25,10 +25,8 @@
|
|
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="flex-1
|
29
|
-
|
30
|
-
<%= body %>
|
31
|
-
</div>
|
28
|
+
<div class="relative flex-1 <%= white_panel_classes %> <%= @body_classes %> <% if sidebar? %> w-2/3 overflow-auto <% else %> w-full <% end %>">
|
29
|
+
<%= body %>
|
32
30
|
</div>
|
33
31
|
<% if sidebar? %>
|
34
32
|
<div class="w-full sm:w-1/3 flex-shrink-0 h-full <%= white_panel_classes %>">
|
@@ -5,6 +5,8 @@ class Avo::PanelComponent < ViewComponent::Base
|
|
5
5
|
attr_reader :name
|
6
6
|
attr_reader :classes
|
7
7
|
|
8
|
+
delegate :white_panel_classes, to: :helpers
|
9
|
+
|
8
10
|
renders_one :tools
|
9
11
|
renders_one :body
|
10
12
|
renders_one :sidebar
|
@@ -26,10 +28,6 @@ class Avo::PanelComponent < ViewComponent::Base
|
|
26
28
|
|
27
29
|
private
|
28
30
|
|
29
|
-
def white_panel_classes
|
30
|
-
"bg-white rounded shadow"
|
31
|
-
end
|
32
|
-
|
33
31
|
def data_attributes
|
34
32
|
@data.merge({"panel-index": @index})
|
35
33
|
end
|
@@ -37,8 +37,11 @@
|
|
37
37
|
<%# Example link below %>
|
38
38
|
<%#= render Avo::ProfileItemComponent.new label: 'Profile', path: '/profile', icon: 'user-circle' %>
|
39
39
|
<%= button_to helpers.main_app.send(destroy_user_session_path),
|
40
|
-
method: :delete,
|
41
40
|
form: { "data-turbo" => "false" },
|
41
|
+
method: :delete,
|
42
|
+
data: {
|
43
|
+
confirm: t('avo.are_you_sure')
|
44
|
+
},
|
42
45
|
class: "flex-1 flex items-center justify-center bg-white text-left cursor-pointer text-red-600 font-semibold hover:bg-red-100 block px-4 py-1 w-full py-3 text-center rounded w-full",
|
43
46
|
form_class: 'flex-1' do %>
|
44
47
|
<%= helpers.svg 'logout', class: 'h-4 mr-1' %> <%= t('avo.sign_out') %>
|
@@ -20,7 +20,7 @@
|
|
20
20
|
</div>
|
21
21
|
</div>
|
22
22
|
<% else %>
|
23
|
-
<div class="flex flex-wrap gap-2
|
23
|
+
<div class="flex flex-wrap gap-2 p-2 <%= white_panel_classes %>" data-target="tab-switcher" data-style="pills">
|
24
24
|
<% visible_items.each do |tab| %>
|
25
25
|
<%= a_link tab_path(tab),
|
26
26
|
color: selected?(tab) ? :primary : :gray,
|
@@ -11,6 +11,8 @@ class Avo::TabSwitcherComponent < Avo::BaseComponent
|
|
11
11
|
attr_reader :view
|
12
12
|
attr_reader :style
|
13
13
|
|
14
|
+
delegate :white_panel_classes, to: :helpers
|
15
|
+
|
14
16
|
def initialize(resource:, group:, current_tab:, active_tab_name:, view:, style:)
|
15
17
|
@active_tab_name = active_tab_name
|
16
18
|
@resource = resource
|
@@ -25,18 +25,16 @@
|
|
25
25
|
<% end %>
|
26
26
|
<% if can_see_the_destroy_button? %>
|
27
27
|
<%= a_link destroy_path,
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
'resource-id': @resource.model.id,
|
39
|
-
} do %>
|
28
|
+
style: :text,
|
29
|
+
color: :red,
|
30
|
+
icon: 'trash',
|
31
|
+
form_class: 'flex flex-col sm:flex-row sm:inline-flex',
|
32
|
+
data: {
|
33
|
+
turbo_confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
|
34
|
+
turbo_method: :delete,
|
35
|
+
control: :destroy,
|
36
|
+
'resource-id': @resource.model.id,
|
37
|
+
} do %>
|
40
38
|
<%= t('avo.delete').capitalize %>
|
41
39
|
<% end %>
|
42
40
|
<% end %>
|
@@ -46,10 +46,8 @@
|
|
46
46
|
</div>
|
47
47
|
<% if view_type.to_sym == :table %>
|
48
48
|
<% 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>
|
49
|
+
<div class="w-full relative flex-1 flex mac-styled-scrollbar overflow-auto mt-0">
|
50
|
+
<%= render(Avo::Index::ResourceTableComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model, parent_resource: @parent_resource, pagy: @pagy, query: @query)) %>
|
53
51
|
</div>
|
54
52
|
<% else %>
|
55
53
|
<%= helpers.empty_state resource_name: @resource.name.downcase.pluralize, related_name: params[:related_name], view_type: view_type, add_background: true %>
|
@@ -21,17 +21,15 @@
|
|
21
21
|
<% end %>
|
22
22
|
<% elsif control.delete_button? %>
|
23
23
|
<% if can_see_the_destroy_button? %>
|
24
|
-
<%=
|
25
|
-
method: :delete,
|
26
|
-
local: true,
|
24
|
+
<%= a_link helpers.resource_path(model: @resource.model, resource: @resource),
|
27
25
|
style: :text,
|
28
|
-
loading: true,
|
29
|
-
confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
|
30
26
|
color: :red,
|
31
27
|
icon: 'trash',
|
32
28
|
form_class: 'flex flex-col sm:flex-row sm:inline-flex',
|
33
29
|
title: control.title,
|
34
30
|
data: {
|
31
|
+
turbo_confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
|
32
|
+
turbo_method: :delete,
|
35
33
|
control: :destroy,
|
36
34
|
tippy: control.title ? :tooltip : nil,
|
37
35
|
'resource-id': @resource.model.id,
|
@@ -84,13 +82,13 @@
|
|
84
82
|
<% elsif control.detach_button? %>
|
85
83
|
<% if @reflection.present? && @resource.model.present? && can_detach? %>
|
86
84
|
<%= a_button url: detach_path,
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
85
|
+
icon: 'detach',
|
86
|
+
method: :delete,
|
87
|
+
form_class: 'flex flex-col sm:flex-row sm:inline-flex',
|
88
|
+
style: :text,
|
89
|
+
data: {
|
90
|
+
confirm: "Are you sure you want to detach this #{title}."
|
91
|
+
} do %>
|
94
92
|
<%= control.label %>
|
95
93
|
<% end %>
|
96
94
|
<% end %>
|
@@ -126,19 +124,17 @@
|
|
126
124
|
<%= t('avo.go_back') %>
|
127
125
|
<% end %>
|
128
126
|
<% if can_see_the_destroy_button? %>
|
129
|
-
<%=
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
'resource-id': @resource.model.id,
|
141
|
-
} do %>
|
127
|
+
<%= a_link destroy_path,
|
128
|
+
style: :text,
|
129
|
+
color: :red,
|
130
|
+
icon: 'trash',
|
131
|
+
form_class: 'flex flex-col sm:flex-row sm:inline-flex',
|
132
|
+
data: {
|
133
|
+
turbo_confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
|
134
|
+
turbo_method: :delete,
|
135
|
+
control: :destroy,
|
136
|
+
'resource-id': @resource.model.id,
|
137
|
+
} do %>
|
142
138
|
<%= t('avo.delete').capitalize %>
|
143
139
|
<% end %>
|
144
140
|
<% end %>
|
@@ -7,6 +7,9 @@ function universalTimestamp(timestampStr) {
|
|
7
7
|
return new Date(new Date(timestampStr).getTime() + (new Date(timestampStr).getTimezoneOffset() * 60 * 1000))
|
8
8
|
}
|
9
9
|
|
10
|
+
const RAW_DATE_FORMAT = 'y/LL/dd'
|
11
|
+
const RAW_TIME_FORMAT = 'TT'
|
12
|
+
|
10
13
|
export default class extends Controller {
|
11
14
|
static targets = ['input', 'fakeInput']
|
12
15
|
|
@@ -19,6 +22,10 @@ export default class extends Controller {
|
|
19
22
|
firstDayOfWeek: Number,
|
20
23
|
time24Hr: Boolean,
|
21
24
|
disableMobile: Boolean,
|
25
|
+
noCalendar: Boolean,
|
26
|
+
relative: Boolean,
|
27
|
+
fieldType: { type: String, default: 'dateTime' },
|
28
|
+
pickerOptions: { type: Object, default: {} },
|
22
29
|
}
|
23
30
|
|
24
31
|
flatpickrInstance;
|
@@ -53,6 +60,18 @@ export default class extends Controller {
|
|
53
60
|
return this.viewValue === 'show'
|
54
61
|
}
|
55
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
|
+
|
56
75
|
// Parse the time as if it were UTC
|
57
76
|
get parsedValue() {
|
58
77
|
return DateTime.fromISO(this.initialValue, { zone: 'UTC' })
|
@@ -90,8 +109,8 @@ export default class extends Controller {
|
|
90
109
|
initShow() {
|
91
110
|
let value = this.parsedValue
|
92
111
|
|
93
|
-
// Set the zone only if the type of field is date time.
|
94
|
-
if (this.enableTimeValue) {
|
112
|
+
// Set the zone only if the type of field is date time or relative time.
|
113
|
+
if (this.enableTimeValue && this.relativeValue) {
|
95
114
|
value = value.setZone(this.displayTimezone)
|
96
115
|
}
|
97
116
|
|
@@ -109,6 +128,8 @@ export default class extends Controller {
|
|
109
128
|
},
|
110
129
|
altInput: true,
|
111
130
|
onChange: this.onChange.bind(this),
|
131
|
+
noCalendar: false,
|
132
|
+
...this.pickerOptionsValue,
|
112
133
|
}
|
113
134
|
|
114
135
|
// Set the format of the displayed input field.
|
@@ -124,24 +145,45 @@ export default class extends Controller {
|
|
124
145
|
options.enableTime = this.enableTimeValue
|
125
146
|
options.enableSeconds = this.enableTimeValue
|
126
147
|
|
127
|
-
//
|
128
|
-
|
129
|
-
options.defaultDate = this.parsedValue.setZone(this.displayTimezone).toISO()
|
148
|
+
// Hide calendar and only keep time picker.
|
149
|
+
options.noCalendar = this.noCalendarValue
|
130
150
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
151
|
+
if (this.initialValue) {
|
152
|
+
// Enable timezone display
|
153
|
+
if (this.enableTimeValue && this.relativeValue) {
|
154
|
+
options.defaultDate = this.parsedValue.setZone(this.displayTimezone).toISO()
|
155
|
+
|
156
|
+
options.dateFormat = 'Y-m-d H:i:S'
|
157
|
+
} else {
|
158
|
+
// Because the browser treats the date like a timestamp and updates it at 00:00 hour, when on a western timezone the date will be converted with one day offset.
|
159
|
+
// Ex: 2022-01-30 will render as 2022-01-29 on an American timezone
|
160
|
+
options.defaultDate = universalTimestamp(this.initialValue)
|
161
|
+
}
|
136
162
|
}
|
137
163
|
|
138
164
|
this.flatpickrInstance = flatpickr(this.fakeInputTarget, options)
|
139
165
|
|
140
|
-
if
|
141
|
-
|
142
|
-
|
143
|
-
this.updateRealInput(universalTimestamp(this.initialValue))
|
166
|
+
// Don't try to parse the value if the input is empty.
|
167
|
+
if (!this.initialValue) {
|
168
|
+
return
|
144
169
|
}
|
170
|
+
|
171
|
+
let value
|
172
|
+
switch (this.fieldTypeValue) {
|
173
|
+
case 'time':
|
174
|
+
// For time values, we should maintain the real value and format it to a time-friendly format.
|
175
|
+
value = this.parsedValue.setZone(this.displayTimezone, { keepLocalTime: true }).toFormat(RAW_TIME_FORMAT)
|
176
|
+
break
|
177
|
+
case 'date':
|
178
|
+
value = DateTime.fromJSDate(universalTimestamp(this.initialValue)).toFormat(RAW_DATE_FORMAT)
|
179
|
+
break
|
180
|
+
default:
|
181
|
+
case 'dateTime':
|
182
|
+
value = this.parsedValue.setZone(this.displayTimezone).toISO()
|
183
|
+
break
|
184
|
+
}
|
185
|
+
|
186
|
+
this.updateRealInput(value)
|
145
187
|
}
|
146
188
|
|
147
189
|
onChange(selectedDates) {
|
@@ -152,24 +194,34 @@ export default class extends Controller {
|
|
152
194
|
return
|
153
195
|
}
|
154
196
|
|
155
|
-
let time
|
156
197
|
let args = {}
|
157
198
|
|
158
|
-
|
199
|
+
// For values that involve time we should keep the local time.
|
200
|
+
if (this.timezoneValue || !this.relativeValue) {
|
159
201
|
args = { keepLocalTime: true }
|
160
202
|
} else {
|
161
203
|
args = { keepLocalTime: false }
|
162
204
|
}
|
163
205
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
206
|
+
let value
|
207
|
+
switch (this.fieldTypeValue) {
|
208
|
+
case 'time':
|
209
|
+
// For time values, we should maintain the real value and format it to a time-friendly format.
|
210
|
+
value = DateTime.fromISO(selectedDates[0].toISOString()).setZone('UTC', args).toFormat(RAW_TIME_FORMAT)
|
211
|
+
break
|
212
|
+
case 'date':
|
213
|
+
value = DateTime.fromISO(selectedDates[0].toISOString()).setZone('UTC', { keepLocalTime: true }).toFormat(RAW_DATE_FORMAT)
|
214
|
+
break
|
215
|
+
default:
|
216
|
+
case 'dateTime':
|
217
|
+
value = DateTime.fromISO(selectedDates[0].toISOString()).setZone('UTC', args).toISO()
|
218
|
+
break
|
168
219
|
}
|
169
220
|
|
170
|
-
this.updateRealInput(
|
221
|
+
this.updateRealInput(value)
|
171
222
|
}
|
172
223
|
|
224
|
+
// Value should be a string
|
173
225
|
updateRealInput(value) {
|
174
226
|
this.inputTarget.value = value
|
175
227
|
}
|
@@ -73,6 +73,9 @@ export default class extends Controller {
|
|
73
73
|
Mousetrap.bind(['command+k', 'ctrl+k'], () => this.showSearchPanel())
|
74
74
|
}
|
75
75
|
|
76
|
+
// This line fixes a bug where the search box would be duplicated on back navigation.
|
77
|
+
this.autocompleteTarget.innerHTML = ''
|
78
|
+
|
76
79
|
autocomplete({
|
77
80
|
container: this.autocompleteTarget,
|
78
81
|
placeholder: this.translationKeys.placeholder,
|
data/avo.gemspec
CHANGED
@@ -40,7 +40,7 @@ Gem::Specification.new do |spec|
|
|
40
40
|
spec.add_dependency "httparty"
|
41
41
|
spec.add_dependency "active_link_to"
|
42
42
|
spec.add_dependency "image_processing"
|
43
|
-
spec.add_dependency "view_component"
|
43
|
+
spec.add_dependency "view_component"
|
44
44
|
spec.add_dependency "turbo-rails"
|
45
45
|
spec.add_dependency "addressable"
|
46
46
|
spec.add_dependency "meta-tags"
|
data/db/factories.rb
CHANGED
@@ -69,6 +69,7 @@ FactoryBot.define do
|
|
69
69
|
skills { [Faker::Educator.subject, Faker::Educator.subject, Faker::Educator.subject, Faker::Educator.subject, Faker::Educator.subject] }
|
70
70
|
country { Course.countries.sample }
|
71
71
|
city { Course.cities.stringify_keys[country].sample }
|
72
|
+
starting_at { Time.now }
|
72
73
|
end
|
73
74
|
|
74
75
|
factory :course_link, class: "Course::Link" do
|