BigW Consortium Gitlab
Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
gitlab-ce
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Forest Godfrey
gitlab-ce
Commits
03b7df7b
Commit
03b7df7b
authored
Sep 05, 2017
by
Bryce Johnson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Lightly refactor prettyTime module.
parent
a3b74f1a
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
156 additions
and
255 deletions
+156
-255
pretty_time.js
app/assets/javascripts/lib/utils/pretty_time.js
+50
-57
collapsed_state.js
...ripts/sidebar/components/time_tracking/collapsed_state.js
+2
-3
comparison_pane.js
...ripts/sidebar/components/time_tracking/comparison_pane.js
+4
-13
pretty_time_spec.js
spec/javascripts/pretty_time_spec.js
+100
-182
No files found.
app/assets/javascripts/lib/utils/pretty_time.js
View file @
03b7df7b
import
_
from
'underscore'
;
(()
=>
{
/*
* TODO: Make these methods more configurable (e.g. stringifyTime condensed or
* non-condensed, abbreviateTimelengths)
* */
const
utils
=
window
.
gl
.
utils
=
gl
.
utils
||
{};
const
prettyTime
=
utils
.
prettyTime
=
{
/*
* 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.
*/
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
,
};
/*
* 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
=
prettyTime
.
secondsToMinutes
(
seconds
);
let
unorderedMinutes
=
Math
.
abs
(
seconds
/
MINUTES_PER_HOUR
);
return
_
.
mapObject
(
timePeriodConstraints
,
(
minutesPerPeriod
)
=>
{
const
periodCount
=
Math
.
floor
(
unorderedMinutes
/
minutesPerPeriod
);
return
_
.
mapObject
(
timePeriodConstraints
,
(
minutesPerPeriod
)
=>
{
const
periodCount
=
Math
.
floor
(
unorderedMinutes
/
minutesPerPeriod
);
unorderedMinutes
-=
(
periodCount
*
minutesPerPeriod
);
unorderedMinutes
-=
(
periodCount
*
minutesPerPeriod
);
return
periodCount
;
});
},
return
periodCount
;
});
}
/*
* Accepts a timeObject
and returns a condensed string representation of it
* (e.g. '1w 2d 3h 1m' or '1h 30m'). Zero value units are not included.
*/
/*
* 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.
*/
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'
;
},
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.
*/
/*
* 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.
*/
abbreviateTime
(
timeStr
)
{
return
timeStr
.
split
(
' '
)
.
filter
(
unitStr
=>
unitStr
.
charAt
(
0
)
!==
'0'
)[
0
];
},
export
function
abbreviateTime
(
timeStr
)
{
return
timeStr
.
split
(
' '
)
.
filter
(
unitStr
=>
unitStr
.
charAt
(
0
)
!==
'0'
)[
0
];
}
secondsToMinutes
(
seconds
)
{
return
Math
.
abs
(
seconds
/
60
);
},
};
})(
window
.
gl
||
(
window
.
gl
=
{}));
app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.js
View file @
03b7df7b
import
stopwatchSvg
from
'icons/_icon_stopwatch.svg'
;
import
'../../../lib/utils/pretty_time'
;
import
{
abbreviateTime
}
from
'../../../lib/utils/pretty_time'
;
export
default
{
name
:
'time-tracking-collapsed-state'
,
...
...
@@ -79,7 +78,7 @@ export default {
},
methods
:
{
abbreviateTime
(
timeStr
)
{
return
gl
.
utils
.
prettyTime
.
abbreviateTime
(
timeStr
);
return
abbreviateTime
(
timeStr
);
},
},
template
:
`
...
...
app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.js
View file @
03b7df7b
import
'../../../lib/utils/pretty_time'
;
const
prettyTime
=
gl
.
utils
.
prettyTime
;
import
{
parseSeconds
,
stringifyTime
}
from
'../../../lib/utils/pretty_time'
;
export
default
{
name
:
'time-tracking-comparison-pane'
,
...
...
@@ -23,12 +21,12 @@ export default {
},
},
computed
:
{
parsedRemaining
()
{
parsed
Time
Remaining
()
{
const
diffSeconds
=
this
.
timeEstimate
-
this
.
timeSpent
;
return
p
rettyTime
.
p
arseSeconds
(
diffSeconds
);
return
parseSeconds
(
diffSeconds
);
},
timeRemainingHumanReadable
()
{
return
prettyTime
.
stringifyTime
(
this
.
parsed
Remaining
);
return
stringifyTime
(
this
.
parsedTime
Remaining
);
},
timeRemainingTooltip
()
{
const
prefix
=
this
.
timeRemainingMinutes
<
0
?
'Over by'
:
'Time remaining:'
;
...
...
@@ -44,13 +42,6 @@ export default {
timeRemainingStatusClass
()
{
return
this
.
timeEstimate
>=
this
.
timeSpent
?
'within_estimate'
:
'over_estimate'
;
},
/* Parsed time values */
parsedEstimate
()
{
return
prettyTime
.
parseSeconds
(
this
.
timeEstimate
);
},
parsedSpent
()
{
return
prettyTime
.
parseSeconds
(
this
.
timeSpent
);
},
},
template
:
`
<div class="time-tracking-comparison-pane">
...
...
spec/javascripts/pretty_time_spec.js
View file @
03b7df7b
import
'~/lib/utils/pretty_time'
;
import
{
parseSeconds
,
abbreviateTime
,
stringifyTime
}
from
'~/lib/utils/pretty_time'
;
(()
=>
{
const
prettyTime
=
gl
.
utils
.
prettyTime
;
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'
,
function
()
{
describe
(
'parseSeconds'
,
function
()
{
it
(
'should correctly parse a negative value'
,
function
()
{
const
parser
=
prettyTime
.
parseSeconds
;
describe
(
'prettyTime methods'
,
()
=>
{
describe
(
'parseSeconds'
,
()
=>
{
it
(
'should correctly parse a negative value'
,
()
=>
{
const
zeroSeconds
=
parseSeconds
(
-
1000
)
;
const
zeroSeconds
=
parser
(
-
1000
);
expect
(
zeroSeconds
.
minutes
).
toBe
(
16
);
expect
(
zeroSeconds
.
hours
).
toBe
(
0
);
expect
(
zeroSeconds
.
days
).
toBe
(
0
);
expect
(
zeroSeconds
.
weeks
).
toBe
(
0
);
});
it
(
'should correctly parse a zero value'
,
function
()
{
const
parser
=
prettyTime
.
parseSeconds
;
const
zeroSeconds
=
parser
(
0
);
expect
(
zeroSeconds
.
minutes
).
toBe
(
0
);
expect
(
zeroSeconds
.
hours
).
toBe
(
0
);
expect
(
zeroSeconds
.
days
).
toBe
(
0
);
expect
(
zeroSeconds
.
weeks
).
toBe
(
0
);
});
it
(
'should correctly parse a small non-zero second values'
,
function
()
{
const
parser
=
prettyTime
.
parseSeconds
;
const
subOneMinute
=
parser
(
10
);
expect
(
subOneMinute
.
minutes
).
toBe
(
0
);
expect
(
subOneMinute
.
hours
).
toBe
(
0
);
expect
(
subOneMinute
.
days
).
toBe
(
0
);
expect
(
subOneMinute
.
weeks
).
toBe
(
0
);
const
aboveOneMinute
=
parser
(
100
);
expect
(
aboveOneMinute
.
minutes
).
toBe
(
1
);
expect
(
aboveOneMinute
.
hours
).
toBe
(
0
);
expect
(
aboveOneMinute
.
days
).
toBe
(
0
);
expect
(
aboveOneMinute
.
weeks
).
toBe
(
0
);
const
manyMinutes
=
parser
(
1000
);
expect
(
manyMinutes
.
minutes
).
toBe
(
16
);
expect
(
manyMinutes
.
hours
).
toBe
(
0
);
expect
(
manyMinutes
.
days
).
toBe
(
0
);
expect
(
manyMinutes
.
weeks
).
toBe
(
0
);
});
it
(
'should correctly parse large second values'
,
function
()
{
const
parser
=
prettyTime
.
parseSeconds
;
const
aboveOneHour
=
parser
(
4800
);
expect
(
aboveOneHour
.
minutes
).
toBe
(
20
);
expect
(
aboveOneHour
.
hours
).
toBe
(
1
);
expect
(
aboveOneHour
.
days
).
toBe
(
0
);
expect
(
aboveOneHour
.
weeks
).
toBe
(
0
);
const
aboveOneDay
=
parser
(
110000
);
expect
(
aboveOneDay
.
minutes
).
toBe
(
33
);
expect
(
aboveOneDay
.
hours
).
toBe
(
6
);
expect
(
aboveOneDay
.
days
).
toBe
(
3
);
expect
(
aboveOneDay
.
weeks
).
toBe
(
0
);
const
aboveOneWeek
=
parser
(
25000000
);
expect
(
aboveOneWeek
.
minutes
).
toBe
(
26
);
expect
(
aboveOneWeek
.
hours
).
toBe
(
0
);
expect
(
aboveOneWeek
.
days
).
toBe
(
3
);
expect
(
aboveOneWeek
.
weeks
).
toBe
(
173
);
});
assertTimeUnits
(
zeroSeconds
,
16
,
0
,
0
,
0
);
});
it
(
'should correctly accept a custom param for hoursPerDay'
,
function
()
{
const
parser
=
prettyTime
.
parseSeconds
;
const
config
=
{
hoursPerDay
:
24
};
it
(
'should correctly parse a zero value'
,
()
=>
{
const
zeroSeconds
=
parseSeconds
(
0
);
const
aboveOneHour
=
parser
(
4800
,
config
);
assertTimeUnits
(
zeroSeconds
,
0
,
0
,
0
,
0
);
});
expect
(
aboveOneHour
.
minutes
).
toBe
(
20
);
expect
(
aboveOneHour
.
hours
).
toBe
(
1
);
expect
(
aboveOneHour
.
days
).
toBe
(
0
);
expect
(
aboveOneHour
.
weeks
).
toBe
(
0
);
it
(
'should correctly parse a small non-zero second values'
,
()
=>
{
const
subOneMinute
=
parseSeconds
(
10
);
const
aboveOneMinute
=
parseSeconds
(
10
0
);
const
manyMinutes
=
parseSeconds
(
100
0
);
const
aboveOneDay
=
parser
(
110000
,
config
);
assertTimeUnits
(
subOneMinute
,
0
,
0
,
0
,
0
);
assertTimeUnits
(
aboveOneMinute
,
1
,
0
,
0
,
0
);
assertTimeUnits
(
manyMinutes
,
16
,
0
,
0
,
0
);
});
expect
(
aboveOneDay
.
minutes
).
toBe
(
33
);
expect
(
aboveOneDay
.
hours
).
toBe
(
6
);
expect
(
aboveOneDay
.
days
).
toBe
(
1
);
expect
(
aboveOneDay
.
weeks
).
toBe
(
0
);
it
(
'should correctly parse large second values'
,
()
=>
{
const
aboveOneHour
=
parseSeconds
(
4800
);
const
aboveOneDay
=
parseSeconds
(
110000
);
const
aboveOneWeek
=
parseSeconds
(
2500000
0
);
const
aboveOneWeek
=
parser
(
25000000
,
config
);
assertTimeUnits
(
aboveOneHour
,
20
,
1
,
0
,
0
);
assertTimeUnits
(
aboveOneDay
,
33
,
6
,
3
,
0
);
assertTimeUnits
(
aboveOneWeek
,
26
,
0
,
3
,
173
);
});
expect
(
aboveOneWeek
.
minutes
).
toBe
(
26
);
expect
(
aboveOneWeek
.
hours
).
toBe
(
8
);
expect
(
aboveOneWeek
.
days
).
toBe
(
4
);
it
(
'should correctly accept a custom param for hoursPerDay'
,
()
=>
{
const
config
=
{
hoursPerDay
:
24
};
expect
(
aboveOneWeek
.
weeks
).
toBe
(
57
);
});
const
aboveOneHour
=
parseSeconds
(
4800
,
config
);
const
aboveOneDay
=
parseSeconds
(
110000
,
config
);
const
aboveOneWeek
=
parseSeconds
(
25000000
,
config
);
it
(
'should correctly accept a custom param for daysPerWeek'
,
function
()
{
const
parser
=
prettyTime
.
parseSeconds
;
const
config
=
{
daysPerWeek
:
7
};
assertTimeUnits
(
aboveOneHour
,
20
,
1
,
0
,
0
);
assertTimeUnits
(
aboveOneDay
,
33
,
6
,
1
,
0
);
assertTimeUnits
(
aboveOneWeek
,
26
,
8
,
4
,
57
);
});
const
aboveOneHour
=
parser
(
4800
,
config
);
it
(
'should correctly accept a custom param for daysPerWeek'
,
()
=>
{
const
config
=
{
daysPerWeek
:
7
};
expect
(
aboveOneHour
.
minutes
).
toBe
(
20
);
expect
(
aboveOneHour
.
hours
).
toBe
(
1
);
expect
(
aboveOneHour
.
days
).
toBe
(
0
);
expect
(
aboveOneHour
.
weeks
).
toBe
(
0
);
const
aboveOneHour
=
parseSeconds
(
4800
,
config
);
const
aboveOneDay
=
parseSeconds
(
110000
,
config
);
const
aboveOneWeek
=
parseSeconds
(
25000000
,
config
);
const
aboveOneDay
=
parser
(
110000
,
config
);
assertTimeUnits
(
aboveOneHour
,
20
,
1
,
0
,
0
);
assertTimeUnits
(
aboveOneDay
,
33
,
6
,
3
,
0
);
assertTimeUnits
(
aboveOneWeek
,
26
,
0
,
0
,
124
);
});
expect
(
aboveOneDay
.
minutes
).
toBe
(
33
);
expect
(
aboveOneDay
.
hours
).
toBe
(
6
);
expect
(
aboveOneDay
.
days
).
toBe
(
3
);
expect
(
aboveOneDay
.
weeks
).
toBe
(
0
);
it
(
'should correctly accept custom params for daysPerWeek and hoursPerDay'
,
()
=>
{
const
config
=
{
daysPerWeek
:
55
,
hoursPerDay
:
14
};
const
aboveOneWeek
=
parser
(
25000000
,
config
);
const
aboveOneHour
=
parseSeconds
(
4800
,
config
);
const
aboveOneDay
=
parseSeconds
(
110000
,
config
);
const
aboveOneWeek
=
parseSeconds
(
25000000
,
config
);
expect
(
aboveOneWeek
.
minutes
).
toBe
(
26
);
expect
(
aboveOneWeek
.
hours
).
toBe
(
0
);
expect
(
aboveOneWeek
.
days
).
toBe
(
0
);
assertTimeUnits
(
aboveOneHour
,
20
,
1
,
0
,
0
);
assertTimeUnits
(
aboveOneDay
,
33
,
2
,
2
,
0
);
assertTimeUnits
(
aboveOneWeek
,
26
,
0
,
1
,
9
);
});
});
expect
(
aboveOneWeek
.
weeks
).
toBe
(
124
);
});
describe
(
'stringifyTime'
,
()
=>
{
it
(
'should stringify values with all non-zero units'
,
()
=>
{
const
timeObject
=
{
weeks
:
1
,
days
:
4
,
hours
:
7
,
minutes
:
20
,
};
it
(
'should correctly accept custom params for daysPerWeek and hoursPerDay'
,
function
()
{
const
parser
=
prettyTime
.
parseSeconds
;
const
config
=
{
daysPerWeek
:
55
,
hoursPerDay
:
14
};
const
timeString
=
stringifyTime
(
timeObject
);
const
aboveOneHour
=
parser
(
4800
,
config
);
expect
(
timeString
).
toBe
(
'1w 4d 7h 20m'
);
});
expect
(
aboveOneHour
.
minutes
).
toBe
(
20
);
expect
(
aboveOneHour
.
hours
).
toBe
(
1
);
expect
(
aboveOneHour
.
days
).
toBe
(
0
);
expect
(
aboveOneHour
.
weeks
).
toBe
(
0
);
it
(
'should stringify values with some non-zero units'
,
()
=>
{
const
timeObject
=
{
weeks
:
0
,
days
:
4
,
hours
:
0
,
minutes
:
20
,
};
const
aboveOneDay
=
parser
(
110000
,
config
);
const
timeString
=
stringifyTime
(
timeObject
);
expect
(
aboveOneDay
.
minutes
).
toBe
(
33
);
expect
(
aboveOneDay
.
hours
).
toBe
(
2
);
expect
(
aboveOneDay
.
days
).
toBe
(
2
);
expect
(
aboveOneDay
.
weeks
).
toBe
(
0
);
expect
(
timeString
).
toBe
(
'4d 20m'
);
});
const
aboveOneWeek
=
parser
(
25000000
,
config
);
it
(
'should stringify values with no non-zero units'
,
()
=>
{
const
timeObject
=
{
weeks
:
0
,
days
:
0
,
hours
:
0
,
minutes
:
0
,
};
expect
(
aboveOneWeek
.
minutes
).
toBe
(
26
);
expect
(
aboveOneWeek
.
hours
).
toBe
(
0
);
expect
(
aboveOneWeek
.
days
).
toBe
(
1
);
const
timeString
=
stringifyTime
(
timeObject
);
expect
(
aboveOneWeek
.
weeks
).
toBe
(
9
);
});
expect
(
timeString
).
toBe
(
'0m'
);
});
});
describe
(
'stringifyTime'
,
function
()
{
it
(
'should stringify values with all non-zero units'
,
function
()
{
const
timeObject
=
{
weeks
:
1
,
days
:
4
,
hours
:
7
,
minutes
:
20
,
};
const
timeString
=
prettyTime
.
stringifyTime
(
timeObject
);
expect
(
timeString
).
toBe
(
'1w 4d 7h 20m'
);
});
it
(
'should stringify values with some non-zero units'
,
function
()
{
const
timeObject
=
{
weeks
:
0
,
days
:
4
,
hours
:
0
,
minutes
:
20
,
};
const
timeString
=
prettyTime
.
stringifyTime
(
timeObject
);
expect
(
timeString
).
toBe
(
'4d 20m'
);
});
it
(
'should stringify values with no non-zero units'
,
function
()
{
const
timeObject
=
{
weeks
:
0
,
days
:
0
,
hours
:
0
,
minutes
:
0
,
};
const
timeString
=
prettyTime
.
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'
);
});
describe
(
'abbreviateTime'
,
function
()
{
it
(
'should abbreviate stringified times for weeks'
,
function
()
{
const
fullTimeString
=
'1w 3d 4h 5m'
;
expect
(
prettyTime
.
abbreviateTime
(
fullTimeString
)).
toBe
(
'1w'
);
});
it
(
'should abbreviate stringified times for non-weeks'
,
function
()
{
const
fullTimeString
=
'0w 3d 4h 5m'
;
expect
(
prettyTime
.
abbreviateTime
(
fullTimeString
)).
toBe
(
'3d'
);
});
it
(
'should abbreviate stringified times for non-weeks'
,
()
=>
{
const
fullTimeString
=
'0w 3d 4h 5m'
;
expect
(
abbreviateTime
(
fullTimeString
)).
toBe
(
'3d'
);
});
});
})
(
window
.
gl
||
(
window
.
gl
=
{}))
;
});
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