Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
c78607fa
Commit
c78607fa
authored
Oct 25, 2018
by
Kushal Pandya
Committed by
Filipa Lacerda
Oct 25, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
EE Port: Combine all datetime library functions into `datetime_utility.js`
parent
b8275cdc
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
482 additions
and
491 deletions
+482
-491
app/assets/javascripts/due_date_select.js
app/assets/javascripts/due_date_select.js
+1
-2
app/assets/javascripts/issuable_form.js
app/assets/javascripts/issuable_form.js
+20
-14
app/assets/javascripts/lib/utils/datefix.js
app/assets/javascripts/lib/utils/datefix.js
+0
-28
app/assets/javascripts/lib/utils/datetime_utility.js
app/assets/javascripts/lib/utils/datetime_utility.js
+94
-12
app/assets/javascripts/lib/utils/pretty_time.js
app/assets/javascripts/lib/utils/pretty_time.js
+0
-63
app/assets/javascripts/member_expiration_date.js
app/assets/javascripts/member_expiration_date.js
+1
-1
app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue
...ipts/sidebar/components/time_tracking/collapsed_state.vue
+96
-96
app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue
...ipts/sidebar/components/time_tracking/comparison_pane.vue
+1
-1
app/assets/javascripts/vue_shared/components/pikaday.vue
app/assets/javascripts/vue_shared/components/pikaday.vue
+1
-1
ee/app/assets/javascripts/epics/sidebar/stores/sidebar_store.js
.../assets/javascripts/epics/sidebar/stores/sidebar_store.js
+1
-1
ee/app/assets/javascripts/geo_nodes/components/node_detail_sections/node_details_section_sync.vue
...onents/node_detail_sections/node_details_section_sync.vue
+106
-109
ee/app/assets/javascripts/roadmap/store/roadmap_store.js
ee/app/assets/javascripts/roadmap/store/roadmap_store.js
+1
-1
spec/javascripts/datetime_utility_spec.js
spec/javascripts/datetime_utility_spec.js
+160
-0
spec/javascripts/lib/utils/datefix_spec.js
spec/javascripts/lib/utils/datefix_spec.js
+0
-27
spec/javascripts/pretty_time_spec.js
spec/javascripts/pretty_time_spec.js
+0
-135
No files found.
app/assets/javascripts/due_date_select.js
View file @
c78607fa
...
@@ -3,8 +3,7 @@ import Pikaday from 'pikaday';
...
@@ -3,8 +3,7 @@ import Pikaday from 'pikaday';
import
dateFormat
from
'
dateformat
'
;
import
dateFormat
from
'
dateformat
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
__
}
from
'
~/locale
'
;
import
axios
from
'
./lib/utils/axios_utils
'
;
import
axios
from
'
./lib/utils/axios_utils
'
;
import
{
timeFor
}
from
'
./lib/utils/datetime_utility
'
;
import
{
timeFor
,
parsePikadayDate
,
pikadayToString
}
from
'
./lib/utils/datetime_utility
'
;
import
{
parsePikadayDate
,
pikadayToString
}
from
'
./lib/utils/datefix
'
;
import
boardsStore
from
'
./boards/stores/boards_store
'
;
import
boardsStore
from
'
./boards/stores/boards_store
'
;
class
DueDateSelect
{
class
DueDateSelect
{
...
...
app/assets/javascripts/issuable_form.js
View file @
c78607fa
/* eslint-disable no-new, no-unused-vars, consistent-return, no-else-return */
/* global GitLab */
import
$
from
'
jquery
'
;
import
$
from
'
jquery
'
;
import
Pikaday
from
'
pikaday
'
;
import
Pikaday
from
'
pikaday
'
;
import
Autosave
from
'
./autosave
'
;
import
Autosave
from
'
./autosave
'
;
...
@@ -8,7 +5,7 @@ import UsersSelect from './users_select';
...
@@ -8,7 +5,7 @@ import UsersSelect from './users_select';
import
GfmAutoComplete
from
'
./gfm_auto_complete
'
;
import
GfmAutoComplete
from
'
./gfm_auto_complete
'
;
import
ZenMode
from
'
./zen_mode
'
;
import
ZenMode
from
'
./zen_mode
'
;
import
AutoWidthDropdownSelect
from
'
./issuable/auto_width_dropdown_select
'
;
import
AutoWidthDropdownSelect
from
'
./issuable/auto_width_dropdown_select
'
;
import
{
parsePikadayDate
,
pikadayToString
}
from
'
./lib/utils/date
fix
'
;
import
{
parsePikadayDate
,
pikadayToString
}
from
'
./lib/utils/date
time_utility
'
;
import
groupsSelect
from
'
./groups_select
'
;
import
groupsSelect
from
'
./groups_select
'
;
export
default
class
IssuableForm
{
export
default
class
IssuableForm
{
...
@@ -20,10 +17,12 @@ export default class IssuableForm {
...
@@ -20,10 +17,12 @@ export default class IssuableForm {
this
.
handleSubmit
=
this
.
handleSubmit
.
bind
(
this
);
this
.
handleSubmit
=
this
.
handleSubmit
.
bind
(
this
);
this
.
wipRegex
=
/^
\s
*
(\[
WIP
\]\s
*|WIP:
\s
*|WIP
\s
+
)
+
\s
*/i
;
this
.
wipRegex
=
/^
\s
*
(\[
WIP
\]\s
*|WIP:
\s
*|WIP
\s
+
)
+
\s
*/i
;
new
GfmAutoComplete
(
gl
.
GfmAutoComplete
&&
gl
.
GfmAutoComplete
.
dataSources
).
setup
();
this
.
gfmAutoComplete
=
new
GfmAutoComplete
(
new
UsersSelect
();
gl
.
GfmAutoComplete
&&
gl
.
GfmAutoComplete
.
dataSources
,
).
setup
();
this
.
usersSelect
=
new
UsersSelect
();
groupsSelect
();
groupsSelect
();
new
ZenMode
();
this
.
zenMode
=
new
ZenMode
();
this
.
titleField
=
this
.
form
.
find
(
'
input[name*="[title]"]
'
);
this
.
titleField
=
this
.
form
.
find
(
'
input[name*="[title]"]
'
);
this
.
descriptionField
=
this
.
form
.
find
(
'
textarea[name*="[description]"]
'
);
this
.
descriptionField
=
this
.
form
.
find
(
'
textarea[name*="[description]"]
'
);
...
@@ -59,8 +58,16 @@ export default class IssuableForm {
...
@@ -59,8 +58,16 @@ export default class IssuableForm {
}
}
initAutosave
()
{
initAutosave
()
{
new
Autosave
(
this
.
titleField
,
[
document
.
location
.
pathname
,
document
.
location
.
search
,
'
title
'
]);
this
.
autosave
=
new
Autosave
(
this
.
titleField
,
[
return
new
Autosave
(
this
.
descriptionField
,
[
document
.
location
.
pathname
,
document
.
location
.
search
,
'
description
'
]);
document
.
location
.
pathname
,
document
.
location
.
search
,
'
title
'
,
]);
return
new
Autosave
(
this
.
descriptionField
,
[
document
.
location
.
pathname
,
document
.
location
.
search
,
'
description
'
,
]);
}
}
handleSubmit
()
{
handleSubmit
()
{
...
@@ -76,7 +83,7 @@ export default class IssuableForm {
...
@@ -76,7 +83,7 @@ export default class IssuableForm {
this
.
$wipExplanation
=
this
.
form
.
find
(
'
.js-wip-explanation
'
);
this
.
$wipExplanation
=
this
.
form
.
find
(
'
.js-wip-explanation
'
);
this
.
$noWipExplanation
=
this
.
form
.
find
(
'
.js-no-wip-explanation
'
);
this
.
$noWipExplanation
=
this
.
form
.
find
(
'
.js-no-wip-explanation
'
);
if
(
!
(
this
.
$wipExplanation
.
length
&&
this
.
$noWipExplanation
.
length
))
{
if
(
!
(
this
.
$wipExplanation
.
length
&&
this
.
$noWipExplanation
.
length
))
{
return
;
return
undefined
;
}
}
this
.
form
.
on
(
'
click
'
,
'
.js-toggle-wip
'
,
this
.
toggleWip
);
this
.
form
.
on
(
'
click
'
,
'
.js-toggle-wip
'
,
this
.
toggleWip
);
this
.
titleField
.
on
(
'
keyup blur
'
,
this
.
renderWipExplanation
);
this
.
titleField
.
on
(
'
keyup blur
'
,
this
.
renderWipExplanation
);
...
@@ -91,10 +98,9 @@ export default class IssuableForm {
...
@@ -91,10 +98,9 @@ export default class IssuableForm {
if
(
this
.
workInProgress
())
{
if
(
this
.
workInProgress
())
{
this
.
$wipExplanation
.
show
();
this
.
$wipExplanation
.
show
();
return
this
.
$noWipExplanation
.
hide
();
return
this
.
$noWipExplanation
.
hide
();
}
else
{
this
.
$wipExplanation
.
hide
();
return
this
.
$noWipExplanation
.
show
();
}
}
this
.
$wipExplanation
.
hide
();
return
this
.
$noWipExplanation
.
show
();
}
}
toggleWip
(
event
)
{
toggleWip
(
event
)
{
...
@@ -112,7 +118,7 @@ export default class IssuableForm {
...
@@ -112,7 +118,7 @@ export default class IssuableForm {
}
}
addWip
()
{
addWip
()
{
this
.
titleField
.
val
(
`WIP:
${
(
this
.
titleField
.
val
()
)}
`
);
this
.
titleField
.
val
(
`WIP:
${
this
.
titleField
.
val
(
)}
`
);
}
}
initTargetBranchDropdown
()
{
initTargetBranchDropdown
()
{
...
...
app/assets/javascripts/lib/utils/datefix.js
deleted
100644 → 0
View file @
b8275cdc
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
}
`
;
};
app/assets/javascripts/lib/utils/datetime_utility.js
View file @
c78607fa
import
$
from
'
jquery
'
;
import
$
from
'
jquery
'
;
import
_
from
'
underscore
'
;
import
timeago
from
'
timeago.js
'
;
import
timeago
from
'
timeago.js
'
;
import
dateFormat
from
'
dateformat
'
;
import
dateFormat
from
'
dateformat
'
;
import
{
pluralize
}
from
'
./text_utility
'
;
import
{
pluralize
}
from
'
./text_utility
'
;
...
@@ -46,6 +47,8 @@ const getMonthNames = abbreviated => {
...
@@ -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
* Given a date object returns the day of the week in English
* @param {date} date
* @param {date} date
...
@@ -74,10 +77,10 @@ let timeagoInstance;
...
@@ -74,10 +77,10 @@ let timeagoInstance;
/**
/**
* Sets a timeago Instance
* Sets a timeago Instance
*/
*/
export
function
getTimeago
()
{
export
const
getTimeago
=
()
=>
{
if
(
!
timeagoInstance
)
{
if
(
!
timeagoInstance
)
{
const
localeRemaining
=
function
getLocaleRemaining
(
number
,
index
)
{
const
localeRemaining
=
(
number
,
index
)
=>
return
[
[
[
s__
(
'
Timeago|just now
'
),
s__
(
'
Timeago|right now
'
)],
[
s__
(
'
Timeago|just now
'
),
s__
(
'
Timeago|right now
'
)],
[
s__
(
'
Timeago|%s seconds ago
'
),
s__
(
'
Timeago|%s seconds remaining
'
)],
[
s__
(
'
Timeago|%s seconds ago
'
),
s__
(
'
Timeago|%s seconds remaining
'
)],
[
s__
(
'
Timeago|1 minute ago
'
),
s__
(
'
Timeago|1 minute remaining
'
)],
[
s__
(
'
Timeago|1 minute ago
'
),
s__
(
'
Timeago|1 minute remaining
'
)],
...
@@ -93,9 +96,9 @@ export function getTimeago() {
...
@@ -93,9 +96,9 @@ export function getTimeago() {
[
s__
(
'
Timeago|1 year ago
'
),
s__
(
'
Timeago|1 year remaining
'
)],
[
s__
(
'
Timeago|1 year ago
'
),
s__
(
'
Timeago|1 year remaining
'
)],
[
s__
(
'
Timeago|%s years ago
'
),
s__
(
'
Timeago|%s years remaining
'
)],
[
s__
(
'
Timeago|%s years ago
'
),
s__
(
'
Timeago|%s years remaining
'
)],
][
index
];
][
index
];
};
const
locale
=
function
getLocale
(
number
,
index
)
{
const
locale
=
(
number
,
index
)
=>
return
[
[
[
s__
(
'
Timeago|just now
'
),
s__
(
'
Timeago|right now
'
)],
[
s__
(
'
Timeago|just now
'
),
s__
(
'
Timeago|right now
'
)],
[
s__
(
'
Timeago|%s seconds ago
'
),
s__
(
'
Timeago|in %s seconds
'
)],
[
s__
(
'
Timeago|%s seconds ago
'
),
s__
(
'
Timeago|in %s seconds
'
)],
[
s__
(
'
Timeago|1 minute ago
'
),
s__
(
'
Timeago|in 1 minute
'
)],
[
s__
(
'
Timeago|1 minute ago
'
),
s__
(
'
Timeago|in 1 minute
'
)],
...
@@ -111,7 +114,6 @@ export function getTimeago() {
...
@@ -111,7 +114,6 @@ export function getTimeago() {
[
s__
(
'
Timeago|1 year ago
'
),
s__
(
'
Timeago|in 1 year
'
)],
[
s__
(
'
Timeago|1 year ago
'
),
s__
(
'
Timeago|in 1 year
'
)],
[
s__
(
'
Timeago|%s years ago
'
),
s__
(
'
Timeago|in %s years
'
)],
[
s__
(
'
Timeago|%s years ago
'
),
s__
(
'
Timeago|in %s years
'
)],
][
index
];
][
index
];
};
timeago
.
register
(
timeagoLanguageCode
,
locale
);
timeago
.
register
(
timeagoLanguageCode
,
locale
);
timeago
.
register
(
`
${
timeagoLanguageCode
}
-remaining`
,
localeRemaining
);
timeago
.
register
(
`
${
timeagoLanguageCode
}
-remaining`
,
localeRemaining
);
...
@@ -119,7 +121,7 @@ export function getTimeago() {
...
@@ -119,7 +121,7 @@ export function getTimeago() {
}
}
return
timeagoInstance
;
return
timeagoInstance
;
}
}
;
/**
/**
* For the given element, renders a timeago instance.
* For the given element, renders a timeago instance.
...
@@ -184,7 +186,7 @@ export const getDayDifference = (a, b) => {
...
@@ -184,7 +186,7 @@ export const getDayDifference = (a, b) => {
* @param {Number} seconds
* @param {Number} seconds
* @return {String}
* @return {String}
*/
*/
export
function
timeIntervalInWords
(
intervalInSeconds
)
{
export
const
timeIntervalInWords
=
intervalInSeconds
=>
{
const
secondsInteger
=
parseInt
(
intervalInSeconds
,
10
);
const
secondsInteger
=
parseInt
(
intervalInSeconds
,
10
);
const
minutes
=
Math
.
floor
(
secondsInteger
/
60
);
const
minutes
=
Math
.
floor
(
secondsInteger
/
60
);
const
seconds
=
secondsInteger
-
minutes
*
60
;
const
seconds
=
secondsInteger
-
minutes
*
60
;
...
@@ -196,9 +198,9 @@ export function timeIntervalInWords(intervalInSeconds) {
...
@@ -196,9 +198,9 @@ export function timeIntervalInWords(intervalInSeconds) {
text
=
`
${
seconds
}
${
pluralize
(
'
second
'
,
seconds
)}
`
;
text
=
`
${
seconds
}
${
pluralize
(
'
second
'
,
seconds
)}
`
;
}
}
return
text
;
return
text
;
}
}
;
export
function
dateInWords
(
date
,
abbreviated
=
false
,
hideYear
=
false
)
{
export
const
dateInWords
=
(
date
,
abbreviated
=
false
,
hideYear
=
false
)
=>
{
if
(
!
date
)
return
date
;
if
(
!
date
)
return
date
;
const
month
=
date
.
getMonth
();
const
month
=
date
.
getMonth
();
...
@@ -240,7 +242,7 @@ export function dateInWords(date, abbreviated = false, hideYear = false) {
...
@@ -240,7 +242,7 @@ export function dateInWords(date, abbreviated = false, hideYear = false) {
}
}
return
`
${
monthName
}
${
date
.
getDate
()}
,
${
year
}
`
;
return
`
${
monthName
}
${
date
.
getDate
()}
,
${
year
}
`
;
}
}
;
/**
/**
* Returns month name based on provided date.
* Returns month name based on provided date.
...
@@ -391,3 +393,83 @@ export const formatTime = milliseconds => {
...
@@ -391,3 +393,83 @@ export const formatTime = milliseconds => {
formattedTime
+=
remainingSeconds
;
formattedTime
+=
remainingSeconds
;
return
formattedTime
;
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
];
app/assets/javascripts/lib/utils/pretty_time.js
deleted
100644 → 0
View file @
b8275cdc
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
];
}
app/assets/javascripts/member_expiration_date.js
View file @
c78607fa
import
$
from
'
jquery
'
;
import
$
from
'
jquery
'
;
import
Pikaday
from
'
pikaday
'
;
import
Pikaday
from
'
pikaday
'
;
import
{
parsePikadayDate
,
pikadayToString
}
from
'
./lib/utils/date
fix
'
;
import
{
parsePikadayDate
,
pikadayToString
}
from
'
./lib/utils/date
time_utility
'
;
// Add datepickers to all `js-access-expiration-date` elements. If those elements are
// 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
// children of an element with the `clearable-input` class, and have a sibling
...
...
app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue
View file @
c78607fa
<
script
>
<
script
>
import
{
__
,
sprintf
}
from
'
~/locale
'
;
import
{
__
,
sprintf
}
from
'
~/locale
'
;
import
{
abbreviateTime
}
from
'
~/lib/utils/pretty_time
'
;
import
{
abbreviateTime
}
from
'
~/lib/utils/datetime_utility
'
;
import
icon
from
'
~/vue_shared/components/icon.vue
'
;
import
icon
from
'
~/vue_shared/components/icon.vue
'
;
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
export
default
{
export
default
{
name
:
'
TimeTrackingCollapsedState
'
,
name
:
'
TimeTrackingCollapsedState
'
,
components
:
{
components
:
{
icon
,
icon
,
},
directives
:
{
tooltip
,
},
props
:
{
showComparisonState
:
{
type
:
Boolean
,
required
:
true
,
},
},
directives
:
{
showSpentOnlyState
:
{
tooltip
,
type
:
Boolean
,
required
:
true
,
},
},
props
:
{
showEstimateOnlyState
:
{
showComparisonState
:
{
type
:
Boolean
,
type
:
Boolean
,
required
:
true
,
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
:
''
,
},
},
},
computed
:
{
showNoTimeTrackingState
:
{
timeSpent
()
{
type
:
Boolean
,
return
this
.
abbreviateTime
(
this
.
timeSpentHumanReadable
);
required
:
true
,
},
},
timeEstimate
()
{
timeSpentHumanReadable
:
{
return
this
.
abbreviateTime
(
this
.
timeEstimateHumanReadable
);
type
:
String
,
},
required
:
false
,
divClass
()
{
default
:
''
,
if
(
this
.
showComparisonState
)
{
},
return
'
compare
'
;
timeEstimateHumanReadable
:
{
}
else
if
(
this
.
showEstimateOnlyState
)
{
type
:
String
,
return
'
estimate-only
'
;
required
:
false
,
}
else
if
(
this
.
showSpentOnlyState
)
{
default
:
''
,
return
'
spend-only
'
;
},
}
else
if
(
this
.
showNoTimeTrackingState
)
{
},
return
'
no-tracking
'
;
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
''
;
return
''
;
},
}
else
if
(
this
.
showEstimateOnlyState
||
this
.
showSpentOnlyState
)
{
spanClass
()
{
return
'
bold
'
;
if
(
this
.
showComparisonState
)
{
}
else
if
(
this
.
showNoTimeTrackingState
)
{
return
''
;
return
'
no-value
'
;
}
else
if
(
this
.
showEstimateOnlyState
||
this
.
showSpentOnlyState
)
{
}
return
'
bold
'
;
}
else
if
(
this
.
showNoTimeTrackingState
)
{
return
'
no-value
'
;
}
return
''
;
return
''
;
},
},
text
()
{
text
()
{
if
(
this
.
showComparisonState
)
{
if
(
this
.
showComparisonState
)
{
return
`
${
this
.
timeSpent
}
/
${
this
.
timeEstimate
}
`
;
return
`
${
this
.
timeSpent
}
/
${
this
.
timeEstimate
}
`
;
}
else
if
(
this
.
showEstimateOnlyState
)
{
}
else
if
(
this
.
showEstimateOnlyState
)
{
return
`-- /
${
this
.
timeEstimate
}
`
;
return
`-- /
${
this
.
timeEstimate
}
`
;
}
else
if
(
this
.
showSpentOnlyState
)
{
}
else
if
(
this
.
showSpentOnlyState
)
{
return
`
${
this
.
timeSpent
}
/ --`
;
return
`
${
this
.
timeSpent
}
/ --`
;
}
else
if
(
this
.
showNoTimeTrackingState
)
{
}
else
if
(
this
.
showNoTimeTrackingState
)
{
return
'
None
'
;
return
'
None
'
;
}
}
return
''
;
return
''
;
},
},
timeTrackedTooltipText
()
{
timeTrackedTooltipText
()
{
let
title
;
let
title
;
if
(
this
.
showComparisonState
)
{
if
(
this
.
showComparisonState
)
{
title
=
__
(
'
Time remaining
'
);
title
=
__
(
'
Time remaining
'
);
}
else
if
(
this
.
showEstimateOnlyState
)
{
}
else
if
(
this
.
showEstimateOnlyState
)
{
title
=
__
(
'
Estimated
'
);
title
=
__
(
'
Estimated
'
);
}
else
if
(
this
.
showSpentOnlyState
)
{
}
else
if
(
this
.
showSpentOnlyState
)
{
title
=
__
(
'
Time spent
'
);
title
=
__
(
'
Time spent
'
);
}
}
return
sprintf
(
'
%{title}: %{text}
'
,
({
title
,
text
:
this
.
text
}));
return
sprintf
(
'
%{title}: %{text}
'
,
{
title
,
text
:
this
.
text
});
},
},
tooltipText
()
{
tooltipText
()
{
return
this
.
showNoTimeTrackingState
?
__
(
'
Time tracking
'
)
:
this
.
timeTrackedTooltipText
;
return
this
.
showNoTimeTrackingState
?
__
(
'
Time tracking
'
)
:
this
.
timeTrackedTooltipText
;
},
},
},
methods
:
{
},
abbreviateTime
(
timeStr
)
{
methods
:
{
return
abbreviateTime
(
timeStr
);
abbreviateTime
(
timeStr
)
{
},
return
abbreviateTime
(
timeStr
);
},
},
};
},
};
</
script
>
</
script
>
<
template
>
<
template
>
...
...
app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue
View file @
c78607fa
<
script
>
<
script
>
import
{
parseSeconds
,
stringifyTime
}
from
'
../../../lib/utils/pretty_time
'
;
import
{
parseSeconds
,
stringifyTime
}
from
'
~/lib/utils/datetime_utility
'
;
import
tooltip
from
'
../../../vue_shared/directives/tooltip
'
;
import
tooltip
from
'
../../../vue_shared/directives/tooltip
'
;
export
default
{
export
default
{
...
...
app/assets/javascripts/vue_shared/components/pikaday.vue
View file @
c78607fa
<
script
>
<
script
>
import
Pikaday
from
'
pikaday
'
;
import
Pikaday
from
'
pikaday
'
;
import
{
parsePikadayDate
,
pikadayToString
}
from
'
../../lib/utils/datefix
'
;
import
{
parsePikadayDate
,
pikadayToString
}
from
'
~/lib/utils/datetime_utility
'
;
export
default
{
export
default
{
name
:
'
DatePicker
'
,
name
:
'
DatePicker
'
,
...
...
ee/app/assets/javascripts/epics/sidebar/stores/sidebar_store.js
View file @
c78607fa
import
{
parsePikadayDate
}
from
'
~/lib/utils/date
fix
'
;
import
{
parsePikadayDate
}
from
'
~/lib/utils/date
time_utility
'
;
export
default
class
SidebarStore
{
export
default
class
SidebarStore
{
constructor
({
constructor
({
...
...
ee/app/assets/javascripts/geo_nodes/components/node_detail_sections/node_details_section_sync.vue
View file @
c78607fa
<
script
>
<
script
>
import
{
s__
,
__
}
from
'
~/locale
'
;
import
{
s__
,
__
}
from
'
~/locale
'
;
import
{
parseSeconds
,
stringifyTime
}
from
'
~/lib/utils/pretty_time
'
;
import
{
parseSeconds
,
stringifyTime
}
from
'
~/lib/utils/datetime_utility
'
;
import
{
VALUE_TYPE
,
CUSTOM_TYPE
}
from
'
../../constants
'
;
import
{
VALUE_TYPE
,
CUSTOM_TYPE
}
from
'
../../constants
'
;
import
DetailsSectionMixin
from
'
../../mixins/details_section_mixin
'
;
import
DetailsSectionMixin
from
'
../../mixins/details_section_mixin
'
;
import
GeoNodeDetailItem
from
'
../geo_node_detail_item.vue
'
;
import
GeoNodeDetailItem
from
'
../geo_node_detail_item.vue
'
;
import
SectionRevealButton
from
'
./section_reveal_button.vue
'
;
import
SectionRevealButton
from
'
./section_reveal_button.vue
'
;
export
default
{
export
default
{
components
:
{
components
:
{
SectionRevealButton
,
SectionRevealButton
,
GeoNodeDetailItem
,
GeoNodeDetailItem
,
},
mixins
:
[
DetailsSectionMixin
],
props
:
{
nodeDetails
:
{
type
:
Object
,
required
:
true
,
},
},
mixins
:
[
},
DetailsSectionMixin
,
data
()
{
],
return
{
props
:
{
showSectionItems
:
false
,
nodeDetails
:
{
nodeDetailItems
:
[
type
:
Object
,
{
required
:
true
,
itemTitle
:
s__
(
'
GeoNodes|Sync settings
'
),
},
itemValue
:
this
.
syncSettings
(),
},
itemValueType
:
VALUE_TYPE
.
CUSTOM
,
data
()
{
customType
:
CUSTOM_TYPE
.
SYNC
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Repositories
'
),
itemValue
:
this
.
nodeDetails
.
repositories
,
itemValueType
:
VALUE_TYPE
.
GRAPH
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Wikis
'
),
itemValue
:
this
.
nodeDetails
.
wikis
,
itemValueType
:
VALUE_TYPE
.
GRAPH
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Local LFS objects
'
),
itemValue
:
this
.
nodeDetails
.
lfs
,
itemValueType
:
VALUE_TYPE
.
GRAPH
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Local attachments
'
),
itemValue
:
this
.
nodeDetails
.
attachments
,
itemValueType
:
VALUE_TYPE
.
GRAPH
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Local job artifacts
'
),
itemValue
:
this
.
nodeDetails
.
jobArtifacts
,
itemValueType
:
VALUE_TYPE
.
GRAPH
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Data replication lag
'
),
itemValue
:
this
.
dbReplicationLag
(),
itemValueType
:
VALUE_TYPE
.
PLAIN
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Last event ID seen from primary
'
),
itemValue
:
this
.
lastEventStatus
(),
itemValueType
:
VALUE_TYPE
.
CUSTOM
,
customType
:
CUSTOM_TYPE
.
EVENT
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Last event ID processed by cursor
'
),
itemValue
:
this
.
cursorLastEventStatus
(),
itemValueType
:
VALUE_TYPE
.
CUSTOM
,
customType
:
CUSTOM_TYPE
.
EVENT
,
eventTypeLogStatus
:
true
,
},
],
};
},
methods
:
{
syncSettings
()
{
return
{
return
{
showSectionItems
:
false
,
syncStatusUnavailable
:
this
.
nodeDetails
.
syncStatusUnavailable
,
nodeDetailItems
:
[
selectiveSyncType
:
this
.
nodeDetails
.
selectiveSyncType
,
{
lastEvent
:
this
.
nodeDetails
.
lastEvent
,
itemTitle
:
s__
(
'
GeoNodes|Sync settings
'
),
cursorLastEvent
:
this
.
nodeDetails
.
cursorLastEvent
,
itemValue
:
this
.
syncSettings
(),
itemValueType
:
VALUE_TYPE
.
CUSTOM
,
customType
:
CUSTOM_TYPE
.
SYNC
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Repositories
'
),
itemValue
:
this
.
nodeDetails
.
repositories
,
itemValueType
:
VALUE_TYPE
.
GRAPH
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Wikis
'
),
itemValue
:
this
.
nodeDetails
.
wikis
,
itemValueType
:
VALUE_TYPE
.
GRAPH
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Local LFS objects
'
),
itemValue
:
this
.
nodeDetails
.
lfs
,
itemValueType
:
VALUE_TYPE
.
GRAPH
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Local attachments
'
),
itemValue
:
this
.
nodeDetails
.
attachments
,
itemValueType
:
VALUE_TYPE
.
GRAPH
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Local job artifacts
'
),
itemValue
:
this
.
nodeDetails
.
jobArtifacts
,
itemValueType
:
VALUE_TYPE
.
GRAPH
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Data replication lag
'
),
itemValue
:
this
.
dbReplicationLag
(),
itemValueType
:
VALUE_TYPE
.
PLAIN
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Last event ID seen from primary
'
),
itemValue
:
this
.
lastEventStatus
(),
itemValueType
:
VALUE_TYPE
.
CUSTOM
,
customType
:
CUSTOM_TYPE
.
EVENT
,
},
{
itemTitle
:
s__
(
'
GeoNodes|Last event ID processed by cursor
'
),
itemValue
:
this
.
cursorLastEventStatus
(),
itemValueType
:
VALUE_TYPE
.
CUSTOM
,
customType
:
CUSTOM_TYPE
.
EVENT
,
eventTypeLogStatus
:
true
,
},
],
};
};
},
},
methods
:
{
dbReplicationLag
()
{
syncSettings
()
{
// Replication lag can be nil if the secondary isn't actually streaming
return
{
if
(
this
.
nodeDetails
.
dbReplicationLag
!==
null
&&
this
.
nodeDetails
.
dbReplicationLag
>=
0
)
{
syncStatusUnavailable
:
this
.
nodeDetails
.
syncStatusUnavailable
,
const
parsedTime
=
parseSeconds
(
this
.
nodeDetails
.
dbReplicationLag
,
{
selectiveSyncType
:
this
.
nodeDetails
.
selectiveSyncType
,
hoursPerDay
:
24
,
lastEvent
:
this
.
nodeDetails
.
lastEvent
,
daysPerWeek
:
7
,
cursorLastEvent
:
this
.
nodeDetails
.
cursorLastEvent
,
});
};
},
dbReplicationLag
()
{
// Replication lag can be nil if the secondary isn't actually streaming
if
(
this
.
nodeDetails
.
dbReplicationLag
!==
null
&&
this
.
nodeDetails
.
dbReplicationLag
>=
0
)
{
const
parsedTime
=
parseSeconds
(
this
.
nodeDetails
.
dbReplicationLag
,
{
hoursPerDay
:
24
,
daysPerWeek
:
7
,
});
return
stringifyTime
(
parsedTime
);
return
stringifyTime
(
parsedTime
);
}
}
return
__
(
'
Unknown
'
);
return
__
(
'
Unknown
'
);
},
},
lastEventStatus
()
{
lastEventStatus
()
{
return
{
return
{
eventId
:
this
.
nodeDetails
.
lastEvent
.
id
,
eventId
:
this
.
nodeDetails
.
lastEvent
.
id
,
eventTimeStamp
:
this
.
nodeDetails
.
lastEvent
.
timeStamp
,
eventTimeStamp
:
this
.
nodeDetails
.
lastEvent
.
timeStamp
,
};
};
},
},
cursorLastEventStatus
()
{
cursorLastEventStatus
()
{
return
{
return
{
eventId
:
this
.
nodeDetails
.
cursorLastEvent
.
id
,
eventId
:
this
.
nodeDetails
.
cursorLastEvent
.
id
,
eventTimeStamp
:
this
.
nodeDetails
.
cursorLastEvent
.
timeStamp
,
eventTimeStamp
:
this
.
nodeDetails
.
cursorLastEvent
.
timeStamp
,
};
};
},
},
handleSectionToggle
(
toggleState
)
{
handleSectionToggle
(
toggleState
)
{
this
.
showSectionItems
=
toggleState
;
this
.
showSectionItems
=
toggleState
;
},
},
},
};
},
};
</
script
>
</
script
>
<
template
>
<
template
>
...
...
ee/app/assets/javascripts/roadmap/store/roadmap_store.js
View file @
c78607fa
import
{
convertObjectPropsToCamelCase
}
from
'
~/lib/utils/common_utils
'
;
import
{
convertObjectPropsToCamelCase
}
from
'
~/lib/utils/common_utils
'
;
import
{
parsePikadayDate
}
from
'
~/lib/utils/date
fix
'
;
import
{
parsePikadayDate
}
from
'
~/lib/utils/date
time_utility
'
;
import
{
PRESET_TYPES
}
from
'
../constants
'
;
import
{
PRESET_TYPES
}
from
'
../constants
'
;
...
...
spec/javascripts/datetime_utility_spec.js
View file @
c78607fa
...
@@ -192,3 +192,163 @@ describe('formatTime', () => {
...
@@ -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
'
);
});
});
});
spec/javascripts/lib/utils/datefix_spec.js
deleted
100644 → 0
View file @
b8275cdc
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
'
);
});
});
});
spec/javascripts/pretty_time_spec.js
deleted
100644 → 0
View file @
b8275cdc
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
'
);
});
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment