Merge branch '53055-combine-date-util-functions' into 'master'
Combine all datetime library functions into `datetime_utility.js` This MR moves datetime methods from `app/assets/javascripts/lib/utils/pretty_time.js` & `app/assets/javascripts/lib/utils/datefix.js` into `app/assets/javascripts/lib/utils/datetime_utility.js`. Closes #53055 See merge request gitlab-org/gitlab-ce!22570
This commit is contained in:
commit
86d8fd86a7
13 changed files with 381 additions and 382 deletions
|
@ -3,8 +3,7 @@ import Pikaday from 'pikaday';
|
|||
import dateFormat from 'dateformat';
|
||||
import { __ } from '~/locale';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import { timeFor } from './lib/utils/datetime_utility';
|
||||
import { parsePikadayDate, pikadayToString } from './lib/utils/datefix';
|
||||
import { timeFor, parsePikadayDate, pikadayToString } from './lib/utils/datetime_utility';
|
||||
import boardsStore from './boards/stores/boards_store';
|
||||
|
||||
class DueDateSelect {
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
/* eslint-disable no-new, no-unused-vars, consistent-return, no-else-return */
|
||||
/* global GitLab */
|
||||
|
||||
import $ from 'jquery';
|
||||
import Pikaday from 'pikaday';
|
||||
import Autosave from './autosave';
|
||||
|
@ -8,7 +5,7 @@ import UsersSelect from './users_select';
|
|||
import GfmAutoComplete from './gfm_auto_complete';
|
||||
import ZenMode from './zen_mode';
|
||||
import AutoWidthDropdownSelect from './issuable/auto_width_dropdown_select';
|
||||
import { parsePikadayDate, pikadayToString } from './lib/utils/datefix';
|
||||
import { parsePikadayDate, pikadayToString } from './lib/utils/datetime_utility';
|
||||
|
||||
export default class IssuableForm {
|
||||
constructor(form) {
|
||||
|
@ -19,9 +16,11 @@ export default class IssuableForm {
|
|||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.wipRegex = /^\s*(\[WIP\]\s*|WIP:\s*|WIP\s+)+\s*/i;
|
||||
|
||||
new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources).setup();
|
||||
new UsersSelect();
|
||||
new ZenMode();
|
||||
this.gfmAutoComplete = new GfmAutoComplete(
|
||||
gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources,
|
||||
).setup();
|
||||
this.usersSelect = new UsersSelect();
|
||||
this.zenMode = new ZenMode();
|
||||
|
||||
this.titleField = this.form.find('input[name*="[title]"]');
|
||||
this.descriptionField = this.form.find('textarea[name*="[description]"]');
|
||||
|
@ -57,8 +56,16 @@ export default class IssuableForm {
|
|||
}
|
||||
|
||||
initAutosave() {
|
||||
new Autosave(this.titleField, [document.location.pathname, document.location.search, 'title']);
|
||||
return new Autosave(this.descriptionField, [document.location.pathname, document.location.search, 'description']);
|
||||
this.autosave = new Autosave(this.titleField, [
|
||||
document.location.pathname,
|
||||
document.location.search,
|
||||
'title',
|
||||
]);
|
||||
return new Autosave(this.descriptionField, [
|
||||
document.location.pathname,
|
||||
document.location.search,
|
||||
'description',
|
||||
]);
|
||||
}
|
||||
|
||||
handleSubmit() {
|
||||
|
@ -74,7 +81,7 @@ export default class IssuableForm {
|
|||
this.$wipExplanation = this.form.find('.js-wip-explanation');
|
||||
this.$noWipExplanation = this.form.find('.js-no-wip-explanation');
|
||||
if (!(this.$wipExplanation.length && this.$noWipExplanation.length)) {
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
this.form.on('click', '.js-toggle-wip', this.toggleWip);
|
||||
this.titleField.on('keyup blur', this.renderWipExplanation);
|
||||
|
@ -89,10 +96,9 @@ export default class IssuableForm {
|
|||
if (this.workInProgress()) {
|
||||
this.$wipExplanation.show();
|
||||
return this.$noWipExplanation.hide();
|
||||
} else {
|
||||
this.$wipExplanation.hide();
|
||||
return this.$noWipExplanation.show();
|
||||
}
|
||||
this.$wipExplanation.hide();
|
||||
return this.$noWipExplanation.show();
|
||||
}
|
||||
|
||||
toggleWip(event) {
|
||||
|
@ -110,7 +116,7 @@ export default class IssuableForm {
|
|||
}
|
||||
|
||||
addWip() {
|
||||
this.titleField.val(`WIP: ${(this.titleField.val())}`);
|
||||
this.titleField.val(`WIP: ${this.titleField.val()}`);
|
||||
}
|
||||
|
||||
initTargetBranchDropdown() {
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
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);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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}`;
|
||||
};
|
|
@ -1,4 +1,5 @@
|
|||
import $ from 'jquery';
|
||||
import _ from 'underscore';
|
||||
import timeago from 'timeago.js';
|
||||
import dateFormat from 'dateformat';
|
||||
import { pluralize } from './text_utility';
|
||||
|
@ -46,6 +47,8 @@ const getMonthNames = abbreviated => {
|
|||
];
|
||||
};
|
||||
|
||||
export const pad = (val, len = 2) => `0${val}`.slice(-len);
|
||||
|
||||
/**
|
||||
* Given a date object returns the day of the week in English
|
||||
* @param {date} date
|
||||
|
@ -74,10 +77,10 @@ let timeagoInstance;
|
|||
/**
|
||||
* Sets a timeago Instance
|
||||
*/
|
||||
export function getTimeago() {
|
||||
export const getTimeago = () => {
|
||||
if (!timeagoInstance) {
|
||||
const localeRemaining = function getLocaleRemaining(number, index) {
|
||||
return [
|
||||
const localeRemaining = (number, index) =>
|
||||
[
|
||||
[s__('Timeago|just now'), s__('Timeago|right now')],
|
||||
[s__('Timeago|%s seconds ago'), s__('Timeago|%s seconds remaining')],
|
||||
[s__('Timeago|1 minute ago'), s__('Timeago|1 minute remaining')],
|
||||
|
@ -93,9 +96,9 @@ export function getTimeago() {
|
|||
[s__('Timeago|1 year ago'), s__('Timeago|1 year remaining')],
|
||||
[s__('Timeago|%s years ago'), s__('Timeago|%s years remaining')],
|
||||
][index];
|
||||
};
|
||||
const locale = function getLocale(number, index) {
|
||||
return [
|
||||
|
||||
const locale = (number, index) =>
|
||||
[
|
||||
[s__('Timeago|just now'), s__('Timeago|right now')],
|
||||
[s__('Timeago|%s seconds ago'), s__('Timeago|in %s seconds')],
|
||||
[s__('Timeago|1 minute ago'), s__('Timeago|in 1 minute')],
|
||||
|
@ -111,7 +114,6 @@ export function getTimeago() {
|
|||
[s__('Timeago|1 year ago'), s__('Timeago|in 1 year')],
|
||||
[s__('Timeago|%s years ago'), s__('Timeago|in %s years')],
|
||||
][index];
|
||||
};
|
||||
|
||||
timeago.register(timeagoLanguageCode, locale);
|
||||
timeago.register(`${timeagoLanguageCode}-remaining`, localeRemaining);
|
||||
|
@ -119,7 +121,7 @@ export function getTimeago() {
|
|||
}
|
||||
|
||||
return timeagoInstance;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* For the given element, renders a timeago instance.
|
||||
|
@ -184,7 +186,7 @@ export const getDayDifference = (a, b) => {
|
|||
* @param {Number} seconds
|
||||
* @return {String}
|
||||
*/
|
||||
export function timeIntervalInWords(intervalInSeconds) {
|
||||
export const timeIntervalInWords = intervalInSeconds => {
|
||||
const secondsInteger = parseInt(intervalInSeconds, 10);
|
||||
const minutes = Math.floor(secondsInteger / 60);
|
||||
const seconds = secondsInteger - minutes * 60;
|
||||
|
@ -196,9 +198,9 @@ export function timeIntervalInWords(intervalInSeconds) {
|
|||
text = `${seconds} ${pluralize('second', seconds)}`;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
};
|
||||
|
||||
export function dateInWords(date, abbreviated = false, hideYear = false) {
|
||||
export const dateInWords = (date, abbreviated = false, hideYear = false) => {
|
||||
if (!date) return date;
|
||||
|
||||
const month = date.getMonth();
|
||||
|
@ -240,7 +242,7 @@ export function dateInWords(date, abbreviated = false, hideYear = false) {
|
|||
}
|
||||
|
||||
return `${monthName} ${date.getDate()}, ${year}`;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns month name based on provided date.
|
||||
|
@ -391,3 +393,83 @@ export const formatTime = milliseconds => {
|
|||
formattedTime += remainingSeconds;
|
||||
return formattedTime;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Accepts seconds and returns a timeObject { weeks: #, days: #, hours: #, minutes: # }
|
||||
* Seconds can be negative or positive, zero or non-zero. Can be configured for any day
|
||||
* or week length.
|
||||
*/
|
||||
export const parseSeconds = (seconds, { daysPerWeek = 5, hoursPerDay = 8 } = {}) => {
|
||||
const DAYS_PER_WEEK = daysPerWeek;
|
||||
const HOURS_PER_DAY = hoursPerDay;
|
||||
const MINUTES_PER_HOUR = 60;
|
||||
const MINUTES_PER_WEEK = DAYS_PER_WEEK * HOURS_PER_DAY * MINUTES_PER_HOUR;
|
||||
const MINUTES_PER_DAY = HOURS_PER_DAY * MINUTES_PER_HOUR;
|
||||
|
||||
const timePeriodConstraints = {
|
||||
weeks: MINUTES_PER_WEEK,
|
||||
days: MINUTES_PER_DAY,
|
||||
hours: MINUTES_PER_HOUR,
|
||||
minutes: 1,
|
||||
};
|
||||
|
||||
let unorderedMinutes = Math.abs(seconds / MINUTES_PER_HOUR);
|
||||
|
||||
return _.mapObject(timePeriodConstraints, minutesPerPeriod => {
|
||||
const periodCount = Math.floor(unorderedMinutes / minutesPerPeriod);
|
||||
|
||||
unorderedMinutes -= periodCount * minutesPerPeriod;
|
||||
|
||||
return periodCount;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Accepts a timeObject (see parseSeconds) and returns a condensed string representation of it
|
||||
* (e.g. '1w 2d 3h 1m' or '1h 30m'). Zero value units are not included.
|
||||
*/
|
||||
export const stringifyTime = timeObject => {
|
||||
const reducedTime = _.reduce(
|
||||
timeObject,
|
||||
(memo, unitValue, unitName) => {
|
||||
const isNonZero = !!unitValue;
|
||||
return isNonZero ? `${memo} ${unitValue}${unitName.charAt(0)}` : memo;
|
||||
},
|
||||
'',
|
||||
).trim();
|
||||
return reducedTime.length ? reducedTime : '0m';
|
||||
};
|
||||
|
||||
/**
|
||||
* Accepts a time string of any size (e.g. '1w 2d 3h 5m' or '1w 2d') and returns
|
||||
* the first non-zero unit/value pair.
|
||||
*/
|
||||
export const abbreviateTime = timeStr =>
|
||||
timeStr.split(' ').filter(unitStr => unitStr.charAt(0) !== '0')[0];
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
import _ from 'underscore';
|
||||
|
||||
/*
|
||||
* TODO: Make these methods more configurable (e.g. stringifyTime condensed or
|
||||
* non-condensed, abbreviateTimelengths)
|
||||
* */
|
||||
|
||||
/*
|
||||
* Accepts seconds and returns a timeObject { weeks: #, days: #, hours: #, minutes: # }
|
||||
* Seconds can be negative or positive, zero or non-zero. Can be configured for any day
|
||||
* or week length.
|
||||
*/
|
||||
|
||||
export function parseSeconds(seconds, { daysPerWeek = 5, hoursPerDay = 8 } = {}) {
|
||||
const DAYS_PER_WEEK = daysPerWeek;
|
||||
const HOURS_PER_DAY = hoursPerDay;
|
||||
const MINUTES_PER_HOUR = 60;
|
||||
const MINUTES_PER_WEEK = DAYS_PER_WEEK * HOURS_PER_DAY * MINUTES_PER_HOUR;
|
||||
const MINUTES_PER_DAY = HOURS_PER_DAY * MINUTES_PER_HOUR;
|
||||
|
||||
const timePeriodConstraints = {
|
||||
weeks: MINUTES_PER_WEEK,
|
||||
days: MINUTES_PER_DAY,
|
||||
hours: MINUTES_PER_HOUR,
|
||||
minutes: 1,
|
||||
};
|
||||
|
||||
let unorderedMinutes = Math.abs(seconds / MINUTES_PER_HOUR);
|
||||
|
||||
return _.mapObject(timePeriodConstraints, minutesPerPeriod => {
|
||||
const periodCount = Math.floor(unorderedMinutes / minutesPerPeriod);
|
||||
|
||||
unorderedMinutes -= periodCount * minutesPerPeriod;
|
||||
|
||||
return periodCount;
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Accepts a timeObject (see parseSeconds) and returns a condensed string representation of it
|
||||
* (e.g. '1w 2d 3h 1m' or '1h 30m'). Zero value units are not included.
|
||||
*/
|
||||
|
||||
export function stringifyTime(timeObject) {
|
||||
const reducedTime = _.reduce(
|
||||
timeObject,
|
||||
(memo, unitValue, unitName) => {
|
||||
const isNonZero = !!unitValue;
|
||||
return isNonZero ? `${memo} ${unitValue}${unitName.charAt(0)}` : memo;
|
||||
},
|
||||
'',
|
||||
).trim();
|
||||
return reducedTime.length ? reducedTime : '0m';
|
||||
}
|
||||
|
||||
/*
|
||||
* Accepts a time string of any size (e.g. '1w 2d 3h 5m' or '1w 2d') and returns
|
||||
* the first non-zero unit/value pair.
|
||||
*/
|
||||
|
||||
export function abbreviateTime(timeStr) {
|
||||
return timeStr.split(' ').filter(unitStr => unitStr.charAt(0) !== '0')[0];
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import $ from 'jquery';
|
||||
import Pikaday from 'pikaday';
|
||||
import { parsePikadayDate, pikadayToString } from './lib/utils/datefix';
|
||||
import { parsePikadayDate, pikadayToString } from './lib/utils/datetime_utility';
|
||||
|
||||
// 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
|
||||
|
|
|
@ -1,111 +1,111 @@
|
|||
<script>
|
||||
import { __, sprintf } from '~/locale';
|
||||
import { abbreviateTime } from '~/lib/utils/pretty_time';
|
||||
import icon from '~/vue_shared/components/icon.vue';
|
||||
import tooltip from '~/vue_shared/directives/tooltip';
|
||||
import { __, sprintf } from '~/locale';
|
||||
import { abbreviateTime } from '~/lib/utils/datetime_utility';
|
||||
import icon from '~/vue_shared/components/icon.vue';
|
||||
import tooltip from '~/vue_shared/directives/tooltip';
|
||||
|
||||
export default {
|
||||
name: 'TimeTrackingCollapsedState',
|
||||
components: {
|
||||
icon,
|
||||
export default {
|
||||
name: 'TimeTrackingCollapsedState',
|
||||
components: {
|
||||
icon,
|
||||
},
|
||||
directives: {
|
||||
tooltip,
|
||||
},
|
||||
props: {
|
||||
showComparisonState: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
directives: {
|
||||
tooltip,
|
||||
showSpentOnlyState: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
props: {
|
||||
showComparisonState: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
showSpentOnlyState: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
showEstimateOnlyState: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
showNoTimeTrackingState: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
timeSpentHumanReadable: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
timeEstimateHumanReadable: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
showEstimateOnlyState: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
computed: {
|
||||
timeSpent() {
|
||||
return this.abbreviateTime(this.timeSpentHumanReadable);
|
||||
},
|
||||
timeEstimate() {
|
||||
return this.abbreviateTime(this.timeEstimateHumanReadable);
|
||||
},
|
||||
divClass() {
|
||||
if (this.showComparisonState) {
|
||||
return 'compare';
|
||||
} else if (this.showEstimateOnlyState) {
|
||||
return 'estimate-only';
|
||||
} else if (this.showSpentOnlyState) {
|
||||
return 'spend-only';
|
||||
} else if (this.showNoTimeTrackingState) {
|
||||
return 'no-tracking';
|
||||
}
|
||||
showNoTimeTrackingState: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
timeSpentHumanReadable: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
timeEstimateHumanReadable: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
timeSpent() {
|
||||
return this.abbreviateTime(this.timeSpentHumanReadable);
|
||||
},
|
||||
timeEstimate() {
|
||||
return this.abbreviateTime(this.timeEstimateHumanReadable);
|
||||
},
|
||||
divClass() {
|
||||
if (this.showComparisonState) {
|
||||
return 'compare';
|
||||
} else if (this.showEstimateOnlyState) {
|
||||
return 'estimate-only';
|
||||
} else if (this.showSpentOnlyState) {
|
||||
return 'spend-only';
|
||||
} else if (this.showNoTimeTrackingState) {
|
||||
return 'no-tracking';
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
spanClass() {
|
||||
if (this.showComparisonState) {
|
||||
return '';
|
||||
},
|
||||
spanClass() {
|
||||
if (this.showComparisonState) {
|
||||
return '';
|
||||
} else if (this.showEstimateOnlyState || this.showSpentOnlyState) {
|
||||
return 'bold';
|
||||
} else if (this.showNoTimeTrackingState) {
|
||||
return 'no-value';
|
||||
}
|
||||
} else if (this.showEstimateOnlyState || this.showSpentOnlyState) {
|
||||
return 'bold';
|
||||
} else if (this.showNoTimeTrackingState) {
|
||||
return 'no-value';
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
text() {
|
||||
if (this.showComparisonState) {
|
||||
return `${this.timeSpent} / ${this.timeEstimate}`;
|
||||
} else if (this.showEstimateOnlyState) {
|
||||
return `-- / ${this.timeEstimate}`;
|
||||
} else if (this.showSpentOnlyState) {
|
||||
return `${this.timeSpent} / --`;
|
||||
} else if (this.showNoTimeTrackingState) {
|
||||
return 'None';
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
timeTrackedTooltipText() {
|
||||
let title;
|
||||
if (this.showComparisonState) {
|
||||
title = __('Time remaining');
|
||||
} else if (this.showEstimateOnlyState) {
|
||||
title = __('Estimated');
|
||||
} else if (this.showSpentOnlyState) {
|
||||
title = __('Time spent');
|
||||
}
|
||||
|
||||
return sprintf('%{title}: %{text}', ({ title, text: this.text }));
|
||||
},
|
||||
tooltipText() {
|
||||
return this.showNoTimeTrackingState ? __('Time tracking') : this.timeTrackedTooltipText;
|
||||
},
|
||||
return '';
|
||||
},
|
||||
methods: {
|
||||
abbreviateTime(timeStr) {
|
||||
return abbreviateTime(timeStr);
|
||||
},
|
||||
text() {
|
||||
if (this.showComparisonState) {
|
||||
return `${this.timeSpent} / ${this.timeEstimate}`;
|
||||
} else if (this.showEstimateOnlyState) {
|
||||
return `-- / ${this.timeEstimate}`;
|
||||
} else if (this.showSpentOnlyState) {
|
||||
return `${this.timeSpent} / --`;
|
||||
} else if (this.showNoTimeTrackingState) {
|
||||
return 'None';
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
};
|
||||
timeTrackedTooltipText() {
|
||||
let title;
|
||||
if (this.showComparisonState) {
|
||||
title = __('Time remaining');
|
||||
} else if (this.showEstimateOnlyState) {
|
||||
title = __('Estimated');
|
||||
} else if (this.showSpentOnlyState) {
|
||||
title = __('Time spent');
|
||||
}
|
||||
|
||||
return sprintf('%{title}: %{text}', { title, text: this.text });
|
||||
},
|
||||
tooltipText() {
|
||||
return this.showNoTimeTrackingState ? __('Time tracking') : this.timeTrackedTooltipText;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
abbreviateTime(timeStr) {
|
||||
return abbreviateTime(timeStr);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { parseSeconds, stringifyTime } from '../../../lib/utils/pretty_time';
|
||||
import { parseSeconds, stringifyTime } from '~/lib/utils/datetime_utility';
|
||||
import tooltip from '../../../vue_shared/directives/tooltip';
|
||||
|
||||
export default {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import Pikaday from 'pikaday';
|
||||
import { parsePikadayDate, pikadayToString } from '../../lib/utils/datefix';
|
||||
import { parsePikadayDate, pikadayToString } from '~/lib/utils/datetime_utility';
|
||||
|
||||
export default {
|
||||
name: 'DatePicker',
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Combine all datetime library functions into 'datetime_utility.js'
|
||||
merge_request: 22570
|
||||
author:
|
||||
type: other
|
|
@ -192,3 +192,163 @@ describe('formatTime', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('datefix', () => {
|
||||
describe('pad', () => {
|
||||
it('should add a 0 when length is smaller than 2', () => {
|
||||
expect(datetimeUtility.pad(2)).toEqual('02');
|
||||
});
|
||||
|
||||
it('should not add a zero when lenght matches the default', () => {
|
||||
expect(datetimeUtility.pad(12)).toEqual('12');
|
||||
});
|
||||
|
||||
it('should add a 0 when lenght is smaller than the provided', () => {
|
||||
expect(datetimeUtility.pad(12, 3)).toEqual('012');
|
||||
});
|
||||
});
|
||||
|
||||
describe('parsePikadayDate', () => {
|
||||
// removed because of https://gitlab.com/gitlab-org/gitlab-ce/issues/39834
|
||||
});
|
||||
|
||||
describe('pikadayToString', () => {
|
||||
it('should format a UTC date into yyyy-mm-dd format', () => {
|
||||
expect(datetimeUtility.pikadayToString(new Date('2020-01-29:00:00'))).toEqual('2020-01-29');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('prettyTime methods', () => {
|
||||
const assertTimeUnits = (obj, minutes, hours, days, weeks) => {
|
||||
expect(obj.minutes).toBe(minutes);
|
||||
expect(obj.hours).toBe(hours);
|
||||
expect(obj.days).toBe(days);
|
||||
expect(obj.weeks).toBe(weeks);
|
||||
};
|
||||
|
||||
describe('parseSeconds', () => {
|
||||
it('should correctly parse a negative value', () => {
|
||||
const zeroSeconds = datetimeUtility.parseSeconds(-1000);
|
||||
|
||||
assertTimeUnits(zeroSeconds, 16, 0, 0, 0);
|
||||
});
|
||||
|
||||
it('should correctly parse a zero value', () => {
|
||||
const zeroSeconds = datetimeUtility.parseSeconds(0);
|
||||
|
||||
assertTimeUnits(zeroSeconds, 0, 0, 0, 0);
|
||||
});
|
||||
|
||||
it('should correctly parse a small non-zero second values', () => {
|
||||
const subOneMinute = datetimeUtility.parseSeconds(10);
|
||||
const aboveOneMinute = datetimeUtility.parseSeconds(100);
|
||||
const manyMinutes = datetimeUtility.parseSeconds(1000);
|
||||
|
||||
assertTimeUnits(subOneMinute, 0, 0, 0, 0);
|
||||
assertTimeUnits(aboveOneMinute, 1, 0, 0, 0);
|
||||
assertTimeUnits(manyMinutes, 16, 0, 0, 0);
|
||||
});
|
||||
|
||||
it('should correctly parse large second values', () => {
|
||||
const aboveOneHour = datetimeUtility.parseSeconds(4800);
|
||||
const aboveOneDay = datetimeUtility.parseSeconds(110000);
|
||||
const aboveOneWeek = datetimeUtility.parseSeconds(25000000);
|
||||
|
||||
assertTimeUnits(aboveOneHour, 20, 1, 0, 0);
|
||||
assertTimeUnits(aboveOneDay, 33, 6, 3, 0);
|
||||
assertTimeUnits(aboveOneWeek, 26, 0, 3, 173);
|
||||
});
|
||||
|
||||
it('should correctly accept a custom param for hoursPerDay', () => {
|
||||
const config = { hoursPerDay: 24 };
|
||||
|
||||
const aboveOneHour = datetimeUtility.parseSeconds(4800, config);
|
||||
const aboveOneDay = datetimeUtility.parseSeconds(110000, config);
|
||||
const aboveOneWeek = datetimeUtility.parseSeconds(25000000, config);
|
||||
|
||||
assertTimeUnits(aboveOneHour, 20, 1, 0, 0);
|
||||
assertTimeUnits(aboveOneDay, 33, 6, 1, 0);
|
||||
assertTimeUnits(aboveOneWeek, 26, 8, 4, 57);
|
||||
});
|
||||
|
||||
it('should correctly accept a custom param for daysPerWeek', () => {
|
||||
const config = { daysPerWeek: 7 };
|
||||
|
||||
const aboveOneHour = datetimeUtility.parseSeconds(4800, config);
|
||||
const aboveOneDay = datetimeUtility.parseSeconds(110000, config);
|
||||
const aboveOneWeek = datetimeUtility.parseSeconds(25000000, config);
|
||||
|
||||
assertTimeUnits(aboveOneHour, 20, 1, 0, 0);
|
||||
assertTimeUnits(aboveOneDay, 33, 6, 3, 0);
|
||||
assertTimeUnits(aboveOneWeek, 26, 0, 0, 124);
|
||||
});
|
||||
|
||||
it('should correctly accept custom params for daysPerWeek and hoursPerDay', () => {
|
||||
const config = { daysPerWeek: 55, hoursPerDay: 14 };
|
||||
|
||||
const aboveOneHour = datetimeUtility.parseSeconds(4800, config);
|
||||
const aboveOneDay = datetimeUtility.parseSeconds(110000, config);
|
||||
const aboveOneWeek = datetimeUtility.parseSeconds(25000000, config);
|
||||
|
||||
assertTimeUnits(aboveOneHour, 20, 1, 0, 0);
|
||||
assertTimeUnits(aboveOneDay, 33, 2, 2, 0);
|
||||
assertTimeUnits(aboveOneWeek, 26, 0, 1, 9);
|
||||
});
|
||||
});
|
||||
|
||||
describe('stringifyTime', () => {
|
||||
it('should stringify values with all non-zero units', () => {
|
||||
const timeObject = {
|
||||
weeks: 1,
|
||||
days: 4,
|
||||
hours: 7,
|
||||
minutes: 20,
|
||||
};
|
||||
|
||||
const timeString = datetimeUtility.stringifyTime(timeObject);
|
||||
|
||||
expect(timeString).toBe('1w 4d 7h 20m');
|
||||
});
|
||||
|
||||
it('should stringify values with some non-zero units', () => {
|
||||
const timeObject = {
|
||||
weeks: 0,
|
||||
days: 4,
|
||||
hours: 0,
|
||||
minutes: 20,
|
||||
};
|
||||
|
||||
const timeString = datetimeUtility.stringifyTime(timeObject);
|
||||
|
||||
expect(timeString).toBe('4d 20m');
|
||||
});
|
||||
|
||||
it('should stringify values with no non-zero units', () => {
|
||||
const timeObject = {
|
||||
weeks: 0,
|
||||
days: 0,
|
||||
hours: 0,
|
||||
minutes: 0,
|
||||
};
|
||||
|
||||
const timeString = datetimeUtility.stringifyTime(timeObject);
|
||||
|
||||
expect(timeString).toBe('0m');
|
||||
});
|
||||
});
|
||||
|
||||
describe('abbreviateTime', () => {
|
||||
it('should abbreviate stringified times for weeks', () => {
|
||||
const fullTimeString = '1w 3d 4h 5m';
|
||||
|
||||
expect(datetimeUtility.abbreviateTime(fullTimeString)).toBe('1w');
|
||||
});
|
||||
|
||||
it('should abbreviate stringified times for non-weeks', () => {
|
||||
const fullTimeString = '0w 3d 4h 5m';
|
||||
|
||||
expect(datetimeUtility.abbreviateTime(fullTimeString)).toBe('3d');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
import { pad, 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', () => {
|
||||
// removed because of https://gitlab.com/gitlab-org/gitlab-ce/issues/39834
|
||||
});
|
||||
|
||||
describe('pikadayToString', () => {
|
||||
it('should format a UTC date into yyyy-mm-dd format', () => {
|
||||
expect(pikadayToString(new Date('2020-01-29:00:00'))).toEqual('2020-01-29');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,135 +0,0 @@
|
|||
import { parseSeconds, abbreviateTime, stringifyTime } from '~/lib/utils/pretty_time';
|
||||
|
||||
function assertTimeUnits(obj, minutes, hours, days, weeks) {
|
||||
expect(obj.minutes).toBe(minutes);
|
||||
expect(obj.hours).toBe(hours);
|
||||
expect(obj.days).toBe(days);
|
||||
expect(obj.weeks).toBe(weeks);
|
||||
}
|
||||
|
||||
describe('prettyTime methods', () => {
|
||||
describe('parseSeconds', () => {
|
||||
it('should correctly parse a negative value', () => {
|
||||
const zeroSeconds = parseSeconds(-1000);
|
||||
|
||||
assertTimeUnits(zeroSeconds, 16, 0, 0, 0);
|
||||
});
|
||||
|
||||
it('should correctly parse a zero value', () => {
|
||||
const zeroSeconds = parseSeconds(0);
|
||||
|
||||
assertTimeUnits(zeroSeconds, 0, 0, 0, 0);
|
||||
});
|
||||
|
||||
it('should correctly parse a small non-zero second values', () => {
|
||||
const subOneMinute = parseSeconds(10);
|
||||
const aboveOneMinute = parseSeconds(100);
|
||||
const manyMinutes = parseSeconds(1000);
|
||||
|
||||
assertTimeUnits(subOneMinute, 0, 0, 0, 0);
|
||||
assertTimeUnits(aboveOneMinute, 1, 0, 0, 0);
|
||||
assertTimeUnits(manyMinutes, 16, 0, 0, 0);
|
||||
});
|
||||
|
||||
it('should correctly parse large second values', () => {
|
||||
const aboveOneHour = parseSeconds(4800);
|
||||
const aboveOneDay = parseSeconds(110000);
|
||||
const aboveOneWeek = parseSeconds(25000000);
|
||||
|
||||
assertTimeUnits(aboveOneHour, 20, 1, 0, 0);
|
||||
assertTimeUnits(aboveOneDay, 33, 6, 3, 0);
|
||||
assertTimeUnits(aboveOneWeek, 26, 0, 3, 173);
|
||||
});
|
||||
|
||||
it('should correctly accept a custom param for hoursPerDay', () => {
|
||||
const config = { hoursPerDay: 24 };
|
||||
|
||||
const aboveOneHour = parseSeconds(4800, config);
|
||||
const aboveOneDay = parseSeconds(110000, config);
|
||||
const aboveOneWeek = parseSeconds(25000000, config);
|
||||
|
||||
assertTimeUnits(aboveOneHour, 20, 1, 0, 0);
|
||||
assertTimeUnits(aboveOneDay, 33, 6, 1, 0);
|
||||
assertTimeUnits(aboveOneWeek, 26, 8, 4, 57);
|
||||
});
|
||||
|
||||
it('should correctly accept a custom param for daysPerWeek', () => {
|
||||
const config = { daysPerWeek: 7 };
|
||||
|
||||
const aboveOneHour = parseSeconds(4800, config);
|
||||
const aboveOneDay = parseSeconds(110000, config);
|
||||
const aboveOneWeek = parseSeconds(25000000, config);
|
||||
|
||||
assertTimeUnits(aboveOneHour, 20, 1, 0, 0);
|
||||
assertTimeUnits(aboveOneDay, 33, 6, 3, 0);
|
||||
assertTimeUnits(aboveOneWeek, 26, 0, 0, 124);
|
||||
});
|
||||
|
||||
it('should correctly accept custom params for daysPerWeek and hoursPerDay', () => {
|
||||
const config = { daysPerWeek: 55, hoursPerDay: 14 };
|
||||
|
||||
const aboveOneHour = parseSeconds(4800, config);
|
||||
const aboveOneDay = parseSeconds(110000, config);
|
||||
const aboveOneWeek = parseSeconds(25000000, config);
|
||||
|
||||
assertTimeUnits(aboveOneHour, 20, 1, 0, 0);
|
||||
assertTimeUnits(aboveOneDay, 33, 2, 2, 0);
|
||||
assertTimeUnits(aboveOneWeek, 26, 0, 1, 9);
|
||||
});
|
||||
});
|
||||
|
||||
describe('stringifyTime', () => {
|
||||
it('should stringify values with all non-zero units', () => {
|
||||
const timeObject = {
|
||||
weeks: 1,
|
||||
days: 4,
|
||||
hours: 7,
|
||||
minutes: 20,
|
||||
};
|
||||
|
||||
const timeString = stringifyTime(timeObject);
|
||||
|
||||
expect(timeString).toBe('1w 4d 7h 20m');
|
||||
});
|
||||
|
||||
it('should stringify values with some non-zero units', () => {
|
||||
const timeObject = {
|
||||
weeks: 0,
|
||||
days: 4,
|
||||
hours: 0,
|
||||
minutes: 20,
|
||||
};
|
||||
|
||||
const timeString = stringifyTime(timeObject);
|
||||
|
||||
expect(timeString).toBe('4d 20m');
|
||||
});
|
||||
|
||||
it('should stringify values with no non-zero units', () => {
|
||||
const timeObject = {
|
||||
weeks: 0,
|
||||
days: 0,
|
||||
hours: 0,
|
||||
minutes: 0,
|
||||
};
|
||||
|
||||
const timeString = stringifyTime(timeObject);
|
||||
|
||||
expect(timeString).toBe('0m');
|
||||
});
|
||||
});
|
||||
|
||||
describe('abbreviateTime', () => {
|
||||
it('should abbreviate stringified times for weeks', () => {
|
||||
const fullTimeString = '1w 3d 4h 5m';
|
||||
|
||||
expect(abbreviateTime(fullTimeString)).toBe('1w');
|
||||
});
|
||||
|
||||
it('should abbreviate stringified times for non-weeks', () => {
|
||||
const fullTimeString = '0w 3d 4h 5m';
|
||||
|
||||
expect(abbreviateTime(fullTimeString)).toBe('3d');
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue