diff --git a/packages/dashboard/app/__tests__/activity-log-mobile-layout.test.ts b/packages/dashboard/app/__tests__/activity-log-layout.test.ts similarity index 82% rename from packages/dashboard/app/__tests__/activity-log-mobile-layout.test.ts rename to packages/dashboard/app/__tests__/activity-log-layout.test.ts index 7390f1e466..537596c24a 100644 --- a/packages/dashboard/app/__tests__/activity-log-mobile-layout.test.ts +++ b/packages/dashboard/app/__tests__/activity-log-layout.test.ts @@ -1,19 +1,15 @@ import { describe, it, expect } from "vitest"; import { loadAllAppCss } from "../test/cssFixture"; -import { readFileSync } from "fs"; -import { resolve } from "path"; /** - * Stylesheet regression test for Activity Log mobile layout. + * Stylesheet regression test for Activity Log modal layout. * - * Parses `packages/dashboard/app/styles.css` and asserts that an - * `@media (max-width: 768px)` block contains Activity Log mobile rules - * for stacked/wrapped controls and entry layout. These selectors must - * remain inside a mobile media query so the Activity Log renders - * correctly on narrow screens. + * Parses the app CSS bundle and asserts that desktop viewport constraints + * keep the modal on screen while mobile rules keep controls usable on + * narrow screens. */ -describe("activity-log-mobile-layout.css", () => { +describe("activity-log-layout.css", () => { const cssContent = loadAllAppCss(); /** Extract all content inside @media (max-width: 768px) blocks. */ @@ -42,12 +38,27 @@ describe("activity-log-mobile-layout.css", () => { // ── Modal sizing ──────────────────────────────────────────────────── - it("uses modal-lg base class for consistent wide sizing", () => { - // The activity-log-modal should NOT set its own max-width; modal-lg handles width + it("keeps desktop modal width within the viewport", () => { const modalBlock = cssContent.match(/\.activity-log-modal\s*\{[^}]*\}/)?.[0]; expect(modalBlock).toBeTruthy(); - // Should NOT contain max-width (handled by modal-lg base class) - expect(modalBlock).not.toMatch(/max-width:\s*\d+px/); + expect(modalBlock).toContain("width: min(95vw, 640px);"); + expect(modalBlock).toContain("max-width: 95vw;"); + }); + + it("keeps desktop modal height inside the visible viewport", () => { + const modalBlock = cssContent.match(/\.activity-log-modal\s*\{[^}]*\}/)?.[0]; + expect(modalBlock).toBeTruthy(); + expect(modalBlock).toMatch(/max-height:\s*calc\(100dvh - var\(--overlay-padding-top,\s*10vh\) - 16px\);/); + expect(modalBlock).toContain("overflow: hidden;"); + }); + + it("allows content pane to shrink and scroll inside the capped modal", () => { + const contentBlock = cssContent.match( + /\.activity-log-content\s*\{(?=[^}]*overflow-y:\s*auto;)(?=[^}]*min-height:\s*0;)[^}]*\}/, + )?.[0]; + expect(contentBlock).toBeTruthy(); + expect(contentBlock).toContain("overflow-y: auto;"); + expect(contentBlock).toContain("min-height: 0;"); }); // ── Close button ──────────────────────────────────────────────────── diff --git a/packages/dashboard/app/components/ScriptsModal.css b/packages/dashboard/app/components/ScriptsModal.css index 33be4d3ecd..0dd03147c3 100644 --- a/packages/dashboard/app/components/ScriptsModal.css +++ b/packages/dashboard/app/components/ScriptsModal.css @@ -1180,9 +1180,12 @@ /* ── Activity Log Modal ─────────────────────────────────────────── */ .activity-log-modal { - max-height: 80vh; + width: min(95vw, 640px); + max-width: 95vw; + max-height: calc(100dvh - var(--overlay-padding-top, 10vh) - 16px); display: flex; flex-direction: column; + overflow: hidden; } .activity-log-header { @@ -1250,7 +1253,7 @@ flex: 1; overflow-y: auto; padding: var(--space-lg) var(--space-xl); - min-height: 300px; + min-height: 0; } .activity-log-empty {