import { useState, useEffect, useRef } from 'react' import { useQuery } from '@tanstack/react-query' import { Terminal, RefreshCw, Download, Pause, Play } from 'lucide-react' import { Card, CardHeader } from '../components/Card' import { fetchSkills, fetchLogs } from '../lib/api' export function Logs() { const [selectedSkill, setSelectedSkill] = useState('all') const [isPaused, setIsPaused] = useState(false) const [filter, setFilter] = useState('') const logsEndRef = useRef(null) const { data: skills } = useQuery({ queryKey: ['skills'], queryFn: fetchSkills, }) const { data: logs, refetch } = useQuery({ queryKey: ['logs', selectedSkill], queryFn: () => fetchLogs(selectedSkill, 200), refetchInterval: isPaused ? false : 2000, }) useEffect(() => { if (!isPaused) { logsEndRef.current?.scrollIntoView({ behavior: 'smooth' }) } }, [logs, isPaused]) const filteredLogs = logs?.filter(line => filter ? line.toLowerCase().includes(filter.toLowerCase()) : true ) const downloadLogs = () => { if (!logs) return const blob = new Blob([logs.join('\n')], { type: 'text/plain' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `${selectedSkill}-logs-${new Date().toISOString()}.txt` a.click() URL.revokeObjectURL(url) } return (

Logs

{/* Filters */}
setFilter(e.target.value)} placeholder="Filter logs..." className="w-full px-4 py-2 bg-gray-800 border border-gray-700 rounded-lg text-white placeholder-gray-500 focus:outline-none focus:border-purple-500" />
{/* Log Output */} Output {!isPaused && ( Live )}
} />
{filteredLogs?.length === 0 ? (

No logs available

) : ( <> {filteredLogs?.map((line, i) => ( ))}
)}
) } function LogLine({ line, filter }: { line: string; filter: string }) { // Detect log level const isError = /error|exception|fail/i.test(line) const isWarning = /warn/i.test(line) const isInfo = /info/i.test(line) const isDebug = /debug/i.test(line) let colorClass = 'text-gray-400' if (isError) colorClass = 'text-red-400' else if (isWarning) colorClass = 'text-yellow-400' else if (isInfo) colorClass = 'text-blue-400' else if (isDebug) colorClass = 'text-gray-500' // Highlight filter matches if (filter) { const regex = new RegExp(`(${filter})`, 'gi') const parts = line.split(regex) return (
{parts.map((part, i) => part.toLowerCase() === filter.toLowerCase() ? ( {part} ) : ( part ) )}
) } return
{line}
}