diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/components/DashboardSidebarWorkspaceChips/components/DashboardSidebarAgentsChip/DashboardSidebarAgentsChip.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/components/DashboardSidebarWorkspaceChips/components/DashboardSidebarAgentsChip/DashboardSidebarAgentsChip.tsx index cc484483df7..5b52508a0eb 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/components/DashboardSidebarWorkspaceChips/components/DashboardSidebarAgentsChip/DashboardSidebarAgentsChip.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/components/DashboardSidebarWorkspaceChips/components/DashboardSidebarAgentsChip/DashboardSidebarAgentsChip.tsx @@ -4,13 +4,8 @@ import { HoverCardContent, HoverCardTrigger, } from "@superset/ui/hover-card"; -import { Separator } from "@superset/ui/separator"; -import { toast } from "@superset/ui/sonner"; import { cn } from "@superset/ui/utils"; -import { LuLoaderCircle, LuX } from "react-icons/lu"; -import { STROKE_WIDTH } from "renderer/screens/main/components/WorkspaceSidebar/constants"; import { STATUS_PRIORITY } from "shared/tabs-types"; -import { useDashboardSidebarAgentKill } from "../../hooks/useDashboardSidebarAgentKill"; import { useDashboardSidebarChipHoverSuppression } from "../../hooks/useDashboardSidebarChipHoverSuppression"; import type { DashboardSidebarRunningAgent } from "../../hooks/useDashboardSidebarWorkspaceRunningAgents"; import { DashboardSidebarAgentAvatar } from "./components/DashboardSidebarAgentAvatar"; @@ -24,14 +19,13 @@ interface DashboardSidebarAgentsChipProps { /** * Running-agents chip on the workspace row: one avatar (the agent whose * status most needs attention, newest session on ties) plus the total count. - * Hovering or clicking the chip opens a card listing each agent with its own - * open/stop actions; clicking the chip again closes the card. + * Hovering or clicking the chip opens a card listing each agent with an + * open action; clicking the chip again closes the card. */ export function DashboardSidebarAgentsChip({ workspaceId, agents, }: DashboardSidebarAgentsChipProps) { - const { isPending, killAgents } = useDashboardSidebarAgentKill(workspaceId); const { isOpen, onOpenChange, onPointerEnter, onPointerLeave, toggleOpen } = useDashboardSidebarChipHoverSuppression(); @@ -44,20 +38,6 @@ export function DashboardSidebarAgentsChip({ return agent.startedAt > best.startedAt ? agent : best; }); - const handleStopAll = async () => { - if (isPending) return; - const stoppedCount = await killAgents( - agents.map((agent) => agent.terminalId), - ); - if (stoppedCount > 0) { - toast.success( - stoppedCount === 1 - ? "Stopped 1 agent" - : `Stopped ${stoppedCount} agents`, - ); - } - }; - return ( svg]:size-2.5 hover:bg-muted hover:text-foreground disabled:opacity-70", + "[&>svg]:size-2.5 hover:bg-muted hover:text-foreground", )} > - {isPending ? ( - - ) : ( - {agents.length} - )} + {agents.length} @@ -123,16 +94,6 @@ export function DashboardSidebarAgentsChip({ /> ))} - - ); diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/components/DashboardSidebarWorkspaceChips/components/DashboardSidebarAgentsChip/components/DashboardSidebarAgentHoverRow/DashboardSidebarAgentHoverRow.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/components/DashboardSidebarWorkspaceChips/components/DashboardSidebarAgentsChip/components/DashboardSidebarAgentHoverRow/DashboardSidebarAgentHoverRow.tsx index 2b322d19475..fe464c7ccfb 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/components/DashboardSidebarWorkspaceChips/components/DashboardSidebarAgentsChip/components/DashboardSidebarAgentHoverRow/DashboardSidebarAgentHoverRow.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/components/DashboardSidebarWorkspaceChips/components/DashboardSidebarAgentsChip/components/DashboardSidebarAgentHoverRow/DashboardSidebarAgentHoverRow.tsx @@ -1,10 +1,7 @@ import { cn } from "@superset/ui/utils"; import { useNavigate } from "@tanstack/react-router"; -import { LuX } from "react-icons/lu"; import { navigateToV2Workspace } from "renderer/routes/_authenticated/_dashboard/utils/workspace-navigation"; import { getStatusTooltip } from "renderer/screens/main/components/StatusIndicator"; -import { STROKE_WIDTH } from "renderer/screens/main/components/WorkspaceSidebar/constants"; -import { useDashboardSidebarAgentKill } from "../../../../hooks/useDashboardSidebarAgentKill"; import type { DashboardSidebarRunningAgent, RunningAgentStatus, @@ -29,7 +26,6 @@ export function DashboardSidebarAgentHoverRow({ agent, }: DashboardSidebarAgentHoverRowProps) { const navigate = useNavigate(); - const { isPending, killAgent } = useDashboardSidebarAgentKill(workspaceId); const handleOpen = () => { void navigateToV2Workspace(workspaceId, navigate, { @@ -44,7 +40,7 @@ export function DashboardSidebarAgentHoverRow({ agent.status === "idle" ? "Idle" : getStatusTooltip(agent.status); return ( -
+
- {/* Status text and the × occupy one grid cell, swapped via visibility - so the row never changes size on hover. */} - - - {statusLabel} - - + + {statusLabel}
); diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/components/DashboardSidebarWorkspaceChips/hooks/useDashboardSidebarAgentKill/index.ts b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/components/DashboardSidebarWorkspaceChips/hooks/useDashboardSidebarAgentKill/index.ts deleted file mode 100644 index dfda5e5966c..00000000000 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/components/DashboardSidebarWorkspaceChips/hooks/useDashboardSidebarAgentKill/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { useDashboardSidebarAgentKill } from "./useDashboardSidebarAgentKill"; diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/components/DashboardSidebarWorkspaceChips/hooks/useDashboardSidebarAgentKill/useDashboardSidebarAgentKill.ts b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/components/DashboardSidebarWorkspaceChips/hooks/useDashboardSidebarAgentKill/useDashboardSidebarAgentKill.ts deleted file mode 100644 index e22d258a9cf..00000000000 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/components/DashboardSidebarWorkspaceChips/hooks/useDashboardSidebarAgentKill/useDashboardSidebarAgentKill.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { toast } from "@superset/ui/sonner"; -import { useQueryClient } from "@tanstack/react-query"; -import { useCallback, useState } from "react"; -import { getTerminalAgentBindingsQueryKey } from "renderer/hooks/host-service/useTerminalAgentBindings"; -import { useWorkspaceHostUrl } from "renderer/hooks/host-service/useWorkspaceHostUrl"; -import { getHostServiceClientByUrl } from "renderer/lib/host-service-client"; - -interface UseDashboardSidebarAgentKillResult { - isPending: boolean; - killAgent: (terminalId: string) => Promise; - /** Kill several agents at once; resolves with the number actually killed. */ - killAgents: (terminalIds: string[]) => Promise; -} - -/** - * Kill the host terminal session an agent is bound to. Disposing the session - * ends the agent process; its sidebar chip drops once the bindings query - * refreshes (the `agent:lifecycle` event invalidates it too, but we invalidate - * eagerly so the chip disappears without waiting on the event). - */ -export function useDashboardSidebarAgentKill( - workspaceId: string, -): UseDashboardSidebarAgentKillResult { - const hostUrl = useWorkspaceHostUrl(workspaceId); - const queryClient = useQueryClient(); - const [isPending, setIsPending] = useState(false); - - const killAgent = useCallback( - async (terminalId: string): Promise => { - if (!hostUrl) { - toast.error("Failed to kill agent", { - description: "No host is available for this workspace", - }); - return; - } - setIsPending(true); - try { - await getHostServiceClientByUrl(hostUrl).terminal.killSession.mutate({ - terminalId, - workspaceId, - }); - } catch (error) { - console.error("[sidebar-agent] Failed to kill agent:", error); - toast.error("Failed to kill agent"); - } finally { - void queryClient.invalidateQueries({ - queryKey: getTerminalAgentBindingsQueryKey(workspaceId), - }); - setIsPending(false); - } - }, - [hostUrl, workspaceId, queryClient], - ); - - const killAgents = useCallback( - async (terminalIds: string[]): Promise => { - if (terminalIds.length === 0) return 0; - if (!hostUrl) { - toast.error("Failed to stop agents", { - description: "No host is available for this workspace", - }); - return 0; - } - setIsPending(true); - try { - const results = await Promise.allSettled( - terminalIds.map((terminalId) => - getHostServiceClientByUrl(hostUrl).terminal.killSession.mutate({ - terminalId, - workspaceId, - }), - ), - ); - const failedCount = results.filter( - (result) => result.status === "rejected", - ).length; - if (failedCount > 0) { - toast.error( - failedCount === 1 - ? "Failed to stop 1 agent" - : `Failed to stop ${failedCount} agents`, - ); - } - return results.length - failedCount; - } finally { - void queryClient.invalidateQueries({ - queryKey: getTerminalAgentBindingsQueryKey(workspaceId), - }); - setIsPending(false); - } - }, - [hostUrl, workspaceId, queryClient], - ); - - return { isPending, killAgent, killAgents }; -}