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) => (
))}
)}
);
}