@kernhq/module-tracker 0.7.1 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/client/format.test.ts +29 -0
- package/src/client/format.ts +19 -6
- package/src/client/types.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kernhq/module-tracker",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"description": "Kern tracker module: projects, work item types, custom fields, workflows, issues, KQL, cycles, views, reports, intake, time tracking (server + client skeleton)",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"type": "module",
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { formatDuration } from './format.js'
|
|
3
|
+
|
|
4
|
+
describe('formatDuration', () => {
|
|
5
|
+
it('keeps minutes below an hour', () => {
|
|
6
|
+
// A timer running for twenty minutes used to read "0h".
|
|
7
|
+
expect(formatDuration(60)).toBe('1m')
|
|
8
|
+
expect(formatDuration(20 * 60)).toBe('20m')
|
|
9
|
+
expect(formatDuration(59 * 60)).toBe('59m')
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('keeps minutes below a day', () => {
|
|
13
|
+
// 90 logged minutes used to read "2h", which is not a rounding, it is wrong.
|
|
14
|
+
expect(formatDuration(90 * 60)).toBe('1h 30m')
|
|
15
|
+
expect(formatDuration(2 * 3600)).toBe('2h')
|
|
16
|
+
expect(formatDuration(7 * 3600 + 45 * 60)).toBe('7h 45m')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('drops minutes above a day, where they stop being the point', () => {
|
|
20
|
+
expect(formatDuration(26 * 3600)).toBe('1d 2h')
|
|
21
|
+
expect(formatDuration(48 * 3600)).toBe('2d')
|
|
22
|
+
expect(formatDuration(26 * 3600 + 30 * 60)).toBe('1d 2h')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('says nothing rather than something wrong for nothing at all', () => {
|
|
26
|
+
expect(formatDuration(0)).toBe('0h')
|
|
27
|
+
expect(formatDuration(-5)).toBe('0h')
|
|
28
|
+
})
|
|
29
|
+
})
|
package/src/client/format.ts
CHANGED
|
@@ -153,12 +153,25 @@ export function daysUntil(dueDate: string, today = new Date()): number {
|
|
|
153
153
|
return Math.round((due - start) / 86_400_000)
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
/**
|
|
156
|
+
/**
|
|
157
|
+
* Seconds of time as somebody would say it: `45m`, `1h 30m`, `3h`, `1d 2h`.
|
|
158
|
+
*
|
|
159
|
+
* Minutes matter below a day. Rounding to whole hours reported 90 logged minutes as "2h" and a
|
|
160
|
+
* timer running for twenty as "0h" — for an estimate that is a rounding, for time somebody tracked
|
|
161
|
+
* it is wrong, and the same function shows both.
|
|
162
|
+
*
|
|
163
|
+
* Above a day, minutes stop being the point and are dropped.
|
|
164
|
+
*/
|
|
157
165
|
export function formatDuration(seconds: number): string {
|
|
158
166
|
if (seconds <= 0) return '0h'
|
|
159
|
-
const
|
|
160
|
-
if (
|
|
161
|
-
|
|
162
|
-
const
|
|
163
|
-
|
|
167
|
+
const totalMinutes = Math.round(seconds / 60)
|
|
168
|
+
if (totalMinutes < 60) return `${totalMinutes}m`
|
|
169
|
+
|
|
170
|
+
const totalHours = Math.floor(totalMinutes / 60)
|
|
171
|
+
const minutes = totalMinutes % 60
|
|
172
|
+
if (totalHours < 24) return minutes ? `${totalHours}h ${minutes}m` : `${totalHours}h`
|
|
173
|
+
|
|
174
|
+
const days = Math.floor(totalHours / 24)
|
|
175
|
+
const hours = totalHours % 24
|
|
176
|
+
return hours ? `${days}d ${hours}h` : `${days}d`
|
|
164
177
|
}
|