fix(site/src/pages/AgentsPage): replace navigating buttons with anchor tags (#23426)

This commit is contained in:
Danielle Maywood
2026-03-23 12:20:56 +00:00
committed by GitHub
parent 1ad3c898a0
commit ee9b46fe08
10 changed files with 25 additions and 58 deletions
@@ -68,8 +68,6 @@ const AgentCreatePage: FC = () => {
navigate(`/agents/${createdChat.id}`);
};
const handleOpenAnalytics = () => navigate("/agents/analytics");
return (
<>
<AgentPageHeader>
@@ -86,7 +84,6 @@ const AgentCreatePage: FC = () => {
isModelCatalogLoading={chatModelsQuery.isLoading}
isModelConfigsLoading={chatModelConfigsQuery.isLoading}
modelCatalogError={chatModelsQuery.error}
onOpenAnalytics={handleOpenAnalytics}
/>
</>
);
+1 -6
View File
@@ -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}
@@ -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<AgentCreateFormProps> = ({
@@ -128,7 +128,6 @@ export const AgentCreateForm: FC<AgentCreateFormProps> = ({
isModelCatalogLoading,
isModelConfigsLoading,
modelCatalogError,
onOpenAnalytics,
}) => {
const { organizations } = useDashboard();
const { initialInputValue, handleContentChange, submitDraft, resetDraft } =
@@ -335,11 +334,9 @@ export const AgentCreateForm: FC<AgentCreateFormProps> = ({
severity="info"
className="py-2"
actions={
onOpenAnalytics && (
<Button variant="subtle" size="sm" onClick={onOpenAnalytics}>
View Usage
</Button>
)
<Button asChild variant="subtle" size="sm">
<Link to="/agents/analytics">View Usage</Link>
</Button>
}
>
{formatUsageLimitMessage(createError.response.data)}
@@ -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();
},
};
@@ -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<ConversationTimelineProps> = ({
retryState,
isAwaitingFirstStreamChunk,
detailError,
onOpenAnalytics,
onEditUserMessage,
editingMessageId,
savingMessageId,
@@ -877,7 +876,6 @@ export const ConversationTimeline: FC<ConversationTimelineProps> = ({
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<ConversationTimelineProps> = ({
severity={isUsageLimitError ? "info" : "error"}
className="py-2"
actions={
showUsageAction && (
<Button variant="subtle" size="sm" onClick={onOpenAnalytics}>
View Usage
isUsageLimitError && (
<Button asChild variant="subtle" size="sm">
<Link to="/agents/analytics">View Usage</Link>
</Button>
)
}
@@ -4,7 +4,6 @@ import { AgentDetailTopBar } from "./TopBar";
const defaultProps = {
chatTitle: "Build authentication feature",
onOpenParentChat: () => {},
panel: {
showSidebarPanel: false,
onToggleSidebar: () => {},
@@ -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<AgentDetailTopBarProps> = ({
chatTitle,
parentChat,
onOpenParentChat,
panel,
workspace,
onArchiveAgent,
@@ -76,7 +74,6 @@ export const AgentDetailTopBar: FC<AgentDetailTopBarProps> = ({
onToggleSidebarCollapsed,
diffStatusData,
}) => {
const navigate = useNavigate();
const { isEmbedded } = useEmbedContext();
const prUrl = diffStatusData?.url;
@@ -93,13 +90,14 @@ export const AgentDetailTopBar: FC<AgentDetailTopBarProps> = ({
{/* Mobile back button */}
{!isEmbedded && (
<Button
asChild
variant="subtle"
size="icon"
onClick={() => navigate("/agents")}
aria-label="Back"
className="inline-flex h-7 w-7 min-w-0 shrink-0 md:hidden"
>
<ArrowLeftIcon />
<Link to="/agents" aria-label="Back">
<ArrowLeftIcon />
</Link>
</Button>
)}
{/* Desktop expand button: visible when sidebar is manually collapsed. */}
@@ -121,12 +119,14 @@ export const AgentDetailTopBar: FC<AgentDetailTopBarProps> = ({
{parentChat && (
<>
<Button
asChild
size="sm"
variant="subtle"
className="h-auto max-w-[16rem] rounded-sm px-1 py-0.5 text-sm text-content-secondary shadow-none hover:bg-transparent hover:text-content-primary"
onClick={() => onOpenParentChat(parentChat.id)}
>
<span className="truncate">{parentChat.title}</span>
<Link to={`/agents/${parentChat.id}`}>
<span className="truncate">{parentChat.title}</span>
</Link>
</Button>
<ChevronRightIcon className="h-3.5 w-3.5 shrink-0 text-content-secondary/70 -ml-0.5" />
</>
@@ -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<AgentDetailTimelineProps> = ({
store,
persistedErrorReason,
onOpenAnalytics,
onEditUserMessage,
editingMessageId,
savingMessageId,
@@ -102,7 +100,6 @@ const MessageListProvider: FC<AgentDetailTimelineProps> = ({
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}
@@ -128,7 +128,6 @@ const meta: Meta<typeof AgentDetailView> = {
handleViewWorkspace: fn(),
handleOpenTerminal: fn(),
handleCommit: fn(),
onNavigateToChat: fn(),
handleInterrupt: fn(),
handleDeleteQueuedMessage: fn(),
handlePromoteQueuedMessage: fn(),
@@ -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<void>;
@@ -158,7 +154,6 @@ export const AgentDetailView: FC<AgentDetailViewProps> = ({
isInterruptPending,
isSidebarCollapsed,
onToggleSidebarCollapsed,
onOpenAnalytics,
showSidebarPanel,
onSetShowSidebarPanel,
prNumber,
@@ -171,7 +166,6 @@ export const AgentDetailView: FC<AgentDetailViewProps> = ({
handleViewWorkspace,
handleOpenTerminal,
handleCommit,
onNavigateToChat,
handleInterrupt,
handleDeleteQueuedMessage,
handlePromoteQueuedMessage,
@@ -221,7 +215,6 @@ export const AgentDetailView: FC<AgentDetailViewProps> = ({
<AgentDetailTopBar
chatTitle={chatTitle}
parentChat={parentChat}
onOpenParentChat={(chatId) => onNavigateToChat(chatId)}
panel={{
showSidebarPanel,
onToggleSidebar: () => onSetShowSidebarPanel((prev) => !prev),
@@ -275,7 +268,6 @@ export const AgentDetailView: FC<AgentDetailViewProps> = ({
? { 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<AgentDetailLoadingViewProps> = ({
onOpenTerminal: () => {},
sshCommand: undefined,
}}
onOpenParentChat={() => {}}
onArchiveAgent={() => {}}
onUnarchiveAgent={() => {}}
onArchiveAndDeleteWorkspace={() => {}}
@@ -482,7 +473,6 @@ export const AgentDetailNotFoundView: FC<AgentDetailNotFoundViewProps> = ({
onOpenTerminal: () => {},
sshCommand: undefined,
}}
onOpenParentChat={() => {}}
onArchiveAgent={() => {}}
onUnarchiveAgent={() => {}}
onArchiveAndDeleteWorkspace={() => {}}