From ee9b46fe08fc65e7e4fdd732bac612f57dda6b56 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Mon, 23 Mar 2026 12:20:56 +0000 Subject: [PATCH] fix(site/src/pages/AgentsPage): replace navigating buttons with anchor tags (#23426) --- site/src/pages/AgentsPage/AgentCreatePage.tsx | 3 --- site/src/pages/AgentsPage/AgentDetail.tsx | 7 +------ .../AgentsPage/components/AgentCreateForm.tsx | 11 ++++------- .../ConversationTimeline.stories.tsx | 16 +++++++--------- .../AgentDetail/ConversationTimeline.tsx | 10 ++++------ .../components/AgentDetail/TopBar.stories.tsx | 1 - .../components/AgentDetail/TopBar.tsx | 18 +++++++++--------- .../components/AgentDetailContent.tsx | 6 ------ .../components/AgentDetailView.stories.tsx | 1 - .../AgentsPage/components/AgentDetailView.tsx | 10 ---------- 10 files changed, 25 insertions(+), 58 deletions(-) diff --git a/site/src/pages/AgentsPage/AgentCreatePage.tsx b/site/src/pages/AgentsPage/AgentCreatePage.tsx index db409c00a0..9e56c9d301 100644 --- a/site/src/pages/AgentsPage/AgentCreatePage.tsx +++ b/site/src/pages/AgentsPage/AgentCreatePage.tsx @@ -68,8 +68,6 @@ const AgentCreatePage: FC = () => { navigate(`/agents/${createdChat.id}`); }; - const handleOpenAnalytics = () => navigate("/agents/analytics"); - return ( <> @@ -86,7 +84,6 @@ const AgentCreatePage: FC = () => { isModelCatalogLoading={chatModelsQuery.isLoading} isModelConfigsLoading={chatModelConfigsQuery.isLoading} modelCatalogError={chatModelsQuery.error} - onOpenAnalytics={handleOpenAnalytics} /> ); diff --git a/site/src/pages/AgentsPage/AgentDetail.tsx b/site/src/pages/AgentsPage/AgentDetail.tsx index d850a5aff8..5b744e2e6d 100644 --- a/site/src/pages/AgentsPage/AgentDetail.tsx +++ b/site/src/pages/AgentsPage/AgentDetail.tsx @@ -30,7 +30,7 @@ import { useQuery, useQueryClient, } from "react-query"; -import { useNavigate, useOutletContext, useParams } from "react-router"; +import { useOutletContext, useParams } from "react-router"; import { toast } from "sonner"; import type { UrlTransform } from "streamdown"; import { isMobileViewport } from "utils/mobile"; @@ -232,7 +232,6 @@ export function useConversationEditingState(deps: { } const AgentDetail: FC = () => { - const navigate = useNavigate(); const { agentId } = useParams<{ agentId: string }>(); const { chatErrorReasons, @@ -313,8 +312,6 @@ const AgentDetail: FC = () => { const isModelCatalogLoading = chatModelsQuery.isLoading; const modelCatalogError = chatModelsQuery.error; - const handleOpenAnalytics = () => navigate("/agents/analytics"); - // Subscribe to live workspace updates so that agent status changes // (e.g. connected/disconnected) are reflected without a page refresh. useEffect(() => { @@ -861,7 +858,6 @@ const AgentDetail: FC = () => { isInterruptPending={interruptMutation.isPending} isSidebarCollapsed={isSidebarCollapsed} onToggleSidebarCollapsed={onToggleSidebarCollapsed} - onOpenAnalytics={handleOpenAnalytics} showSidebarPanel={showSidebarPanel} onSetShowSidebarPanel={handleSetShowSidebarPanel} prNumber={prNumber} @@ -874,7 +870,6 @@ const AgentDetail: FC = () => { handleViewWorkspace={handleViewWorkspace} handleOpenTerminal={handleOpenTerminal} handleCommit={handleCommit} - onNavigateToChat={(chatId) => navigate(`/agents/${chatId}`)} handleInterrupt={handleInterrupt} handleDeleteQueuedMessage={handleDeleteQueuedMessage} handlePromoteQueuedMessage={handlePromoteQueuedMessage} diff --git a/site/src/pages/AgentsPage/components/AgentCreateForm.tsx b/site/src/pages/AgentsPage/components/AgentCreateForm.tsx index 65286febcc..3a7b443d28 100644 --- a/site/src/pages/AgentsPage/components/AgentCreateForm.tsx +++ b/site/src/pages/AgentsPage/components/AgentCreateForm.tsx @@ -23,6 +23,7 @@ import { Check, MonitorIcon } from "lucide-react"; import { useDashboard } from "modules/dashboard/useDashboard"; import { type FC, useEffect, useRef, useState } from "react"; import { useQuery } from "react-query"; +import { Link } from "react-router"; import { toast } from "sonner"; import { useFileAttachments } from "../hooks/useFileAttachments"; import { @@ -115,7 +116,6 @@ interface AgentCreateFormProps { modelConfigs: readonly TypesGen.ChatModelConfig[]; isModelConfigsLoading: boolean; modelCatalogError: unknown; - onOpenAnalytics?: () => void; } export const AgentCreateForm: FC = ({ @@ -128,7 +128,6 @@ export const AgentCreateForm: FC = ({ isModelCatalogLoading, isModelConfigsLoading, modelCatalogError, - onOpenAnalytics, }) => { const { organizations } = useDashboard(); const { initialInputValue, handleContentChange, submitDraft, resetDraft } = @@ -335,11 +334,9 @@ export const AgentCreateForm: FC = ({ severity="info" className="py-2" actions={ - onOpenAnalytics && ( - - ) + } > {formatUsageLimitMessage(createError.response.data)} diff --git a/site/src/pages/AgentsPage/components/AgentDetail/ConversationTimeline.stories.tsx b/site/src/pages/AgentsPage/components/AgentDetail/ConversationTimeline.stories.tsx index bfdb29f588..75c9f3915c 100644 --- a/site/src/pages/AgentsPage/components/AgentDetail/ConversationTimeline.stories.tsx +++ b/site/src/pages/AgentsPage/components/AgentDetail/ConversationTimeline.stories.tsx @@ -1,6 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import type * as TypesGen from "api/typesGenerated"; -import { expect, fn, userEvent, within } from "storybook/test"; +import { expect, within } from "storybook/test"; import { ConversationTimeline } from "./ConversationTimeline"; import { parseMessagesWithMergedTools } from "./messageParsing"; @@ -249,17 +249,16 @@ export const UsageLimitExceeded: Story = { message: "You've used $50.00 of your $50.00 spend limit. Your limit resets on July 1, 2025.", }, - onOpenAnalytics: fn(), + subagentTitles: new Map(), subagentStatusOverrides: new Map(), }, - play: async ({ args, canvasElement }) => { + play: async ({ canvasElement }) => { const canvas = within(canvasElement); expect(canvas.getByText(/spend limit/i)).toBeVisible(); - const btn = canvas.getByRole("button", { name: /view usage/i }); - expect(btn).toBeVisible(); - await userEvent.click(btn); - expect(args.onOpenAnalytics).toHaveBeenCalled(); + const link = canvas.getByRole("link", { name: /view usage/i }); + expect(link).toBeVisible(); + expect(link).toHaveAttribute("href", "/agents/analytics"); }, }; @@ -269,7 +268,6 @@ export const GenericErrorDoesNotShowUsageAction: Story = { ...defaultArgs, parsedMessages: [], detailError: { kind: "generic", message: "Provider request failed." }, - onOpenAnalytics: fn(), subagentTitles: new Map(), subagentStatusOverrides: new Map(), }, @@ -277,7 +275,7 @@ export const GenericErrorDoesNotShowUsageAction: Story = { const canvas = within(canvasElement); expect(canvas.getByText(/provider request failed/i)).toBeVisible(); expect( - canvas.queryByRole("button", { name: /view usage/i }), + canvas.queryByRole("link", { name: /view usage/i }), ).not.toBeInTheDocument(); }, }; diff --git a/site/src/pages/AgentsPage/components/AgentDetail/ConversationTimeline.tsx b/site/src/pages/AgentsPage/components/AgentDetail/ConversationTimeline.tsx index 57efa423fd..15738d26e5 100644 --- a/site/src/pages/AgentsPage/components/AgentDetail/ConversationTimeline.tsx +++ b/site/src/pages/AgentsPage/components/AgentDetail/ConversationTimeline.tsx @@ -27,6 +27,7 @@ import { useRef, useState, } from "react"; +import { Link } from "react-router"; import type { UrlTransform } from "streamdown"; import { cn } from "utils/cn"; import type { ChatDetailError } from "../../utils/usageLimitMessage"; @@ -846,7 +847,6 @@ interface ConversationTimelineProps { retryState?: { attempt: number; error: string } | null; isAwaitingFirstStreamChunk: boolean; detailError?: ChatDetailError | null; - onOpenAnalytics?: () => void; onEditUserMessage?: ( messageId: number, text: string, @@ -868,7 +868,6 @@ export const ConversationTimeline: FC = ({ retryState, isAwaitingFirstStreamChunk, detailError, - onOpenAnalytics, onEditUserMessage, editingMessageId, savingMessageId, @@ -877,7 +876,6 @@ export const ConversationTimeline: FC = ({ const shouldRenderStreamAfterMessages = hasStreamOutput && parsedMessages.length > 0; const isUsageLimitError = detailError?.kind === "usage-limit"; - const showUsageAction = onOpenAnalytics !== undefined && isUsageLimitError; // Build a set of message IDs that appear after the message // currently being edited so they can be visually faded. @@ -954,9 +952,9 @@ export const ConversationTimeline: FC = ({ severity={isUsageLimitError ? "info" : "error"} className="py-2" actions={ - showUsageAction && ( - ) } diff --git a/site/src/pages/AgentsPage/components/AgentDetail/TopBar.stories.tsx b/site/src/pages/AgentsPage/components/AgentDetail/TopBar.stories.tsx index a269aef5a8..553f42c629 100644 --- a/site/src/pages/AgentsPage/components/AgentDetail/TopBar.stories.tsx +++ b/site/src/pages/AgentsPage/components/AgentDetail/TopBar.stories.tsx @@ -4,7 +4,6 @@ import { AgentDetailTopBar } from "./TopBar"; const defaultProps = { chatTitle: "Build authentication feature", - onOpenParentChat: () => {}, panel: { showSidebarPanel: false, onToggleSidebar: () => {}, diff --git a/site/src/pages/AgentsPage/components/AgentDetail/TopBar.tsx b/site/src/pages/AgentsPage/components/AgentDetail/TopBar.tsx index 2fc0a07548..181afe9ad5 100644 --- a/site/src/pages/AgentsPage/components/AgentDetail/TopBar.tsx +++ b/site/src/pages/AgentsPage/components/AgentDetail/TopBar.tsx @@ -24,7 +24,7 @@ import { Trash2Icon, } from "lucide-react"; import type { FC } from "react"; -import { useNavigate } from "react-router"; +import { Link } from "react-router"; import { toast } from "sonner"; import { cn } from "utils/cn"; import { parsePullRequestUrl } from "../../utils/pullRequest"; @@ -48,7 +48,6 @@ interface WorkspaceActions { type AgentDetailTopBarProps = { chatTitle?: string; parentChat?: TypesGen.Chat; - onOpenParentChat: (chatId: string) => void; panel: SidebarPanelState; workspace: WorkspaceActions; onArchiveAgent: () => void; @@ -64,7 +63,6 @@ type AgentDetailTopBarProps = { export const AgentDetailTopBar: FC = ({ chatTitle, parentChat, - onOpenParentChat, panel, workspace, onArchiveAgent, @@ -76,7 +74,6 @@ export const AgentDetailTopBar: FC = ({ onToggleSidebarCollapsed, diffStatusData, }) => { - const navigate = useNavigate(); const { isEmbedded } = useEmbedContext(); const prUrl = diffStatusData?.url; @@ -93,13 +90,14 @@ export const AgentDetailTopBar: FC = ({ {/* Mobile back button */} {!isEmbedded && ( )} {/* Desktop expand button: visible when sidebar is manually collapsed. */} @@ -121,12 +119,14 @@ export const AgentDetailTopBar: FC = ({ {parentChat && ( <> diff --git a/site/src/pages/AgentsPage/components/AgentDetailContent.tsx b/site/src/pages/AgentsPage/components/AgentDetailContent.tsx index 4bf1c1729a..faf8860774 100644 --- a/site/src/pages/AgentsPage/components/AgentDetailContent.tsx +++ b/site/src/pages/AgentsPage/components/AgentDetailContent.tsx @@ -42,7 +42,6 @@ const isChatMessage = ( interface AgentDetailTimelineProps { store: ChatStoreHandle; persistedErrorReason: ChatDetailError | undefined; - onOpenAnalytics?: () => void; onEditUserMessage?: ( messageId: number, text: string, @@ -59,7 +58,6 @@ interface AgentDetailTimelineProps { const MessageListProvider: FC = ({ store, persistedErrorReason, - onOpenAnalytics, onEditUserMessage, editingMessageId, savingMessageId, @@ -102,7 +100,6 @@ const MessageListProvider: FC = ({ detailError={detailError} latestMessageNeedsAssistantResponse={latestMessageNeedsAssistantResponse} chatStatus={chatStatus} - onOpenAnalytics={onOpenAnalytics} onEditUserMessage={onEditUserMessage} editingMessageId={editingMessageId} savingMessageId={savingMessageId} @@ -123,7 +120,6 @@ const StreamingBridge: FC<{ detailError: ChatDetailError | undefined; latestMessageNeedsAssistantResponse: boolean; chatStatus: TypesGen.ChatStatus | null; - onOpenAnalytics?: () => void; onEditUserMessage?: ( messageId: number, text: string, @@ -142,7 +138,6 @@ const StreamingBridge: FC<{ detailError, latestMessageNeedsAssistantResponse, chatStatus, - onOpenAnalytics, onEditUserMessage, editingMessageId, savingMessageId, @@ -168,7 +163,6 @@ const StreamingBridge: FC<{ retryState={retryState} isAwaitingFirstStreamChunk={isAwaitingFirstStreamChunk} detailError={detailError} - onOpenAnalytics={onOpenAnalytics} onEditUserMessage={onEditUserMessage} editingMessageId={editingMessageId} savingMessageId={savingMessageId} diff --git a/site/src/pages/AgentsPage/components/AgentDetailView.stories.tsx b/site/src/pages/AgentsPage/components/AgentDetailView.stories.tsx index db32338c48..0ed29ba989 100644 --- a/site/src/pages/AgentsPage/components/AgentDetailView.stories.tsx +++ b/site/src/pages/AgentsPage/components/AgentDetailView.stories.tsx @@ -128,7 +128,6 @@ const meta: Meta = { handleViewWorkspace: fn(), handleOpenTerminal: fn(), handleCommit: fn(), - onNavigateToChat: fn(), handleInterrupt: fn(), handleDeleteQueuedMessage: fn(), handlePromoteQueuedMessage: fn(), diff --git a/site/src/pages/AgentsPage/components/AgentDetailView.tsx b/site/src/pages/AgentsPage/components/AgentDetailView.tsx index 867283b7c4..d8ee0350cc 100644 --- a/site/src/pages/AgentsPage/components/AgentDetailView.tsx +++ b/site/src/pages/AgentsPage/components/AgentDetailView.tsx @@ -83,7 +83,6 @@ interface AgentDetailViewProps { // Sidebar / panel state. isSidebarCollapsed: boolean; onToggleSidebarCollapsed: () => void; - onOpenAnalytics?: () => void; // Right panel state (owned by the parent so loading and // loaded views share the same layout). @@ -107,9 +106,6 @@ interface AgentDetailViewProps { handleOpenTerminal: () => void; handleCommit: (repoRoot: string) => void; - // Navigation. - onNavigateToChat: (chatId: string) => void; - // Chat action handlers. handleInterrupt: () => void; handleDeleteQueuedMessage: (id: number) => Promise; @@ -158,7 +154,6 @@ export const AgentDetailView: FC = ({ isInterruptPending, isSidebarCollapsed, onToggleSidebarCollapsed, - onOpenAnalytics, showSidebarPanel, onSetShowSidebarPanel, prNumber, @@ -171,7 +166,6 @@ export const AgentDetailView: FC = ({ handleViewWorkspace, handleOpenTerminal, handleCommit, - onNavigateToChat, handleInterrupt, handleDeleteQueuedMessage, handlePromoteQueuedMessage, @@ -221,7 +215,6 @@ export const AgentDetailView: FC = ({ onNavigateToChat(chatId)} panel={{ showSidebarPanel, onToggleSidebar: () => onSetShowSidebarPanel((prev) => !prev), @@ -275,7 +268,6 @@ export const AgentDetailView: FC = ({ ? { kind: "generic" as const, message: chatRecord.last_error } : undefined) } - onOpenAnalytics={onOpenAnalytics} onEditUserMessage={editing.handleEditUserMessage} editingMessageId={editing.editingMessageId} savingMessageId={pendingEditMessageId} @@ -408,7 +400,6 @@ export const AgentDetailLoadingView: FC = ({ onOpenTerminal: () => {}, sshCommand: undefined, }} - onOpenParentChat={() => {}} onArchiveAgent={() => {}} onUnarchiveAgent={() => {}} onArchiveAndDeleteWorkspace={() => {}} @@ -482,7 +473,6 @@ export const AgentDetailNotFoundView: FC = ({ onOpenTerminal: () => {}, sshCommand: undefined, }} - onOpenParentChat={() => {}} onArchiveAgent={() => {}} onUnarchiveAgent={() => {}} onArchiveAndDeleteWorkspace={() => {}}