From 0b6795e96f2abf2a184fe585051480ce04235005 Mon Sep 17 00:00:00 2001 From: Fusion Date: Tue, 12 May 2026 01:07:35 -0700 Subject: [PATCH] feat(FN-4065): fix sidebar action overflow in AgentsView Fixes sidebar action containment in the dashboard AgentsView component and adds test coverage for the sidebar action overflow contract. Fusion-Task-Id: FN-4065 --- .../dashboard/app/components/AgentsView.css | 38 ++++- .../dashboard/app/components/AgentsView.tsx | 144 +++++++++--------- .../components/__tests__/AgentsView.test.tsx | 26 +++- 3 files changed, 126 insertions(+), 82 deletions(-) diff --git a/packages/dashboard/app/components/AgentsView.css b/packages/dashboard/app/components/AgentsView.css index cbe206e02..95d6dff5b 100644 --- a/packages/dashboard/app/components/AgentsView.css +++ b/packages/dashboard/app/components/AgentsView.css @@ -698,16 +698,30 @@ } .agent-card-actions { - display: flex; + display: grid; + grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-sm); - align-items: center; - flex-wrap: nowrap; + align-items: start; + width: 100%; + min-width: 0; container-type: inline-size; container-name: agent-card-actions; } +.agent-card-actions-group { + display: flex; + flex-wrap: wrap; + gap: var(--space-sm); + align-items: center; + min-width: 0; +} + +.agent-card-actions-group--secondary { + justify-content: flex-end; +} + .agent-card-actions .btn { - flex-shrink: 0; + flex: 0 0 auto; white-space: nowrap; } @@ -715,21 +729,29 @@ gap: var(--space-xs); } +.agents-split-sidebar .agent-card-actions-group { + gap: var(--space-xs); +} + .agents-split-sidebar .agent-card-actions .btn { gap: var(--space-xs); padding: var(--space-xs) var(--space-sm); } @container agent-card-actions (max-width: calc(var(--space-2xl) * 9)) { + .agents-split-sidebar .agent-card-actions { + grid-template-columns: minmax(0, 1fr); + } + + .agents-split-sidebar .agent-card-actions-group--secondary { + justify-content: flex-start; + } + .agents-split-sidebar .agent-card-actions .agent-card-action-label { display: none; } } -.agent-card-details-btn { - margin-left: auto; -} - .agent-card--clickable { cursor: pointer; } diff --git a/packages/dashboard/app/components/AgentsView.tsx b/packages/dashboard/app/components/AgentsView.tsx index bf85c43b0..e27d45197 100644 --- a/packages/dashboard/app/components/AgentsView.tsx +++ b/packages/dashboard/app/components/AgentsView.tsx @@ -1368,94 +1368,98 @@ export function AgentsView({ addToast, projectId, onOpenTaskLogs, agentOnboardin
- {agent.state === "idle" && ( - - )} - {agent.state === "active" && ( - <> +
+ {agent.state === "idle" && ( + )} + {agent.state === "active" && ( + <> + + + + )} + {agent.state === "paused" && ( - - )} - {agent.state === "paused" && ( - - )} - {agent.state === "running" && ( - <> + )} + {agent.state === "running" && ( + <> + + + + )} + {agent.state === "error" && ( - - - )} - {agent.state === "error" && ( + )} +
+
- )} - - {(agent.state === "idle" || agent.state === "paused") && ( - - )} + {(agent.state === "idle" || agent.state === "paused") && ( + + )} +
); diff --git a/packages/dashboard/app/components/__tests__/AgentsView.test.tsx b/packages/dashboard/app/components/__tests__/AgentsView.test.tsx index c3651aee3..c9e8d8876 100644 --- a/packages/dashboard/app/components/__tests__/AgentsView.test.tsx +++ b/packages/dashboard/app/components/__tests__/AgentsView.test.tsx @@ -651,18 +651,36 @@ describe("AgentsView", () => { expect(screen.getAllByText("Details").length).toBeGreaterThanOrEqual(4); }); - it("keeps a visible icon affordance on View Details buttons when labels are compacted", async () => { - render(); + it("keeps a visible icon affordance on split-sidebar action buttons when labels are compacted", async () => { + const { container } = render(); - const detailsButton = await screen.findByRole("button", { name: "View details for Test Agent 1" }); + const sidebarCard = await waitFor(() => { + const card = container.querySelector(".agents-split-sidebar .agent-card"); + expect(card).toBeTruthy(); + return card as HTMLElement; + }); + const actions = sidebarCard.querySelector(".agent-card-actions"); + const primaryGroup = sidebarCard.querySelector(".agent-card-actions-group--primary"); + const secondaryGroup = sidebarCard.querySelector(".agent-card-actions-group--secondary"); + const detailsButton = within(sidebarCard).getByRole("button", { name: "View details for Test Agent 1" }); + + expect(actions).toBeTruthy(); + expect(primaryGroup).toBeTruthy(); + expect(secondaryGroup).toBeTruthy(); + expect(primaryGroup?.querySelector("button")).toBeTruthy(); + expect(secondaryGroup?.contains(detailsButton)).toBe(true); expect(detailsButton.querySelector("svg")).toBeTruthy(); + expect(sidebarCard.querySelectorAll(".agent-card-action-label").length).toBeGreaterThan(0); }); - it("hides split-sidebar action labels only within an agent-card-actions container query", () => { + it("uses a grid-and-wrap containment contract for split-sidebar action rows", () => { const css = loadAllAppCss(); + expect(css).toMatch(/\.agent-card-actions\s*\{[^}]*display:\s*grid;[^}]*grid-template-columns:\s*minmax\(0, 1fr\) auto;[^}]*width:\s*100%;[^}]*min-width:\s*0;[^}]*\}/); + expect(css).toMatch(/\.agent-card-actions-group\s*\{[^}]*display:\s*flex;[^}]*flex-wrap:\s*wrap;[^}]*min-width:\s*0;[^}]*\}/); expect(css).not.toContain(".agents-split-sidebar .agent-card-actions .agent-card-action-label {\n display: none;\n}"); expect(css).toContain("@container agent-card-actions (max-width: calc(var(--space-2xl) * 9))"); + expect(css).toContain(".agents-split-sidebar .agent-card-actions {\n grid-template-columns: minmax(0, 1fr);\n }"); expect(css).toContain(".agents-split-sidebar .agent-card-actions .agent-card-action-label {\n display: none;\n }"); });