diff --git a/frontend-modern/browser-verification.json b/frontend-modern/browser-verification.json index 6bcf4a39e7..a5b4534b89 100644 --- a/frontend-modern/browser-verification.json +++ b/frontend-modern/browser-verification.json @@ -1,25 +1,21 @@ { "version": 1, - "base_sha": "ce1e99ba4e37b735d22158ac74a93afa26d7611f", - "verified_at": "2026-09-14T21:45:40.182293Z", + "base_sha": "1778f7d16c80c2ac9911a6fd8a11db7f967f3a99", + "verified_at": "2026-09-19T13:50:38Z", "result": "passed", "changed_paths": [ - "frontend-modern/src/api/notifications.ts", - "frontend-modern/src/components/Alerts/WebhookConfigList.tsx", - "frontend-modern/src/components/Alerts/useWebhookConfigState.ts" + "frontend-modern/src/features/alerts/AlertOverviewStatsCards.tsx" ], "content_sha256": { - "frontend-modern/src/api/notifications.ts": "ed4d7dd4946ed2295dff919134f394d0139d270bb446d069f4ddc8a9784b1667", - "frontend-modern/src/components/Alerts/WebhookConfigList.tsx": "0830ab5c9f7e0173dbdf3e92ed0e0c9cbf0a34942edb58001a3220d43b39d6c3", - "frontend-modern/src/components/Alerts/useWebhookConfigState.ts": "b641c911baeda41adfbf82621ede005db2bdc032f25786d4533c422b59b64047" + "frontend-modern/src/features/alerts/AlertOverviewStatsCards.tsx": "90f0b5102f2362c05a70c374afe5a386a679a1ebed3ab69580eb17278c38df05" }, "routes": [ - "/browser-tests/severity.html" + "/browser-tests/alerts-overview.html" ], "viewports": [ { - "width": 1440, - "height": 1000 + "width": 2010, + "height": 1072 }, { "width": 390, @@ -27,18 +23,15 @@ } ], "states": [ - "Existing warning email and webhook", - "All, critical and warning severity saved and reloaded", - "Cancelled webhook edit", - "New warning webhook persisted" + "Alerts overview stats with three active alerts including one critical", + "Triggered (24h) row carrying the small critical annotation", + "Acknowledged and Workload Overrides rows without the annotation" ], "interactions": [ - "Change production email severity selector, save through NotificationsAPI to synthetic backend, reload page and assert each supported value", - "Edit production webhook, save and reload each supported severity", - "Cancel changed webhook severity and verify original warning preserved", - "Create warning webhook and reload synthetic persisted store", - "Inspect desktop edit and narrow saved screenshots" + "Render the production AlertOverviewStatsCards component with a synthetic overview state at 2010x1072", + "Measure the text right edge of all three numeric value cells and confirm they are identical (359.41px)", + "Resize to 390x844 and confirm the numeric column stays aligned with no horizontal overflow" ], - "command": "pulse-worker-browser severity-browser.cjs", - "notes": "Production-component fixture built with Vite esnext and project CSS. Synthetic email HTTP responses and webhook localStorage persistence; no live backend, notification delivery or whole-application navigation proof. Runtime source hashes match the verified implementation. Desktop edit and narrow saved screenshots inspected." + "command": "pulse-worker-browser frontend-modern/alerts-visual.cjs", + "notes": "Offline Playwright Chromium 1.56.1 run of the production Alerts overview stats component with a synthetic state and project CSS; no live backend, API or WebSocket path. Value text right edges measured equal for all three rows (desktop 359.41px; narrow 266.27px); the Triggered (24h) row keeps its 1 critical annotation in its own right-aligned cell; narrow document scrollWidth 390 = clientWidth 390; no page errors. Desktop and narrow screenshots inspected." } diff --git a/frontend-modern/src/features/alerts/AlertOverviewStatsCards.tsx b/frontend-modern/src/features/alerts/AlertOverviewStatsCards.tsx index c743973d1c..dcfc348a16 100644 --- a/frontend-modern/src/features/alerts/AlertOverviewStatsCards.tsx +++ b/frontend-modern/src/features/alerts/AlertOverviewStatsCards.tsx @@ -14,7 +14,8 @@ interface AlertOverviewStatsCardsProps { const dotCellClass = 'w-6 pl-3 pr-0'; const labelCellClass = 'text-base-content'; -const valueCellClass = 'pr-3 text-right font-semibold tabular-nums text-base-content'; +const valueCellClass = 'pr-1.5 text-right font-semibold tabular-nums text-base-content'; +const criticalCellClass = 'pr-3 text-right'; const VARIANT_ACTIVE: Record<'triggered' | 'acknowledged', StatusIndicatorVariant> = { triggered: 'warning', @@ -45,8 +46,10 @@ export function AlertOverviewStatsCards(props: AlertOverviewStatsCardsProps) { {labels().last24Hours} {props.state.alertStats().total24h} + + 0}> - + {props.state.alertStats().critical24h} critical @@ -67,6 +70,7 @@ export function AlertOverviewStatsCards(props: AlertOverviewStatsCardsProps) { {props.state.alertStats().acknowledged} + @@ -76,6 +80,7 @@ export function AlertOverviewStatsCards(props: AlertOverviewStatsCardsProps) { {props.state.alertStats().overrides} + diff --git a/frontend-modern/src/features/alerts/__tests__/OverviewTab.total24h.test.tsx b/frontend-modern/src/features/alerts/__tests__/OverviewTab.total24h.test.tsx index 1309b153d9..a8f7539356 100644 --- a/frontend-modern/src/features/alerts/__tests__/OverviewTab.total24h.test.tsx +++ b/frontend-modern/src/features/alerts/__tests__/OverviewTab.total24h.test.tsx @@ -163,6 +163,25 @@ describe('OverviewTab Last 24 Hours stat', () => { expect(statValue?.textContent).toBe('3'); }); + it('keeps the critical annotation in its own cell so counts stay right-aligned', () => { + const recentTime = new Date(Date.now() - 1_800_000).toISOString(); + + const activeAlerts: Record = { + critical: { ...makeAlert('critical', recentTime), level: 'critical' }, + }; + + render(() => ); + + const label = screen.getByText('Triggered (24h)'); + const cells = Array.from(label.closest('tr')!.querySelectorAll('td')); + const valueIndex = cells.findIndex( + (cell) => cell.getAttribute('data-testid') === 'alert-overview-stat-value', + ); + expect(valueIndex).toBeGreaterThanOrEqual(0); + expect(cells[valueIndex].textContent).toBe('1'); + expect(cells[valueIndex + 1]?.textContent).toContain('1 critical'); + }); + it('excludes future-dated alerts (clock skew)', () => { const futureTime = new Date(Date.now() + 3_600_000).toISOString();