diff --git a/ui/src/pages/AgentDetail.tsx b/ui/src/pages/AgentDetail.tsx index f9d92dabe5..0d09353efd 100644 --- a/ui/src/pages/AgentDetail.tsx +++ b/ui/src/pages/AgentDetail.tsx @@ -1264,7 +1264,6 @@ export function AgentDetail() { agent={agent} companyId={resolvedCompanyId} assignLabel="Assign Task" - showRun={false} showStatus={false} canRunWithProviderTrace={canUseProviderTrace} actionsDisabled={agentAction.isPending} diff --git a/ui/src/pages/Agents.production.tsx b/ui/src/pages/Agents.production.tsx index 8e519f538b..7ba12ed9e4 100644 --- a/ui/src/pages/Agents.production.tsx +++ b/ui/src/pages/Agents.production.tsx @@ -13,7 +13,6 @@ import { useSidebar } from "../context/SidebarContext"; import { queryKeys } from "../lib/queryKeys"; import { isPlatformManagedEnvironment } from "../lib/managed-sandbox-environment"; import { AgentStatusBadge, AgentStatusCapsule } from "../components/StatusBadge"; -import { AgentActionButtons } from "../components/AgentActionButtons"; import { MembershipAction } from "../components/MembershipAction"; import { StarToggle } from "../components/StarToggle"; import { EntityRow } from "../components/EntityRow"; @@ -442,22 +441,6 @@ export function Agents() { - {/* Row actions mirror the agent detail page; stop the click - from bubbling to the row link so buttons don't navigate. - Hidden on mobile so the agent name keeps room to render. */} -
{ - e.preventDefault(); - e.stopPropagation(); - }} - > - -
({ @@ -357,6 +358,40 @@ describe("Agents", () => { vi.clearAllMocks(); }); + it.each([ + ["streamlined", Agents], + ["production", ProductionAgents], + ] as const)("omits the action bar from %s agent list rows", async (_mode, AgentList) => { + mockAgentsApi.list.mockResolvedValue([ + makeAgent({ name: "Alpha", status: "active" }), + makeAgent({ id: "agent-paused", name: "Paused agent", status: "paused" }), + ]); + root = createRoot(container); + await act(async () => { + root!.render( + + + + + , + ); + }); + await flushReact(); + await flushReact(); + const listToggle = container.querySelector('button[aria-label="List view"]'); + await act(async () => { listToggle?.click(); }); + await flushReact(); + + for (const name of ["Alpha", "Paused agent"]) { + const row = findAgentRow(container, name); + expect(row).not.toBeNull(); + expect(row?.getAttribute("href")).toMatch(/^\/agents\//); + expect(row?.querySelector('button[aria-label^="Open actions for"]')).toBeNull(); + const buttons = Array.from(row?.querySelectorAll("button") ?? []).map((button) => button.textContent); + expect(buttons).not.toEqual(expect.arrayContaining([expect.stringMatching(/Assign Task|Run Heartbeat|Run with provider trace|Pause|Resume/)])); + } + }); + it("shows the configured model beside the adapter on the all agents page", async () => { root = createRoot(container); await act(async () => { @@ -479,15 +514,11 @@ describe("Agents", () => { expect(subtitle).toBeDefined(); expect(subtitle?.classList.contains("truncate")).toBe(true); const actions = row?.querySelector('button[aria-label="Open actions for Paperclip Engineer With A Much Longer Display Name"]'); - expect(actions).not.toBeNull(); - // Neither the action button nor its ancestors may hide the mobile menu. - for (let node = actions; node && node !== row; node = node.parentElement) { - expect(node.classList.contains("hidden")).toBe(false); - } - await act(async () => { (actions as HTMLButtonElement).click(); }); - await flushReact(); - expect(document.body.textContent).toContain("Duplicate"); - expect(document.body.textContent).toContain("Terminate"); + expect(actions).toBeNull(); + expect(row?.textContent).not.toContain("Assign Task"); + expect(row?.textContent).not.toContain("Run Heartbeat"); + expect(row?.textContent).not.toContain("Run with provider trace"); + expect(row?.textContent).not.toContain("Pause"); }); it("uses the built-in agents route segment as the built-in filter", async () => { diff --git a/ui/src/pages/Agents.tsx b/ui/src/pages/Agents.tsx index 9c83b9ec01..1c0584c05a 100644 --- a/ui/src/pages/Agents.tsx +++ b/ui/src/pages/Agents.tsx @@ -6,7 +6,6 @@ import { builtInAgentsApi, type BuiltInAgentState } from "../api/builtInAgents"; import { environmentsApi } from "../api/environments"; import { heartbeatsApi } from "../api/heartbeats"; import { instanceSettingsApi } from "../api/instanceSettings"; -import { accessApi } from "../api/access"; import { useCompany } from "../context/CompanyContext"; import { useDialogActions } from "../context/DialogContext"; import { useBreadcrumbs } from "../context/BreadcrumbContext"; @@ -15,7 +14,6 @@ import { useStreamlinedUiEnabled } from "../hooks/useStreamlinedUiEnabled"; import { queryKeys } from "../lib/queryKeys"; import { isPlatformManagedEnvironment } from "../lib/managed-sandbox-environment"; import { AgentStatusBadge, AgentStatusCapsule } from "../components/StatusBadge"; -import { AgentActionButtons } from "../components/AgentActionButtons"; import { MembershipAction } from "../components/MembershipAction"; import { StarToggle } from "../components/StarToggle"; import { EntityRow } from "../components/EntityRow"; @@ -211,15 +209,6 @@ export function Agents({ initialView = "list" }: { initialView?: AgentsView } = setView(streamlinedUiEnabled ? initialView : "org"); }, [initialView, streamlinedUiEnabled]); - const { data: boardAccess } = useQuery({ - queryKey: queryKeys.access.currentBoardAccess, - queryFn: () => accessApi.getCurrentBoardAccess(), - retry: false, - }); - const canUseProviderTrace = - boardAccess?.source === "local_implicit" || - boardAccess?.isInstanceAdmin === true; - const { data: instanceSettings } = useQuery({ queryKey: queryKeys.instance.settings, queryFn: () => instanceSettingsApi.get(), @@ -411,32 +400,11 @@ export function Agents({ initialView = "list" }: { initialView?: AgentsView } = ) : ( )} - secondaryRow={ -
- {builtInCluster && ( -
- {builtInCluster} -
- )} - {/* Actions have their own wrapping line, so names keep their width. */} -
{ - e.preventDefault(); - e.stopPropagation(); - }} - > - -
+ secondaryRow={builtInCluster && ( +
+ {builtInCluster}
- } + )} meta={
{builtInCluster && (