import type { Dashboard } from "@umt/contracts"; import { Brush, HardDrive } from "lucide-react"; import { useNavigate } from "react-router"; import { toast } from "sonner"; import { useCacheCleanup, useCacheVolumes } from "~/api/downloads.ts"; import { ConfirmDialog } from "~/components/console/confirm-dialog.tsx"; import { ErrorState, LoadingState } from "~/components/console/empty-state.tsx"; import { StatusBadge } from "~/components/console/status-badge.tsx"; import { Button } from "~/components/ui/button.tsx"; import { errorMessage } from "~/lib/api.ts"; import { cn, formatBytes } from "~/lib/utils.ts"; type Volume = Dashboard["cache"]["volumes"][number]; function VolumeBar({ v }: { v: Volume }) { const pct = v.usedPercent; const tripped = pct !== null && pct >= v.hardThresholdPercent; const nearing = pct !== null && !tripped && pct >= v.resumePercent; return (
{v.volumeKey} {pct === null ? "使用率未知" : `${pct.toFixed(1)}%`} {v.usedBytes !== null && v.totalBytes !== null ? ` · ${formatBytes(v.usedBytes, 1)} / ${formatBytes(v.totalBytes, 1)}` : ""}
{pct !== null ? (
) : null}
硬阈值 {v.hardThresholdPercent}% / 恢复 {v.resumePercent}% 在途 {formatBytes(v.pendingBytes, 1)} 预留 {formatBytes(v.reservedBytes, 1)} 可清理 {formatBytes(v.cleanableBytes, 1)} 保留锁定 {formatBytes(v.retentionLockedBytes, 1)}
{pct === null ? 读不到磁盘状态,已暂停新提交 : null} {tripped ? 已达硬阈值,停止新提交 : null} {v.pausedByThreshold ? 阈值暂停 {v.pausedByThreshold} 个任务 : null}
{v.notes.map((n) => (

{n}

))}
); } /** 缓存卷用量 / 阈值条 + 手动清理入口 */ export function CacheVolumes() { const vols = useCacheVolumes(); const cleanup = useCacheCleanup(); const navigate = useNavigate(); return (

缓存与保留

立即清理 } title="按规则清理下载缓存?" description="只清理已入库、且满足保留期与 H&R 的纳管任务,其余不动。" confirmLabel="清理" onConfirm={() => cleanup.mutateAsync(undefined).then( (r) => { toast.success(`已排队清理任务 ${r.taskId.slice(0, 8)}`, { description: "结果见任务详情" }); navigate(`/console/engine/${r.runId}`); }, (e) => toast.error(errorMessage(e)), ) } />
{vols.isPending ? ( ) : vols.error ? ( void vols.refetch()} /> ) : !vols.data.length ? (

还没有缓存卷数据。配置下载器并完成巡检后显示。

) : (
{vols.data.map((v) => ( ))}
)}
); }