Skip to content

Commit

Permalink
Fix datetime delocalization issues by using ISO8601 time format
Browse files Browse the repository at this point in the history
Closes #3344
  • Loading branch information
mshibuya committed Sep 4, 2021
1 parent 4379451 commit 4b359bf
Show file tree
Hide file tree
Showing 28 changed files with 599 additions and 291 deletions.
1 change: 0 additions & 1 deletion .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,6 @@ Style/RescueStandardError:
Exclude:
- 'lib/rails_admin/adapters/mongoid.rb'
- 'lib/rails_admin/adapters/mongoid/bson.rb'
- 'lib/rails_admin/support/i18n.rb'

# Offense count: 2
# Cop supports --auto-correct.
Expand Down
83 changes: 40 additions & 43 deletions app/assets/javascripts/rails_admin/ra.filter-box.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,57 +34,46 @@
}
break;
case 'date':
additional_control =
$('<input size="20" class="date additional-fieldset default input-sm form-control" type="text" />')
.css('display', (!field_operator || field_operator == "default") ? 'inline-block' : 'none')
.prop('name', value_name + '[]')
.prop('value', field_value[0] || '')
.add(
$('<input size="20" placeholder="-∞" class="date additional-fieldset between input-sm form-control" type="text" />')
.css('display', (field_operator == "between") ? 'inline-block' : 'none')
.prop('name', value_name + '[]')
.prop('value', field_value[1] || '')
)
.add(
$('<input size="20" placeholder="∞" class="date additional-fieldset between input-sm form-control" type="text" />')
.css('display', (field_operator == "between") ? 'inline-block' : 'none')
.prop('name', value_name + '[]')
.prop('value', field_value[2] || '')
);
case 'datetime':
case 'timestamp':
case 'time':
control = control || $('<select class="switch-additional-fieldsets input-sm form-control"></select>')
.prop('name', operator_name)
.append($('<option data-additional-fieldset="default" value="default"></option>').prop('selected', field_operator == "default").text(RailsAdmin.I18n.t("date")))
.append($('<option data-additional-fieldset="default" value="default"></option>').prop('selected', field_operator == "default").text(RailsAdmin.I18n.t(field_type == "time" ? "time" : "date")))
.append($('<option data-additional-fieldset="between" value="between"></option>').prop('selected', field_operator == "between").text(RailsAdmin.I18n.t("between_and_")))
.append($('<option value="today"></option>').prop('selected', field_operator == "today").text(RailsAdmin.I18n.t("today")))
.append($('<option value="yesterday"></option>').prop('selected', field_operator == "yesterday").text(RailsAdmin.I18n.t("yesterday")))
.append($('<option value="this_week"></option>').prop('selected', field_operator == "this_week").text(RailsAdmin.I18n.t("this_week")))
.append($('<option value="last_week"></option>').prop('selected', field_operator == "last_week").text(RailsAdmin.I18n.t("last_week")))
if (field_type != 'time') {
control.append([
$('<option value="today"></option>').prop('selected', field_operator == "today").text(RailsAdmin.I18n.t("today")),
$('<option value="yesterday"></option>').prop('selected', field_operator == "yesterday").text(RailsAdmin.I18n.t("yesterday")),
$('<option value="this_week"></option>').prop('selected', field_operator == "this_week").text(RailsAdmin.I18n.t("this_week")),
$('<option value="last_week"></option>').prop('selected', field_operator == "last_week").text(RailsAdmin.I18n.t("last_week")),
])
}
if (!required) {
control.append([
'<option disabled="disabled">---------</option>',
$('<option value="_not_null"></option>').prop('selected', field_operator == "_not_null").text(RailsAdmin.I18n.t("is_present")),
$('<option value="_null"></option>').prop('selected', field_operator == "_null").text(RailsAdmin.I18n.t("is_blank"))
])
}
additional_control = additional_control ||
$('<input size="25" class="datetime additional-fieldset default input-sm form-control" type="text" />')
.css('display', (!field_operator || field_operator == "default") ? 'inline-block' : 'none')
.prop('name', value_name + '[]')
.prop('value', field_value[0] || '')
.add(
$('<input size="25" placeholder="-∞" class="datetime additional-fieldset between input-sm form-control" type="text" />')
.css('display', (field_operator == "between") ? 'inline-block' : 'none')
.prop('name', value_name + '[]')
.prop('value', field_value[1] || '')
)
.add(
$('<input size="25" placeholder="∞" class="datetime additional-fieldset between input-sm form-control" type="text" />')
.css('display', (field_operator == "between") ? 'inline-block' : 'none')
.prop('name', value_name + '[]')
.prop('value', field_value[2] || '')
);
additional_control =
$.map([undefined, '-∞', '∞'], function(placeholder, index){
var visible = index == 0 ? (!field_operator || field_operator == "default") : (field_operator == "between");
return $('<span class="additional-fieldset"></span>')
.addClass(index == 0 ? 'default' : 'between')
.css('display', visible ? 'inline-block' : 'none')
.html(
$('<input type="hidden" />')
.prop('name', value_name + '[]')
.prop('value', field_value[index] || '')
.add(
$('<input class="input-sm form-control" type="text" />')
.addClass(field_type == 'date' ? 'date' : 'datetime')
.prop('size', field_type == 'date' || field_type == 'time' ? 20 : 25)
.prop('placeholder', placeholder)
)
);
});
break;
case 'enum':
var multiple_values = ((field_value instanceof Array) ? true : false)
Expand Down Expand Up @@ -193,10 +182,18 @@

$('#filters_box').append($content);

$content.find('.date, .datetime').datetimepicker({
locale: RailsAdmin.I18n.locale,
showTodayButton: true,
format: options['datetimepicker_format']
$content.find('.date, .datetime').each(function() {
$(this).datetimepicker({
date: moment($(this).siblings('[type=hidden]').val()),
locale: RailsAdmin.I18n.locale,
showTodayButton: true,
format: options['datetimepicker_format']
});
$(this).on('dp.change', function(e) {
if (e.date) {
$(this).siblings('[type=hidden]').val(e.date.format('YYYY-MM-DD[T]HH:mm:ss'));
}
});
});

$("hr.filters_box:hidden").show('slow');
Expand Down
6 changes: 6 additions & 0 deletions app/assets/javascripts/rails_admin/ra.widgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,15 @@
var options;
options = $(this).data('options');
$.extend(options, {
date: moment($(this).siblings('[type=hidden]').val()),
locale: RailsAdmin.I18n.locale
});
$(this).datetimepicker(options);
$(this).on('dp.change', function(e) {
if (e.date) {
$(this).siblings('[type=hidden]').val(e.date.format('YYYY-MM-DD[T]HH:mm:ss'));
}
});
});
content.find('[data-enumeration]').each(function() {
if ($(this).is('[multiple]')) {
Expand Down
4 changes: 0 additions & 4 deletions app/helpers/rails_admin/application_helper.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
require 'rails_admin/support/i18n'

module RailsAdmin
module ApplicationHelper
include RailsAdmin::Support::I18n

def capitalize_first_letter(wording)
return nil unless wording.present? && wording.is_a?(String)

Expand Down
2 changes: 1 addition & 1 deletion app/helpers/rails_admin/main_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def ordered_filter_options
when :enum
options[:select_options] = options_for_select(field.with(object: @abstract_model.model.new).enum, filter_hash['v'])
when :date, :datetime, :time
options[:datetimepicker_format] = field.parser.to_momentjs
options[:datetimepicker_format] = field.momentjs_format
end
options[:label] = field.label
options[:name] = field.name
Expand Down
3 changes: 2 additions & 1 deletion app/views/rails_admin/main/_form_datetime.html.haml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.form-inline
.input-group
= form.send field.view_helper, field.method_name, field.html_attributes.reverse_merge({value: field.form_value, class: 'form-control', data: {datetimepicker: true, options: field.datepicker_options.to_json}})
= form.hidden_field(field.method_name, id: nil, value: field.form_value)
= form.text_field field.method_name, field.html_attributes.reverse_merge({class: 'form-control', data: {datetimepicker: true, options: field.datepicker_options.to_json}, name: nil, value: nil})
= form.label(field.method_name, class: 'input-group-addon') do
%i.fa.fa-fw.fa-calendar
2 changes: 1 addition & 1 deletion app/views/rails_admin/main/index.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
- else
- ''
%li
%a{href: '#', :"data-field-label" => field.label, :"data-field-name" => field.name, :"data-field-operator" => field.default_filter_operator, :"data-field-options" => field_options.html_safe, :"data-field-required" => field.required.to_s, :"data-field-type" => field.type, :"data-field-value" => "", :"data-field-datetimepicker-format" => (field.try(:parser) && field.parser.to_momentjs)}= capitalize_first_letter(field.label)
%a{href: '#', :"data-field-label" => field.label, :"data-field-name" => field.name, :"data-field-operator" => field.default_filter_operator, :"data-field-options" => field_options.html_safe, :"data-field-required" => field.required.to_s, :"data-field-type" => field.type, :"data-field-value" => "", :"data-field-datetimepicker-format" => field.try(:momentjs_format)}= capitalize_first_letter(field.label)
%style
- properties.select{ |p| p.column_width.present? }.each do |property|
Expand Down
1 change: 1 addition & 0 deletions config/locales/rails_admin.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ en:
yesterday: Yesterday
this_week: This week
last_week: Last week
time: Time ...
number: Number ...
contains: Contains
is_exactly: Is exactly
Expand Down
6 changes: 3 additions & 3 deletions lib/rails_admin/abstract_model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def build_statement_for_type_generic
case @type
when :date
build_statement_for_date
when :datetime, :timestamp
when :datetime, :timestamp, :time
build_statement_for_datetime_or_timestamp
end
end
Expand Down Expand Up @@ -178,8 +178,8 @@ def build_statement_for_date

def build_statement_for_datetime_or_timestamp
start_date, end_date = get_filtering_duration
start_date = start_date.try(:beginning_of_day) if start_date
end_date = end_date.try(:end_of_day) if end_date
start_date = start_date.beginning_of_day if start_date.is_a?(Date)
end_date = end_date.end_of_day if end_date.is_a?(Date)
range_filter(start_date, end_date)
end

Expand Down
4 changes: 3 additions & 1 deletion lib/rails_admin/adapters/active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,9 @@ def boolean_unary_operators
alias_method :numeric_unary_operators, :boolean_unary_operators

def range_filter(min, max)
if min && max
if min && max && min == max
["(#{@column} = ?)", min]
elsif min && max
["(#{@column} BETWEEN ? AND ?)", min, max]
elsif min
["(#{@column} >= ?)", min]
Expand Down
4 changes: 3 additions & 1 deletion lib/rails_admin/adapters/mongoid.rb
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,9 @@ def build_statement_for_belongs_to_association_or_bson_object_id
end

def range_filter(min, max)
if min && max
if min && max && min == max
{@column => min}
elsif min && max
{@column => {'$gte' => min, '$lte' => max}}
elsif min
{@column => {'$gte' => min}}
Expand Down
11 changes: 4 additions & 7 deletions lib/rails_admin/config/fields/types/date.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ module Types
class Date < RailsAdmin::Config::Fields::Types::Datetime
RailsAdmin::Config::Fields::Types.register(self)

def parse_value(value)
::Date.parse(value) if value.present?
end

register_instance_option :date_format do
:long
end
Expand All @@ -15,13 +19,6 @@ class Date < RailsAdmin::Config::Fields::Types::Datetime
[:date, :formats]
end

register_instance_option :datepicker_options do
{
showTodayButton: true,
format: parser.to_momentjs,
}
end

register_instance_option :html_attributes do
{
required: required?,
Expand Down
29 changes: 14 additions & 15 deletions lib/rails_admin/config/fields/types/datetime.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,14 @@ module Types
class Datetime < RailsAdmin::Config::Fields::Base
RailsAdmin::Config::Fields::Types.register(self)

def parser
RailsAdmin::Support::Datetime.new(strftime_format)
end

def parse_value(value)
parser.parse_string(value)
::Time.zone.parse(value)
end

def parse_input(params)
params[name] = parse_value(params[name]) if params[name]
end

def value
parent_value = super
if %w(DateTime Date Time).include?(parent_value.class.name)
parent_value.in_time_zone
else
parent_value
end
end

register_instance_option :date_format do
:long
end
Expand All @@ -43,10 +30,14 @@ def value
"%B %d, %Y %H:%M"
end

def momentjs_format
RailsAdmin::Support::Datetime.to_momentjs(strftime_format)
end

register_instance_option :datepicker_options do
{
showTodayButton: true,
format: parser.to_momentjs,
format: momentjs_format,
}
end

Expand All @@ -61,6 +52,10 @@ def value
true
end

register_instance_option :queryable? do
false
end

register_instance_option :formatted_value do
if time = (value || default_value)
::I18n.l(time, format: strftime_format)
Expand All @@ -72,6 +67,10 @@ def value
register_instance_option :partial do
:form_datetime
end

def form_value
value&.in_time_zone&.strftime('%FT%T') || form_default_value
end
end
end
end
Expand Down
5 changes: 1 addition & 4 deletions lib/rails_admin/config/fields/types/time.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ class Time < RailsAdmin::Config::Fields::Types::Datetime
RailsAdmin::Config::Fields::Types.register(self)

def parse_value(value)
parent_value = super(value)
return unless parent_value
value_with_tz = parent_value.in_time_zone
::DateTime.parse(value_with_tz.strftime('%Y-%m-%d %H:%M:%S'))
abstract_model.model.type_for_attribute(name.to_s).serialize(super)&.change(year: 2000, month: 1, day: 1)
end

register_instance_option :strftime_format do
Expand Down
4 changes: 0 additions & 4 deletions lib/rails_admin/config/fields/types/timestamp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ module Types
class Timestamp < RailsAdmin::Config::Fields::Types::Datetime
# Register field type for the type loader
RailsAdmin::Config::Fields::Types.register(self)

@format = :long
@i18n_scope = [:time, :formats]
@js_plugin_options = {}
end
end
end
Expand Down
Loading

0 comments on commit 4b359bf

Please sign in to comment.