diff --git a/.changeset/fn-7633-priority-execution-oversight-height.md b/.changeset/fn-7633-priority-execution-oversight-height.md new file mode 100644 index 0000000000..264805cf6c --- /dev/null +++ b/.changeset/fn-7633-priority-execution-oversight-height.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Align Priority and Execution-mode control heights with the Oversight dropdown in task detail. +category: fix +dev: `.detail-priority-chip`, `.detail-execution-mode-toggle`, and `.detail-oversight-menu-trigger` in TaskDetailModal.css now all pin an explicit `height` (not just `min-height`) from the shared `--detail-priority-control-min-height` token, so none can outgrow or undershoot the others regardless of flex stretch behavior; extends the FN-7585/FN-7618 shared-token pattern. diff --git a/packages/dashboard/app/components/TaskDetailModal.css b/packages/dashboard/app/components/TaskDetailModal.css index b32ad8734b..9022026b87 100644 --- a/packages/dashboard/app/components/TaskDetailModal.css +++ b/packages/dashboard/app/components/TaskDetailModal.css @@ -393,6 +393,21 @@ The task-detail modal metadata must keep priority, execution mode, provenance, P .detail-priority-chip { gap: var(--space-xs); + /* + FNXC:TaskDetail 2026-07-07-15:40: + FN-7633 — Priority, Execution-mode, and the Oversight trigger must all + resolve the exact SAME box height, not merely the same floor. FN-7618 gave + the Oversight trigger `align-self: stretch` inside its own `inline-flex` + wrapper, so it fills the cluster row height, while this control (and + Execution-mode) were only floored via `min-height` and could resolve + shorter once their content/line-height differed from the trigger's. Pin an + explicit `height` (not just `min-height`) from the SAME + `--detail-priority-control-min-height` token used everywhere else in this + cluster so no control can outgrow or undershoot the others regardless of + flex stretch behavior. `min-height` stays as a floor for any context where + content needs more room (e.g. unexpected font scaling). + */ + height: var(--detail-priority-control-min-height); min-height: var(--detail-priority-control-min-height); padding-block: var(--space-xs); box-sizing: border-box; @@ -498,6 +513,15 @@ uppercases its content; this only removes a duplicated, drift-prone override. display: inline-flex; align-items: center; gap: var(--space-xs); + /* + FNXC:TaskDetail 2026-07-07-15:40: + FN-7633 — same shared-height fix as `.detail-priority-chip` above: pin an + explicit `height` (not just `min-height`) from the shared + `--detail-priority-control-min-height` token so this control cannot resolve + shorter than the Oversight trigger, which FN-7618 made stretch to the + cluster row height via its wrapper's `align-self: stretch`. + */ + height: var(--detail-priority-control-min-height); min-height: var(--detail-priority-control-min-height); padding-block: var(--space-xs); box-sizing: border-box; @@ -711,7 +735,6 @@ affect its size or anchoring — only the trigger's box height changes. display: inline-flex; align-items: center; gap: var(--space-xs); - min-height: var(--detail-priority-control-min-height); padding-block: var(--space-xs); box-sizing: border-box; /* @@ -727,11 +750,22 @@ affect its size or anchoring — only the trigger's box height changes. FNXC:TaskDetail 2026-07-05-14:00: FN-7618 — `align-self: stretch` makes the trigger fill the height of its `.detail-oversight-menu-dropdown` wrapper (now `inline-flex`/`align-items: - stretch`), which itself stretches to the shared cluster row height. The - `min-height` token above remains as the floor for any context where the - wrapper isn't stretched (e.g. isolated rendering), so the trigger never - drops below Priority/Execution-mode's height either way. + stretch`), which itself stretches to the shared cluster row height. Kept + below as a harmless safety net (a no-op once `height` is explicit) for any + context where the wrapper isn't stretched. + + FNXC:TaskDetail 2026-07-07-15:40: + FN-7633 — relying on `align-self: stretch` alone made this trigger resolve + a TALLER box than Priority/Execution-mode, which only had `min-height` as a + floor (not a fixed height), so the three controls no longer read as one + uniform row. Pin the SAME explicit `height` (not just `min-height`) from + the shared `--detail-priority-control-min-height` token used by + `.detail-priority-chip` and `.detail-execution-mode-toggle` above, so all + three controls resolve identical box heights regardless of flex + stretch/content differences. `min-height` stays as the floor. */ + height: var(--detail-priority-control-min-height); + min-height: var(--detail-priority-control-min-height); align-self: stretch; border-width: var(--btn-border-width); border-color: var(--border); diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx index 294fb16a5e..8827228a40 100644 --- a/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx +++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx @@ -304,6 +304,55 @@ describe("TaskDetailModal", () => { expect(mobileBlock).not.toMatch(/\.detail-oversight-menu-trigger\s*\{[^}]*align-self:\s*(?:auto|center|flex-start|flex-end);/); }); + it("resolves the same fixed box height for Priority, Execution-mode, and the Oversight trigger, not just a shared floor (FN-7633)", () => { + const css = readDashboardStylesSource(); + const mobileBlock = getCssAtRuleBlockContaining(css, "@media (max-width: 768px)", ".detail-meta-inline-controls"); + + const priorityChipBlock = getExactCssRuleBlock(css, ".detail-priority-chip"); + const executionToggleBlock = getExactCssRuleBlock(css, ".detail-execution-mode-toggle"); + const oversightTriggerBlock = getExactCssRuleBlock(css, ".detail-oversight-menu-trigger"); + const oversightMenuBlock = getExactCssRuleBlock(css, ".detail-oversight-menu"); + + // FN-7618 gave the Oversight trigger `align-self: stretch` so it fills + // its wrapper's stretched row height, while Priority and Execution-mode + // were only floored via `min-height` — a floor is not a guarantee of + // equality, so on desktop the trigger could resolve taller than its + // siblings whenever their content/line-height differed. Assert all + // three now pin an explicit, EQUAL `height` (not merely `min-height`) + // from the SAME shared token, so none can outgrow or undershoot the + // others regardless of flex stretch/content differences. + for (const block of [priorityChipBlock, executionToggleBlock, oversightTriggerBlock]) { + expect(block).toContain("height: var(--detail-priority-control-min-height);"); + expect(block).toContain("min-height: var(--detail-priority-control-min-height);"); + expect(block).toContain("box-sizing: border-box;"); + } + + // Guard against a future regression reintroducing a second, independent + // literal height source (e.g. a hardcoded px height) instead of reusing + // the shared token. + expect(css).not.toMatch(/\.detail-priority-chip\s*\{[^}]*height:\s*\d+px/); + expect(css).not.toMatch(/\.detail-execution-mode-toggle\s*\{[^}]*height:\s*\d+px/); + expect(css).not.toMatch(/\.detail-oversight-menu-trigger\s*\{[^}]*height:\s*\d+px/); + + // The fixed height must hold at non-mobile widths (the reported + // symptom) — the base (non-media-scoped) rules above already assert + // this since `getExactCssRuleBlock` matches the top-level selector, not + // one nested in a media query. + + // No `@media (max-width: 768px)` override redefines any of the three + // selectors with a diverging `height`, so the mobile wrap fallback + // keeps all three controls the same height too. + for (const selector of [".detail-priority-chip", ".detail-execution-mode-toggle", ".detail-oversight-menu-trigger"]) { + const mobileSelectorBlock = getExactCssRuleBlock(mobileBlock, selector); + expect(mobileSelectorBlock).toBe(""); + } + + // The popover itself must remain untouched by the height fix — still + // absolutely positioned, no explicit height forcing it to stretch. + expect(oversightMenuBlock).toContain("position: absolute;"); + expect(oversightMenuBlock).not.toMatch(/^\s*height:/m); + }); + it("renders the Priority dropdown chip like the Oversight dropdown chip, on every surface (FN-7597)", () => { const css = readDashboardStylesSource();