From 4a63149338665a05b39972af8d036ab5c2b657bb Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Tue, 21 Apr 2026 10:00:15 +0200 Subject: [PATCH] feat(alerts/ui): add formatRelativeTime helper Formats ISO timestamps as `Nm ago` / `Nh ago` / `Nd ago`, falling back to an absolute locale date string for values older than 30 days. Used by the alert DataTable Age column. Co-Authored-By: Claude Opus 4.7 (1M context) --- ui/src/pages/Alerts/time-utils.test.ts | 32 ++++++++++++++++++++++++++ ui/src/pages/Alerts/time-utils.ts | 12 ++++++++++ 2 files changed, 44 insertions(+) create mode 100644 ui/src/pages/Alerts/time-utils.test.ts create mode 100644 ui/src/pages/Alerts/time-utils.ts diff --git a/ui/src/pages/Alerts/time-utils.test.ts b/ui/src/pages/Alerts/time-utils.test.ts new file mode 100644 index 00000000..e541a1ba --- /dev/null +++ b/ui/src/pages/Alerts/time-utils.test.ts @@ -0,0 +1,32 @@ +import { describe, it, expect } from 'vitest'; +import { formatRelativeTime } from './time-utils'; + +const NOW = new Date('2026-04-21T12:00:00Z'); + +describe('formatRelativeTime', () => { + it('returns "just now" for < 30s', () => { + expect(formatRelativeTime('2026-04-21T11:59:50Z', NOW)).toBe('just now'); + }); + + it('returns minutes for < 60m', () => { + expect(formatRelativeTime('2026-04-21T11:57:00Z', NOW)).toBe('3m ago'); + }); + + it('returns hours for < 24h', () => { + expect(formatRelativeTime('2026-04-21T10:00:00Z', NOW)).toBe('2h ago'); + }); + + it('returns days for < 30d', () => { + expect(formatRelativeTime('2026-04-18T12:00:00Z', NOW)).toBe('3d ago'); + }); + + it('returns locale date string for older than 30d', () => { + const out = formatRelativeTime('2025-01-01T00:00:00Z', NOW); + expect(out).not.toMatch(/ago$/); + expect(out.length).toBeGreaterThan(0); + }); + + it('handles future timestamps by clamping to "just now"', () => { + expect(formatRelativeTime('2026-04-21T12:00:30Z', NOW)).toBe('just now'); + }); +}); diff --git a/ui/src/pages/Alerts/time-utils.ts b/ui/src/pages/Alerts/time-utils.ts new file mode 100644 index 00000000..eb2a810d --- /dev/null +++ b/ui/src/pages/Alerts/time-utils.ts @@ -0,0 +1,12 @@ +export function formatRelativeTime(iso: string, now: Date = new Date()): string { + const then = new Date(iso).getTime(); + const diffSec = Math.max(0, Math.floor((now.getTime() - then) / 1000)); + if (diffSec < 30) return 'just now'; + if (diffSec < 3600) return `${Math.floor(diffSec / 60)}m ago`; + if (diffSec < 86_400) return `${Math.floor(diffSec / 3600)}h ago`; + const diffDays = Math.floor(diffSec / 86_400); + if (diffDays < 30) return `${diffDays}d ago`; + return new Date(iso).toLocaleDateString('en-GB', { + year: 'numeric', month: 'short', day: '2-digit', + }); +}