summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/boards/components/board_sidebar.js3
-rw-r--r--app/assets/javascripts/dispatcher.js5
-rw-r--r--app/assets/javascripts/due_date_select.js52
-rw-r--r--app/assets/javascripts/init_issuable_sidebar.js4
-rw-r--r--app/assets/javascripts/issuable_form.js8
-rw-r--r--app/assets/javascripts/lib/utils/datefix.js33
-rw-r--r--app/assets/javascripts/main.js2
-rw-r--r--app/assets/javascripts/member_expiration_date.js9
-rw-r--r--changelogs/unreleased/38986-due-date.yml5
-rw-r--r--config/dependency_decisions.yml7
-rw-r--r--package.json2
-rw-r--r--spec/javascripts/lib/utils/datefix_spec.js29
-rw-r--r--yarn.lock6
13 files changed, 115 insertions, 50 deletions
diff --git a/app/assets/javascripts/boards/components/board_sidebar.js b/app/assets/javascripts/boards/components/board_sidebar.js
index 7f3afefc9cc..c1f902a785a 100644
--- a/app/assets/javascripts/boards/components/board_sidebar.js
+++ b/app/assets/javascripts/boards/components/board_sidebar.js
@@ -9,6 +9,7 @@ import Flash from '../../flash';
import eventHub from '../../sidebar/event_hub';
import AssigneeTitle from '../../sidebar/components/assignees/assignee_title';
import Assignees from '../../sidebar/components/assignees/assignees';
+import DueDateSelectors from '../../due_date_select';
import './sidebar/remove_issue';
const Store = gl.issueBoards.BoardsStore;
@@ -113,7 +114,7 @@ gl.issueBoards.BoardSidebar = Vue.extend({
mounted () {
new IssuableContext(this.currentUser);
new MilestoneSelect();
- new gl.DueDateSelectors();
+ new DueDateSelectors();
new LabelsSelect();
new Sidebar();
gl.Subscription.bindAll('.subscription');
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index b66652db33b..2885923aeda 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -86,6 +86,7 @@ import ShortcutsIssuable from './shortcuts_issuable';
import U2FAuthenticate from './u2f/authenticate';
import Members from './members';
import memberExpirationDate from './member_expiration_date';
+import DueDateSelectors from './due_date_select';
(function() {
var Dispatcher;
@@ -232,7 +233,7 @@ import memberExpirationDate from './member_expiration_date';
case 'groups:milestones:edit':
case 'groups:milestones:update':
new ZenMode();
- new gl.DueDateSelectors();
+ new DueDateSelectors();
new GLForm($('.milestone-form'), true);
break;
case 'projects:compare:show':
@@ -532,7 +533,7 @@ import memberExpirationDate from './member_expiration_date';
break;
case 'profiles:personal_access_tokens:index':
case 'admin:impersonation_tokens:index':
- new gl.DueDateSelectors();
+ new DueDateSelectors();
break;
case 'projects:clusters:show':
import(/* webpackChunkName: "clusters" */ './clusters')
diff --git a/app/assets/javascripts/due_date_select.js b/app/assets/javascripts/due_date_select.js
index ee71728184f..ada985913bb 100644
--- a/app/assets/javascripts/due_date_select.js
+++ b/app/assets/javascripts/due_date_select.js
@@ -1,8 +1,7 @@
-/* eslint-disable wrap-iife, func-names, space-before-function-paren, comma-dangle, prefer-template, consistent-return, class-methods-use-this, arrow-body-style, no-unused-vars, no-underscore-dangle, no-new, max-len, no-sequences, no-unused-expressions, no-param-reassign */
/* global dateFormat */
import Pikaday from 'pikaday';
-import DateFix from './lib/utils/datefix';
+import { parsePikadayDate, pikadayToString } from './lib/utils/datefix';
class DueDateSelect {
constructor({ $dropdown, $loading } = {}) {
@@ -17,8 +16,8 @@ class DueDateSelect {
this.$value = $block.find('.value');
this.$valueContent = $block.find('.value-content');
this.$sidebarValue = $('.js-due-date-sidebar-value', $block);
- this.fieldName = $dropdown.data('field-name'),
- this.abilityName = $dropdown.data('ability-name'),
+ this.fieldName = $dropdown.data('field-name');
+ this.abilityName = $dropdown.data('ability-name');
this.issueUpdateURL = $dropdown.data('issue-update');
this.rawSelectedDate = null;
@@ -39,20 +38,20 @@ class DueDateSelect {
hidden: () => {
this.$selectbox.hide();
this.$value.css('display', '');
- }
+ },
});
}
initDatePicker() {
const $dueDateInput = $(`input[name='${this.fieldName}']`);
- const dateFix = DateFix.dashedFix($dueDateInput.val());
const calendar = new Pikaday({
field: $dueDateInput.get(0),
theme: 'gitlab-theme',
format: 'yyyy-mm-dd',
+ parse: dateString => parsePikadayDate(dateString),
+ toString: date => pikadayToString(date),
onSelect: (dateText) => {
- const formattedDate = dateFormat(new Date(dateText), 'yyyy-mm-dd');
- $dueDateInput.val(formattedDate);
+ $dueDateInput.val(calendar.toString(dateText));
if (this.$dropdown.hasClass('js-issue-boards-due-date')) {
gl.issueBoards.BoardsStore.detail.issue.dueDate = $dueDateInput.val();
@@ -60,10 +59,10 @@ class DueDateSelect {
} else {
this.saveDueDate(true);
}
- }
+ },
});
- calendar.setDate(dateFix);
+ calendar.setDate(parsePikadayDate($dueDateInput.val()));
this.$datePicker.append(calendar.el);
this.$datePicker.data('pikaday', calendar);
}
@@ -79,8 +78,8 @@ class DueDateSelect {
gl.issueBoards.BoardsStore.detail.issue.dueDate = '';
this.updateIssueBoardIssue();
} else {
- $("input[name='" + this.fieldName + "']").val('');
- return this.saveDueDate(false);
+ $(`input[name='${this.fieldName}']`).val('');
+ this.saveDueDate(false);
}
});
}
@@ -111,7 +110,7 @@ class DueDateSelect {
this.datePayload = datePayload;
}
- updateIssueBoardIssue () {
+ updateIssueBoardIssue() {
this.$loading.fadeIn();
this.$dropdown.trigger('loading.gl.dropdown');
this.$selectbox.hide();
@@ -149,8 +148,8 @@ class DueDateSelect {
return selectedDateValue.length ?
$('.js-remove-due-date-holder').removeClass('hidden') :
$('.js-remove-due-date-holder').addClass('hidden');
- }
- }).done((data) => {
+ },
+ }).done(() => {
if (isDropdown) {
this.$dropdown.trigger('loaded.gl.dropdown');
this.$dropdown.dropdown('toggle');
@@ -160,27 +159,28 @@ class DueDateSelect {
}
}
-class DueDateSelectors {
+export default class DueDateSelectors {
constructor() {
this.initMilestoneDatePicker();
this.initIssuableSelect();
}
-
+ // eslint-disable-next-line class-methods-use-this
initMilestoneDatePicker() {
- $('.datepicker').each(function() {
+ $('.datepicker').each(function initPikadayMilestone() {
const $datePicker = $(this);
- const dateFix = DateFix.dashedFix($datePicker.val());
const calendar = new Pikaday({
field: $datePicker.get(0),
theme: 'gitlab-theme animate-picker',
format: 'yyyy-mm-dd',
container: $datePicker.parent().get(0),
+ parse: dateString => parsePikadayDate(dateString),
+ toString: date => pikadayToString(date),
onSelect(dateText) {
- $datePicker.val(dateFormat(new Date(dateText), 'yyyy-mm-dd'));
- }
+ $datePicker.val(calendar.toString(dateText));
+ },
});
- calendar.setDate(dateFix);
+ calendar.setDate(parsePikadayDate($datePicker.val()));
$datePicker.data('pikaday', calendar);
});
@@ -191,19 +191,17 @@ class DueDateSelectors {
calendar.setDate(null);
});
}
-
+ // eslint-disable-next-line class-methods-use-this
initIssuableSelect() {
const $loading = $('.js-issuable-update .due_date').find('.block-loading').hide();
$('.js-due-date-select').each((i, dropdown) => {
const $dropdown = $(dropdown);
+ // eslint-disable-next-line no-new
new DueDateSelect({
$dropdown,
- $loading
+ $loading,
});
});
}
}
-
-window.gl = window.gl || {};
-window.gl.DueDateSelectors = DueDateSelectors;
diff --git a/app/assets/javascripts/init_issuable_sidebar.js b/app/assets/javascripts/init_issuable_sidebar.js
index 29e3d2ea94e..32a1a269f9a 100644
--- a/app/assets/javascripts/init_issuable_sidebar.js
+++ b/app/assets/javascripts/init_issuable_sidebar.js
@@ -4,6 +4,8 @@
/* global IssuableContext */
/* global Sidebar */
+import DueDateSelectors from './due_date_select';
+
export default () => {
const sidebarOptions = JSON.parse(document.querySelector('.js-sidebar-options').innerHTML);
@@ -13,6 +15,6 @@ export default () => {
new LabelsSelect();
new IssuableContext(sidebarOptions.currentUser);
gl.Subscription.bindAll('.subscription');
- new gl.DueDateSelectors();
+ new DueDateSelectors();
window.sidebar = new Sidebar();
};
diff --git a/app/assets/javascripts/issuable_form.js b/app/assets/javascripts/issuable_form.js
index 470c39c6f76..cd2562bc6a9 100644
--- a/app/assets/javascripts/issuable_form.js
+++ b/app/assets/javascripts/issuable_form.js
@@ -1,12 +1,12 @@
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-use-before-define, no-useless-escape, no-new, quotes, object-shorthand, no-unused-vars, comma-dangle, no-alert, consistent-return, no-else-return, prefer-template, one-var, one-var-declaration-per-line, curly, max-len */
/* global GitLab */
/* global Autosave */
-/* global dateFormat */
import Pikaday from 'pikaday';
import UsersSelect from './users_select';
import GfmAutoComplete from './gfm_auto_complete';
import ZenMode from './zen_mode';
+import { parsePikadayDate, pikadayToString } from './lib/utils/datefix';
(function() {
this.IssuableForm = (function() {
@@ -38,11 +38,13 @@ import ZenMode from './zen_mode';
theme: 'gitlab-theme animate-picker',
format: 'yyyy-mm-dd',
container: $issuableDueDate.parent().get(0),
+ parse: dateString => parsePikadayDate(dateString),
+ toString: date => pikadayToString(date),
onSelect: function(dateText) {
- $issuableDueDate.val(dateFormat(new Date(dateText), 'yyyy-mm-dd'));
+ $issuableDueDate.val(calendar.toString(dateText));
}
});
- calendar.setDate(new Date($issuableDueDate.val()));
+ calendar.setDate(parsePikadayDate($issuableDueDate.val()));
}
}
diff --git a/app/assets/javascripts/lib/utils/datefix.js b/app/assets/javascripts/lib/utils/datefix.js
index 990dc3f6d1a..e98c9068367 100644
--- a/app/assets/javascripts/lib/utils/datefix.js
+++ b/app/assets/javascripts/lib/utils/datefix.js
@@ -1,8 +1,29 @@
-const DateFix = {
- dashedFix(val) {
- const [y, m, d] = val.split('-');
- return new Date(y, m - 1, d);
- },
+
+export const pad = (val, len = 2) => (`0${val}`).slice(-len);
+
+/**
+ * Formats dates in Pickaday
+ * @param {String} dateString Date in yyyy-mm-dd format
+ * @return {Date} UTC format
+ */
+export const parsePikadayDate = (dateString) => {
+ const parts = dateString.split('-');
+ const year = parseInt(parts[0], 10);
+ const month = parseInt(parts[1] - 1, 10);
+ const day = parseInt(parts[2], 10);
+
+ return new Date(year, month, day);
};
-export default DateFix;
+/**
+ * Used `onSelect` method in pickaday
+ * @param {Date} date UTC format
+ * @return {String} Date formated in yyyy-mm-dd
+ */
+export const pikadayToString = (date) => {
+ const day = pad(date.getDate());
+ const month = pad(date.getMonth() + 1);
+ const year = date.getFullYear();
+
+ return `${year}-${month}-${day}`;
+};
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index 2fc47d5963b..4cf07e99161 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -51,8 +51,6 @@ import './confirm_danger_modal';
import './copy_as_gfm';
import './copy_to_clipboard';
import './diff';
-import './dropzone_input';
-import './due_date_select';
import './files_comment_button';
import Flash, { removeFlashClickListener } from './flash';
import './gl_dropdown';
diff --git a/app/assets/javascripts/member_expiration_date.js b/app/assets/javascripts/member_expiration_date.js
index 26b24fdafda..84e70e35bad 100644
--- a/app/assets/javascripts/member_expiration_date.js
+++ b/app/assets/javascripts/member_expiration_date.js
@@ -1,6 +1,5 @@
-/* global dateFormat */
-
import Pikaday from 'pikaday';
+import { parsePikadayDate, pikadayToString } from './lib/utils/datefix';
// Add datepickers to all `js-access-expiration-date` elements. If those elements are
// children of an element with the `clearable-input` class, and have a sibling
@@ -22,8 +21,10 @@ export default function memberExpirationDate(selector = '.js-access-expiration-d
format: 'yyyy-mm-dd',
minDate: new Date(),
container: $input.parent().get(0),
+ parse: dateString => parsePikadayDate(dateString),
+ toString: date => pikadayToString(date),
onSelect(dateText) {
- $input.val(dateFormat(new Date(dateText), 'yyyy-mm-dd'));
+ $input.val(calendar.toString(dateText));
$input.trigger('change');
@@ -31,7 +32,7 @@ export default function memberExpirationDate(selector = '.js-access-expiration-d
},
});
- calendar.setDate(new Date($input.val()));
+ calendar.setDate(parsePikadayDate($input.val()));
$input.data('pikaday', calendar);
});
diff --git a/changelogs/unreleased/38986-due-date.yml b/changelogs/unreleased/38986-due-date.yml
new file mode 100644
index 00000000000..7799b8d297e
--- /dev/null
+++ b/changelogs/unreleased/38986-due-date.yml
@@ -0,0 +1,5 @@
+---
+title: Fix timezone bug in Pikaday and upgrade Pikaday version
+merge_request:
+author:
+type: fixed
diff --git a/config/dependency_decisions.yml b/config/dependency_decisions.yml
index db31b01a7d2..3af7f7bd5c0 100644
--- a/config/dependency_decisions.yml
+++ b/config/dependency_decisions.yml
@@ -464,3 +464,10 @@
:why: Our own library - https://gitlab.com/gitlab-org/gitlab-svgs
:versions: []
:when: 2017-09-19 14:36:32.795496000 Z
+- - :license
+ - pikaday
+ - MIT
+ - :who:
+ :why:
+ :versions: []
+ :when: 2017-10-17 17:46:12.367554000 Z
diff --git a/package.json b/package.json
index 620b39766f4..057cd8f7bc7 100644
--- a/package.json
+++ b/package.json
@@ -46,7 +46,7 @@
"monaco-editor": "0.10.0",
"mousetrap": "^1.4.6",
"name-all-modules-plugin": "^1.0.1",
- "pikaday": "^1.5.1",
+ "pikaday": "^1.6.1",
"prismjs": "^1.6.0",
"raphael": "^2.2.7",
"raven-js": "^3.14.0",
diff --git a/spec/javascripts/lib/utils/datefix_spec.js b/spec/javascripts/lib/utils/datefix_spec.js
new file mode 100644
index 00000000000..0b9fde2be67
--- /dev/null
+++ b/spec/javascripts/lib/utils/datefix_spec.js
@@ -0,0 +1,29 @@
+import { pad, parsePikadayDate, pikadayToString } from '~/lib/utils/datefix';
+
+describe('datefix', () => {
+ describe('pad', () => {
+ it('should add a 0 when length is smaller than 2', () => {
+ expect(pad(2)).toEqual('02');
+ });
+
+ it('should not add a zero when lenght matches the default', () => {
+ expect(pad(12)).toEqual('12');
+ });
+
+ it('should add a 0 when lenght is smaller than the provided', () => {
+ expect(pad(12, 3)).toEqual('012');
+ });
+ });
+
+ describe('parsePikadayDate', () => {
+ it('should return a UTC date', () => {
+ expect(parsePikadayDate('2020-01-29')).toEqual(new Date('2020-01-29'));
+ });
+ });
+
+ describe('pikadayToString', () => {
+ it('should format a UTC date into yyyy-mm-dd format', () => {
+ expect(pikadayToString(new Date('2020-01-29'))).toEqual('2020-01-29');
+ });
+ });
+});
diff --git a/yarn.lock b/yarn.lock
index b830278eab0..91ffbe5d4b0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4677,9 +4677,9 @@ pify@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
-pikaday@^1.5.1:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/pikaday/-/pikaday-1.5.1.tgz#0a48549bc1a14ea1d08c44074d761bc2f2bfcfd3"
+pikaday@^1.6.1:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/pikaday/-/pikaday-1.6.1.tgz#b91bcb9b8539cedd8d6d08e4e7465e12095671b0"
optionalDependencies:
moment "2.x"