From d037647c2171dae89e53d7af4cd6fdcee20f9194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=AC=E6=98=8E?= <83812544+Ed1s0nZ@users.noreply.github.com> Date: Tue, 21 Apr 2026 19:13:08 +0800 Subject: [PATCH] Add files via upload --- web/static/css/style.css | 91 +++++++++++++++++++++- web/static/i18n/en-US.json | 10 +-- web/static/i18n/zh-CN.json | 10 +-- web/static/js/settings.js | 154 +++++++++++++++++++++++++++++++------ 4 files changed, 231 insertions(+), 34 deletions(-) diff --git a/web/static/css/style.css b/web/static/css/style.css index f4300451..46d0ba03 100644 --- a/web/static/css/style.css +++ b/web/static/css/style.css @@ -3965,7 +3965,7 @@ header { .tool-item { display: flex; - align-items: center; + align-items: flex-start; gap: 12px; padding: 10px 12px; border-radius: 6px; @@ -3980,8 +3980,10 @@ header { .tool-item input[type="checkbox"] { width: 18px; height: 18px; + margin-top: 2px; cursor: pointer; accent-color: var(--accent-color); + flex-shrink: 0; } .tool-item-info { @@ -4021,6 +4023,93 @@ header { white-space: nowrap; } +/* 展开图标 */ +.tool-expand-icon { + font-size: 0.625rem; + color: var(--text-tertiary); + transition: transform 0.2s; + user-select: none; + flex-shrink: 0; +} + +/* 展开后的详情面板 */ +.tool-item-detail { + margin-top: 8px; + padding: 12px; + background: var(--bg-tertiary); + border-radius: 8px; + border: 1px solid var(--border-color); + font-size: 0.8125rem; +} + +.tool-detail-desc { + color: var(--text-secondary); + line-height: 1.6; + margin-bottom: 8px; + white-space: pre-wrap; + word-break: break-word; +} + +.tool-detail-section-title { + font-size: 0.75rem; + font-weight: 600; + color: var(--text-tertiary); + text-transform: uppercase; + letter-spacing: 0.5px; + margin-bottom: 6px; +} + +/* 参数表格 */ +.tool-schema-table { + width: 100%; + border-collapse: collapse; + font-size: 0.8125rem; +} + +.tool-schema-table th { + text-align: left; + padding: 6px 10px; + background: var(--bg-secondary); + color: var(--text-secondary); + font-size: 0.75rem; + font-weight: 600; + border-bottom: 1px solid var(--border-color); +} + +.tool-schema-table td { + padding: 6px 10px; + border-bottom: 1px solid var(--border-color); + color: var(--text-primary); + vertical-align: top; +} + +.tool-schema-table code { + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: 0.8125rem; + color: var(--accent-color); +} + +/* 可点击的外部工具徽章 */ +.external-tool-badge.clickable { + cursor: pointer; + transition: background 0.2s, border-color 0.2s; +} + +.external-tool-badge.clickable:hover { + background: rgba(255, 152, 0, 0.25); + border-color: rgba(255, 152, 0, 0.6); +} + +/* 外部 MCP 卡片高亮动画 */ +.external-mcp-item.highlight { + animation: mcpHighlight 2s ease-out; +} + +@keyframes mcpHighlight { + 0% { box-shadow: 0 0 0 3px var(--accent-color); border-color: var(--accent-color); } + 100% { box-shadow: none; border-color: var(--border-color); } +} + .tool-item.hidden { display: none; } diff --git a/web/static/i18n/en-US.json b/web/static/i18n/en-US.json index 2ba3f1ba..6b3cff14 100644 --- a/web/static/i18n/en-US.json +++ b/web/static/i18n/en-US.json @@ -1564,15 +1564,15 @@ "externalMcpModal": { "configJson": "Config JSON", "formatLabel": "Format:", - "formatDesc": "JSON object; key = config name, value = config. Use Start/Stop buttons to control state.", + "formatDesc": "JSON object; key = config name, value = config. Use Start/Stop buttons to control state. Supports ${VAR} and ${VAR:-default} env variable syntax.", "configExample": "Configuration example:", "stdioMode": "stdio mode:", "httpMode": "HTTP mode:", "sseMode": "SSE mode:", - "placeholder": "{\n \"hexstrike-ai\": {\n \"command\": \"python3\",\n \"args\": [\"/path/to/script.py\"],\n \"description\": \"Description\",\n \"timeout\": 300\n }\n}", - "exampleStdio": "{\n \"hexstrike-ai\": {\n \"command\": \"python3\",\n \"args\": [\"/path/to/script.py\", \"--server\", \"http://example.com\"],\n \"description\": \"Description\",\n \"timeout\": 300\n }\n}", - "exampleHttp": "{\n \"cyberstrike-ai-http\": {\n \"transport\": \"http\",\n \"url\": \"http://127.0.0.1:8081/mcp\"\n }\n}", - "exampleSse": "{\n \"cyberstrike-ai-sse\": {\n \"transport\": \"sse\",\n \"url\": \"http://127.0.0.1:8081/mcp/sse\"\n }\n}", + "placeholder": "{\n \"my-server\": {\n \"command\": \"python3\",\n \"args\": [\"${HOME}/mcp/server.py\"],\n \"env\": { \"API_KEY\": \"${API_KEY}\" },\n \"timeout\": 300\n }\n}", + "exampleStdio": "{\n \"my-server\": {\n \"command\": \"python3\",\n \"args\": [\"${HOME}/mcp/server.py\"],\n \"env\": { \"API_KEY\": \"${API_KEY}\", \"LOG_LEVEL\": \"${LOG_LEVEL:-INFO}\" },\n \"timeout\": 300\n }\n}", + "exampleHttp": "{\n \"remote-mcp\": {\n \"type\": \"http\",\n \"url\": \"https://mcp.example.com/mcp\",\n \"headers\": { \"Authorization\": \"Bearer ${MCP_TOKEN}\" }\n }\n}", + "exampleSse": "{\n \"sse-mcp\": {\n \"type\": \"sse\",\n \"url\": \"http://127.0.0.1:8081/mcp/sse\"\n }\n}", "exampleDescription": "Example description", "formatJson": "Format JSON", "loadExample": "Load example" diff --git a/web/static/i18n/zh-CN.json b/web/static/i18n/zh-CN.json index 40831985..4102481c 100644 --- a/web/static/i18n/zh-CN.json +++ b/web/static/i18n/zh-CN.json @@ -1564,15 +1564,15 @@ "externalMcpModal": { "configJson": "配置JSON", "formatLabel": "配置格式:", - "formatDesc": "JSON对象,key为配置名称,value为配置内容。状态通过\"启动/停止\"按钮控制,无需在JSON中配置。", + "formatDesc": "JSON对象,key为配置名称,value为配置内容。状态通过\"启动/停止\"按钮控制,无需在JSON中配置。支持 ${VAR} 和 ${VAR:-默认值} 环境变量语法。", "configExample": "配置示例:", "stdioMode": "stdio模式:", "httpMode": "HTTP模式:", "sseMode": "SSE模式:", - "placeholder": "{\n \"hexstrike-ai\": {\n \"command\": \"python3\",\n \"args\": [\"/path/to/script.py\"],\n \"description\": \"描述\",\n \"timeout\": 300\n }\n}", - "exampleStdio": "{\n \"hexstrike-ai\": {\n \"command\": \"python3\",\n \"args\": [\"/path/to/script.py\", \"--server\", \"http://example.com\"],\n \"description\": \"描述\",\n \"timeout\": 300\n }\n}", - "exampleHttp": "{\n \"cyberstrike-ai-http\": {\n \"transport\": \"http\",\n \"url\": \"http://127.0.0.1:8081/mcp\"\n }\n}", - "exampleSse": "{\n \"cyberstrike-ai-sse\": {\n \"transport\": \"sse\",\n \"url\": \"http://127.0.0.1:8081/mcp/sse\"\n }\n}", + "placeholder": "{\n \"my-server\": {\n \"command\": \"python3\",\n \"args\": [\"${HOME}/mcp/server.py\"],\n \"env\": { \"API_KEY\": \"${API_KEY}\" },\n \"timeout\": 300\n }\n}", + "exampleStdio": "{\n \"my-server\": {\n \"command\": \"python3\",\n \"args\": [\"${HOME}/mcp/server.py\"],\n \"env\": { \"API_KEY\": \"${API_KEY}\", \"LOG_LEVEL\": \"${LOG_LEVEL:-INFO}\" },\n \"timeout\": 300\n }\n}", + "exampleHttp": "{\n \"remote-mcp\": {\n \"type\": \"http\",\n \"url\": \"https://mcp.example.com/mcp\",\n \"headers\": { \"Authorization\": \"Bearer ${MCP_TOKEN}\" }\n }\n}", + "exampleSse": "{\n \"sse-mcp\": {\n \"type\": \"sse\",\n \"url\": \"http://127.0.0.1:8081/mcp/sse\"\n }\n}", "exampleDescription": "示例描述", "formatJson": "格式化JSON", "loadExample": "加载示例" diff --git a/web/static/js/settings.js b/web/static/js/settings.js index 48f35bca..4dd39ce8 100644 --- a/web/static/js/settings.js +++ b/web/static/js/settings.js @@ -501,26 +501,32 @@ function renderToolsList() { external_mcp: tool.external_mcp || '' }; - // 外部工具标签,显示来源信息 + // 外部工具标签,显示来源信息(可点击跳转到对应 MCP 卡片) let externalBadge = ''; if (toolState.is_external || tool.is_external) { const externalMcpName = toolState.external_mcp || tool.external_mcp || ''; const badgeText = externalMcpName ? (typeof window.t === 'function' ? window.t('mcp.externalFrom', { name: escapeHtml(externalMcpName) }) : `外部 (${escapeHtml(externalMcpName)})`) : (typeof window.t === 'function' ? window.t('mcp.externalBadge') : '外部'); - const badgeTitle = externalMcpName ? (typeof window.t === 'function' ? window.t('mcp.externalToolFrom', { name: escapeHtml(externalMcpName) }) : `外部MCP工具 - 来源:${escapeHtml(externalMcpName)}`) : (typeof window.t === 'function' ? window.t('mcp.externalBadge') : '外部MCP工具'); - externalBadge = `${badgeText}`; + const badgeTitle = externalMcpName ? (typeof window.t === 'function' ? window.t('mcp.externalToolFrom', { name: escapeHtml(externalMcpName) }) + ' — 点击跳转' : `外部MCP工具 - 来源:${escapeHtml(externalMcpName)} — 点击跳转`) : (typeof window.t === 'function' ? window.t('mcp.externalBadge') : '外部MCP工具'); + if (externalMcpName) { + externalBadge = `${badgeText}`; + } else { + externalBadge = `${badgeText}`; + } } - + // 生成唯一的checkbox id,使用工具唯一标识符 const checkboxId = `tool-${escapeHtml(toolKey).replace(/::/g, '--')}`; - + toolItem.innerHTML = ` -
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
${escapeHtml(key)} |
+ ${escapeHtml(String(type))} | +${isReq ? '✔' : ''} | +${escapeHtml(desc)} | +