Spaces:
Build error
Build error
| import React, { useEffect, useState } from 'react'; | |
| import { MonitoringLog } from '../types'; | |
| import { Terminal, AlertTriangle, CheckCircle, Clock, FileText } from 'lucide-react'; | |
| const LogMonitor: React.FC = () => { | |
| const [logs, setLogs] = useState<MonitoringLog[]>([]); | |
| const [summary, setSummary] = useState<string>("Waiting for logs to generate summary..."); | |
| const [isMonitoring, setIsMonitoring] = useState(false); | |
| // Simulate incoming logs | |
| useEffect(() => { | |
| let interval: ReturnType<typeof setInterval>; | |
| if (isMonitoring) { | |
| interval = setInterval(() => { | |
| const sources: ('JulesAPI' | 'HuggingFace' | 'System')[] = ['JulesAPI', 'HuggingFace', 'System']; | |
| const levels: ('INFO' | 'WARN' | 'ERROR')[] = ['INFO', 'INFO', 'INFO', 'WARN', 'INFO']; // Mostly info | |
| const randomSource = sources[Math.floor(Math.random() * sources.length)]; | |
| const randomLevel = levels[Math.floor(Math.random() * levels.length)]; | |
| const newLog: MonitoringLog = { | |
| id: Math.random().toString(36), | |
| timestamp: new Date().toISOString(), | |
| source: randomSource, | |
| level: randomLevel, | |
| message: generateMockLogMessage(randomSource, randomLevel) | |
| }; | |
| setLogs(prev => { | |
| const newLogs = [newLog, ...prev].slice(0, 100); | |
| updateSummary(newLogs); // Trigger summary update | |
| return newLogs; | |
| }); | |
| }, 3000); | |
| } | |
| return () => clearInterval(interval); | |
| }, [isMonitoring]); | |
| const generateMockLogMessage = (source: string, level: string) => { | |
| if (source === 'JulesAPI') { | |
| return level === 'ERROR' | |
| ? 'Session ID #8492 connection timeout.' | |
| : 'Received activity update: Code generation in progress.'; | |
| } | |
| if (source === 'HuggingFace') { | |
| return level === 'WARN' | |
| ? 'Build container utilizing 85% memory.' | |
| : 'Successfully pulled layer sha256:e7c96db...'; | |
| } | |
| return 'Health check ping passed.'; | |
| }; | |
| const updateSummary = (currentLogs: MonitoringLog[]) => { | |
| const errors = currentLogs.filter(l => l.level === 'ERROR').length; | |
| const warns = currentLogs.filter(l => l.level === 'WARN').length; | |
| const latest = currentLogs[0]; | |
| setSummary(`Status: ${errors > 0 ? 'Issues Detected' : 'Healthy'}. | |
| Found ${errors} errors and ${warns} warnings in the last batch. | |
| Latest activity from ${latest?.source || 'System'}: ${latest?.message || 'None'}. | |
| Sending condensed report to Jules...`); | |
| }; | |
| return ( | |
| <div className="bg-gray-900 rounded-xl border border-gray-800 h-full flex flex-col"> | |
| <div className="p-4 border-b border-gray-800 flex justify-between items-center bg-gray-900/50"> | |
| <div className="flex items-center gap-3"> | |
| <div className="p-2 bg-gray-800 rounded-lg"> | |
| <Terminal className="w-5 h-5 text-emerald-400" /> | |
| </div> | |
| <div> | |
| <h2 className="text-lg font-bold text-white">Live Monitor</h2> | |
| <div className="flex items-center gap-2 text-xs text-gray-400"> | |
| <span>Monitoring Agent Active</span> | |
| <span className="w-1 h-1 bg-gray-500 rounded-full"></span> | |
| <span>Polling Interval: 10s</span> | |
| </div> | |
| </div> | |
| </div> | |
| <button | |
| onClick={() => setIsMonitoring(!isMonitoring)} | |
| className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${ | |
| isMonitoring | |
| ? 'bg-red-500/10 text-red-400 border border-red-500/20 hover:bg-red-500/20' | |
| : 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 hover:bg-emerald-500/20' | |
| }`} | |
| > | |
| {isMonitoring ? 'Stop Monitoring' : 'Start Monitoring'} | |
| </button> | |
| </div> | |
| {/* Summary Panel */} | |
| <div className="bg-blue-900/10 border-b border-blue-900/20 p-4"> | |
| <div className="flex items-center gap-2 mb-2"> | |
| <FileText className="w-4 h-4 text-blue-400" /> | |
| <h3 className="text-sm font-semibold text-blue-300">Agent Summary (For Jules)</h3> | |
| </div> | |
| <p className="text-sm text-gray-300 font-mono leading-relaxed whitespace-pre-line"> | |
| {isMonitoring ? summary : "Start monitoring to generate summaries..."} | |
| </p> | |
| </div> | |
| <div className="flex-1 overflow-y-auto p-2 font-mono text-sm bg-black/50 space-y-1"> | |
| {logs.length === 0 ? ( | |
| <div className="h-full flex flex-col items-center justify-center text-gray-500 gap-2"> | |
| <Clock className="w-8 h-8 opacity-50" /> | |
| <p>Waiting for logs stream...</p> | |
| </div> | |
| ) : ( | |
| logs.map((log) => ( | |
| <div key={log.id} className="flex gap-3 hover:bg-white/5 p-1.5 rounded transition-colors group"> | |
| <span className="text-gray-500 text-xs w-32 shrink-0">{log.timestamp.split('T')[1].slice(0, 12)}</span> | |
| <span className={`text-xs font-bold w-24 shrink-0 uppercase ${ | |
| log.source === 'JulesAPI' ? 'text-blue-400' : | |
| log.source === 'HuggingFace' ? 'text-yellow-400' : 'text-purple-400' | |
| }`}> | |
| {log.source} | |
| </span> | |
| <span className={`text-xs font-bold w-12 shrink-0 ${ | |
| log.level === 'ERROR' ? 'text-red-500' : | |
| log.level === 'WARN' ? 'text-orange-400' : 'text-gray-400' | |
| }`}> | |
| [{log.level}] | |
| </span> | |
| <span className="text-gray-300 break-all">{log.message}</span> | |
| </div> | |
| )) | |
| )} | |
| </div> | |
| <div className="p-3 border-t border-gray-800 bg-gray-900 text-xs text-gray-500 flex justify-between"> | |
| <span>Connected to gradio_logsview</span> | |
| <span>Mode: Summarization</span> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default LogMonitor; |