Add files via upload

This commit is contained in:
公明
2026-08-06 17:12:21 +08:00
committed by GitHub
parent 30513dbbfd
commit d3714c9913
15 changed files with 435 additions and 214 deletions
+35 -23
View File
@@ -564,6 +564,18 @@ function escapeHtmlLocal(text) {
return div.innerHTML;
}
function escapeJsString(text) {
return JSON.stringify(String(text == null ? '' : text));
}
function escapeAttrLocal(text) {
return escapeHtmlLocal(text).replace(/"/g, '"').replace(/'/g, ''');
}
function escapeJsStringAttr(text) {
return escapeAttrLocal(escapeJsString(text));
}
function formatTimelinePlainTextHtml(text) {
return '<pre class="timeline-plain-text">' + escapeHtml(text == null ? '' : String(text)) + '</pre>';
}
@@ -5786,7 +5798,7 @@ function buildMcpTimelineSvg(points, rangeKey) {
const isPeak = c.i === peakIdx && (c.p.total || 0) > 0;
const dotClass = 'mcp-stats-timeline-dot' + (isPeak ? ' mcp-stats-timeline-dot--peak' : '');
return `<circle class="${dotClass}" cx="${c.x.toFixed(2)}" cy="${c.y.toFixed(2)}" r="${isPeak ? 2 : 1.5}"
data-time="${escapeHtml(tipTime)}"
data-time="${escapeAttrLocal(tipTime)}"
data-total="${c.p.total || 0}"
data-failed="${c.p.failed || 0}" />`;
}).join('');
@@ -5800,9 +5812,9 @@ function buildMcpTimelineSvg(points, rangeKey) {
const tipTime = formatMcpTimelineLabel(c.p.t, rangeKey, locale);
return `<g class="mcp-stats-timeline-bar-group">
<rect class="mcp-stats-timeline-bar${total > 0 ? ' is-active' : ''}" x="${(c.x - barW / 2).toFixed(2)}" y="${y.toFixed(2)}" width="${barW.toFixed(2)}" height="${h.toFixed(2)}" rx="1.6"
data-time="${escapeHtml(tipTime)}" data-total="${total}" data-failed="${failed}" />
data-time="${escapeAttrLocal(tipTime)}" data-total="${total}" data-failed="${failed}" />
${failedH > 0 ? `<rect class="mcp-stats-timeline-bar-fail" x="${(c.x - barW / 2).toFixed(2)}" y="${(baseY - failedH).toFixed(2)}" width="${barW.toFixed(2)}" height="${failedH.toFixed(2)}" rx="1.6"
data-time="${escapeHtml(tipTime)}" data-total="${total}" data-failed="${failed}" />` : ''}
data-time="${escapeAttrLocal(tipTime)}" data-total="${total}" data-failed="${failed}" />` : ''}
</g>`;
}).join('');
@@ -6421,11 +6433,11 @@ function renderMcpStatsInsightPanel(topTools, totals, activeToolFilter = '', opt
|| `${s.name}${s.calls} 次调用,占 ${s.pct}%`;
return `<li class="mcp-stats-dist-legend-item-wrap">
<button type="button" class="mcp-stats-dist-legend-item${isActive ? ' is-active' : ''}"
data-tool-name="${escapeHtml(s.name)}"
data-tool-name="${escapeAttrLocal(s.name)}"
data-pct="${s.pct}"
data-calls="${s.calls}"
data-is-others="0"
aria-label="${escapeHtml(rowAria)}"
aria-label="${escapeAttrLocal(rowAria)}"
aria-pressed="${isActive ? 'true' : 'false'}">${inner}</button>
</li>`;
}).join('');
@@ -6452,8 +6464,8 @@ function renderMcpStatsInsightPanel(topTools, totals, activeToolFilter = '', opt
</div>`;
return `
<div class="mcp-stats-dist-panel${embedded ? ' mcp-stats-dist-panel--embedded' : ''}" aria-label="${escapeHtml(distTitle)}"
data-center-label="${escapeHtml(centerLabel)}"
<div class="mcp-stats-dist-panel${embedded ? ' mcp-stats-dist-panel--embedded' : ''}" aria-label="${escapeAttrLocal(distTitle)}"
data-center-label="${escapeAttrLocal(centerLabel)}"
data-center-value="${top6SharePct}"
data-center-suffix="%">
${headerHtml}
@@ -6664,13 +6676,13 @@ function renderMcpStatsToolTable(topTools, totals, activeToolFilter = '') {
|| `${name}${total} 次调用,成功率 ${toolRate}%`;
rowsHtml += `
<tr class="mcp-stats-tool-row${isActive ? ' is-active' : ''}"
data-tool-name="${escapeHtml(rawName)}"
data-tool-name="${escapeAttrLocal(rawName)}"
tabindex="0"
role="button"
aria-label="${escapeHtml(rowAria)}"
aria-label="${escapeAttrLocal(rowAria)}"
aria-pressed="${isActive ? 'true' : 'false'}">
<td class="col-rank"><span class="mcp-stats-rank${rankClass}">${index + 1}</span></td>
<td class="col-tool" title="${escapeHtml(name)}">
<td class="col-tool" title="${escapeAttrLocal(name)}">
<span class="mcp-stats-tool-dot" style="background:${dotColor}" aria-hidden="true"></span>
<span class="mcp-stats-tool-label">${escapeHtml(name)}</span>
</td>
@@ -6719,8 +6731,8 @@ function renderMcpStatsToolsPanel(topTools, totals, activeToolFilter = '') {
const segAria = mcpMonitorT('distSegmentAria', { name: displayName, pct: s.pct, calls: s.calls })
|| `${displayName},占 ${s.pct}%${s.calls}`;
return `<span class="mcp-stats-proportion-seg${isActive ? ' is-active' : ''}"
data-tool-name="${escapeHtml(s.name)}" data-pct="${s.pct}" data-calls="${s.calls}" data-is-others="0"
role="button" tabindex="0" aria-label="${escapeHtml(segAria)}"
data-tool-name="${escapeAttrLocal(s.name)}" data-pct="${s.pct}" data-calls="${s.calls}" data-is-others="0"
role="button" tabindex="0" aria-label="${escapeAttrLocal(segAria)}"
style="flex:${s.pctNum} 1 0;background:${s.color}" title="${escapeHtml(title)}"></span>`;
}).join('');
@@ -6748,12 +6760,12 @@ function renderMcpStatsToolsPanel(topTools, totals, activeToolFilter = '') {
const successLabel = mcpMonitorT('successCount', { n: success }) || `成功 ${success}`;
const failedLabel = mcpMonitorT('failedCount', { n: failed }) || `失败 ${failed}`;
return `<li class="mcp-stats-tool-item${isActive ? ' is-active' : ''}"
data-tool-name="${escapeHtml(rawName)}" tabindex="0" role="button"
aria-label="${escapeHtml(rowAria)}" aria-pressed="${isActive ? 'true' : 'false'}">
data-tool-name="${escapeAttrLocal(rawName)}" tabindex="0" role="button"
aria-label="${escapeAttrLocal(rowAria)}" aria-pressed="${isActive ? 'true' : 'false'}">
<div class="mcp-stats-tool-item__top">
<span class="mcp-stats-tool-item__rank mcp-stats-rank${rankClass}">${index + 1}</span>
<span class="mcp-stats-tool-item__dot" style="background:${color}" aria-hidden="true"></span>
<span class="mcp-stats-tool-item__name" title="${escapeHtml(name)}">${escapeHtml(name)}</span>
<span class="mcp-stats-tool-item__name" title="${escapeAttrLocal(name)}">${escapeHtml(name)}</span>
<span class="mcp-stats-tool-item__share">${sharePct}%</span>
</div>
<div class="mcp-stats-tool-item__middle">
@@ -6813,8 +6825,8 @@ function renderMcpStatsChartAside(topTools, totals, activeToolFilter = '') {
return `
<div class="mcp-stats-dist-panel mcp-stats-dist-panel--compact"
aria-label="${escapeHtml(distTitle)}"
data-center-label="${escapeHtml(centerLabel)}"
aria-label="${escapeAttrLocal(distTitle)}"
data-center-label="${escapeAttrLocal(centerLabel)}"
data-center-value="${top6SharePct}"
data-center-suffix="%">
<p class="mcp-stats-panel__aside-title">${escapeHtml(distTitle)}</p>
@@ -6975,11 +6987,11 @@ function renderMonitorExecutions(executions = [], statusFilter = 'all') {
const duration = formatExecutionDuration(exec.startTime, exec.endTime);
const toolName = escapeHtml(formatMonitorToolName(exec.toolName) || unknownToolLabel);
const rawExecId = exec.id || '';
const executionId = escapeHtml(rawExecId);
const executionId = escapeAttrLocal(rawExecId);
const jsExecId = escapeJsStringAttr(rawExecId);
const terminateBtn = status === 'running'
? `<button type="button" class="btn-secondary btn-monitor-abort" data-require-permission="monitor:write" onclick="cancelMCPToolExecution('${rawExecId.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}')">${escapeHtml(terminateLabel)}</button>`
? `<button type="button" class="btn-secondary btn-monitor-abort" data-require-permission="monitor:write" onclick="cancelMCPToolExecution(${jsExecId})">${escapeHtml(terminateLabel)}</button>`
: '';
const jsExecId = rawExecId.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
const isSelected = monitorState.selectedExecutions.has(rawExecId);
const rowKey = monitorRenderKey([exec, isSelected, locale || 'en-US']);
return {
@@ -6988,7 +7000,7 @@ function renderMonitorExecutions(executions = [], statusFilter = 'all') {
html: `
<tr data-execution-id="${executionId}">
<td>
<input type="checkbox" class="monitor-execution-checkbox theme-checkbox" value="${executionId}" ${isSelected ? 'checked' : ''} onchange="toggleExecutionSelection('${jsExecId}', this.checked)" />
<input type="checkbox" class="monitor-execution-checkbox theme-checkbox" value="${executionId}" ${isSelected ? 'checked' : ''} onchange="toggleExecutionSelection(${jsExecId}, this.checked)" />
</td>
<td>${toolName}</td>
<td><span class="${statusClass}">${escapeHtml(statusLabel)}</span></td>
@@ -6996,9 +7008,9 @@ function renderMonitorExecutions(executions = [], statusFilter = 'all') {
<td class="monitor-execution-duration">${escapeHtml(duration)}</td>
<td>
<div class="monitor-execution-actions">
<button class="btn-secondary" onclick="showMCPDetail('${executionId}')">${escapeHtml(viewDetailLabel)}</button>
<button class="btn-secondary" onclick="showMCPDetail(${jsExecId})">${escapeHtml(viewDetailLabel)}</button>
${terminateBtn}
<button class="btn-secondary btn-delete" data-require-permission="monitor:delete" onclick="deleteExecution('${executionId}')" title="${escapeHtml(deleteExecTitle)}">${escapeHtml(deleteLabel)}</button>
<button class="btn-secondary btn-delete" data-require-permission="monitor:delete" onclick="deleteExecution(${jsExecId})" title="${escapeHtml(deleteExecTitle)}">${escapeHtml(deleteLabel)}</button>
</div>
</td>
</tr>