Commit 683f739f authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Merge branch '340795-don-t-set-default-timezone-to-utc-for-users' into 'master'

Remove default value for time zone user preference

See merge request gitlab-org/gitlab!70834
parents 0b183f7a a1ba00ef
...@@ -27,19 +27,22 @@ export const findTimezoneByIdentifier = (tzList = [], identifier = null) => { ...@@ -27,19 +27,22 @@ export const findTimezoneByIdentifier = (tzList = [], identifier = null) => {
}; };
export default class TimezoneDropdown { export default class TimezoneDropdown {
constructor({ $dropdownEl, $inputEl, onSelectTimezone, displayFormat } = defaults) { constructor({
$dropdownEl,
$inputEl,
onSelectTimezone,
displayFormat,
allowEmpty = false,
} = defaults) {
this.$dropdown = $dropdownEl; this.$dropdown = $dropdownEl;
this.$dropdownToggle = this.$dropdown.find('.dropdown-toggle-text'); this.$dropdownToggle = this.$dropdown.find('.dropdown-toggle-text');
this.$input = $inputEl; this.$input = $inputEl;
this.timezoneData = this.$dropdown.data('data'); this.timezoneData = this.$dropdown.data('data') || [];
this.onSelectTimezone = onSelectTimezone; this.onSelectTimezone = onSelectTimezone;
this.displayFormat = displayFormat || defaults.displayFormat; this.displayFormat = displayFormat || defaults.displayFormat;
this.allowEmpty = allowEmpty;
this.initialTimezone =
findTimezoneByIdentifier(this.timezoneData, this.$input.val()) || defaultTimezone;
this.initDefaultTimezone();
this.initDropdown(); this.initDropdown();
} }
...@@ -52,24 +55,25 @@ export default class TimezoneDropdown { ...@@ -52,24 +55,25 @@ export default class TimezoneDropdown {
search: { search: {
fields: ['name'], fields: ['name'],
}, },
clicked: (cfg) => this.updateInputValue(cfg), clicked: (cfg) => this.handleDropdownChange(cfg),
text: (item) => formatTimezone(item), text: (item) => formatTimezone(item),
}); });
this.setDropdownToggle(this.displayFormat(this.initialTimezone)); const initialTimezone = findTimezoneByIdentifier(this.timezoneData, this.$input.val());
}
initDefaultTimezone() { if (initialTimezone !== null) {
if (!this.$input.val()) { this.setDropdownValue(initialTimezone);
this.$input.val(defaultTimezone.name); } else if (!this.allowEmpty) {
this.setDropdownValue(defaultTimezone);
} }
} }
setDropdownToggle(dropdownText) { setDropdownValue(timezone) {
this.$dropdownToggle.text(dropdownText); this.$dropdownToggle.text(this.displayFormat(timezone));
this.$input.val(timezone.name);
} }
updateInputValue({ selectedObj, e }) { handleDropdownChange({ selectedObj, e }) {
e.preventDefault(); e.preventDefault();
this.$input.val(selectedObj.identifier); this.$input.val(selectedObj.identifier);
if (this.onSelectTimezone) { if (this.onSelectTimezone) {
......
...@@ -21,6 +21,7 @@ export default class Profile { ...@@ -21,6 +21,7 @@ export default class Profile {
$inputEl: this.$inputEl, $inputEl: this.$inputEl,
$dropdownEl: $('.js-timezone-dropdown'), $dropdownEl: $('.js-timezone-dropdown'),
displayFormat: (selectedItem) => formatTimezone(selectedItem), displayFormat: (selectedItem) => formatTimezone(selectedItem),
allowEmpty: true,
}); });
} }
......
...@@ -33,6 +33,8 @@ module TimeZoneHelper ...@@ -33,6 +33,8 @@ module TimeZoneHelper
end end
def local_time(timezone) def local_time(timezone)
return if timezone.blank?
time_zone_instance = ActiveSupport::TimeZone.new(timezone) || Time.zone time_zone_instance = ActiveSupport::TimeZone.new(timezone) || Time.zone
time_zone_instance.now.strftime("%-l:%M %p") time_zone_instance.now.strftime("%-l:%M %p")
end end
......
...@@ -23,7 +23,6 @@ class UserPreference < ApplicationRecord ...@@ -23,7 +23,6 @@ class UserPreference < ApplicationRecord
ignore_columns :experience_level, remove_with: '14.10', remove_after: '2021-03-22' ignore_columns :experience_level, remove_with: '14.10', remove_after: '2021-03-22'
default_value_for :tab_width, value: Gitlab::TabWidth::DEFAULT, allows_nil: false default_value_for :tab_width, value: Gitlab::TabWidth::DEFAULT, allows_nil: false
default_value_for :timezone, value: Time.zone.tzinfo.name, allows_nil: false
default_value_for :time_display_relative, value: true, allows_nil: false default_value_for :time_display_relative, value: true, allows_nil: false
default_value_for :time_format_in_24h, value: false, allows_nil: false default_value_for :time_format_in_24h, value: false, allows_nil: false
default_value_for :render_whitespace_in_code, value: false, allows_nil: false default_value_for :render_whitespace_in_code, value: false, allows_nil: false
......
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
%p= s_("Profiles|Set your local time zone") %p= s_("Profiles|Set your local time zone")
.col-lg-8 .col-lg-8
%h5= _("Time zone") %h5= _("Time zone")
= dropdown_tag(_("Select a time zone"), options: { toggle_class: 'gl-button btn js-timezone-dropdown input-lg', title: _("Select a time zone"), filter: true, placeholder: s_("OfSearchInADropdown|Filter"), data: { data: timezone_data } } ) = dropdown_tag(_("Select a time zone"), options: { toggle_class: 'gl-button btn js-timezone-dropdown input-lg gl-w-full!', title: _("Select a time zone"), filter: true, placeholder: s_("OfSearchInADropdown|Filter"), data: { data: timezone_data } } )
%input.hidden{ :type => 'hidden', :id => 'user_timezone', :name => 'user[timezone]', value: @user.timezone } %input.hidden{ :type => 'hidden', :id => 'user_timezone', :name => 'user[timezone]', value: @user.timezone }
.col-lg-12 .col-lg-12
%hr %hr
......
...@@ -84,10 +84,12 @@ ...@@ -84,10 +84,12 @@
= sprite_icon('location', css_class: 'fgray') = sprite_icon('location', css_class: 'fgray')
%span{ itemprop: 'addressLocality' } %span{ itemprop: 'addressLocality' }
= @user.location = @user.location
= render 'middle_dot_divider', stacking: true do - user_local_time = local_time(@user.timezone)
= sprite_icon('clock', css_class: 'fgray') - unless user_local_time.nil?
%span = render 'middle_dot_divider', stacking: true, data: { testid: 'user-local-time' } do
= local_time(@user.timezone) = sprite_icon('clock', css_class: 'fgray')
%span
= user_local_time
- unless work_information(@user).blank? - unless work_information(@user).blank?
= render 'middle_dot_divider', stacking: true do = render 'middle_dot_divider', stacking: true do
= sprite_icon('work', css_class: 'fgray') = sprite_icon('work', css_class: 'fgray')
......
...@@ -48,8 +48,12 @@ gitlab-ctl restart ...@@ -48,8 +48,12 @@ gitlab-ctl restart
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/29669) in GitLab 13.9. > - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/29669) in GitLab 13.9.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/29669) in GitLab 14.1. > - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/29669) in GitLab 14.1.
A user can set their time zone in their profile. If a user has not set their time zone, it defaults Users can set their time zone in their profile. On GitLab.com, the default time zone is UTC.
to the time zone [configured at the instance level](#changing-your-time-zone). On GitLab.com, the
default time zone is UTC. New users do not have a default time zone in [GitLab 14.4 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/340795). New users must
explicitly set their time zone before it displays on their profile.
In GitLab 14.3 and earlier, users with no configured time zone default to the time zone
[configured at the instance level](#changing-your-time-zone).
For more information, see [Set your time zone](../user/profile/index.md#set-your-time-zone). For more information, see [Set your time zone](../user/profile/index.md#set-your-time-zone).
...@@ -561,14 +561,11 @@ RSpec.describe 'User edit profile' do ...@@ -561,14 +561,11 @@ RSpec.describe 'User edit profile' do
page.find("a", text: "Nuku'alofa").click page.find("a", text: "Nuku'alofa").click
tz = page.find('.user-time-preferences #user_timezone', visible: false) expect(page).to have_field(:user_timezone, with: 'Pacific/Tongatapu', type: :hidden)
expect(tz.value).to eq('Pacific/Tongatapu')
end end
it 'timezone defaults to servers default' do it 'timezone defaults to empty' do
timezone_name = Time.zone.tzinfo.name expect(page).to have_field(:user_timezone, with: '', type: :hidden)
expect(page.find('.user-time-preferences #user_timezone', visible: false).value).to eq(timezone_name)
end end
end end
end end
......
...@@ -81,6 +81,7 @@ RSpec.describe 'User page' do ...@@ -81,6 +81,7 @@ RSpec.describe 'User page' do
context 'timezone' do context 'timezone' do
let_it_be(:timezone) { 'America/Los_Angeles' } let_it_be(:timezone) { 'America/Los_Angeles' }
let_it_be(:local_time_selector) { '[data-testid="user-local-time"]' }
before do before do
travel_to Time.find_zone(timezone).local(2021, 7, 20, 15, 30, 45) travel_to Time.find_zone(timezone).local(2021, 7, 20, 15, 30, 45)
...@@ -92,7 +93,19 @@ RSpec.describe 'User page' do ...@@ -92,7 +93,19 @@ RSpec.describe 'User page' do
it 'shows local time' do it 'shows local time' do
subject subject
expect(page).to have_content('3:30 PM') within local_time_selector do
expect(page).to have_content('3:30 PM')
end
end
end
context 'when timezone is not set' do
let_it_be(:user) { create(:user, timezone: nil) }
it 'does not show local time' do
subject
expect(page).not_to have_selector(local_time_selector)
end end
end end
...@@ -102,7 +115,9 @@ RSpec.describe 'User page' do ...@@ -102,7 +115,9 @@ RSpec.describe 'User page' do
it 'shows local time using the configured default timezone (UTC in this case)' do it 'shows local time using the configured default timezone (UTC in this case)' do
subject subject
expect(page).to have_content('10:30 PM') within local_time_selector do
expect(page).to have_content('10:30 PM')
end
end end
end end
end end
......
...@@ -10,7 +10,17 @@ describe('Timezone Dropdown', () => { ...@@ -10,7 +10,17 @@ describe('Timezone Dropdown', () => {
let $dropdownEl = null; let $dropdownEl = null;
let $wrapper = null; let $wrapper = null;
const tzListSel = '.dropdown-content ul li a.is-active'; const tzListSel = '.dropdown-content ul li a.is-active';
const tzDropdownToggleText = '.dropdown-toggle-text';
const initTimezoneDropdown = (options = {}) => {
// eslint-disable-next-line no-new
new TimezoneDropdown({
$inputEl,
$dropdownEl,
...options,
});
};
const findDropdownToggleText = () => $wrapper.find('.dropdown-toggle-text');
describe('Initialize', () => { describe('Initialize', () => {
describe('with dropdown already loaded', () => { describe('with dropdown already loaded', () => {
...@@ -18,16 +28,13 @@ describe('Timezone Dropdown', () => { ...@@ -18,16 +28,13 @@ describe('Timezone Dropdown', () => {
loadFixtures('pipeline_schedules/edit.html'); loadFixtures('pipeline_schedules/edit.html');
$wrapper = $('.dropdown'); $wrapper = $('.dropdown');
$inputEl = $('#schedule_cron_timezone'); $inputEl = $('#schedule_cron_timezone');
$inputEl.val('');
$dropdownEl = $('.js-timezone-dropdown'); $dropdownEl = $('.js-timezone-dropdown');
// eslint-disable-next-line no-new
new TimezoneDropdown({
$inputEl,
$dropdownEl,
});
}); });
it('can take an $inputEl in the constructor', () => { it('can take an $inputEl in the constructor', () => {
initTimezoneDropdown();
const tzStr = '[UTC + 5.5] Sri Jayawardenepura'; const tzStr = '[UTC + 5.5] Sri Jayawardenepura';
const tzValue = 'Asia/Colombo'; const tzValue = 'Asia/Colombo';
...@@ -42,6 +49,8 @@ describe('Timezone Dropdown', () => { ...@@ -42,6 +49,8 @@ describe('Timezone Dropdown', () => {
}); });
it('will format data array of timezones into a list of offsets', () => { it('will format data array of timezones into a list of offsets', () => {
initTimezoneDropdown();
const data = $dropdownEl.data('data'); const data = $dropdownEl.data('data');
const formatted = $wrapper.find(tzListSel).text(); const formatted = $wrapper.find(tzListSel).text();
...@@ -50,10 +59,28 @@ describe('Timezone Dropdown', () => { ...@@ -50,10 +59,28 @@ describe('Timezone Dropdown', () => {
}); });
}); });
it('will default the timezone to UTC', () => { describe('when `allowEmpty` property is `false`', () => {
const tz = $inputEl.val(); beforeEach(() => {
initTimezoneDropdown();
});
it('will default the timezone to UTC', () => {
const tz = $inputEl.val();
expect(tz).toBe('UTC'); expect(tz).toBe('UTC');
});
});
describe('when `allowEmpty` property is `true`', () => {
beforeEach(() => {
initTimezoneDropdown({
allowEmpty: true,
});
});
it('will default the value of the input to an empty string', () => {
expect($inputEl.val()).toBe('');
});
}); });
}); });
...@@ -68,23 +95,15 @@ describe('Timezone Dropdown', () => { ...@@ -68,23 +95,15 @@ describe('Timezone Dropdown', () => {
it('will populate the list of UTC offsets after the dropdown is loaded', () => { it('will populate the list of UTC offsets after the dropdown is loaded', () => {
expect($wrapper.find(tzListSel).length).toEqual(0); expect($wrapper.find(tzListSel).length).toEqual(0);
// eslint-disable-next-line no-new initTimezoneDropdown();
new TimezoneDropdown({
$inputEl,
$dropdownEl,
});
expect($wrapper.find(tzListSel).length).toEqual($($dropdownEl).data('data').length); expect($wrapper.find(tzListSel).length).toEqual($($dropdownEl).data('data').length);
}); });
it('will call a provided handler when a new timezone is selected', () => { it('will call a provided handler when a new timezone is selected', () => {
const onSelectTimezone = jest.fn(); const onSelectTimezone = jest.fn();
// eslint-disable-next-line no-new
new TimezoneDropdown({ initTimezoneDropdown({ onSelectTimezone });
$inputEl,
$dropdownEl,
onSelectTimezone,
});
$wrapper.find(tzListSel).first().trigger('click'); $wrapper.find(tzListSel).first().trigger('click');
...@@ -94,24 +113,15 @@ describe('Timezone Dropdown', () => { ...@@ -94,24 +113,15 @@ describe('Timezone Dropdown', () => {
it('will correctly set the dropdown label if a timezone identifier is set on the inputEl', () => { it('will correctly set the dropdown label if a timezone identifier is set on the inputEl', () => {
$inputEl.val('America/St_Johns'); $inputEl.val('America/St_Johns');
// eslint-disable-next-line no-new initTimezoneDropdown({ displayFormat: (selectedItem) => formatTimezone(selectedItem) });
new TimezoneDropdown({
$inputEl,
$dropdownEl,
displayFormat: (selectedItem) => formatTimezone(selectedItem),
});
expect($wrapper.find(tzDropdownToggleText).html()).toEqual('[UTC - 2.5] Newfoundland'); expect(findDropdownToggleText().html()).toEqual('[UTC - 2.5] Newfoundland');
}); });
it('will call a provided `displayFormat` handler to format the dropdown value', () => { it('will call a provided `displayFormat` handler to format the dropdown value', () => {
const displayFormat = jest.fn(); const displayFormat = jest.fn();
// eslint-disable-next-line no-new
new TimezoneDropdown({ initTimezoneDropdown({ displayFormat });
$inputEl,
$dropdownEl,
displayFormat,
});
$wrapper.find(tzListSel).first().trigger('click'); $wrapper.find(tzListSel).first().trigger('click');
......
...@@ -76,6 +76,18 @@ RSpec.describe TimeZoneHelper, :aggregate_failures do ...@@ -76,6 +76,18 @@ RSpec.describe TimeZoneHelper, :aggregate_failures do
travel_to Time.find_zone(timezone).local(2021, 7, 20, 15, 30, 45) travel_to Time.find_zone(timezone).local(2021, 7, 20, 15, 30, 45)
end end
context 'when timezone is `nil`' do
it 'returns `nil`' do
expect(helper.local_time(nil)).to eq(nil)
end
end
context 'when timezone is blank' do
it 'returns `nil`' do
expect(helper.local_time('')).to eq(nil)
end
end
context 'when a valid timezone is passed' do context 'when a valid timezone is passed' do
it 'returns local time' do it 'returns local time' do
expect(helper.local_time(timezone)).to eq('3:30 PM') expect(helper.local_time(timezone)).to eq('3:30 PM')
......
...@@ -80,12 +80,6 @@ RSpec.describe UserPreference do ...@@ -80,12 +80,6 @@ RSpec.describe UserPreference do
end end
end end
describe '#timezone' do
it 'returns server time as default' do
expect(user_preference.timezone).to eq(Time.zone.tzinfo.name)
end
end
describe '#tab_width' do describe '#tab_width' do
it 'is set to 8 by default' do it 'is set to 8 by default' do
# Intentionally not using factory here to test the constructor. # Intentionally not using factory here to test the constructor.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment