From 45fdfff3b7bfbb9db17983edce9fd617eac4a093 Mon Sep 17 00:00:00 2001 From: ciregenz Date: Sun, 24 May 2026 01:55:50 -0700 Subject: [PATCH] [eric] actions: sort MCPs by connected+on, then on, then off (stable, no more jumping) --- frontend/src/app/pages/Tools/Tools.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/pages/Tools/Tools.tsx b/frontend/src/app/pages/Tools/Tools.tsx index 5c9a8323..13397e0b 100644 --- a/frontend/src/app/pages/Tools/Tools.tsx +++ b/frontend/src/app/pages/Tools/Tools.tsx @@ -462,7 +462,16 @@ const Tools: React.FC = () => { const { servers: regServersRaw, total: regTotal, loading: regLoading, stats: regStats, detail: regDetail, detailLoading: regDetailLoading } = useAppSelector((s) => s.mcpRegistry); const devMode = useAppSelector((s) => s.settings.data.dev_mode); const allTools = Object.values(items); - const tools = allTools; + // Deterministic order so cards don't jump around on refetch: connected + on first, then on, + // then anything toggled off (connection state ignored once it's off). A-Z within each tier. + const tools = useMemo(() => { + const tier = (t: ToolDefinition) => + t.enabled === false ? 2 : (t.auth_status === 'connected' ? 0 : 1); + return Object.values(items).sort((a, b) => { + const d = tier(a) - tier(b); + return d !== 0 ? d : (a.name || '').localeCompare(b.name || ''); + }); + }, [items]); const uninstalledIntegrations = useMemo(() => INTEGRATIONS.filter((ig) => !allTools.find((t) => t.name === ig.name)), [allTools]); const getIntegrationForTool = useCallback((tool: ToolDefinition) => INTEGRATIONS.find((ig) => ig.name === tool.name), []); @@ -1493,7 +1502,7 @@ const Tools: React.FC = () => { return (