import { useEffect, useRef, useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { Play, Pause, Download, Trash2, Loader2, Terminal, RefreshCw } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { logsApi } from '@/lib/api'; interface LogEntry { timestamp: string; message: string; stream: 'stdout' | 'stderr' | 'system'; } interface ServiceLogsProps { serviceId: string; serviceName: string; } export default function ServiceLogs({ serviceId, serviceName }: ServiceLogsProps) { const [isStreaming, setIsStreaming] = useState(false); const [logs, setLogs] = useState([]); const [autoScroll, setAutoScroll] = useState(true); const logContainerRef = useRef(null); const { data: fetchedLogs, isLoading, isFetching, refetch } = useQuery({ queryKey: ['logs', serviceId, isStreaming], queryFn: async () => { const response = await logsApi.getServiceLogs(serviceId, { tail: 200, follow: false }); return response.logs.map((log) => ({ timestamp: log.timestamp, message: log.message, stream: log.stream as 'stdout' | 'stderr' | 'system', })); }, refetchInterval: isStreaming ? 3000 : false, }); useEffect(() => { if (fetchedLogs) { setLogs(fetchedLogs); } }, [fetchedLogs]); useEffect(() => { if (autoScroll && logContainerRef.current) { logContainerRef.current.scrollTop = logContainerRef.current.scrollHeight; } }, [logs, autoScroll]); const clearLogs = () => { setLogs([]); }; const downloadLogs = () => { const content = logs .map((log) => `[${log.timestamp}] ${log.message}`) .join('\n'); const blob = new Blob([content], { type: 'text/plain' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${serviceName}-${new Date().toISOString()}.log`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); }; const handleScroll = () => { if (logContainerRef.current) { const { scrollTop, scrollHeight, clientHeight } = logContainerRef.current; const isAtBottom = scrollHeight - scrollTop - clientHeight < 100; setAutoScroll(isAtBottom); } }; if (isLoading) { return (
); } return (
Service Logs
{isStreaming ? ( ) : ( )}
{logs.length === 0 ? (
No logs available. Start the service or enable streaming to see logs.
) : ( logs.map((log, index) => (
[{new Date(log.timestamp).toLocaleTimeString()}] {log.message}
)) )}
{logs.length} log entries {autoScroll && ' • Auto-scroll enabled'} {isStreaming && ( Polling... )}
); }