From 0db2795d1da8cbee74ab334b2cb2b7aacff3cb02 Mon Sep 17 00:00:00 2001 From: Forgotten Date: Mon, 23 Feb 2026 14:50:20 -0600 Subject: [PATCH] fix: convert navigate() calls to Link components for cmd-click support Replaced button/div onClick + navigate() patterns with React Router components so that cmd-click (or ctrl-click) opens pages in a new browser tab. Changes across: - AgentDetail: RunListItem, "Issues Touched" items, "Manage" config link, "Back to runs" mobile button - CompanySwitcher: "Company Settings" and "Manage Companies" items - Approvals: pass detailLink prop instead of onOpen callback - Org: OrgTree nodes now render as Links Co-Authored-By: Claude Opus 4.6 --- ui/src/components/CompanySwitcher.tsx | 19 +++++++------ ui/src/pages/AgentDetail.tsx | 40 +++++++++++---------------- ui/src/pages/Approvals.tsx | 2 +- ui/src/pages/Org.tsx | 26 ++++++++--------- 4 files changed, 41 insertions(+), 46 deletions(-) diff --git a/ui/src/components/CompanySwitcher.tsx b/ui/src/components/CompanySwitcher.tsx index 7cabd7d1..17ddb3fa 100644 --- a/ui/src/components/CompanySwitcher.tsx +++ b/ui/src/components/CompanySwitcher.tsx @@ -1,5 +1,5 @@ import { ChevronsUpDown, Plus, Settings } from "lucide-react"; -import { useNavigate } from "react-router-dom"; +import { Link } from "react-router-dom"; import { useCompany } from "../context/CompanyContext"; import { DropdownMenu, @@ -26,7 +26,6 @@ function statusDotColor(status?: string): string { export function CompanySwitcher() { const { companies, selectedCompany, setSelectedCompanyId } = useCompany(); - const navigate = useNavigate(); return ( @@ -63,13 +62,17 @@ export function CompanySwitcher() { No companies )} - navigate("/company/settings")}> - - Company Settings + + + + Company Settings + - navigate("/companies")}> - - Manage Companies + + + + Manage Companies + diff --git a/ui/src/pages/AgentDetail.tsx b/ui/src/pages/AgentDetail.tsx index da2cf48a..bb3d9951 100644 --- a/ui/src/pages/AgentDetail.tsx +++ b/ui/src/pages/AgentDetail.tsx @@ -604,8 +604,6 @@ function SummaryRow({ label, children }: { label: string; children: React.ReactN } function LatestRunCard({ runs, agentId }: { runs: HeartbeatRun[]; agentId: string }) { - const navigate = useNavigate(); - if (runs.length === 0) return null; const sorted = [...runs].sort( @@ -687,8 +685,6 @@ function AgentOverview({ directReports: Agent[]; agentId: string; }) { - const navigate = useNavigate(); - return (
{/* Latest Run */} @@ -1023,7 +1019,6 @@ function ConfigSummary({ reportsToAgent: Agent | null; directReports: Agent[]; }) { - const navigate = useNavigate(); const config = agent.adapterConfig as Record; const promptText = typeof config?.promptTemplate === "string" ? config.promptTemplate : ""; @@ -1031,13 +1026,13 @@ function ConfigSummary({

Configuration

- +
@@ -1393,7 +1388,6 @@ function ConfigurationTab({ /* ---- Runs Tab ---- */ function RunListItem({ run, isSelected, agentId }: { run: HeartbeatRun; isSelected: boolean; agentId: string }) { - const navigate = useNavigate(); const statusInfo = runStatusIcons[run.status] ?? { icon: Clock, color: "text-neutral-400" }; const StatusIcon = statusInfo.icon; const metrics = runMetrics(run); @@ -1402,12 +1396,12 @@ function RunListItem({ run, isSelected, agentId }: { run: HeartbeatRun; isSelect : run.error ?? ""; return ( - + ); } function RunsTab({ runs, companyId, agentId, selectedRunId, adapterType }: { runs: HeartbeatRun[]; companyId: string; agentId: string; selectedRunId: string | null; adapterType: string }) { - const navigate = useNavigate(); const { isMobile } = useSidebar(); if (runs.length === 0) { @@ -1464,13 +1457,13 @@ function RunsTab({ runs, companyId, agentId, selectedRunId, adapterType }: { run if (selectedRun) { return (
- +
); @@ -1513,7 +1506,6 @@ function RunsTab({ runs, companyId, agentId, selectedRunId, adapterType }: { run function RunDetail({ run, adapterType }: { run: HeartbeatRun; adapterType: string }) { const queryClient = useQueryClient(); - const navigate = useNavigate(); const metrics = runMetrics(run); const [sessionOpen, setSessionOpen] = useState(false); const [claudeLoginResult, setClaudeLoginResult] = useState(null); @@ -1758,17 +1750,17 @@ function RunDetail({ run, adapterType }: { run: HeartbeatRun; adapterType: strin Issues Touched ({touchedIssues.length})
{touchedIssues.map((issue) => ( - + ))}
diff --git a/ui/src/pages/Approvals.tsx b/ui/src/pages/Approvals.tsx index bb8e856f..7fdd6ec3 100644 --- a/ui/src/pages/Approvals.tsx +++ b/ui/src/pages/Approvals.tsx @@ -117,7 +117,7 @@ export function Approvals() { requesterAgent={approval.requestedByAgentId ? (agents ?? []).find((a) => a.id === approval.requestedByAgentId) ?? null : null} onApprove={() => approveMutation.mutate(approval.id)} onReject={() => rejectMutation.mutate(approval.id)} - onOpen={() => navigate(`/approvals/${approval.id}`)} + detailLink={`/approvals/${approval.id}`} isPending={approveMutation.isPending || rejectMutation.isPending} /> ))} diff --git a/ui/src/pages/Org.tsx b/ui/src/pages/Org.tsx index b03e736d..2928e104 100644 --- a/ui/src/pages/Org.tsx +++ b/ui/src/pages/Org.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { useNavigate } from "react-router-dom"; +import { Link } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; import { agentsApi, type OrgNode } from "../api/agents"; import { useCompany } from "../context/CompanyContext"; @@ -13,16 +13,16 @@ import { cn } from "../lib/utils"; function OrgTree({ nodes, depth = 0, - onSelect, + hrefFn, }: { nodes: OrgNode[]; depth?: number; - onSelect: (id: string) => void; + hrefFn: (id: string) => string; }) { return (
{nodes.map((node) => ( - + ))}
); @@ -31,26 +31,27 @@ function OrgTree({ function OrgTreeNode({ node, depth, - onSelect, + hrefFn, }: { node: OrgNode; depth: number; - onSelect: (id: string) => void; + hrefFn: (id: string) => string; }) { const [expanded, setExpanded] = useState(true); const hasChildren = node.reports.length > 0; return (
-
onSelect(node.id)} > {hasChildren ? (
+ {hasChildren && expanded && ( - + )}
); @@ -90,7 +91,6 @@ function OrgTreeNode({ export function Org() { const { selectedCompanyId } = useCompany(); const { setBreadcrumbs } = useBreadcrumbs(); - const navigate = useNavigate(); useEffect(() => { setBreadcrumbs([{ label: "Org Chart" }]); @@ -120,7 +120,7 @@ export function Org() { {data && data.length > 0 && (
- navigate(`/agents/${id}`)} /> + `/agents/${id}`} />
)}