mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-23 20:25:56 +00:00
fix(alerts): align overview stat counts
The Alerts overview stats table right-aligned the value cell, but a row carrying the small critical annotation rendered it inline after the count, pushing that count left of the other rows. Give the annotation its own right-aligned cell so the numeric column lines up, and assert the count cell stays numeric in the 24h regression. Contract-Neutral: Behavioral alignment fix; no public-contract or subsystem-shape delta. Change-source: pulse-maintainer
This commit is contained in:
@@ -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."
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
<TableCell class={labelCellClass}>{labels().last24Hours}</TableCell>
|
||||
<TableCell class={valueCellClass} data-testid="alert-overview-stat-value">
|
||||
{props.state.alertStats().total24h}
|
||||
</TableCell>
|
||||
<TableCell class={criticalCellClass}>
|
||||
<Show when={props.state.alertStats().critical24h > 0}>
|
||||
<span class="ml-1.5 text-[10px] font-normal text-red-600 dark:text-red-400">
|
||||
<span class="text-[10px] font-normal text-red-600 dark:text-red-400">
|
||||
{props.state.alertStats().critical24h} critical
|
||||
</span>
|
||||
</Show>
|
||||
@@ -67,6 +70,7 @@ export function AlertOverviewStatsCards(props: AlertOverviewStatsCardsProps) {
|
||||
<TableCell class={valueCellClass} data-testid="alert-overview-stat-value">
|
||||
{props.state.alertStats().acknowledged}
|
||||
</TableCell>
|
||||
<TableCell class={criticalCellClass} />
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell class={dotCellClass}>
|
||||
@@ -76,6 +80,7 @@ export function AlertOverviewStatsCards(props: AlertOverviewStatsCardsProps) {
|
||||
<TableCell class={valueCellClass} data-testid="alert-overview-stat-value">
|
||||
{props.state.alertStats().overrides}
|
||||
</TableCell>
|
||||
<TableCell class={criticalCellClass} />
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
@@ -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<string, Alert> = {
|
||||
critical: { ...makeAlert('critical', recentTime), level: 'critical' },
|
||||
};
|
||||
|
||||
render(() => <OverviewTab {...defaultProps({ activeAlerts })} />);
|
||||
|
||||
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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user