From 6f6c46fb450b4cfc683ad3ecf69b1f9cc0a10ef1 Mon Sep 17 00:00:00 2001 From: AmitChaubey Date: Fri, 12 Jun 2026 16:20:25 +0100 Subject: [PATCH] fix(ui): show agent edit control and prevent chat horizontal overflow Move the edit action to the Agent Details header so long agent names and model strings no longer clip it, and constrain the chat column with min-w-0. Signed-off-by: AmitChaubey --- ui/jest.setup.ts | 16 ++++ ui/src/components/chat/ChatInterface.tsx | 2 +- ui/src/components/chat/ChatLayoutUI.tsx | 19 ++--- .../sidebars/AgentDetailsSidebar.stories.tsx | 3 - .../sidebars/AgentDetailsSidebar.tsx | 52 ++++++++----- .../__tests__/AgentDetailsSidebar.test.tsx | 74 +++++++++++++++++++ 6 files changed, 136 insertions(+), 30 deletions(-) create mode 100644 ui/src/components/sidebars/__tests__/AgentDetailsSidebar.test.tsx diff --git a/ui/jest.setup.ts b/ui/jest.setup.ts index be96e4bc92..32d27029c9 100644 --- a/ui/jest.setup.ts +++ b/ui/jest.setup.ts @@ -31,6 +31,22 @@ global.ResizeObserver = class ResizeObserver { // jsdom: cmdk scrolls selected items into view Element.prototype.scrollIntoView = function scrollIntoView() {}; +// jsdom: SidebarProvider / useIsMobile +Object.defineProperty(window, "matchMedia", { + writable: true, + configurable: true, + value: jest.fn().mockImplementation((query: string) => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), +}); + // Mock next/router jest.mock('next/router', () => ({ useRouter() { diff --git a/ui/src/components/chat/ChatInterface.tsx b/ui/src/components/chat/ChatInterface.tsx index 6c055ae144..ac43cc34d6 100644 --- a/ui/src/components/chat/ChatInterface.tsx +++ b/ui/src/components/chat/ChatInterface.tsx @@ -911,7 +911,7 @@ export default function ChatInterface({ selectedAgentName, selectedNamespace, se ); } return ( -
+
diff --git a/ui/src/components/chat/ChatLayoutUI.tsx b/ui/src/components/chat/ChatLayoutUI.tsx index 2a239c94f0..8bcaa845c3 100644 --- a/ui/src/components/chat/ChatLayoutUI.tsx +++ b/ui/src/components/chat/ChatLayoutUI.tsx @@ -108,17 +108,18 @@ export default function ChatLayoutUI({ agentSessions={sessions} isLoadingSessions={isLoadingSessions} /> -
- - {children} - +
+
+ + {children} + +
diff --git a/ui/src/components/sidebars/AgentDetailsSidebar.stories.tsx b/ui/src/components/sidebars/AgentDetailsSidebar.stories.tsx index 5758051984..721a1779ba 100644 --- a/ui/src/components/sidebars/AgentDetailsSidebar.stories.tsx +++ b/ui/src/components/sidebars/AgentDetailsSidebar.stories.tsx @@ -154,7 +154,6 @@ const mockTools: ToolsResponse[] = [ export const AgentWithTools: Story = { args: { - selectedAgentName: "kagent/momus-gpt", currentAgent: mockAgent, allTools: mockTools, }, @@ -162,7 +161,6 @@ export const AgentWithTools: Story = { export const AgentWithNoTools: Story = { args: { - selectedAgentName: "kagent/simple-agent", currentAgent: mockAgentNoTools, allTools: [], }, @@ -170,7 +168,6 @@ export const AgentWithNoTools: Story = { export const BYOAgent: Story = { args: { - selectedAgentName: "kagent/custom-agent", currentAgent: mockBYOAgent, allTools: [], }, diff --git a/ui/src/components/sidebars/AgentDetailsSidebar.tsx b/ui/src/components/sidebars/AgentDetailsSidebar.tsx index 0d877ed290..065f85cced 100644 --- a/ui/src/components/sidebars/AgentDetailsSidebar.tsx +++ b/ui/src/components/sidebars/AgentDetailsSidebar.tsx @@ -17,12 +17,11 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/comp import { Badge } from "@/components/ui/badge"; interface AgentDetailsSidebarProps { - selectedAgentName: string; currentAgent: AgentResponse; allTools: ToolsResponse[]; } -export function AgentDetailsSidebar({ selectedAgentName, currentAgent, allTools }: AgentDetailsSidebarProps) { +export function AgentDetailsSidebar({ currentAgent, allTools }: AgentDetailsSidebarProps) { const [toolDescriptions, setToolDescriptions] = useState>({}); const [expandedTools, setExpandedTools] = useState>({}); const [availableAgents, setAvailableAgents] = useState([]); @@ -233,28 +232,47 @@ export function AgentDetailsSidebar({ selectedAgentName, currentAgent, allTools // Declarative agents (including SandboxAgent with declarative spec) share model-backed config. const isDeclarativeLikeAgent = selectedTeam?.agent.spec.type === "Declarative"; + const agentNamespace = selectedTeam.agent.metadata.namespace ?? ""; + const agentName = selectedTeam.agent.metadata.name ?? ""; + const agentRef = `${agentNamespace}/${agentName}`; + const editHref = `/agents/new?${new URLSearchParams({ + edit: "true", + name: agentName, + namespace: agentNamespace, + }).toString()}`; + return ( <> - Agent Details + + Agent Details + + -
- - {selectedTeam?.agent.metadata.namespace}/{selectedTeam?.agent.metadata.name} {selectedTeam?.model && `(${selectedTeam?.model})`} - - + {agentRef} + + {selectedTeam?.model && ( +

+ {selectedTeam.model} +

+ )}

{selectedTeam?.agent.spec.description}

diff --git a/ui/src/components/sidebars/__tests__/AgentDetailsSidebar.test.tsx b/ui/src/components/sidebars/__tests__/AgentDetailsSidebar.test.tsx new file mode 100644 index 0000000000..44e65c9381 --- /dev/null +++ b/ui/src/components/sidebars/__tests__/AgentDetailsSidebar.test.tsx @@ -0,0 +1,74 @@ +/** + * @jest-environment jsdom + */ +import { render, screen } from "@testing-library/react"; +import { AgentDetailsSidebar } from "@/components/sidebars/AgentDetailsSidebar"; +import { SidebarProvider } from "@/components/ui/sidebar"; +import type { AgentResponse } from "@/types"; + +jest.mock("@/app/actions/agents", () => ({ + getAgents: jest.fn().mockResolvedValue({ data: [] }), +})); + +function renderSidebar(currentAgent: AgentResponse) { + return render( + + + , + ); +} + +const longNameAgent: AgentResponse = { + id: 1, + agent: { + metadata: { + name: "test-my-agent-qwen7b", + namespace: "ak-poc-testing", + }, + spec: { + description: "testing me agent bro", + type: "Declarative", + }, + }, + model: "vllm/Qwen/Qwen2.5-7B-Instruct", + modelProvider: "openai", + modelConfigRef: "ak-poc-testing/qwen7b", + deploymentReady: true, + accepted: true, + tools: [ + { + type: "Agent", + agent: { + name: "k8s-agent", + namespace: "ak-poc-testing", + kind: "Agent", + apiGroup: "kagent.dev", + }, + }, + ], +}; + +describe("AgentDetailsSidebar", () => { + it("shows the edit control in the header for agents with long names and model strings", () => { + renderSidebar(longNameAgent); + + const editLink = screen.getByRole("link", { + name: "Edit agent ak-poc-testing/test-my-agent-qwen7b", + }); + expect(editLink).toBeInTheDocument(); + expect(editLink).toHaveAttribute( + "href", + "/agents/new?edit=true&name=test-my-agent-qwen7b&namespace=ak-poc-testing", + ); + }); + + it("renders agent ref and model on separate truncated lines", () => { + renderSidebar(longNameAgent); + + expect(screen.getByText("ak-poc-testing/test-my-agent-qwen7b")).toBeInTheDocument(); + expect(screen.getByText("vllm/Qwen/Qwen2.5-7B-Instruct")).toBeInTheDocument(); + }); +});