import { useState, useEffect, useRef } from "preact/hooks"; import { useOperations } from "../hooks/useOperations"; import type { Operation } from "../hooks/useOperations"; function formatElapsed(startedAt: number, completedAt: number | null): string { const end = completedAt || Date.now(); const seconds = Math.floor((end - startedAt) / 1000); if (seconds < 60) return `${seconds}s`; const minutes = Math.floor(seconds / 60); const secs = seconds % 60; return `${minutes}m ${secs}s`; } function formatBytes(bytes: number): string { if (bytes === 0) return "0 B"; const units = ["B", "KB", "MB", "GB"]; let i = 0; let size = bytes; while (size >= 1024 && i < units.length - 1) { size /= 1024; i++; } return `${size.toFixed(i === 0 ? 0 : 1)} ${units[i]}`; } function OpIcon({ type }: { type: string }) { switch (type) { case "upload": return ; case "clone": return ; case "delete": return ; default: return null; } } function StatusIndicator({ status }: { status: string }) { switch (status) { case "active": return ; case "done": return ( ); case "error": case "cancelled": return ( ); default: return null; } } function OperationRow({ op, onCancel }: { op: Operation; onCancel: (id: string) => void }) { const [elapsed, setElapsed] = useState(formatElapsed(op.startedAt, op.completedAt)); useEffect(() => { if (op.status !== "active") { setElapsed(formatElapsed(op.startedAt, op.completedAt)); return; } const interval = setInterval(() => { setElapsed(formatElapsed(op.startedAt, null)); }, 1000); return () => clearInterval(interval); }, [op.status, op.startedAt, op.completedAt]); const hasProgress = op.status === "active" && op.progress > 0; const isIndeterminate = op.status === "active" && op.progress === 0; const hasBytes = "totalBytes" in op && (op as any).totalBytes > 0 && op.status === "active"; return (