feat(mcp): enhance wizard with title field and optimize placeholders
- Add MCP title field to wizard (required) - Remove working directory (cwd) field and related logic - Update wizard callback to return both title and JSON - Optimize placeholder text for better user guidance: - Command: "npx or uvx" - Args: "arg1\narg2" - Env: "KEY1=value1\nKEY2=value2" - Headers: "Authorization: Bearer your_token_here\n..." - Simplify args label by removing "(one per line)" hint - Update parent component to handle title from wizard
This commit is contained in:
@@ -152,7 +152,8 @@ const McpFormModal: React.FC<McpFormModalProps> = ({
|
|||||||
setJsonError("");
|
setJsonError("");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleWizardApply = (json: string) => {
|
const handleWizardApply = (title: string, json: string) => {
|
||||||
|
setFormId(title);
|
||||||
setFormJson(json);
|
setFormJson(json);
|
||||||
setJsonError(validateJson(json));
|
setJsonError(validateJson(json));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { isLinux } from "../../lib/platform";
|
|||||||
interface McpWizardModalProps {
|
interface McpWizardModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onApply: (json: string) => void;
|
onApply: (title: string, json: string) => void;
|
||||||
onNotify?: (
|
onNotify?: (
|
||||||
message: string,
|
message: string,
|
||||||
type: "success" | "error",
|
type: "success" | "error",
|
||||||
@@ -75,10 +75,10 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [wizardType, setWizardType] = useState<"stdio" | "http">("stdio");
|
const [wizardType, setWizardType] = useState<"stdio" | "http">("stdio");
|
||||||
|
const [wizardTitle, setWizardTitle] = useState("");
|
||||||
// stdio 字段
|
// stdio 字段
|
||||||
const [wizardCommand, setWizardCommand] = useState("");
|
const [wizardCommand, setWizardCommand] = useState("");
|
||||||
const [wizardArgs, setWizardArgs] = useState("");
|
const [wizardArgs, setWizardArgs] = useState("");
|
||||||
const [wizardCwd, setWizardCwd] = useState("");
|
|
||||||
const [wizardEnv, setWizardEnv] = useState("");
|
const [wizardEnv, setWizardEnv] = useState("");
|
||||||
// http 字段
|
// http 字段
|
||||||
const [wizardUrl, setWizardUrl] = useState("");
|
const [wizardUrl, setWizardUrl] = useState("");
|
||||||
@@ -102,10 +102,6 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
|
|||||||
.filter((s) => s.length > 0);
|
.filter((s) => s.length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wizardCwd.trim()) {
|
|
||||||
config.cwd = wizardCwd.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wizardEnv.trim()) {
|
if (wizardEnv.trim()) {
|
||||||
const env = parseEnvText(wizardEnv);
|
const env = parseEnvText(wizardEnv);
|
||||||
if (Object.keys(env).length > 0) {
|
if (Object.keys(env).length > 0) {
|
||||||
@@ -129,6 +125,10 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleApply = () => {
|
const handleApply = () => {
|
||||||
|
if (!wizardTitle.trim()) {
|
||||||
|
onNotify?.(t("mcp.error.idRequired"), "error", 3000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (wizardType === "stdio" && !wizardCommand.trim()) {
|
if (wizardType === "stdio" && !wizardCommand.trim()) {
|
||||||
onNotify?.(t("mcp.error.commandRequired"), "error", 3000);
|
onNotify?.(t("mcp.error.commandRequired"), "error", 3000);
|
||||||
return;
|
return;
|
||||||
@@ -139,16 +139,16 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const json = generatePreview();
|
const json = generatePreview();
|
||||||
onApply(json);
|
onApply(wizardTitle.trim(), json);
|
||||||
handleClose();
|
handleClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
// 重置表单
|
// 重置表单
|
||||||
setWizardType("stdio");
|
setWizardType("stdio");
|
||||||
|
setWizardTitle("");
|
||||||
setWizardCommand("");
|
setWizardCommand("");
|
||||||
setWizardArgs("");
|
setWizardArgs("");
|
||||||
setWizardCwd("");
|
|
||||||
setWizardEnv("");
|
setWizardEnv("");
|
||||||
setWizardUrl("");
|
setWizardUrl("");
|
||||||
setWizardHeaders("");
|
setWizardHeaders("");
|
||||||
@@ -247,6 +247,21 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Title */}
|
||||||
|
<div>
|
||||||
|
<label className="mb-1 block text-sm font-medium text-gray-900 dark:text-gray-100">
|
||||||
|
{t("mcp.form.title")} <span className="text-red-500">*</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={wizardTitle}
|
||||||
|
onChange={(e) => setWizardTitle(e.target.value)}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
placeholder={t("mcp.form.titlePlaceholder")}
|
||||||
|
className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-emerald-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Stdio 类型字段 */}
|
{/* Stdio 类型字段 */}
|
||||||
{wizardType === "stdio" && (
|
{wizardType === "stdio" && (
|
||||||
<>
|
<>
|
||||||
@@ -280,21 +295,6 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* CWD */}
|
|
||||||
<div>
|
|
||||||
<label className="mb-1 block text-sm font-medium text-gray-900 dark:text-gray-100">
|
|
||||||
{t("mcp.wizard.cwd")}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={wizardCwd}
|
|
||||||
onChange={(e) => setWizardCwd(e.target.value)}
|
|
||||||
onKeyDown={handleKeyDown}
|
|
||||||
placeholder={t("mcp.wizard.cwdPlaceholder")}
|
|
||||||
className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-emerald-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Env */}
|
{/* Env */}
|
||||||
<div>
|
<div>
|
||||||
<label className="mb-1 block text-sm font-medium text-gray-900 dark:text-gray-100">
|
<label className="mb-1 block text-sm font-medium text-gray-900 dark:text-gray-100">
|
||||||
@@ -350,7 +350,6 @@ const McpWizardModal: React.FC<McpWizardModalProps> = ({
|
|||||||
{/* Preview */}
|
{/* Preview */}
|
||||||
{(wizardCommand ||
|
{(wizardCommand ||
|
||||||
wizardArgs ||
|
wizardArgs ||
|
||||||
wizardCwd ||
|
|
||||||
wizardEnv ||
|
wizardEnv ||
|
||||||
wizardUrl ||
|
wizardUrl ||
|
||||||
wizardHeaders) && (
|
wizardHeaders) && (
|
||||||
|
|||||||
@@ -292,24 +292,21 @@
|
|||||||
"hint": "Quickly configure MCP server and auto-generate JSON configuration",
|
"hint": "Quickly configure MCP server and auto-generate JSON configuration",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
"command": "Command",
|
"command": "Command",
|
||||||
"commandPlaceholder": "uvx",
|
"commandPlaceholder": "npx or uvx",
|
||||||
"args": "Arguments (one per line)",
|
"args": "Arguments",
|
||||||
"argsPlaceholder": "mcp-server-fetch\n--config config.json",
|
"argsPlaceholder": "arg1\narg2",
|
||||||
"cwd": "Working Directory",
|
|
||||||
"cwdPlaceholder": "/path/to/project",
|
|
||||||
"env": "Environment Variables",
|
"env": "Environment Variables",
|
||||||
"envPlaceholder": "KEY=VALUE\n(one per line)",
|
"envPlaceholder": "KEY1=value1\nKEY2=value2",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
"urlPlaceholder": "https://api.example.com/mcp",
|
"urlPlaceholder": "https://api.example.com/mcp",
|
||||||
"urlRequired": "Please enter URL",
|
"urlRequired": "Please enter URL",
|
||||||
"headers": "Headers (optional)",
|
"headers": "Headers (optional)",
|
||||||
"headersPlaceholder": "Authorization: Bearer token\nContent-Type: application/json",
|
"headersPlaceholder": "Authorization: Bearer your_token_here\nContent-Type: application/json",
|
||||||
"preview": "Configuration Preview",
|
"preview": "Configuration Preview",
|
||||||
"apply": "Apply Configuration"
|
"apply": "Apply Configuration"
|
||||||
},
|
},
|
||||||
"id": "Identifier (unique)",
|
"id": "Identifier (unique)",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
"cwd": "Working Directory (optional)",
|
|
||||||
"command": "Command",
|
"command": "Command",
|
||||||
"validateCommand": "Validate Command",
|
"validateCommand": "Validate Command",
|
||||||
"args": "Args",
|
"args": "Args",
|
||||||
|
|||||||
@@ -292,24 +292,21 @@
|
|||||||
"hint": "快速配置 MCP 服务器,自动生成 JSON 配置",
|
"hint": "快速配置 MCP 服务器,自动生成 JSON 配置",
|
||||||
"type": "类型",
|
"type": "类型",
|
||||||
"command": "命令",
|
"command": "命令",
|
||||||
"commandPlaceholder": "uvx",
|
"commandPlaceholder": "npx 或 uvx",
|
||||||
"args": "参数(每行一个)",
|
"args": "参数",
|
||||||
"argsPlaceholder": "mcp-server-fetch\n--config config.json",
|
"argsPlaceholder": "arg1\narg2",
|
||||||
"cwd": "工作目录",
|
|
||||||
"cwdPlaceholder": "/path/to/project",
|
|
||||||
"env": "环境变量",
|
"env": "环境变量",
|
||||||
"envPlaceholder": "KEY=VALUE\n(一行一个)",
|
"envPlaceholder": "KEY1=value1\nKEY2=value2",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
"urlPlaceholder": "https://api.example.com/mcp",
|
"urlPlaceholder": "https://api.example.com/mcp",
|
||||||
"urlRequired": "请输入 URL",
|
"urlRequired": "请输入 URL",
|
||||||
"headers": "请求头(可选)",
|
"headers": "请求头(可选)",
|
||||||
"headersPlaceholder": "Authorization: Bearer token\nContent-Type: application/json",
|
"headersPlaceholder": "Authorization: Bearer your_token_here\nContent-Type: application/json",
|
||||||
"preview": "配置预览",
|
"preview": "配置预览",
|
||||||
"apply": "应用配置"
|
"apply": "应用配置"
|
||||||
},
|
},
|
||||||
"id": "标识 (唯一)",
|
"id": "标识 (唯一)",
|
||||||
"type": "类型",
|
"type": "类型",
|
||||||
"cwd": "工作目录 (可选)",
|
|
||||||
"command": "命令",
|
"command": "命令",
|
||||||
"validateCommand": "校验命令",
|
"validateCommand": "校验命令",
|
||||||
"args": "参数",
|
"args": "参数",
|
||||||
|
|||||||
Reference in New Issue
Block a user