'use client' import { useState, useEffect, useCallback } from 'react' import { CrawlJob, CrawlSource, api } from '../_types' export function JobsTab() { const [jobs, setJobs] = useState([]) const [sources, setSources] = useState([]) const [selectedSource, setSelectedSource] = useState('') const [jobType, setJobType] = useState<'full' | 'delta'>('full') const [loading, setLoading] = useState(true) const loadData = useCallback(async () => { setLoading(true) try { const [j, s] = await Promise.all([api('jobs'), api('sources')]) setJobs(j || []) setSources(s || []) if (!selectedSource && s?.length > 0) setSelectedSource(s[0].id) } catch { /* ignore */ } setLoading(false) }, [selectedSource]) useEffect(() => { loadData() }, [loadData]) // Auto-refresh running jobs useEffect(() => { const hasRunning = jobs.some(j => j.status === 'running' || j.status === 'pending') if (!hasRunning) return const interval = setInterval(loadData, 3000) return () => clearInterval(interval) }, [jobs, loadData]) const handleTrigger = async () => { if (!selectedSource) return await api('jobs', { method: 'POST', body: JSON.stringify({ source_id: selectedSource, job_type: jobType }), }) loadData() } const handleCancel = async (id: string) => { await api(`jobs/${id}/cancel`, { method: 'POST' }) loadData() } const statusColor = (s: string) => { switch (s) { case 'completed': return 'bg-green-100 text-green-700' case 'running': return 'bg-blue-100 text-blue-700' case 'pending': return 'bg-yellow-100 text-yellow-700' case 'failed': return 'bg-red-100 text-red-700' case 'cancelled': return 'bg-gray-100 text-gray-600' default: return 'bg-gray-100 text-gray-700' } } return (
{/* Trigger form */}

Neuen Crawl starten

{/* Job list */} {loading ? (
Laden...
) : jobs.length === 0 ? (
Noch keine Crawl-Jobs ausgefuehrt.
) : (
{jobs.map(job => (
{job.status} {job.source_name || 'Quelle'} {job.job_type === 'delta' ? 'Delta' : 'Voll'}
{(job.status === 'running' || job.status === 'pending') && ( )} {new Date(job.created_at).toLocaleString('de-DE')}
{/* Progress */} {job.status === 'running' && job.files_found > 0 && (
{job.files_processed} / {job.files_found} Dateien verarbeitet
)} {/* Stats */}
{job.files_found}
Gefunden
{job.files_processed}
Verarbeitet
{job.files_new}
Neu
{job.files_changed}
Geaendert
{job.files_skipped}
Uebersprungen
{job.files_error}
Fehler
))}
)}
) }