diff --git a/docs/release-control/v6/internal/subsystems/frontend-primitives.md b/docs/release-control/v6/internal/subsystems/frontend-primitives.md index 03a9c7ad7d..4b5949e6b6 100644 --- a/docs/release-control/v6/internal/subsystems/frontend-primitives.md +++ b/docs/release-control/v6/internal/subsystems/frontend-primitives.md @@ -2314,6 +2314,10 @@ not a replacement status card, CTA band, or page-local nested card. `platformTableBandWidthStyle` or the sortable header's `bandWidth`, which sets `--platform-table-band-width`; the shell applies it only inside the band, after the name anchor, so md widths and phone widths are unchanged. + A column whose content must read in full (a status badge) is sized for its + widest label at the narrowest table in each range: a 34rem container for the + band, and the table a 768px viewport leaves (about 695px) for md widths. The + Docker Images Update check column needs 23 percent and 19 percent for that. Below a 360-pixel content width, the shared narrow layout promotes identity to 40 percent and may remove one additional lowest-priority context column via `platform-table-narrow-hidden` rather than shrinking names and metric values diff --git a/docs/release-control/v6/internal/subsystems/unified-resources.md b/docs/release-control/v6/internal/subsystems/unified-resources.md index 3ebdb085bb..967de370dc 100644 --- a/docs/release-control/v6/internal/subsystems/unified-resources.md +++ b/docs/release-control/v6/internal/subsystems/unified-resources.md @@ -882,7 +882,12 @@ failed and server-denied observations alongside a no-invented-grant control. The Docker phone container projection keeps identity, state when applicable, CPU, memory and update; restart counts remain in the existing detail expansion and return at mobile width. Images retain image, size and update verdict on -phones; host and consumers stay reachable in detail. Hidden header/body columns +phones; host and consumers stay reachable in detail. The update verdict reads +in full at every width: the Update check column keeps the ~122px its longest +badge ("Update available", "Managed by Pulse") needs with cell padding, through +a 23 percent tablet-band width taken from Size and a 19 percent md width taken +from Host, Used by and Size. An equal band share and the old 16 percent md width cut +the badge off between 600 and 800px. Hidden header/body columns are symmetric. Swarm rollout tokens render as words with raw state retained in the title; task starts use the shared relative-time primitive with their exact timestamp retained. Native table/model/guardrail tests and the production diff --git a/frontend-modern/browser-verification/7db5e194a586019d.json b/frontend-modern/browser-verification/7db5e194a586019d.json new file mode 100644 index 0000000000..200a52b266 --- /dev/null +++ b/frontend-modern/browser-verification/7db5e194a586019d.json @@ -0,0 +1,99 @@ +{ + "version": 1, + "base_sha": "8e68bab55a68d80c7fa234a89216daa5e3af8f29", + "verified_at": "2026-10-05T13:41:29Z", + "result": "passed", + "changed_paths": [ + "frontend-modern/src/features/docker/DockerImagesTable.tsx" + ], + "content_sha256": { + "frontend-modern/src/features/docker/DockerImagesTable.tsx": "a4b95eaae2c0b67cc8195b3b5f5812cee3499bd583da195f809bf8ff1c4e81f0" + }, + "routes": [ + "/docker/images" + ], + "viewports": [ + { + "width": 390, + "height": 900 + }, + { + "width": 430, + "height": 900 + }, + { + "width": 480, + "height": 900 + }, + { + "width": 540, + "height": 900 + }, + { + "width": 573, + "height": 900 + }, + { + "width": 600, + "height": 900 + }, + { + "width": 640, + "height": 900 + }, + { + "width": 700, + "height": 900 + }, + { + "width": 740, + "height": 900 + }, + { + "width": 767, + "height": 900 + }, + { + "width": 768, + "height": 900 + }, + { + "width": 800, + "height": 900 + }, + { + "width": 900, + "height": 900 + }, + { + "width": 1024, + "height": 900 + }, + { + "width": 1100, + "height": 900 + }, + { + "width": 1280, + "height": 900 + }, + { + "width": 1440, + "height": 900 + } + ], + "states": [ + "Private mock stack (PULSE_MOCK_MODE, random metrics off) serving this tree on main 8e68bab55a, which already carries the Used by block-truncate span from #2514; before = main, after = main plus this change", + "Clip sweep (scrollWidth over clientWidth + 1 on every td and its overflow-hidden or ellipsis descendants, .sr-only excluded) at 15 widths from 390 to 1440: the Update check badge clipped at 600, 640, 700 and 768 on main and nowhere patched; total clipped elements 65 on main, 61 patched; Image, Host, Used by and Size clip counts identical at every width (Used by 1/2/2/1 at 600/640/700/740 both ways, 0 from 768)", + "Label probe: each of the six update labels (Update available 97.9px, Managed by Pulse 105.8px, Check failed, Not checked, Current, Pinned) cloned into the narrowest Update check cell: on main Update available and Managed by Pulse overflow at 600, 640, 700 and 768, and Managed by Pulse alone at 740 and 800; patched every label fits at every width (Update check content box 113px at the 573px band edge, 116px at 768, 108px at 390)", + "Column widths patched: band at 600 Image 171 / Host 100 / Used by 100 / Size 69 / Update check 131 (Host and Used by unchanged from main); md at 768 Image 209 / Host 118 / Used by 160 / Size 76 / Update check 132 (main 209 / 125 / 167 / 83 / 111)", + "Size probe: the widest byte strings (1023 MB, 9.99 GB, 99.9 MB, 1023 KB) fit the narrower Size cell at 573, 640, 767, 768, 800 and 900 (worst 49.6px in a 53 to 74px content box)", + "The UPDATE CHECK header clipped at 600 on main, including with a sort indicator; patched no header clips at any width, sorted or not", + "Before and after element screenshots of the table at 600, 700, 768 and 1440 show the postgres:16.4 Update available badge cut at the cell edge with a stray ellipsis dot on main and whole patched; the phone projection at 390 keeps Image, Size and Update check unchanged" + ], + "interactions": [ + "Loaded /docker/images fresh, waited for the row count to settle, then resized through every viewport before measuring", + "Sorted by Size and by Update check at the 573px band edge and re-measured header clipping", + "Expanded and collapsed the Update available row's detail at 390, 600, 768 and 1440 (aria-expanded true then false, detail row visible); no console errors" + ] +} diff --git a/frontend-modern/src/features/docker/DockerImagesTable.tsx b/frontend-modern/src/features/docker/DockerImagesTable.tsx index 454a028d53..b470bbbbb0 100644 --- a/frontend-modern/src/features/docker/DockerImagesTable.tsx +++ b/frontend-modern/src/features/docker/DockerImagesTable.tsx @@ -140,11 +140,21 @@ export const DockerImagesTable: Component< tableClass="min-w-full table-fixed text-xs md:min-w-[880px]" header={ <> + {/* + The Update check badge needs about 122px with its cell + padding ("Update available", "Managed by Pulse"). An + equal tablet-band share gave it 100px at 600px, and 16% + at md gave it 111px at 768px, so the label was cut off. + Size values are short, so the band takes the extra room + from Size, and md takes a point each from Host, Used by + and Size, which had room to spare there. + */} Image @@ -152,7 +162,8 @@ export const DockerImagesTable: Component< kind="text" sort={sort} sortKey="host" - class="platform-table-phone-hidden md:w-[18%]" + class="platform-table-phone-hidden md:w-[17%]" + bandWidth={17.5} > Host @@ -160,7 +171,8 @@ export const DockerImagesTable: Component< kind="text" sort={sort} sortKey="usedBy" - class="platform-table-phone-hidden md:w-[24%]" + class="platform-table-phone-hidden md:w-[23%]" + bandWidth={17.5} > Used by @@ -168,7 +180,8 @@ export const DockerImagesTable: Component< kind="numeric-value" sort={sort} sortKey="size" - class="platform-table-mobile-w-20 md:w-[12%]" + class="platform-table-mobile-w-20 md:w-[11%]" + bandWidth={12} > Size @@ -176,7 +189,8 @@ export const DockerImagesTable: Component< kind="badge" sort={sort} sortKey="update" - class="platform-table-mobile-w-25 md:w-[16%]" + class="platform-table-mobile-w-25 md:w-[19%]" + bandWidth={23} > diff --git a/frontend-modern/src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts b/frontend-modern/src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts index f55f91896a..61a4dd9678 100644 --- a/frontend-modern/src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts +++ b/frontend-modern/src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts @@ -322,18 +322,24 @@ describe('platform overview layout guardrails', () => { expect(source).toContain('platform-table-mobile-w-30'); } // The images phone row keeps image, size and the update verdict; host and - // consumers move to the row expansion so the verdict is not clipped. + // consumers move to the row expansion so the verdict is not clipped. In + // the tablet band and at md the Update check column keeps the ~122px its + // longest badge needs ("Update available", "Managed by Pulse"), taken + // from Size in the band and from Host, Used by and Size at md. expect(dockerImagesTableSource).toMatch( - /sortKey="size"[\s\S]{0,120}?class="platform-table-mobile-w-20 md:w-\[12%\]"/, + /sortKey="image"[\s\S]{0,120}?class="platform-table-mobile-w-30 md:w-\[30%\]"\s*bandWidth=\{30\}/, ); expect(dockerImagesTableSource).toMatch( - /sortKey="host"[\s\S]{0,120}?class="platform-table-phone-hidden md:w-\[18%\]"/, + /sortKey="size"[\s\S]{0,120}?class="platform-table-mobile-w-20 md:w-\[11%\]"\s*bandWidth=\{12\}/, ); expect(dockerImagesTableSource).toMatch( - /sortKey="usedBy"[\s\S]{0,120}?class="platform-table-phone-hidden md:w-\[24%\]"/, + /sortKey="host"[\s\S]{0,120}?class="platform-table-phone-hidden md:w-\[17%\]"\s*bandWidth=\{17\.5\}/, ); expect(dockerImagesTableSource).toMatch( - /sortKey="update"[\s\S]{0,120}?class="platform-table-mobile-w-25 md:w-\[16%\]"/, + /sortKey="usedBy"[\s\S]{0,120}?class="platform-table-phone-hidden md:w-\[23%\]"\s*bandWidth=\{17\.5\}/, + ); + expect(dockerImagesTableSource).toMatch( + /sortKey="update"[\s\S]{0,120}?class="platform-table-mobile-w-25 md:w-\[19%\]"\s*bandWidth=\{23\}/, ); expect(dockerServicesTableSource).toMatch( /sortKey="mode"[\s\S]{0,120}?class="platform-table-phone-hidden md:w-\[8%\]"/,