mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 02:25:56 +00:00
fix(ui): stop threshold sections clipping at 5000 pixels
CollapsibleSection capped its expanded state at max-h-[5000px] with overflow-hidden, so any section taller than that was silently truncated. The component wraps fourteen sections across the threshold tabs, so this was never limited to the one screen it was reported against. On this instance the guests section measures 10958px at 1440 wide, which the old cap cut roughly in half. The cap existed because CSS cannot transition to height:auto, so the animation needed a concrete bound. Raising it to a larger number only moves the cliff, so the collapse now switches the grid row track between 0fr and 1fr and the track carries the natural height with no ceiling. The transition is scoped to opacity rather than transition-all, and that part is load bearing. Under transition-all the browser holds grid-template-rows at whatever pixel value it had when the class flipped and never resolves the new track, which leaves a section stuck open or stuck shut permanently rather than merely un-animated. The first version of this change did exactly that, and the unit tests all passed because they assert class names rather than computed layout. Only the browser run caught it. Verified at 1440x1000 and 600x900: expanded reports the full row track with inner scrollHeight equal to clientHeight, collapsed reports 0px with the content clipped, and three toggle cycles alternate correctly at both widths. The height tween is gone, which is honest, since it never worked past 5000px and this engine does not interpolate grid-template-rows anyway. Opacity still fades. Refs #1680 Contract-Neutral: CSS-only collapse mechanism in one presentational component; no alert threshold behaviour, payload, or public contract changes, and the browser verification receipt is staged in the same commit
This commit is contained in:
@@ -1,40 +1,32 @@
|
||||
{
|
||||
"version": 1,
|
||||
"base_sha": "9a7afbd2eb5dd511eeadb30588c8479743e9c992",
|
||||
"verified_at": "2026-08-05T13:13:29Z",
|
||||
"base_sha": "364a3f458938a0610eb2a27c1ce81a73d0a0ffa7",
|
||||
"verified_at": "2026-08-05T14:24:00Z",
|
||||
"result": "passed",
|
||||
"changed_paths": [
|
||||
"frontend-modern/src/components/Workloads/GuestRowCells.tsx",
|
||||
"frontend-modern/src/components/Workloads/guestDrawerModel.ts",
|
||||
"frontend-modern/src/components/Workloads/useGuestDrawerState.ts",
|
||||
"frontend-modern/src/utils/format.ts",
|
||||
"frontend-modern/src/utils/workloadGuestPresentation.ts"
|
||||
"frontend-modern/src/components/Alerts/Thresholds/sections/CollapsibleSection.tsx"
|
||||
],
|
||||
"content_sha256": {
|
||||
"frontend-modern/src/components/Workloads/GuestRowCells.tsx": "6be782b43d9918672cee3cf10dab559bced312f7fcaac1f73a37b6273e64ccda",
|
||||
"frontend-modern/src/components/Workloads/guestDrawerModel.ts": "df599fe2a2d282fdf1b2afcde4fe813fe8e23df86a2d1255792ccaa9436f7833",
|
||||
"frontend-modern/src/components/Workloads/useGuestDrawerState.ts": "149410968bfb29f845d47a9d9288fa264751fb7f43816cff78b8ab42d605ee27",
|
||||
"frontend-modern/src/utils/format.ts": "d9e3d7fe2fe58e10666a414f208ed7aef53f2028db4f59c9c8a0e3bfd76e6901",
|
||||
"frontend-modern/src/utils/workloadGuestPresentation.ts": "b1d16be6ee3393d91161f2a97902fd152b7058f12a560e62baa9d023c02fb48b"
|
||||
"frontend-modern/src/components/Alerts/Thresholds/sections/CollapsibleSection.tsx": "4ea1aee30e4c5c0ecc0f07285a2da70f90b234137793d3d6bca1fcb73a9bb108"
|
||||
},
|
||||
"routes": [
|
||||
"/proxmox/overview"
|
||||
"/alerts/thresholds/proxmox"
|
||||
],
|
||||
"viewports": [
|
||||
{ "width": 600, "height": 900 },
|
||||
{ "width": 1440, "height": 1000 }
|
||||
],
|
||||
"states": [
|
||||
"Proxmox workload table with fresh backups green, aging and overdue backups amber, and missing backups red",
|
||||
"Desktop backup tooltips for a 15-day existing backup and a guest with no backup",
|
||||
"Desktop workload drawer showing the 15-day backup in the policy-derived amber tone",
|
||||
"Narrow workload table using amber and red shield indicators beside workload names",
|
||||
"Narrow workload drawer scrolled to the visible 15-day backup card"
|
||||
"Guests section expanded at 1440 wide reporting a 10958px grid row track with computed max-height none and no clipping",
|
||||
"Guests section collapsed at 1440 wide reporting a 0px row track with its content clipped by the inner overflow wrapper",
|
||||
"Guests section expanded at 600 wide reporting a 10810px row track and no clipping",
|
||||
"Nodes section expanded alongside at 2414px, confirming a second CollapsibleSection instance resolves its own track",
|
||||
"Document scroll width equal to client width at both viewports with no console errors"
|
||||
],
|
||||
"interactions": [
|
||||
"Hovered the 15-day and no-backup indicators and verified their tooltip copy and placement",
|
||||
"Opened and closed the 15-day workload drawer at desktop and narrow viewports",
|
||||
"Scrolled the narrow workload view until the full backup card was visible",
|
||||
"Verified the 15-day drawer value stays amber and the browser console remains error-free"
|
||||
"Collapsed and expanded the guests section three times at 1440 wide and confirmed the row track alternates between 0px and the full content height",
|
||||
"Collapsed and expanded the guests section at 600 wide and confirmed the same alternation",
|
||||
"Compared inner scrollHeight against clientHeight in every expanded state to prove the content is no longer truncated at the former 5000px cap",
|
||||
"Confirmed the computed transition-property is opacity, since transition-all pinned grid-template-rows at its pre-toggle pixel value and left the section stuck"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -133,18 +133,38 @@ export const CollapsibleSection: Component<CollapsibleSectionProps> = (props) =>
|
||||
</button>
|
||||
|
||||
{/* Section Content */}
|
||||
{/*
|
||||
Collapse switches the grid row track between 0fr and 1fr rather than
|
||||
animating max-height. CSS cannot transition to height:auto, so the
|
||||
earlier form animated up to a fixed max-h-[5000px] and clipped every
|
||||
section that grew past it (#1680). A taller cap only moves the cliff,
|
||||
so the row track carries the natural height and there is no ceiling.
|
||||
|
||||
The transition is deliberately scoped to opacity. Under transition-all
|
||||
the browser holds grid-template-rows at whatever pixel value it had
|
||||
when the class flipped and never resolves the new track, which leaves
|
||||
a section stuck open or stuck shut permanently rather than merely
|
||||
un-animated. Verified in the browser: with transition-all the expanded
|
||||
track reported 0px indefinitely, and scoping to opacity resolved it to
|
||||
the full content height on the same element.
|
||||
|
||||
The inner wrapper owns overflow-hidden so the collapsed track actually
|
||||
clips its content.
|
||||
*/}
|
||||
<div
|
||||
id={`section-content-${props.id}`}
|
||||
class={`overflow-hidden transition-all duration-200 ease-in-out
|
||||
${isCollapsed() ? 'max-h-0 opacity-0' : 'max-h-[5000px] opacity-100'}`}
|
||||
class={`grid transition-opacity duration-200 ease-in-out
|
||||
${isCollapsed() ? 'grid-rows-[0fr] opacity-0' : 'grid-rows-[1fr] opacity-100'}`}
|
||||
>
|
||||
<div class="p-4">
|
||||
<Show when={showEmpty()}>
|
||||
<div class="text-center py-8 text-muted">
|
||||
<p>{props.emptyMessage}</p>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={!isEmpty() || !props.emptyMessage}>{props.children}</Show>
|
||||
<div class="overflow-hidden min-h-0">
|
||||
<div class="p-4">
|
||||
<Show when={showEmpty()}>
|
||||
<div class="text-center py-8 text-muted">
|
||||
<p>{props.emptyMessage}</p>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={!isEmpty() || !props.emptyMessage}>{props.children}</Show>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user