mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-08-19 01:17:16 +02:00
Add files via upload
This commit is contained in:
@@ -3590,6 +3590,83 @@ header {
|
|||||||
margin-bottom: 32px;
|
margin-bottom: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mcp-management-layout {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
|
||||||
|
gap: 16px;
|
||||||
|
align-items: stretch;
|
||||||
|
height: calc(100vh - 210px);
|
||||||
|
min-height: 520px;
|
||||||
|
max-height: calc(100vh - 210px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-management-panel {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
padding: 14px 16px 16px;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-tools-panel {
|
||||||
|
min-width: 0;
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-external-panel {
|
||||||
|
min-width: 0;
|
||||||
|
order: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-panel-body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-tools-panel .tools-controls,
|
||||||
|
.mcp-external-panel .external-mcp-controls {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-tools-panel .tools-list {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
max-height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-tools-panel .tools-list-items {
|
||||||
|
max-height: none;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-external-panel .external-mcp-list {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-external-panel .external-mcp-controls {
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MCP 双栏内工具操作条允许换行,避免面板内溢出 */
|
||||||
|
.mcp-tools-panel .tools-actions {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
row-gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-tools-panel .search-box {
|
||||||
|
min-width: min(280px, 100%);
|
||||||
|
}
|
||||||
|
|
||||||
.settings-section:last-child {
|
.settings-section:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
@@ -5396,6 +5473,23 @@ header {
|
|||||||
|
|
||||||
/* 响应式优化 */
|
/* 响应式优化 */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
.mcp-management-layout {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
height: auto;
|
||||||
|
min-height: auto;
|
||||||
|
max-height: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-management-panel {
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-tools-panel .tools-list,
|
||||||
|
.mcp-external-panel .external-mcp-list {
|
||||||
|
min-height: 200px;
|
||||||
|
max-height: 52vh;
|
||||||
|
}
|
||||||
|
|
||||||
.tools-actions {
|
.tools-actions {
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -519,7 +519,7 @@ function renderToolsList() {
|
|||||||
|
|
||||||
toolItem.innerHTML = `
|
toolItem.innerHTML = `
|
||||||
<input type="checkbox" id="${checkboxId}" ${toolState.enabled ? 'checked' : ''} ${toolState.is_external || tool.is_external ? 'data-external="true"' : ''} onchange="handleToolCheckboxChange('${escapeHtml(toolKey)}', this.checked)" />
|
<input type="checkbox" id="${checkboxId}" ${toolState.enabled ? 'checked' : ''} ${toolState.is_external || tool.is_external ? 'data-external="true"' : ''} onchange="handleToolCheckboxChange('${escapeHtml(toolKey)}', this.checked)" />
|
||||||
<div class="tool-item-info" onclick="toggleToolDetail(this, '${escapeHtml(toolKey)}', ${tool.is_external ? 'true' : 'false'}, '${escapeHtml(tool.external_mcp || '')}', event)">
|
<div class="tool-item-info">
|
||||||
<div class="tool-item-name">
|
<div class="tool-item-name">
|
||||||
${escapeHtml(tool.name)}
|
${escapeHtml(tool.name)}
|
||||||
${externalBadge}
|
${externalBadge}
|
||||||
@@ -529,6 +529,11 @@ function renderToolsList() {
|
|||||||
<div class="tool-item-detail" style="display:none"></div>
|
<div class="tool-item-detail" style="display:none"></div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
toolItem.addEventListener('click', function (event) {
|
||||||
|
const infoEl = toolItem.querySelector('.tool-item-info');
|
||||||
|
if (!infoEl) return;
|
||||||
|
toggleToolDetail(infoEl, toolKey, !!tool.is_external, tool.external_mcp || '', event);
|
||||||
|
});
|
||||||
listContainer.appendChild(toolItem);
|
listContainer.appendChild(toolItem);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -543,14 +548,16 @@ function renderToolsList() {
|
|||||||
// 展开/折叠工具详情面板(按需从后端加载 schema)
|
// 展开/折叠工具详情面板(按需从后端加载 schema)
|
||||||
function toggleToolDetail(infoEl, toolKey, isExternal, externalMcp, event) {
|
function toggleToolDetail(infoEl, toolKey, isExternal, externalMcp, event) {
|
||||||
// 点击 checkbox 或外部工具徽章时不展开
|
// 点击 checkbox 或外部工具徽章时不展开
|
||||||
if (event.target.tagName === 'INPUT' || event.target.closest('.external-tool-badge')) return;
|
if (event && (event.target.tagName === 'INPUT' || event.target.closest('.external-tool-badge'))) return;
|
||||||
|
|
||||||
const detail = infoEl.querySelector('.tool-item-detail');
|
const detail = infoEl.querySelector('.tool-item-detail');
|
||||||
const icon = infoEl.querySelector('.tool-expand-icon');
|
const icon = infoEl.querySelector('.tool-expand-icon');
|
||||||
if (!detail) return;
|
if (!detail) return;
|
||||||
|
|
||||||
const isOpen = detail.style.display !== 'none';
|
// 使用 data-open 作为主状态,避免仅依赖 style.display 带来的首击偶发判定不一致
|
||||||
|
const isOpen = detail.dataset.open === '1';
|
||||||
detail.style.display = isOpen ? 'none' : 'block';
|
detail.style.display = isOpen ? 'none' : 'block';
|
||||||
|
detail.dataset.open = isOpen ? '0' : '1';
|
||||||
if (icon) icon.textContent = isOpen ? '▶' : '▼';
|
if (icon) icon.textContent = isOpen ? '▶' : '▼';
|
||||||
|
|
||||||
// 首次展开时从后端按需加载
|
// 首次展开时从后端按需加载
|
||||||
@@ -1466,12 +1473,15 @@ async function pollExternalMCPToolCount(name, maxAttempts = 10) {
|
|||||||
function renderExternalMCPList(servers) {
|
function renderExternalMCPList(servers) {
|
||||||
const list = document.getElementById('external-mcp-list');
|
const list = document.getElementById('external-mcp-list');
|
||||||
if (!list) return;
|
if (!list) return;
|
||||||
|
const layout = document.querySelector('.mcp-management-layout');
|
||||||
|
|
||||||
if (Object.keys(servers).length === 0) {
|
if (Object.keys(servers).length === 0) {
|
||||||
|
if (layout) layout.classList.add('external-empty');
|
||||||
const emptyT = typeof window.t === 'function' ? window.t : (k) => k;
|
const emptyT = typeof window.t === 'function' ? window.t : (k) => k;
|
||||||
list.innerHTML = '<div class="empty">📋 ' + emptyT('mcp.noExternalMCP') + '<br><span style="font-size: 0.875rem; margin-top: 8px; display: block;">' + emptyT('mcp.clickToAddExternal') + '</span></div>';
|
list.innerHTML = '<div class="empty">📋 ' + emptyT('mcp.noExternalMCP') + '<br><span style="font-size: 0.875rem; margin-top: 8px; display: block;">' + emptyT('mcp.clickToAddExternal') + '</span></div>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (layout) layout.classList.remove('external-empty');
|
||||||
|
|
||||||
let html = '<div class="external-mcp-items">';
|
let html = '<div class="external-mcp-items">';
|
||||||
for (const [name, server] of Object.entries(servers)) {
|
for (const [name, server] of Object.entries(servers)) {
|
||||||
|
|||||||
@@ -735,17 +735,17 @@
|
|||||||
<h2 data-i18n="mcp.managementTitle">MCP 管理</h2>
|
<h2 data-i18n="mcp.managementTitle">MCP 管理</h2>
|
||||||
<div class="page-header-actions">
|
<div class="page-header-actions">
|
||||||
<button class="btn-secondary" onclick="loadExternalMCPs()"><span data-i18n="common.refresh">刷新</span></button>
|
<button class="btn-secondary" onclick="loadExternalMCPs()"><span data-i18n="common.refresh">刷新</span></button>
|
||||||
<button class="btn-primary" onclick="showAddExternalMCPModal()" data-i18n="mcp.addExternalMCP">添加外部MCP</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
|
<div class="mcp-management-layout">
|
||||||
<!-- MCP工具配置 -->
|
<!-- MCP工具配置 -->
|
||||||
<div class="settings-section" style="margin-bottom: 32px;">
|
<div class="settings-section mcp-management-panel mcp-tools-panel" style="margin-bottom: 32px;">
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
|
||||||
<h3 style="margin: 0;" data-i18n="mcp.toolConfig">MCP 工具配置</h3>
|
<h3 style="margin: 0;" data-i18n="mcp.toolConfig">MCP 工具配置</h3>
|
||||||
<button class="btn-primary" onclick="saveToolsConfig()" data-i18n="mcp.saveToolConfig">保存工具配置</button>
|
<button class="btn-primary" onclick="saveToolsConfig()" data-i18n="mcp.saveToolConfig">保存工具配置</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="tools-controls">
|
<div class="tools-controls mcp-panel-body">
|
||||||
<div class="tools-actions">
|
<div class="tools-actions">
|
||||||
<button class="btn-secondary" onclick="selectAllTools()" data-i18n="mcp.selectAll">全选</button>
|
<button class="btn-secondary" onclick="selectAllTools()" data-i18n="mcp.selectAll">全选</button>
|
||||||
<button class="btn-secondary" onclick="deselectAllTools()" data-i18n="mcp.deselectAll">全不选</button>
|
<button class="btn-secondary" onclick="deselectAllTools()" data-i18n="mcp.deselectAll">全不选</button>
|
||||||
@@ -765,15 +765,19 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 外部MCP配置 -->
|
<!-- 外部MCP配置 -->
|
||||||
<div class="settings-section">
|
<div class="settings-section mcp-management-panel mcp-external-panel">
|
||||||
<h3 data-i18n="mcp.externalConfig">外部 MCP 配置</h3>
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
|
||||||
<div class="external-mcp-controls">
|
<h3 style="margin: 0;" data-i18n="mcp.externalConfig">外部 MCP 配置</h3>
|
||||||
|
<button class="btn-primary" onclick="showAddExternalMCPModal()" data-i18n="mcp.addExternalMCP">添加外部MCP</button>
|
||||||
|
</div>
|
||||||
|
<div class="external-mcp-controls mcp-panel-body">
|
||||||
<div class="external-mcp-actions">
|
<div class="external-mcp-actions">
|
||||||
<div class="external-mcp-stats" id="external-mcp-stats"></div>
|
<div class="external-mcp-stats" id="external-mcp-stats"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="external-mcp-list" class="external-mcp-list"></div>
|
<div id="external-mcp-list" class="external-mcp-list"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user