import { useState, useEffect, useCallback } from 'react'; import { fetchCollectorStatus } from '../../services/collectorStatus'; import type { CollectorInfo } from '../../services/collectorStatus'; interface CollectorMonitorProps { onClose: () => void; } function formatRelativeTime(isoString: string): string { if (!isoString) return '-'; const diff = Date.now() - new Date(isoString).getTime(); if (diff < 0) return '방금'; const sec = Math.floor(diff / 1000); if (sec < 60) return `${sec}초 전`; const min = Math.floor(sec / 60); if (min < 60) return `${min}분 전`; const hr = Math.floor(min / 60); if (hr < 24) return `${hr}시간 전`; return `${Math.floor(hr / 24)}일 전`; } function getStatusColor(info: CollectorInfo): string { if (!info.lastSuccess) return '#ef4444'; const elapsed = Date.now() - new Date(info.lastSuccess).getTime(); if (elapsed < 5 * 60_000) return '#22c55e'; if (elapsed < 30 * 60_000) return '#eab308'; return '#ef4444'; } const CollectorMonitor = ({ onClose }: CollectorMonitorProps) => { const [collectors, setCollectors] = useState([]); const [serverTime, setServerTime] = useState(''); const [error, setError] = useState(''); const refresh = useCallback(async () => { try { const data = await fetchCollectorStatus(); setCollectors(data.collectors); setServerTime(data.serverTime); setError(''); } catch (e) { setError(e instanceof Error ? e.message : '연결 실패'); } }, []); useEffect(() => { refresh(); const interval = setInterval(refresh, 10_000); return () => clearInterval(interval); }, [refresh]); return (
{/* Header */}

수집기 모니터링

{serverTime && ( 서버: {new Date(serverTime).toLocaleTimeString('ko-KR')} )}
{error && (
{error}
)} {/* Table */} {collectors.map((c) => ( ))} {collectors.length === 0 && !error && ( )}
상태 수집기 최근 건수 성공/실패 총 수집 마지막 성공 에러
{c.name} {c.lastCount} {c.totalSuccess} {' / '} 0 ? '#ef4444' : 'inherit' }}>{c.totalFailure} {c.totalItems.toLocaleString()} {formatRelativeTime(c.lastSuccess)} {c.lastError || '-'}
수집기 데이터 로딩 중...
); }; export default CollectorMonitor;