Skip to main content
Glama
KennanYang

Financial Report Generator MCP Server

by KennanYang
error-monitor-panel.tsx6.13 kB
'use client'; import { useState, useEffect } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from '../ui/card'; import { Button } from '../ui/button'; import { Badge } from '../ui/badge'; import { Alert, AlertDescription } from '../ui/alert'; import { errorMonitor } from '../../lib/error-monitor'; import { AlertCircle, Trash2, Download, RefreshCw, Eye, EyeOff } from 'lucide-react'; export function ErrorMonitorPanel() { const [errorLogs, setErrorLogs] = useState<any[]>([]); const [errorStats, setErrorStats] = useState<any>({}); const [showDetails, setShowDetails] = useState(false); const [autoRefresh, setAutoRefresh] = useState(false); const refreshData = () => { setErrorLogs(errorMonitor.getErrorLogs()); setErrorStats(errorMonitor.getErrorStats()); }; useEffect(() => { refreshData(); if (autoRefresh) { const interval = setInterval(refreshData, 5000); // 每5秒刷新一次 return () => clearInterval(interval); } }, [autoRefresh]); const clearLogs = () => { errorMonitor.clearLogs(); refreshData(); }; const exportLogs = () => { const dataStr = JSON.stringify(errorLogs, null, 2); const dataBlob = new Blob([dataStr], { type: 'application/json' }); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = `error-logs-${new Date().toISOString().split('T')[0]}.json`; link.click(); URL.revokeObjectURL(url); }; const getStatusColor = (component: string) => { const count = errorStats.errorsByComponent?.[component] || 0; if (count === 0) return 'bg-green-100 text-green-800'; if (count <= 2) return 'bg-yellow-100 text-yellow-800'; return 'bg-red-100 text-red-800'; }; return ( <Card> <CardHeader> <CardTitle className="flex items-center gap-2"> <AlertCircle className="h-5 w-5 text-red-500" /> 错误监控面板 <Badge variant="secondary" className="ml-auto"> {errorStats.totalErrors || 0} 个错误 </Badge> </CardTitle> </CardHeader> <CardContent className="space-y-4"> {/* 控制按钮 */} <div className="flex gap-2"> <Button onClick={refreshData} variant="outline" size="sm"> <RefreshCw className="h-4 w-4 mr-1" /> 刷新 </Button> <Button onClick={clearLogs} variant="outline" size="sm"> <Trash2 className="h-4 w-4 mr-1" /> 清除日志 </Button> <Button onClick={exportLogs} variant="outline" size="sm"> <Download className="h-4 w-4 mr-1" /> 导出 </Button> <Button onClick={() => setShowDetails(!showDetails)} variant="outline" size="sm" > {showDetails ? <EyeOff className="h-4 w-4 mr-1" /> : <Eye className="h-4 w-4 mr-1" />} {showDetails ? '隐藏详情' : '显示详情'} </Button> <Button onClick={() => setAutoRefresh(!autoRefresh)} variant={autoRefresh ? "default" : "outline"} size="sm" > <RefreshCw className={`h-4 w-4 mr-1 ${autoRefresh ? 'animate-spin' : ''}`} /> 自动刷新 </Button> </div> {/* 错误统计 */} {Object.keys(errorStats.errorsByComponent || {}).length > 0 && ( <div className="space-y-2"> <h4 className="text-sm font-medium">错误统计</h4> <div className="flex flex-wrap gap-2"> {Object.entries(errorStats.errorsByComponent || {}).map(([component, count]) => ( <Badge key={component} className={getStatusColor(component)}> {component}: {count} </Badge> ))} </div> </div> )} {/* 错误日志列表 */} {errorLogs.length > 0 ? ( <div className="space-y-2"> <h4 className="text-sm font-medium">错误日志</h4> <div className="max-h-60 overflow-y-auto space-y-2"> {errorLogs.map((log, index) => ( <div key={log.id} className="p-3 border rounded-md"> <div className="flex items-center justify-between mb-2"> <div className="flex items-center gap-2"> <Badge variant="destructive" className="text-xs"> {log.component} </Badge> <span className="text-xs text-gray-500"> {new Date(log.timestamp).toLocaleString('zh-CN')} </span> </div> <Badge variant="outline" className="text-xs"> #{index + 1} </Badge> </div> <p className="text-sm text-red-600 mb-2">{log.error}</p> {showDetails && log.details && ( <details className="text-xs"> <summary className="cursor-pointer text-gray-600">查看详情</summary> <pre className="mt-2 p-2 bg-gray-100 rounded overflow-auto"> {JSON.stringify(log.details, null, 2)} </pre> </details> )} </div> ))} </div> </div> ) : ( <Alert> <AlertCircle className="h-4 w-4" /> <AlertDescription> 暂无错误日志。系统运行正常! </AlertDescription> </Alert> )} {/* 帮助信息 */} <div className="text-xs text-muted-foreground space-y-1"> <div>* 错误监控面板帮助诊断报告生成器的问题</div> <div>* 自动刷新每5秒更新一次数据</div> <div>* 可以导出错误日志进行分析</div> <div>* 建议在遇到问题时查看此面板</div> </div> </CardContent> </Card> ); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/KennanYang/financial-report'

If you have feedback or need assistance with the MCP directory API, please join our Discord server