From 9971dbd51a6a4ad9724912f3bc10a8d01e645bce Mon Sep 17 00:00:00 2001 From: everson-junior <45975050+everson-junior@users.noreply.github.com> Date: Wed, 5 Aug 2026 21:42:44 -0300 Subject: [PATCH] feat(topology): add click navigation to provider page and filter inactive providers (#9024) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Validated in local merge-train (devbox-vm-06-dev002) @ combined-tip (FAST gates green: static + changed tests + vitest — only pre-existing audit.test.ts flake). Evidence: /home/diegosouzapw/dev/proxys/OmniRoute/.claude/worktrees/merge-train-20260805-213228-suite.log --- .../(dashboard)/dashboard/HomePageClient.tsx | 9 +++- src/app/(dashboard)/home/ProviderTopology.tsx | 25 ++++++++-- .../unit/topology-filtering-and-click.test.ts | 48 +++++++++++++++++++ 3 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 tests/unit/topology-filtering-and-click.test.ts diff --git a/src/app/(dashboard)/dashboard/HomePageClient.tsx b/src/app/(dashboard)/dashboard/HomePageClient.tsx index 3b1e2a91da..b5b5883dfd 100644 --- a/src/app/(dashboard)/dashboard/HomePageClient.tsx +++ b/src/app/(dashboard)/dashboard/HomePageClient.tsx @@ -498,6 +498,12 @@ export default function HomePageClient({ machineId }: HomePageClientProps) { const canonicalProviderId = normalizeProviderId(rawProviderId); if (!canonicalProviderId || byProvider.has(canonicalProviderId)) return; + // Exclude providers with no active connections (or where all connections are deactivated) + const hasActiveConn = providerConnections.some( + (c) => normalizeProviderId(c.provider) === canonicalProviderId && c.isActive !== false + ); + if (!hasActiveConn) return; + const resolvedName = getProviderDisplayLabel(rawProviderId, providerNodes) || name || @@ -515,10 +521,11 @@ export default function HomePageClient({ machineId }: HomePageClientProps) { providerStats .filter((provider) => provider.total > 0) .forEach((provider) => addProvider(provider.id, provider.provider.name)); + providerConnections.forEach((conn) => addProvider(conn.provider)); Object.keys(providerMetrics).forEach((provider) => addProvider(provider)); return Array.from(byProvider.values()); - }, [providerStats, providerMetrics, providerNodes]); + }, [providerStats, providerMetrics, providerNodes, providerConnections]); const { lastProvider, errorProvider } = providerTopology; diff --git a/src/app/(dashboard)/home/ProviderTopology.tsx b/src/app/(dashboard)/home/ProviderTopology.tsx index 2324d93d85..413a7a7a7c 100644 --- a/src/app/(dashboard)/home/ProviderTopology.tsx +++ b/src/app/(dashboard)/home/ProviderTopology.tsx @@ -1,6 +1,7 @@ "use client"; -import { useMemo } from "react"; +import { useMemo, useCallback } from "react"; +import { useRouter } from "next/navigation"; import { useTranslations } from "next-intl"; import { Handle, Position, type Node, type Edge, type NodeTypes } from "@xyflow/react"; import { AI_PROVIDERS } from "@/shared/constants/providers"; @@ -58,7 +59,7 @@ function ProviderNode({ data }: { data: ProviderNodeData }) { return (