/**
* ConnectionsPanel: wizard "Connections" section.
*
* Renders a tool bundle dropdown (virtual-server-first), A2A agent
* multi-select, MCP server (gateway) list, and a preview of
* "X tools + Y connected agents".
*
* Additive: this component is imported optionally by ProjectsView.tsx.
*/
import React, { useMemo, useState } from 'react';
export function ConnectionsPanel(props) {
const { catalog, loading, error, toolSource, setToolSource, selectedA2AAgentIds, setSelectedA2AAgentIds, onRefresh, onSync, syncBusy, } = props;
const servers = catalog?.servers || [];
const tools = catalog?.tools || [];
const agents = catalog?.a2a_agents || [];
const gateways = catalog?.gateways || [];
const [showToolsPreview, setShowToolsPreview] = useState(false);
const enabledTools = useMemo(() => tools.filter((t) => t.enabled !== false), [tools]);
const serverToolCount = useMemo(() => {
if (!toolSource.startsWith('server:'))
return 0;
const sid = toolSource.replace('server:', '');
const s = servers.find((x) => x.id === sid);
return s?.tool_ids?.length || 0;
}, [toolSource, servers]);
const toolCount = useMemo(() => {
if (toolSource === 'none')
return 0;
if (toolSource === 'all')
return enabledTools.length;
if (toolSource.startsWith('server:'))
return serverToolCount;
return 0;
}, [toolSource, enabledTools.length, serverToolCount]);
/** Tools visible under the current tool bundle selection */
const visibleTools = useMemo(() => {
if (toolSource === 'none')
return [];
if (toolSource === 'all')
return enabledTools;
if (toolSource.startsWith('server:')) {
const sid = toolSource.replace('server:', '');
const s = servers.find((x) => x.id === sid);
if (!s)
return [];
const ids = new Set(s.tool_ids || []);
return tools.filter((t) => ids.has(t.id));
}
return [];
}, [toolSource, enabledTools, servers, tools]);
const toggleAgent = (id) => {
setSelectedA2AAgentIds(selectedA2AAgentIds.includes(id)
? selectedA2AAgentIds.filter((x) => x !== id)
: [...selectedA2AAgentIds, id]);
};
return (
Connections
Choose a tool bundle + optional A2A agents.
{onSync && ()}
{loading ?
Loading catalog...
: null}
{error ?
Catalog error: {error}
: null}
{catalog && catalog.forge && !catalog.forge.healthy ? (
Forge not healthy: {catalog.forge.error || 'unknown error'}
) : null}
{/* Tool bundle */}
Tool bundle
This agent can use{' '}
{toolCount} tools +{' '}
{selectedA2AAgentIds.length}{' '}
connected agents.
{/* Enterprise warning for "All enabled tools" */}
{toolSource === 'all' && enabledTools.length > 0 && (
Wide scope: "All enabled tools" grants access to every tool in Forge.
For tighter control, select a Virtual Server bundle instead.
)}
{/* Tools preview (collapsible) */}
{toolCount > 0 && (
{showToolsPreview && (
{visibleTools.map((t) => (
{t.name}
))}
)}
)}
{catalog?.last_updated ? (
Fetched from MCP Context Forge · Last updated: {new Date(catalog.last_updated).toLocaleTimeString()}
) : null}
{/* A2A agents */}
A2A agents (optional)
{agents.length === 0 ? (
No A2A agents registered in MCP Context Forge yet.
{onSync && ()}
) : (
{agents.map((a) => {
const checked = selectedA2AAgentIds.includes(a.id);
return (
);
})}
)}
{/* MCP Servers (Gateways) */}
MCP Servers
{gateways.length === 0 ? (
No MCP servers registered yet.
{onSync && ()}
) : (
{gateways.map((g) => (
{g.name}
{g.url ? (
{g.url}
) : null}
{g.transport ? (
{g.transport}) : null}
))}
)}
);
}