fix(ui): move key tools preview inside Tool Configuration card

This commit is contained in:
Ishaan Jaffer 2026-03-09 16:13:39 -07:00
parent f3d8a74cec
commit 9daa70a842
3 changed files with 55 additions and 54 deletions

View file

@ -1,6 +1,6 @@
import React, { useState } from "react";
import { Form, Input, Tooltip } from "antd";
import { InfoCircleOutlined, ToolOutlined } from "@ant-design/icons";
import { InfoCircleOutlined } from "@ant-design/icons";
import { FormInstance } from "antd/es/form";
import { AUTH_TYPE } from "./types";
import OpenAPIQuickPicker, { OpenAPIRegistryEntry, OpenAPIKeyTool } from "./OpenAPIQuickPicker";
@ -10,25 +10,26 @@ interface OpenAPIFormSectionProps {
accessToken: string | null;
/** Called when a preset is selected so the parent can sync its formValues state. */
onValuesChange: (updates: Record<string, any>) => void;
/** Called when key tools change (from registry preset selection). */
onKeyToolsChange?: (tools: OpenAPIKeyTool[]) => void;
}
/**
* Encapsulates all OpenAPI-specific form fields:
* - popular API quick-picker (logos)
* - spec URL input
* - curated key tools preview (8 tools from registry, expandable)
*/
const OpenAPIFormSection: React.FC<OpenAPIFormSectionProps> = ({
form,
accessToken,
onValuesChange,
onKeyToolsChange,
}) => {
const [selectedPreset, setSelectedPreset] = useState<string | null>(null);
const [keyTools, setKeyTools] = useState<OpenAPIKeyTool[]>([]);
const handlePresetSelect = (entry: OpenAPIRegistryEntry) => {
setSelectedPreset(entry.name);
setKeyTools(entry.key_tools ?? []);
onKeyToolsChange?.(entry.key_tools ?? []);
const updates = {
spec_path: entry.spec_url,
auth_type: AUTH_TYPE.OAUTH2,
@ -66,54 +67,9 @@ const OpenAPIFormSection: React.FC<OpenAPIFormSectionProps> = ({
className="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"
/>
</Form.Item>
{keyTools.length > 0 && (
<KeyToolsPreview tools={keyTools} />
)}
</>
);
};
interface KeyToolsPreviewProps {
tools: OpenAPIKeyTool[];
}
const KeyToolsPreview: React.FC<KeyToolsPreviewProps> = ({ tools }) => {
const [expanded, setExpanded] = useState(false);
const shown = expanded ? tools : tools.slice(0, 4);
return (
<div className="mb-4 p-3 bg-blue-50 border border-blue-100 rounded-lg">
<div className="flex items-center gap-1.5 mb-2">
<ToolOutlined className="text-blue-500 text-xs" />
<span className="text-xs font-medium text-blue-700">
Key tools from this API
</span>
</div>
<div className="flex flex-wrap gap-1.5">
{shown.map((tool) => (
<Tooltip key={tool.name} title={tool.description} placement="top">
<span className="inline-flex items-center px-2 py-0.5 rounded bg-white border border-blue-200 text-xs text-blue-800 font-mono cursor-default hover:border-blue-400 transition-colors">
{tool.name}
</span>
</Tooltip>
))}
</div>
{tools.length > 4 && (
<button
type="button"
onClick={() => setExpanded((v) => !v)}
className="mt-2 text-xs text-blue-600 hover:text-blue-800 cursor-pointer bg-transparent border-none p-0"
>
{expanded
? "Show less"
: `+ ${tools.length - 4} more — all tools load from the spec below`}
</button>
)}
</div>
);
};
export default OpenAPIFormSection;
export type { OpenAPIKeyTool };

View file

@ -10,7 +10,7 @@ import MCPConnectionStatus from "./mcp_connection_status";
import MCPToolConfiguration from "./mcp_tool_configuration";
import StdioConfiguration from "./StdioConfiguration";
import MCPPermissionManagement from "./MCPPermissionManagement";
import OpenAPIFormSection from "./OpenAPIFormSection";
import OpenAPIFormSection, { OpenAPIKeyTool } from "./OpenAPIFormSection";
import { isAdminRole } from "@/utils/roles";
import { validateMCPServerUrl, validateMCPServerName } from "./utils";
import NotificationsManager from "../molecules/notifications_manager";
@ -58,6 +58,7 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
const [toolNameToDisplayName, setToolNameToDisplayName] = useState<Record<string, string>>({});
const [toolNameToDescription, setToolNameToDescription] = useState<Record<string, string>>({});
const [transportType, setTransportType] = useState<string>("");
const [keyTools, setKeyTools] = useState<OpenAPIKeyTool[]>([]);
const [searchValue, setSearchValue] = useState<string>("");
const [oauthAccessToken, setOauthAccessToken] = useState<string | null>(null);
const authType = formValues.auth_type as string | undefined;
@ -612,6 +613,7 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
onValuesChange={(updates) =>
setFormValues((prev) => ({ ...prev, ...updates }))
}
onKeyToolsChange={setKeyTools}
/>
)}
@ -794,6 +796,7 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
toolNameToDescription={toolNameToDescription}
onToolNameToDisplayNameChange={setToolNameToDisplayName}
onToolNameToDescriptionChange={setToolNameToDescription}
keyTools={keyTools}
/>
</div>

View file

@ -1,9 +1,14 @@
import React, { useEffect, useRef, useState } from "react";
import { Card, Title, Text } from "@tremor/react";
import { ToolOutlined, CheckCircleOutlined, SearchOutlined, EditOutlined } from "@ant-design/icons";
import { Badge, Spin, Checkbox, Input } from "antd";
import { Badge, Spin, Checkbox, Input, Tooltip } from "antd";
import { useTestMCPConnection } from "../../hooks/useTestMCPConnection";
interface KeyTool {
name: string;
description: string;
}
interface MCPToolConfigurationProps {
accessToken: string | null;
oauthAccessToken?: string | null;
@ -15,6 +20,8 @@ interface MCPToolConfigurationProps {
toolNameToDescription: Record<string, string>;
onToolNameToDisplayNameChange: (map: Record<string, string>) => void;
onToolNameToDescriptionChange: (map: Record<string, string>) => void;
/** Curated key tools from the OpenAPI registry preset (shown before spec loads). */
keyTools?: KeyTool[];
}
const MCPToolConfiguration: React.FC<MCPToolConfigurationProps> = ({
@ -28,6 +35,7 @@ const MCPToolConfiguration: React.FC<MCPToolConfigurationProps> = ({
toolNameToDescription,
onToolNameToDisplayNameChange,
onToolNameToDescriptionChange,
keyTools,
}) => {
const previousToolsRef = useRef<any[]>([]);
const [toolSearchTerm, setToolSearchTerm] = useState("");
@ -173,10 +181,15 @@ const MCPToolConfiguration: React.FC<MCPToolConfigurationProps> = ({
{isLoadingTools && (
<div className="flex items-center justify-center py-6">
<Spin size="large" />
<Text className="ml-3">Loading tools...</Text>
<Text className="ml-3">Loading tools from spec...</Text>
</div>
)}
{/* Key tools preview — shown while loading or when spec hasn't loaded yet */}
{keyTools && keyTools.length > 0 && (isLoadingTools || (!isLoadingTools && !toolsError && tools.length === 0)) && (
<KeyToolsPreview tools={keyTools} />
)}
{/* Error state */}
{toolsError && !isLoadingTools && (
<div className="text-center py-6 text-red-500 border rounded-lg border-dashed border-red-300 bg-red-50">
@ -188,7 +201,7 @@ const MCPToolConfiguration: React.FC<MCPToolConfigurationProps> = ({
)}
{/* No tools state */}
{!isLoadingTools && !toolsError && tools.length === 0 && canFetchTools && (
{!isLoadingTools && !toolsError && tools.length === 0 && canFetchTools && (!keyTools || keyTools.length === 0) && (
<div className="text-center py-6 text-gray-400 border rounded-lg border-dashed">
<ToolOutlined className="text-2xl mb-2" />
<Text>No tools available for configuration</Text>
@ -364,4 +377,33 @@ const MCPToolConfiguration: React.FC<MCPToolConfigurationProps> = ({
);
};
const KeyToolsPreview: React.FC<{ tools: KeyTool[] }> = ({ tools }) => {
const [expanded, setExpanded] = useState(false);
const shown = expanded ? tools : tools.slice(0, 4);
return (
<div className="p-3 bg-gray-50 border border-gray-200 rounded-lg">
<p className="text-xs font-medium text-gray-500 mb-2">Key tools from this API (preview all tools load from the spec)</p>
<div className="flex flex-wrap gap-1.5">
{shown.map((tool) => (
<Tooltip key={tool.name} title={tool.description} placement="top">
<span className="inline-flex items-center px-2 py-0.5 rounded bg-white border border-gray-300 text-xs text-gray-700 font-mono cursor-default hover:border-blue-400 transition-colors">
{tool.name}
</span>
</Tooltip>
))}
</div>
{tools.length > 4 && (
<button
type="button"
onClick={() => setExpanded((v) => !v)}
className="mt-2 text-xs text-blue-600 hover:text-blue-800 cursor-pointer bg-transparent border-none p-0"
>
{expanded ? "Show less" : `+ ${tools.length - 4} more`}
</button>
)}
</div>
);
};
export default MCPToolConfiguration;