From 3766dfc2a75b45c99feb1eae0ff70ca570b47bfe Mon Sep 17 00:00:00 2001 From: ischindl Date: Mon, 10 Aug 2026 01:49:56 +0200 Subject: [PATCH] fix: Engine Control popover collapsed to ~trigger width (FN-8802 .card clamp) (#3363) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What & why RUFU-042. The open **Engine Controls** popover (footer status bar, bottom-right) carries the shared `.card` class. Since FN-8802, `.card` bases set `min-width: 0; max-width: 100%` (TaskCard.css). The popover's containing block (`.engine-control-menu`) sizes to the narrow trigger button, so `.card`'s `max-width: 100%` clamped the intended `24rem` grid down to ~the trigger's width — a **~5mm-wide invisible popover**. ## Fix (CSS only, `EngineControlMenu.css`) - Footer-scoped desktop rule (`0,3,0`) re-asserts `min-width`/`max-width` clamped to the **viewport** (not the trigger wrapper), deterministically beating the shared `.card` (`0,1,0`) by specificity — same pattern as `.selection-comment-panel.card`. - Mobile `@media (max-width:1024px)` resets `min-width:0; max-width:none` so the full-width gutter panel cannot overflow nor be re-clamped by `.card`. - No `className="card"` removal; shared `.card` base untouched. ## Regression tests Two new tests in `EngineControlMenu.test.tsx` assert the desktop min/max guard and the mobile reset, so the collapse cannot silently return. **17/17 tests pass.** No changeset (`@fusion/dashboard` is a private package). ## Summary by CodeRabbit * **Bug Fixes** * Improved engine control popovers so they size correctly without collapsing or overflowing. * Enhanced mobile layouts to maintain full-width display with appropriate screen gutters. * **Tests** * Added regression coverage for desktop width limits and narrow-screen popover behavior. Co-authored-by: Fusion Co-authored-by: gsxdsm --- .../app/components/EngineControlMenu.css | 27 ++++++++++++++++++ .../__tests__/EngineControlMenu.test.tsx | 28 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/packages/dashboard/app/components/EngineControlMenu.css b/packages/dashboard/app/components/EngineControlMenu.css index 7f5b899bcb..e28a4ca2a0 100644 --- a/packages/dashboard/app/components/EngineControlMenu.css +++ b/packages/dashboard/app/components/EngineControlMenu.css @@ -2,8 +2,24 @@ position: relative; display: inline-flex; align-items: center; + width: max-content; } +/* +FNXC:EngineControls 2026-08-08-15:40 (FN-8802 width-collapse regression, RUFU-042): +The open popover carries the shared `.card` class, whose base now sets `min-width: 0` and +`max-width: 100%` (FN-8802, TaskCard.css). Its containing block is this `.engine-control-menu` +wrapper, which sizes to the narrow trigger button; `.card`'s `max-width: 100%` therefore +clamped the intended grid width down to ~the trigger's width (~5mm), hiding all content. + +The selected text (width/min-width/max-width) below must beat `.card` deterministically, so it +targets the popover in its only real mount context (the ExecutorStatusBar footer segment) with +higher specificity — the same pattern used by `.selection-comment-panel.card`. `max-width` is +clamped to the VIEWPORT (not the trigger wrapper), `min-width` sets the floor so it can never +collapse to a sliver, and the footer-scoped overrides re-assert the width so later `.card` rules +cannot win by load order. +*/ + .engine-control-menu__trigger { color: var(--text-muted); } @@ -186,9 +202,15 @@ FN-8007 defines both desktop pseudo-thumbs locally with the marker's shared size } .executor-status-bar__segment--engine-controls .engine-control-menu > .engine-control-menu__popover.card { + /* RUFU-042 (FN-8802 regression): this footer-scoped rule (0,3,0) out-specifies the shared + `.card` base (0,1,0), which sets `min-width: 0; max-width: 100%` (TaskCard.css). Without + these re-assertions `.card` could clamp the popover to its narrow trigger wrapper (~5mm). + `max-width` is clamped to the VIEWPORT, not the trigger, so the grid width survives. */ position: absolute; right: 0; bottom: calc(100% + var(--space-xs)); + min-width: min(24rem, calc(100vw - (var(--space-lg) * 2))); + max-width: calc(100vw - (var(--space-lg) * 2)); } @media (max-width: 768px) { @@ -232,6 +254,9 @@ FN-8007 defines both desktop pseudo-thumbs locally with the marker's shared size right: var(--space-sm); bottom: var(--engine-control-mobile-bottom-stack); width: auto; + /* RUFU-042 (FN-8802 regression): reset the desktop viewport min/max floor so the phone-width gutter panel never overflows; `.card`'s max-width:100% cannot clamp the left/right-stretched panel. */ + min-width: 0; + max-width: none; max-height: min(28rem, calc(100dvh - var(--engine-control-mobile-bottom-stack) - (var(--space-md) * 2))); overflow: auto; } @@ -243,6 +268,8 @@ FN-8007 defines both desktop pseudo-thumbs locally with the marker's shared size right: var(--space-sm); bottom: var(--engine-control-mobile-bottom-stack); width: auto; + min-width: 0; + max-width: none; max-height: min(28rem, calc(100dvh - var(--engine-control-mobile-bottom-stack) - (var(--space-md) * 2))); overflow: auto; } diff --git a/packages/dashboard/app/components/__tests__/EngineControlMenu.test.tsx b/packages/dashboard/app/components/__tests__/EngineControlMenu.test.tsx index 6160095be9..a7c286ec5a 100644 --- a/packages/dashboard/app/components/__tests__/EngineControlMenu.test.tsx +++ b/packages/dashboard/app/components/__tests__/EngineControlMenu.test.tsx @@ -427,4 +427,32 @@ describe("EngineControlMenu", () => { expect(await screen.findByRole("alert")).toHaveTextContent("settings unavailable"); }); + + // FNXC:EngineControls 2026-08-08-15:40 (FN-8802 width-collapse regression, RUFU-042): + // The open popover carries the shared `.card` class, whose base now sets `min-width: 0` and + // `max-width: 100%` (TaskCard.css). Its containing block is `.engine-control-menu` which sizes + // to the narrow trigger button, so `.card`'s `max-width: 100%` clamped the popover's intended + // grid width down to ~the trigger's width (~5mm). The footer-scoped rule (0,3,0) must re-assert + // a VIEWPORT-clamped min/max width that beats `.card` (0,1,0), so the menu can never collapse + // to a sliver. Keep this guard asserted so the fix cannot silently regress. + it("keeps the footer-scoped popover width immune to the shared `.card` clamp on desktop", () => { + const footerPopover = cssRule(engineControlMenuCss, ".executor-status-bar__segment--engine-controls .engine-control-menu > .engine-control-menu__popover.card"); + expect(footerPopover).toContain("position: absolute;"); + expect(footerPopover).toContain("min-width: min(24rem, calc(100vw - (var(--space-lg) * 2)));"); + expect(footerPopover).toContain("max-width: calc(100vw - (var(--space-lg) * 2));"); + }); + + // FNXC:EngineControls 2026-08-08-15:40 (FN-8802 width-collapse regression, RUFU-042): + // On narrow/tablet widths the popover becomes a full-width gutter panel (`left/right: var(--space-sm)`). + // It must reset the desktop min/max floor and defeat `.card`'s `max-width: 100%` so the phone panel + // stays full-width without overflowing. Assert the media-query rules only (cssRule grabs the first + // selector match, which is the desktop base rule, so match the @media block explicitly). + it("keeps the mobile popover full-width and never overflowed by the desktop min-width floor", () => { + const mobileBlock = engineControlMenuCss.match(/@media \(max-width: 1024px\) \{([\s\S]*?)\}/)?.[1] ?? ""; + expect(mobileBlock).toContain("left: var(--space-sm);"); + expect(mobileBlock).toContain("right: var(--space-sm);"); + expect(mobileBlock).toContain("max-width: none;"); + expect(mobileBlock).toContain("min-width: 0;"); + expect(mobileBlock).toContain("width: auto;"); + }); });