"use client"; import { useState } from "react"; import Link from "next/link"; import { useTranslation } from "../../lib/i18n/context"; import { JobProgress } from "./JobProgress"; import { StatusBadge, JobTypeBadge, Button, MiniProgressBar, Icon } from "./ui"; interface JobRowProps { 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; }; libraryName: string | undefined; highlighted?: boolean; onCancel: (id: string) => void; formatDate: (date: string) => string; formatDuration: (start: string, end: string | null) => string; } export function JobRow({ job, libraryName, highlighted, onCancel, formatDate, formatDuration }: JobRowProps) { const { t } = useTranslation(); const isActive = job.status === "running" || job.status === "pending" || job.status === "extracting_pages" || job.status === "generating_thumbnails"; const [showProgress, setShowProgress] = useState(highlighted || isActive); const handleComplete = () => { setShowProgress(false); window.location.reload(); }; // Calculate duration const duration = job.started_at ? formatDuration(job.started_at, job.finished_at) : "-"; // Get file stats const scanned = job.stats_json?.scanned_files ?? 0; const indexed = job.stats_json?.indexed_files ?? 0; const removed = job.stats_json?.removed_files ?? 0; const errors = job.stats_json?.errors ?? 0; const isPhase2 = job.status === "extracting_pages" || job.status === "generating_thumbnails"; const isThumbnailPhase = job.status === "generating_thumbnails"; const isThumbnailJob = job.type === "thumbnail_rebuild" || job.type === "thumbnail_regenerate"; const hasThumbnailPhase = isPhase2 || isThumbnailJob; const isMetadataBatch = job.type === "metadata_batch"; const isMetadataRefresh = job.type === "metadata_refresh"; // Thumbnails progress (Phase 2: extracting_pages + generating_thumbnails) const thumbInProgress = hasThumbnailPhase && (job.status === "running" || isPhase2); return ( <> {job.id.slice(0, 8)} {job.library_id ? libraryName || job.library_id.slice(0, 8) : "—"}
{job.error_opt && ( ! )} {isActive && ( )}
{/* Running progress */} {isActive && job.total_files != null && (
{job.processed_files ?? 0}/{job.total_files}
)} {/* Completed stats with icons */} {!isActive && (
{/* Files: indexed count */} {indexed > 0 && ( {indexed} )} {/* Removed files */} {removed > 0 && ( {removed} )} {/* Thumbnails */} {hasThumbnailPhase && job.total_files != null && job.total_files > 0 && ( {job.total_files} )} {/* Metadata batch: series processed */} {isMetadataBatch && job.total_files != null && job.total_files > 0 && ( {job.total_files} )} {/* Metadata refresh: links refreshed */} {isMetadataRefresh && job.total_files != null && job.total_files > 0 && ( {job.total_files} )} {/* Errors */} {errors > 0 && ( {errors} )} {/* Scanned only (no other stats) */} {indexed === 0 && removed === 0 && errors === 0 && !hasThumbnailPhase && !isMetadataBatch && !isMetadataRefresh && scanned > 0 && ( {t("jobRow.scanned", { count: scanned })} )} {/* Nothing to show */} {indexed === 0 && removed === 0 && errors === 0 && scanned === 0 && !hasThumbnailPhase && !isMetadataBatch && !isMetadataRefresh && ( )}
)}
{duration} {formatDate(job.created_at)}
{t("jobRow.view")} {(job.status === "pending" || job.status === "running" || job.status === "extracting_pages" || job.status === "generating_thumbnails") && ( )}
{showProgress && isActive && ( )} ); }