"use client"; import { useState, useEffect, useCallback } from "react"; import { Header } from "@/components/layout"; import { AppLayout } from "@/components/layout"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Progress } from "@/components/ui/progress"; import { apiClient, type JobInfo, type QueueStatus } from "@/lib/api"; import { Loader2, RefreshCw, X, Clock, CheckCircle, XCircle, AlertCircle, Play, Pause, } from "lucide-react"; function QueuePage() { const [queueStatus, setQueueStatus] = useState(null); const [loading, setLoading] = useState(true); const [isInitialLoad, setIsInitialLoad] = useState(true); const [error, setError] = useState(null); const loadQueueStatus = useCallback(async () => { try { setLoading(true); setError(null); const status = await apiClient.getQueueStatus(); setQueueStatus(status); } catch (err) { console.error("Failed to load queue status:", err); setError(err instanceof Error ? err.message : "Failed to load queue status"); } finally { setLoading(false); setIsInitialLoad(false); } }, []); useEffect(() => { loadQueueStatus(); // Set up polling for active jobs const interval = setInterval(() => { loadQueueStatus(); }, 2000); // Poll every 2 seconds return () => clearInterval(interval); }, [loadQueueStatus]); const handleCancelJob = async (jobId: string) => { try { await apiClient.cancelJob(jobId); // Refresh queue status after cancellation loadQueueStatus(); } catch (err) { console.error("Failed to cancel job:", err); setError(err instanceof Error ? err.message : "Failed to cancel job"); } }; const handleClearQueue = async () => { if (!confirm("Are you sure you want to clear the entire queue? This will remove all jobs.")) { return; } try { await apiClient.clearQueue(); loadQueueStatus(); } catch (err) { console.error("Failed to clear queue:", err); setError(err instanceof Error ? err.message : "Failed to clear queue"); } }; const getStatusIcon = (status: string) => { switch (status) { case "completed": return ; case "failed": return ; case "cancelled": return ; case "processing": return ; case "queued": case "pending": return ; default: return ; } }; const getStatusBadge = (status: string) => { const variants: Record = { completed: "default", failed: "destructive", cancelled: "secondary", processing: "default", queued: "secondary", pending: "secondary", }; return ( {status} ); }; const getProgressValue = (job: JobInfo): number => { // For completed jobs, ensure progress is 100% if (job.status === "completed") { return 100; } // For failed jobs, show 0% progress if (job.status === "failed" || job.status === "cancelled") { return 0; } // For other statuses, use the progress value from the API return job.progress || 0; }; const formatDate = (dateString?: string) => { if (!dateString) return "N/A"; const date = new Date(dateString); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; }; if (loading && isInitialLoad) { return (
Loading queue...
); } if (error) { return (

Error loading queue

{error}

); } return (
{/* Queue Controls */}

{queueStatus?.size || 0} Job{(queueStatus?.size || 0) !== 1 ? "s" : ""}

{queueStatus?.active_generations ? ( {queueStatus.active_generations} Active ) : null}
{queueStatus && queueStatus.size > 0 && ( )}
{/* Queue Status */} {!queueStatus || queueStatus.jobs.length === 0 ? (

No jobs in queue

Generate some images using the Text to Image, Image to Image, or Inpainting tools.

) : (
{queueStatus.jobs.map((job, index) => (
{/* Job Info */}
{getStatusIcon(job.status)}

Job {job.id || job.request_id}

{getStatusBadge(job.status)}
Type:

{job.prompt ? "Text to Image" : "Unknown"}

Created:

{formatDate(job.created_at)}

Position:

{job.position !== undefined ? job.position + 1 : "N/A"}

{/* Progress Bar */}
Progress: {getProgressValue(job)}%
{/* Prompt Preview */} {job.prompt && (
Prompt:

{job.prompt}

)} {/* Error Message */} {job.error && (
Error:

{job.error}

)}
{/* Actions */}
{(job.status === "queued" || job.status === "processing" || job.status === "pending") && ( )}
))}
)}
); } export default QueuePage;