From 4efb95faba045c37a04eb2c8c6a779a49e4a23b9 Mon Sep 17 00:00:00 2001 From: rcourtman <8825017+rcourtman@users.noreply.github.com> Date: Mon, 5 Oct 2026 21:49:14 +0100 Subject: [PATCH] Size Alert History columns to content so messages read The desktop alert history table gave every visible column an equal share (16.7%, 14.3% or 11.1% by density), so Message, the column that says what happened, got the same 100-160px as Timestamp. At most 21 of 106 messages read in full at any width, and "acknowledged" was cut at a 1024px viewport where Status got 100px. Each track now reads its width from a per-column custom property that the table sets at each density. Timestamp, severity, duration, status, type and node get what their content needs, Resource and Node keep at least their old share, the row actions stay within two lines (one line from an 80rem card), and Message takes the rest. The table width still compensates for collapsed tracks, so the visible ones fill the card; App.architecture.test.ts checks that arithmetic at every density. Measured on a mock stack from 768 to 1920px: fully readable messages rise at every width except the 600px card at a 1024px viewport (for example 15 to 66 at 1440 and 21 to 87 at 1920), every pill fits, Resource and Node truncate exactly as often as before, no header clips, and rows halve to 39px from 1760px. --- .../v6/internal/subsystems/alerts.md | 9 ++ .../subsystems/frontend-primitives.md | 5 + .../1f8abaa05e35815a.json | 91 +++++++++++++++ .../src/__tests__/App.architecture.test.ts | 60 ++++++++++ .../alerts/AlertHistoryTableSection.tsx | 19 ++-- frontend-modern/src/index.css | 104 ++++++++++++++---- .../pages/__tests__/Alerts.helpers.test.ts | 5 + 7 files changed, 264 insertions(+), 29 deletions(-) create mode 100644 frontend-modern/browser-verification/1f8abaa05e35815a.json diff --git a/docs/release-control/v6/internal/subsystems/alerts.md b/docs/release-control/v6/internal/subsystems/alerts.md index d5f84143cd..bdf49f8453 100644 --- a/docs/release-control/v6/internal/subsystems/alerts.md +++ b/docs/release-control/v6/internal/subsystems/alerts.md @@ -1081,6 +1081,15 @@ presentation and sort below warnings, while the history facet exposes a real Info option whose count and filtered rows use the same predicate as every other severity. +The desktop alert history table sizes each column for its content instead of +giving all visible columns an equal share. Timestamp, severity, duration, +status, type and node get what their content needs (status fits +"acknowledged"), Resource and Node keep at least their old share, the two row +actions stay within two lines (one line from an 80rem card), and Message, the +column that says what happened, takes the rest. Equal shares held Message to +the same 100-160px as the timestamp, so at most a fifth of messages read in +full at any width; from a 960px viewport a third to four fifths now do. + Alert history row timestamps render clock time in the viewer's own locale and must carry the absolute date and time as a title. The date otherwise lives only in the day group header, which scrolls out of sight, and a hardcoded diff --git a/docs/release-control/v6/internal/subsystems/frontend-primitives.md b/docs/release-control/v6/internal/subsystems/frontend-primitives.md index e077067776..74545a3f33 100644 --- a/docs/release-control/v6/internal/subsystems/frontend-primitives.md +++ b/docs/release-control/v6/internal/subsystems/frontend-primitives.md @@ -5837,6 +5837,11 @@ not overlap or create horizontal overflow. The 390px operator qualification must assert three visible labels, non-overlapping client rectangles, keyboard reachability, and a contained document before its actual-pixels receipt is recorded. +The Alert History table's density tracks in `index.css` carry per-column widths +through `--alert-history--width` custom properties set on the table at +each density. Fixed layout sizes all nine tracks before collapsed ones are +removed, so the visible widths sum to 100% and the table width is the sum of +all nine; `App.architecture.test.ts` checks both at every density. Alert History investigation detail is also responsive by interaction model, not only by CSS. Desktop may keep Timeline and Resource incident detail inline with its table row, while the virtualized phone card list must open the shared diff --git a/frontend-modern/browser-verification/1f8abaa05e35815a.json b/frontend-modern/browser-verification/1f8abaa05e35815a.json new file mode 100644 index 0000000000..e3cccdaeb1 --- /dev/null +++ b/frontend-modern/browser-verification/1f8abaa05e35815a.json @@ -0,0 +1,91 @@ +{ + "version": 1, + "base_sha": "1dcf9418aae87f9427dbfc6bcae67dbde114bf8a", + "verified_at": "2026-10-05T20:48:44Z", + "result": "passed", + "changed_paths": [ + "frontend-modern/src/features/alerts/AlertHistoryTableSection.tsx", + "frontend-modern/src/index.css" + ], + "content_sha256": { + "frontend-modern/src/features/alerts/AlertHistoryTableSection.tsx": "13521f02ee132d188c1b5f57639f5b73faba81bab3e9f9abd9f77926236352b8", + "frontend-modern/src/index.css": "e4bd257dd742fa95c9ab360b98348b63249ff63f8db4d85e4c5d4ee158f4bcf9" + }, + "routes": [ + "/alerts/history" + ], + "viewports": [ + { + "width": 768, + "height": 900 + }, + { + "width": 820, + "height": 900 + }, + { + "width": 900, + "height": 900 + }, + { + "width": 960, + "height": 900 + }, + { + "width": 1000, + "height": 900 + }, + { + "width": 1024, + "height": 900 + }, + { + "width": 1100, + "height": 900 + }, + { + "width": 1180, + "height": 900 + }, + { + "width": 1280, + "height": 900 + }, + { + "width": 1366, + "height": 900 + }, + { + "width": 1440, + "height": 900 + }, + { + "width": 1490, + "height": 900 + }, + { + "width": 1600, + "height": 900 + }, + { + "width": 1760, + "height": 900 + }, + { + "width": 1920, + "height": 900 + } + ], + "states": [ + "Private mock stack (PULSE_MOCK_MODE, random metrics off) serving this tree on main 1dcf9418aa; before = main, after = main plus this change, 106 alert rows measured in the same session; the table shows from 768 (below it the mobile list renders and is unchanged)", + "Main gave every visible column an equal share (16.7%, 14.3%, 11.1%), so Message got the same 100-160px as Timestamp: messages fully readable (each character checked against its clipping box) were 0-21 of 106 at every width; patched they rise at every width except the 600px card (1024 viewport), where neither shows any in full, for example 768 0 to 4, 1280 8 to 39, 1440 15 to 66, 1760 17 to 83, 1920 21 to 87", + "Status acknowledged (98px) overflowed its content box at 768, 1024 and 1100 on main (cut 6px at 1024); patched every status, type and severity pill fits at every width", + "No column is worse: Resource and Node clip counts are identical to main at every width, no header clips at 768, 1024, 1280, 1490, 1600 or 1760, and median row height is unchanged except 75 to 39px from 1760, where the two row actions fit on one line", + "Card width per density on this layout: 645 at 768, 600 at 1024 (navigation rail), 835 at 1280, 982 at 1440, 1134 at 1600, 1285 at 1760, 1436 at 1920; the visible tracks fill the card exactly at every width (table width equals the card)", + "Before and after screenshots of the table at 1024, 1440 and 1920" + ], + "interactions": [ + "Loaded /alerts/history fresh, waited for the rows, resized through every viewport before measuring", + "Opened and closed the Timeline and the Resource incident panels from the first row at 1024, 1280 and 1760; both open inline and close; no console errors" + ] +} diff --git a/frontend-modern/src/__tests__/App.architecture.test.ts b/frontend-modern/src/__tests__/App.architecture.test.ts index e9d9cc865b..a28bcd1293 100644 --- a/frontend-modern/src/__tests__/App.architecture.test.ts +++ b/frontend-modern/src/__tests__/App.architecture.test.ts @@ -1065,3 +1065,63 @@ describe('Docker phone update reflow boundary', () => { ); }); }); + +describe('Alert History column widths', () => { + // Fixed layout sizes all nine tracks against the table width before the + // collapsed ones are removed, so at each density the visible tracks must sum + // to 100% and the table width must be the sum of all nine; otherwise the + // visible columns stop filling the card or overflow it. + const columns = [ + 'timestamp', + 'resource', + 'type', + 'severity', + 'message', + 'duration', + 'status', + 'node', + 'actions', + ] as const; + const densities: Array<{ name: string; visible: readonly (typeof columns)[number][] }> = [ + { + name: 'base', + visible: ['timestamp', 'resource', 'severity', 'message', 'status', 'actions'], + }, + { + name: '50rem', + visible: ['timestamp', 'resource', 'severity', 'message', 'duration', 'status', 'actions'], + }, + { name: '64rem', visible: columns }, + { name: '80rem', visible: columns }, + ]; + const blocks = [ + ...appStylesSource.matchAll( + /table\.alert-history-responsive-table \{\s*((?:--alert-history-[a-z]+-width: [\d.]+%;\s*)+)width: ([\d.]+)%;/g, + ), + ]; + + it('declares every track width at each density', () => { + expect(blocks).toHaveLength(densities.length); + for (const column of columns) { + expect(appStylesSource).toContain( + `col.alert-history-${column}-track {\n width: var(--alert-history-${column}-width);`, + ); + } + }); + + it('fills the card exactly with the visible tracks', () => { + blocks.forEach((block, index) => { + const widths = Object.fromEntries( + [...block[1].matchAll(/--alert-history-([a-z]+)-width: ([\d.]+)%;/g)].map((match) => [ + match[1], + Number(match[2]), + ]), + ); + expect(Object.keys(widths).sort()).toEqual([...columns].sort()); + const visibleSum = densities[index].visible.reduce((sum, column) => sum + widths[column], 0); + const allSum = columns.reduce((sum, column) => sum + widths[column], 0); + expect(visibleSum).toBeCloseTo(100, 6); + expect(Number(block[2])).toBeCloseTo(allSum, 6); + }); + }); +}); diff --git a/frontend-modern/src/features/alerts/AlertHistoryTableSection.tsx b/frontend-modern/src/features/alerts/AlertHistoryTableSection.tsx index 4760ce5ab9..15af42fcad 100644 --- a/frontend-modern/src/features/alerts/AlertHistoryTableSection.tsx +++ b/frontend-modern/src/features/alerts/AlertHistoryTableSection.tsx @@ -54,16 +54,17 @@ export function AlertHistoryTableSection(props: AlertHistoryTableSectionProps) {