Fix MCP Server resetting back to Overview

This commit is contained in:
yuneng-jiang 2026-01-20 21:38:58 -08:00
parent d5305c6a61
commit 2441b05700
3 changed files with 119 additions and 117 deletions

View file

@ -36,6 +36,8 @@ export const MCPServerView: React.FC<MCPServerViewProps> = ({
const [editing, setEditing] = useState(isEditing);
const [showFullUrl, setShowFullUrl] = useState(false);
const [copiedStates, setCopiedStates] = useState<Record<string, boolean>>({});
const [selectedTabIndex, setSelectedTabIndex] = useState(0);
const handleSuccess = (updated: MCPServer) => {
setEditing(false);
onBack();
@ -72,11 +74,10 @@ export const MCPServerView: React.FC<MCPServerViewProps> = ({
size="small"
icon={copiedStates["mcp-server_name"] ? <CheckIcon size={12} /> : <CopyIcon size={12} />}
onClick={() => copyToClipboard(mcpServer.server_name, "mcp-server_name")}
className={`left-2 z-10 transition-all duration-200 ${
copiedStates["mcp-server_name"]
? "text-green-600 bg-green-50 border-green-200"
: "text-gray-500 hover:text-gray-700 hover:bg-gray-100"
}`}
className={`left-2 z-10 transition-all duration-200 ${copiedStates["mcp-server_name"]
? "text-green-600 bg-green-50 border-green-200"
: "text-gray-500 hover:text-gray-700 hover:bg-gray-100"
}`}
/>
{mcpServer.alias && (
<>
@ -87,11 +88,10 @@ export const MCPServerView: React.FC<MCPServerViewProps> = ({
size="small"
icon={copiedStates["mcp-alias"] ? <CheckIcon size={12} /> : <CopyIcon size={12} />}
onClick={() => copyToClipboard(mcpServer.alias, "mcp-alias")}
className={`left-2 z-10 transition-all duration-200 ${
copiedStates["mcp-alias"]
? "text-green-600 bg-green-50 border-green-200"
: "text-gray-500 hover:text-gray-700 hover:bg-gray-100"
}`}
className={`left-2 z-10 transition-all duration-200 ${copiedStates["mcp-alias"]
? "text-green-600 bg-green-50 border-green-200"
: "text-gray-500 hover:text-gray-700 hover:bg-gray-100"
}`}
/>
</>
)}
@ -103,18 +103,17 @@ export const MCPServerView: React.FC<MCPServerViewProps> = ({
size="small"
icon={copiedStates["mcp-server-id"] ? <CheckIcon size={12} /> : <CopyIcon size={12} />}
onClick={() => copyToClipboard(mcpServer.server_id, "mcp-server-id")}
className={`left-2 z-10 transition-all duration-200 ${
copiedStates["mcp-server-id"]
? "text-green-600 bg-green-50 border-green-200"
: "text-gray-500 hover:text-gray-700 hover:bg-gray-100"
}`}
className={`left-2 z-10 transition-all duration-200 ${copiedStates["mcp-server-id"]
? "text-green-600 bg-green-50 border-green-200"
: "text-gray-500 hover:text-gray-700 hover:bg-gray-100"
}`}
/>
</div>
</div>
</div>
{/* TODO: magic number for index */}
<TabGroup defaultIndex={editing ? 2 : 0}>
<TabGroup index={selectedTabIndex} onIndexChange={setSelectedTabIndex}>
<TabList className="mb-4">
{[
<Tab key="overview">Overview</Tab>,

View file

@ -212,103 +212,28 @@ const MCPServers: React.FC<MCPServerProps> = ({ accessToken, userRole, userID })
return <div className="p-6 text-center text-gray-500">Missing required authentication parameters.</div>;
}
const ServersTab = () =>
selectedServerId ? (
<MCPServerView
mcpServer={
filteredServers.find((server: MCPServer) => server.server_id === selectedServerId) || {
server_id: "",
server_name: "",
alias: "",
url: "",
transport: "",
auth_type: "",
created_at: "",
created_by: "",
updated_at: "",
updated_by: "",
}
}
onBack={() => {
setEditServer(false);
setSelectedServerId(null);
refetch();
}}
isProxyAdmin={isAdminRole(userRole)}
isEditing={editServer}
accessToken={accessToken}
userID={userID}
userRole={userRole}
availableAccessGroups={uniqueMcpAccessGroups}
/>
) : (
<div className="w-full h-full">
<div className="w-full px-6">
<div className="flex flex-col space-y-4">
<div className="flex items-center justify-between bg-gray-50 rounded-lg p-4 border-2 border-gray-200">
<div className="flex items-center gap-4">
<Text className="text-lg font-semibold text-gray-900">Current Team:</Text>
<Select value={selectedTeam} onChange={handleTeamChange} style={{ width: 300 }}>
<Option value="all">
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-blue-500 rounded-full"></div>
<span className="font-medium">{isInternalUser ? "All Available Servers" : "All Servers"}</span>
</div>
</Option>
<Option value="personal">
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-green-500 rounded-full"></div>
<span className="font-medium">Personal</span>
</div>
</Option>
{uniqueTeams.map((team) => (
<Option key={team.team_id} value={team.team_id}>
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-green-500 rounded-full"></div>
<span className="font-medium">{team.team_alias || team.team_id}</span>
</div>
</Option>
))}
</Select>
<Text className="text-lg font-semibold text-gray-900 ml-6">
Access Group:
<Tooltip title="An MCP Access Group is a set of users or teams that have permission to access specific MCP servers. Use access groups to control and organize who can connect to which servers.">
<QuestionCircleOutlined style={{ marginLeft: 4, color: "#888" }} />
</Tooltip>
</Text>
<Select value={selectedMcpAccessGroup} onChange={handleMcpAccessGroupChange} style={{ width: 300 }}>
<Option value="all">
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-blue-500 rounded-full"></div>
<span className="font-medium">All Access Groups</span>
</div>
</Option>
{uniqueMcpAccessGroups.map((group) => (
<Option key={group} value={group}>
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-green-500 rounded-full"></div>
<span className="font-medium">{group}</span>
</div>
</Option>
))}
</Select>
</div>
</div>
</div>
</div>
<div className="w-full px-6 mt-6">
<DataTable
data={filteredServers}
columns={columns}
renderSubComponent={() => <div></div>}
getRowCanExpand={() => false}
isLoading={isLoadingServers}
noDataMessage="No MCP servers configured"
loadingMessage="🚅 Loading MCP servers..."
/>
</div>
</div>
);
// Memoize the selected server to prevent unnecessary re-renders
const selectedServer = React.useMemo(() => {
return filteredServers.find((server: MCPServer) => server.server_id === selectedServerId) || {
server_id: "",
server_name: "",
alias: "",
url: "",
transport: "",
auth_type: "",
created_at: "",
created_by: "",
updated_at: "",
updated_by: "",
};
}, [filteredServers, selectedServerId]);
// Memoize the onBack callback to prevent unnecessary re-renders
const handleBack = React.useCallback(() => {
setEditServer(false);
setSelectedServerId(null);
refetch();
}, [refetch]);
return (
<div className="w-full h-full p-6">
@ -381,7 +306,86 @@ const MCPServers: React.FC<MCPServerProps> = ({ accessToken, userRole, userID })
</TabList>
<TabPanels>
<TabPanel>
<ServersTab />
{selectedServerId ? (
<MCPServerView
key={selectedServerId}
mcpServer={selectedServer}
onBack={handleBack}
isProxyAdmin={isAdminRole(userRole)}
isEditing={editServer}
accessToken={accessToken}
userID={userID}
userRole={userRole}
availableAccessGroups={uniqueMcpAccessGroups}
/>
) : (
<div className="w-full h-full">
<div className="w-full px-6">
<div className="flex flex-col space-y-4">
<div className="flex items-center justify-between bg-gray-50 rounded-lg p-4 border-2 border-gray-200">
<div className="flex items-center gap-4">
<Text className="text-lg font-semibold text-gray-900">Current Team:</Text>
<Select value={selectedTeam} onChange={handleTeamChange} style={{ width: 300 }}>
<Option value="all">
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-blue-500 rounded-full"></div>
<span className="font-medium">{isInternalUser ? "All Available Servers" : "All Servers"}</span>
</div>
</Option>
<Option value="personal">
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-green-500 rounded-full"></div>
<span className="font-medium">Personal</span>
</div>
</Option>
{uniqueTeams.map((team) => (
<Option key={team.team_id} value={team.team_id}>
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-green-500 rounded-full"></div>
<span className="font-medium">{team.team_alias || team.team_id}</span>
</div>
</Option>
))}
</Select>
<Text className="text-lg font-semibold text-gray-900 ml-6">
Access Group:
<Tooltip title="An MCP Access Group is a set of users or teams that have permission to access specific MCP servers. Use access groups to control and organize who can connect to which servers.">
<QuestionCircleOutlined style={{ marginLeft: 4, color: "#888" }} />
</Tooltip>
</Text>
<Select value={selectedMcpAccessGroup} onChange={handleMcpAccessGroupChange} style={{ width: 300 }}>
<Option value="all">
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-blue-500 rounded-full"></div>
<span className="font-medium">All Access Groups</span>
</div>
</Option>
{uniqueMcpAccessGroups.map((group) => (
<Option key={group} value={group}>
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-green-500 rounded-full"></div>
<span className="font-medium">{group}</span>
</div>
</Option>
))}
</Select>
</div>
</div>
</div>
</div>
<div className="w-full px-6 mt-6">
<DataTable
data={filteredServers}
columns={columns}
renderSubComponent={() => <div></div>}
getRowCanExpand={() => false}
isLoading={isLoadingServers}
noDataMessage="No MCP servers configured"
loadingMessage="🚅 Loading MCP servers..."
/>
</div>
</div>
)}
</TabPanel>
<TabPanel>
<MCPConnect />

View file

@ -127,11 +127,10 @@ const MCPToolsViewer = ({
{toolsData.map((tool: MCPTool) => (
<div
key={tool.name}
className={`border rounded-lg p-3 cursor-pointer transition-all hover:shadow-sm ${
selectedTool?.name === tool.name
className={`border rounded-lg p-3 cursor-pointer transition-all hover:shadow-sm ${selectedTool?.name === tool.name
? "border-blue-500 bg-blue-50 ring-1 ring-blue-200"
: "border-gray-200 bg-white hover:border-gray-300"
}`}
}`}
onClick={() => {
setSelectedTool(tool);
setToolResult(null);