diff --git a/.changeset/fix-done-bar-scroll.md b/.changeset/fix-done-bar-scroll.md index edac04f39..f049da4a8 100644 --- a/.changeset/fix-done-bar-scroll.md +++ b/.changeset/fix-done-bar-scroll.md @@ -2,4 +2,4 @@ "@aoagents/ao-web": patch --- -Fix Done/Terminated section on the dashboard not scrolling. The expanded cards grid now has an internal scroll container (mirroring the kanban column body pattern), so older terminated sessions are reachable when many accumulate. +Fix Done/Terminated section on the dashboard not scrolling. The dashboard body now scrolls as a single page — kanban above, Done/Terminated below — so older terminated sessions are reachable when many accumulate. Restores the pre-Warm-Terminal-refresh behavior by dropping the `flex: 1` that was making `.kanban-board-wrap` greedily consume all remaining body height and defeat the body's `overflow-y: auto`. diff --git a/packages/web/src/app/globals.css b/packages/web/src/app/globals.css index d85a5c6c0..f7e239966 100644 --- a/packages/web/src/app/globals.css +++ b/packages/web/src/app/globals.css @@ -1545,7 +1545,6 @@ html.light .xterm .xterm-viewport:hover::-webkit-scrollbar-thumb:active { padding: 0 16px 16px; } -.dashboard-main__body .kanban-board-wrap, .dashboard-main__body .board-wrapper { flex: 1; min-height: 0; @@ -5185,6 +5184,7 @@ html.light .xterm .xterm-viewport:hover::-webkit-scrollbar-thumb:active { position: relative; margin-top: 14px; overflow-x: auto; + flex-shrink: 0; } .board-section-head { @@ -5803,6 +5803,10 @@ html.light .xterm .xterm-viewport:hover::-webkit-scrollbar-thumb:active { /* ── Done / Terminated collapsible bar ────────────────────────────────── */ +.done-bar { + flex-shrink: 0; +} + .done-bar__toggle { display: flex; align-items: center; @@ -5858,21 +5862,6 @@ html.light .xterm .xterm-viewport:hover::-webkit-scrollbar-thumb:active { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 8px; margin-top: 12px; - /* 320px ≈ dashboard header + subhead + body padding + done-bar toggle/margins. - Mirrors the .kanban-board viewport-anchored height pattern (line 5107). */ - max-height: calc(100vh - 320px); - overflow-y: auto; -} - -.done-bar__cards::-webkit-scrollbar { - width: 4px; -} -.done-bar__cards::-webkit-scrollbar-track { - background: transparent; -} -.done-bar__cards::-webkit-scrollbar-thumb { - background: var(--color-scrollbar); - border-radius: 0; } /* ── Done card (compact grid card) ──────────────────────────────────── */ diff --git a/packages/web/src/app/projects/[projectId]/loading.tsx b/packages/web/src/app/projects/[projectId]/loading.tsx index ffeee105c..7df4da536 100644 --- a/packages/web/src/app/projects/[projectId]/loading.tsx +++ b/packages/web/src/app/projects/[projectId]/loading.tsx @@ -1,40 +1,46 @@ export default function ProjectRouteLoading() { return ( -
- - -
-
+
); } diff --git a/packages/web/src/app/projects/[projectId]/page.test.tsx b/packages/web/src/app/projects/[projectId]/page.test.tsx index bb1ab40f6..8ba4b4d21 100644 --- a/packages/web/src/app/projects/[projectId]/page.test.tsx +++ b/packages/web/src/app/projects/[projectId]/page.test.tsx @@ -36,6 +36,33 @@ vi.mock("@/components/Dashboard", () => ({ import ProjectPage from "./page"; describe("ProjectPage", () => { + it("renders the dashboard inside a bounded flex item owned by the project shell", async () => { + hoisted.getProjectRouteDataMock.mockResolvedValue({ + projectId: "project-1", + project: { id: "project-1" }, + projects: [{ id: "project-1", name: "Project 1" }], + degradedProject: null, + }); + hoisted.getDashboardPageDataMock.mockResolvedValue({ + sessions: [], + selectedProjectId: "project-1", + projectName: "Project 1", + projects: [{ id: "project-1", name: "Project 1" }], + orchestrators: [], + attentionZones: "simple", + }); + + render(await ProjectPage({ params: Promise.resolve({ projectId: "project-1" }) })); + + expect(screen.getByTestId("dashboard").parentElement).toHaveClass( + "flex", + "min-h-0", + "min-w-0", + "flex-1", + ); + expect(screen.getByTestId("dashboard").parentElement).not.toHaveClass("min-h-screen"); + }); + it("renders degraded project state when the project is degraded", async () => { hoisted.getProjectRouteDataMock.mockResolvedValue({ projectId: "broken", diff --git a/packages/web/src/app/projects/[projectId]/page.tsx b/packages/web/src/app/projects/[projectId]/page.tsx index 39d317391..92582e82a 100644 --- a/packages/web/src/app/projects/[projectId]/page.tsx +++ b/packages/web/src/app/projects/[projectId]/page.tsx @@ -29,7 +29,7 @@ export default async function ProjectPage(props: { const pageData = await getDashboardPageData(projectId); return ( -
+
-
+

Dashboard