mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-24 12:42:49 +00:00
Keep the Docker image update badge readable at tablet widths (#2516)
## Problem
On `/docker/images` the Update check badge was cut off at tablet widths.
Its longest labels ("Update available", "Managed by Pulse") need about
122px including cell padding.
- In the tablet band (a 34rem container below a 768px viewport) every
non-name column took an equal 17.5% share. That left Update check 100px
at 600px and 110px at 700px.
- The 16% md width left it 111px at 768px.
The badge was cut at the cell edge with a stray ellipsis dot, and the
"UPDATE CHECK" header clipped at 600px.
## Change
`DockerImagesTable.tsx` changes only column widths. The badge label is
unchanged.
| Column | Band (`bandWidth`) | md before → after |
|---|---|---|
| Image | 30 | 30 → 30 |
| Host | 17.5 | 18 → 17 |
| Used by | 17.5 | 24 → 23 |
| Size | 12 | 12 → 11 |
| Update check | 23 | 16 → 19 |
Host and Used by keep the band share they already had. Size gives up the
room in the band, because its widest values ("1023 MB", "9.99 GB",
49.6px) still fit its narrowest cell (53px). The md change takes one
point each from Host, Used by and Size.
`platformOverviewLayout.guardrails.test.ts` pins the new md and band
widths. Contract notes are in `unified-resources.md` (Docker images) and
`frontend-primitives.md` (sizing a badge column for its narrowest table
in each range).
## Verification
I ran a mock-mode private stack on main 8e68bab55a, which already
includes #2514's Used by span change.
- **Clip sweep:** 15 widths from 390 to 1440px, checking `scrollWidth >
clientWidth + 1` on every cell and its overflow-hidden descendants.
- The update badge clipped at 600, 640, 700 and 768px on main, and
nowhere after this change.
- Image, Host, Used by and Size have the same clip counts at every
width. Total clipped elements went from 65 to 61.
- **Label probe:** all six update labels cloned into the narrowest
Update check cell. On main, "Managed by Pulse" overflows from 600 to
800px and "Update available" at 600, 640, 700 and 768px. After this
change, every label fits at every width.
- **Headers:** no header clips at any width, including with a sort
indicator.
- **Interactions:** row expand and collapse works at 390, 600, 768 and
1440px. No console errors.
- **Tests:** `src/features/platformPage` and `src/features/docker` pass
(37 files, 653 tests). The updated guardrail test fails against the old
source.
The browser receipt is
`frontend-modern/browser-verification/7db5e194a586019d.json`.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
@@ -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.
|
||||
*/}
|
||||
<PlatformSortableTableHead
|
||||
kind="name"
|
||||
sort={sort}
|
||||
sortKey="image"
|
||||
class="platform-table-mobile-w-30 md:w-[30%]"
|
||||
bandWidth={30}
|
||||
>
|
||||
Image
|
||||
</PlatformSortableTableHead>
|
||||
@@ -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
|
||||
</PlatformSortableTableHead>
|
||||
@@ -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
|
||||
</PlatformSortableTableHead>
|
||||
@@ -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
|
||||
</PlatformSortableTableHead>
|
||||
@@ -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}
|
||||
>
|
||||
<PlatformResponsiveTableLabel compact="Update" full="Update check" />
|
||||
</PlatformSortableTableHead>
|
||||
|
||||
+11
-5
@@ -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%\]"/,
|
||||
|
||||
Reference in New Issue
Block a user