diff --git a/.changeset/fn-8131-quality-mobile-header.md b/.changeset/fn-8131-quality-mobile-header.md new file mode 100644 index 0000000000..20442858dc --- /dev/null +++ b/.changeset/fn-8131-quality-mobile-header.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Keep Quality hub actions visible beneath the title on mobile. +category: fix +dev: Scope the responsive header-wrap treatment to the bundled Quality plugin. diff --git a/plugins/fusion-plugin-quality/src/__tests__/dashboard-view-mobile-header.test.ts b/plugins/fusion-plugin-quality/src/__tests__/dashboard-view-mobile-header.test.ts new file mode 100644 index 0000000000..5a58e5d221 --- /dev/null +++ b/plugins/fusion-plugin-quality/src/__tests__/dashboard-view-mobile-header.test.ts @@ -0,0 +1,37 @@ +import { readFileSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { describe, expect, it } from "vitest"; + +const srcRoot = join(dirname(fileURLToPath(import.meta.url)), ".."); +const dashboardViewCss = readFileSync(join(srcRoot, "dashboard-view.css"), "utf8"); +const mobileMediaQuery = "@media (max-width: 768px), (max-height: 480px)"; + +function mediaBlock(css: string, query: string): string { + const start = css.indexOf(query); + expect(start, `expected ${query} mobile rule`).toBeGreaterThanOrEqual(0); + + const openBrace = css.indexOf("{", start); + let depth = 0; + for (let index = openBrace; index < css.length; index += 1) { + if (css[index] === "{") depth += 1; + if (css[index] === "}") depth -= 1; + if (depth === 0) return css.slice(openBrace + 1, index); + } + + throw new Error(`unterminated ${query} rule`); +} + +describe("QualityDashboardView mobile header CSS", () => { + it("gives the title its own row and wraps preset actions below it", () => { + const mobileCss = mediaBlock(dashboardViewCss, mobileMediaQuery); + + // FNXC:Quality 2026-07-16-12:45: FN-8131 preserves the mobile invariant for every run-count width and both canonical mobile breakpoint arms. + expect(mobileCss).toMatch(/\.quality-view \.view-header\s*\{[\s\S]*?flex-wrap\s*:\s*wrap\s*;/); + expect(mobileCss).toMatch(/\.quality-view \.view-header__title\s*\{[\s\S]*?flex\s*:\s*1\s+0\s+100%\s*;/); + expect(mobileCss).toMatch(/\.quality-view \.view-header__title\s*\{[\s\S]*?min-width\s*:\s*100%\s*;/); + expect(mobileCss).toMatch(/\.quality-view \.view-header__title span\s*\{[\s\S]*?overflow\s*:\s*visible\s*;/); + expect(mobileCss).toMatch(/\.quality-view \.view-header__actions\s*\{[\s\S]*?width\s*:\s*100%\s*;/); + expect(mobileCss).toMatch(/\.quality-view \.view-header__actions\s*\{[\s\S]*?margin-left\s*:\s*0\s*;/); + }); +}); diff --git a/plugins/fusion-plugin-quality/src/dashboard-view.css b/plugins/fusion-plugin-quality/src/dashboard-view.css index dc493a9e60..96551de06b 100644 --- a/plugins/fusion-plugin-quality/src/dashboard-view.css +++ b/plugins/fusion-plugin-quality/src/dashboard-view.css @@ -172,3 +172,32 @@ or bare h2/table inline styles. .quality-header-actions { display: contents; } + +/* +FNXC:Quality 2026-07-16-12:45: +FN-8131: On mobile, Quality's wide preset and refresh action cluster must give the title its own full-width row and wrap below it instead of shrinking the title to a `Q…` ellipsis or clipping buttons. This mirrors InsightsView FN-7830 while preserving the shared desktop header clamp. +*/ +@media (max-width: 768px), (max-height: 480px) { + .quality-view .view-header { + align-items: flex-start; + flex-wrap: wrap; + gap: var(--space-sm) var(--space-md); + } + + .quality-view .view-header__title { + flex: 1 0 100%; + min-width: 100%; + } + + .quality-view .view-header__title span { + overflow: visible; + text-overflow: clip; + } + + .quality-view .view-header__actions { + justify-content: flex-start; + width: 100%; + max-width: 100%; + margin-left: 0; + } +}