"use client"; import { useState, useEffect } from "react"; import { useTranslation } from "../../lib/i18n/context"; import { JobRow } from "./JobRow"; interface Job { id: string; library_id: string | null; type: string; status: string; created_at: string; started_at: string | null; finished_at: string | null; error_opt: string | null; stats_json: { scanned_files: number; indexed_files: number; removed_files: number; errors: number; } | null; progress_percent: number | null; processed_files: number | null; total_files: number | null; } interface JobsListProps { initialJobs: Job[]; libraries: Map; highlightJobId?: string; } function formatDuration(start: string, end: string | null): string { const startDate = new Date(start); const endDate = end ? new Date(end) : new Date(); const diff = endDate.getTime() - startDate.getTime(); if (diff < 60000) return `${Math.floor(diff / 1000)}s`; if (diff < 3600000) return `${Math.floor(diff / 60000)}m ${Math.floor((diff % 60000) / 1000)}s`; return `${Math.floor(diff / 3600000)}h ${Math.floor((diff % 3600000) / 60000)}m`; } export function JobsList({ initialJobs, libraries, highlightJobId }: JobsListProps) { const { t, locale } = useTranslation(); const [jobs, setJobs] = useState(initialJobs); const formatDate = (dateStr: string): string => { const date = new Date(dateStr); if (isNaN(date.getTime())) return dateStr; const loc = locale === "fr" ? "fr-FR" : "en-US"; return date.toLocaleString(loc, { day: "2-digit", month: "2-digit", year: "numeric", hour: "2-digit", minute: "2-digit", }); }; // Refresh jobs list via SSE useEffect(() => { const eventSource = new EventSource("/api/jobs/stream"); eventSource.onmessage = (event) => { try { const data = JSON.parse(event.data); if (Array.isArray(data)) { setJobs(data); } } catch (error) { console.error("Failed to parse SSE data:", error); } }; eventSource.onerror = (err) => { console.error("SSE error:", err); eventSource.close(); }; return () => { eventSource.close(); }; }, []); const handleCancel = async (id: string) => { const response = await fetch(`/api/jobs/${id}/cancel`, { method: "POST" }); if (response.ok) { setJobs(jobs.map(job => job.id === id ? { ...job, status: "cancelled" } : job )); } else { const data = await response.json().catch(() => ({})); console.error("Failed to cancel job:", data?.error ?? response.status); } }; return (
{jobs.map((job) => ( ))}
{t("jobsList.id")} {t("jobsList.library")} {t("jobsList.type")} {t("jobsList.status")} {t("jobsList.stats")} {t("jobsList.duration")} {t("jobsList.created")} {t("jobsList.actions")}
); }