diff --git a/web/static/css/style.css b/web/static/css/style.css index 7dcad05e..acc5f288 100644 --- a/web/static/css/style.css +++ b/web/static/css/style.css @@ -7196,17 +7196,68 @@ header { stroke-width: 2; } -.mcp-stats-timeline-empty, .mcp-stats-timeline-error { margin: 0; - padding: 20px 8px; + padding: 16px 8px; text-align: center; font-size: 0.75rem; - color: var(--text-muted); + color: #b91c1c; } -.mcp-stats-timeline-error { - color: #b91c1c; +.mcp-stats-timeline-empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 6px; + flex: 1; + min-height: 88px; + padding: 20px 16px; + text-align: center; + border-radius: 8px; + background: rgba(148, 163, 184, 0.06); + border: 1px dashed rgba(148, 163, 184, 0.28); +} + +.mcp-stats-timeline-empty-state--compact { + min-height: 72px; + padding: 14px 10px; + gap: 4px; +} + +.mcp-stats-timeline-empty-state__icon { + color: rgba(148, 163, 184, 0.75); + flex-shrink: 0; +} + +.mcp-stats-timeline-empty-state--compact .mcp-stats-timeline-empty-state__icon { + width: 28px; + height: 28px; +} + +.mcp-stats-timeline-empty-state__title { + margin: 0; + font-size: 0.8125rem; + font-weight: 500; + color: var(--text-secondary); + line-height: 1.4; +} + +.mcp-stats-timeline-empty-state--compact .mcp-stats-timeline-empty-state__title { + font-size: 0.75rem; +} + +.mcp-stats-timeline-empty-state__hint { + margin: 0; + max-width: 28em; + font-size: 0.6875rem; + color: var(--text-muted); + line-height: 1.45; +} + +.mcp-stats-timeline-empty-state--compact .mcp-stats-timeline-empty-state__hint { + font-size: 0.625rem; + max-width: 100%; } .mcp-stats-timeline-tooltip { diff --git a/web/static/i18n/en-US.json b/web/static/i18n/en-US.json index 56134afe..6d0c4833 100644 --- a/web/static/i18n/en-US.json +++ b/web/static/i18n/en-US.json @@ -1583,6 +1583,7 @@ "timelineSummary": "{{total}} calls in range · peak {{peak}}", "timelineSparseHint": "Most buckets are empty; peak {{peak}} calls at {{peakTime}}", "timelineNoData": "No calls in this period", + "timelineEmptyHint": "Switch the time range or invoke MCP tools in chat or tasks", "timelineLoadError": "Failed to load call trend", "timelineTotalLegend": "Total calls", "timelineFailedLegend": "Failed", diff --git a/web/static/i18n/zh-CN.json b/web/static/i18n/zh-CN.json index 372249e9..81ee5273 100644 --- a/web/static/i18n/zh-CN.json +++ b/web/static/i18n/zh-CN.json @@ -1571,6 +1571,7 @@ "timelineSummary": "区间内 {{total}} 次 · 峰值 {{peak}}", "timelineSparseHint": "该时段多数时间为 0,峰值 {{peak}} 次出现在 {{peakTime}}", "timelineNoData": "该时段暂无调用", + "timelineEmptyHint": "切换时间范围查看其他时段,或在对话/任务中调用 MCP 工具", "timelineLoadError": "无法加载调用趋势", "timelineTotalLegend": "总调用", "timelineFailedLegend": "失败", diff --git a/web/static/js/monitor.js b/web/static/js/monitor.js index 3e0de1fe..3e939197 100644 --- a/web/static/js/monitor.js +++ b/web/static/js/monitor.js @@ -3986,7 +3986,9 @@ async function setMcpMonitorTimelineRange(range) { monitorState.timeline = timelineJson; const timelineInner = document.querySelector('#monitor-stats .mcp-stats-combined__timeline-inner'); if (timelineInner) { - timelineInner.innerHTML = renderMcpStatsTimelineBody(monitorState.timeline, monitorState.timelineError); + const combined = timelineInner.closest('.mcp-stats-combined'); + const compactEmpty = combined && !!combined.querySelector('.mcp-stats-combined__main'); + timelineInner.innerHTML = renderMcpStatsTimelineBody(monitorState.timeline, monitorState.timelineError, compactEmpty); bindMcpStatsTimelineEvents(); syncMcpMonitorTimelineRangeUI(range); } else if (monitorState.stats && Object.keys(monitorState.stats).length > 0) { @@ -3996,7 +3998,9 @@ async function setMcpMonitorTimelineRange(range) { monitorState.timelineError = err.message || 'error'; const timelineInner = document.querySelector('#monitor-stats .mcp-stats-combined__timeline-inner'); if (timelineInner) { - timelineInner.innerHTML = renderMcpStatsTimelineBody(monitorState.timeline, monitorState.timelineError); + const combined = timelineInner.closest('.mcp-stats-combined'); + const compactEmpty = combined && !!combined.querySelector('.mcp-stats-combined__main'); + timelineInner.innerHTML = renderMcpStatsTimelineBody(monitorState.timeline, monitorState.timelineError, compactEmpty); bindMcpStatsTimelineEvents(); syncMcpMonitorTimelineRangeUI(range); } @@ -4014,7 +4018,21 @@ function renderMcpStatsTimelineRangeButtons() { }).join(''); } -function renderMcpStatsTimelineBody(timeline, timelineError) { +const MCP_TIMELINE_EMPTY_ICON = ''; + +function renderMcpStatsTimelineEmptyState(compact) { + const noData = mcpMonitorT('timelineNoData') || monitorFallback('该时段暂无调用', 'No calls in this period'); + const emptyHint = mcpMonitorT('timelineEmptyHint') + || monitorFallback('切换时间范围查看其他时段,或在对话/任务中调用 MCP 工具', 'Switch the time range or invoke MCP tools in chat or tasks'); + const compactClass = compact ? ' mcp-stats-timeline-empty-state--compact' : ''; + return `
${escapeHtml(noData)}
+${escapeHtml(emptyHint)}
+${escapeHtml(noData)}
`; + return renderMcpStatsTimelineEmptyState(!!compactEmpty); } const rangeKey = timeline.range || getMcpMonitorTimelineRange(); @@ -4083,7 +4100,7 @@ function renderMcpStatsCombinedSection(topTools, totals, activeToolFilter, timel const timelineCol = showTimeline ? `${escapeHtml(timelineTitle)}
-