fix(ui): cover both agent lists and preserve detail run action

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Dotta 2026-09-09 11:35:06 -05:00
parent bb41aa1a30
commit 6d527b02aa
3 changed files with 35 additions and 18 deletions

View File

@ -1264,7 +1264,6 @@ export function AgentDetail() {
agent={agent}
companyId={resolvedCompanyId}
assignLabel="Assign Task"
showRun={false}
showStatus={false}
canRunWithProviderTrace={canUseProviderTrace}
actionsDisabled={agentAction.isPending}

View File

@ -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() {
<span className="w-20 flex justify-end">
<AgentStatusBadge status={agent.status} />
</span>
{/* 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. */}
<div
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
}}
>
<AgentActionButtons
agent={agent}
companyId={selectedCompanyId}
runLabel="Run Heartbeat"
showStatus={false}
/>
</div>
<StarToggle
size="row"
starred={agentStarred}

View File

@ -9,6 +9,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { ToastProvider } from "../context/ToastContext";
import type { BuiltInAgentState } from "../api/builtInAgents";
import { Agents } from "./Agents";
import { Agents as ProductionAgents } from "./Agents.production";
import type { AgentOrgChainHealth } from "@paperclipai/shared";
const mockRouterState = vi.hoisted(() => ({
@ -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(
<QueryClientProvider client={queryClient}>
<ToastProvider>
<AgentList />
</ToastProvider>
</QueryClientProvider>,
);
});
await flushReact();
await flushReact();
const listToggle = container.querySelector<HTMLButtonElement>('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 () => {