feat(admin): live active-work view (5s refresh)
This commit is contained in:
14
apps/admin/src/lib/elapsed.test.ts
Normal file
14
apps/admin/src/lib/elapsed.test.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { formatTime } from './elapsed';
|
||||
|
||||
describe('formatTime', () => {
|
||||
it('formats seconds as HH:MM:SS', () => {
|
||||
expect(formatTime(0)).toBe('00:00:00');
|
||||
expect(formatTime(65)).toBe('00:01:05');
|
||||
expect(formatTime(3661)).toBe('01:01:01');
|
||||
});
|
||||
|
||||
it('never returns a negative time', () => {
|
||||
expect(formatTime(-10)).toBe('00:00:00');
|
||||
});
|
||||
});
|
||||
11
apps/admin/src/lib/elapsed.ts
Normal file
11
apps/admin/src/lib/elapsed.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
// Pure timing helper — server-authoritative elapsed.
|
||||
// Elapsed is computed from the server start_time (wall-clock), not a tick counter,
|
||||
// so it survives backgrounding. Ported from the worker's lib/stopwatch.ts.
|
||||
|
||||
export function formatTime(totalSeconds: number): string {
|
||||
const s = Math.max(0, Math.floor(totalSeconds));
|
||||
const h = Math.floor(s / 3600);
|
||||
const m = Math.floor((s % 3600) / 60);
|
||||
const sec = s % 60;
|
||||
return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(sec).padStart(2, '0')}`;
|
||||
}
|
||||
Reference in New Issue
Block a user