docs(plan): v0.2 adds Pi subagents and scheduled-jobs board
Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
1 parent
b839ed4056
commit
16ab2a6c84
97 files changed
+592
-648
No files matched your search
@@ -19,10 +19,10 @@ import { errorMessage } from "~/lib/api.ts";
|
||||
import { formatBytes } from "~/lib/utils.ts";
|
||||
|
||||
const STEPS = [
|
||||
"生成下载计划并预留 Slot 与预算(同一 Slot 同时只有一个在途计划)",
|
||||
"去重:已有相同资源或同 hash 任务时走接管,不重复提交",
|
||||
"缓存卷硬阈值检查:超过阈值或读不到磁盘状态时阻止新提交,不能手动绕过",
|
||||
"选择下载器实例并打管理标签提交;下单前复核免费/做种等易变字段",
|
||||
"生成下载计划,预留版本目标和预算;每个版本目标同时只有一个在途计划",
|
||||
"已有相同资源或相同 hash 的任务时直接接管,不重复提交",
|
||||
"缓存卷超过硬阈值或读不到磁盘状态时无法提交",
|
||||
"提交前复核免费、做种等易变字段",
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -56,10 +56,10 @@ export function DownloadDialog({
|
||||
if (r.submitted && r.plan) {
|
||||
setRejected(null);
|
||||
setDone(r.plan.id);
|
||||
toast.success(`已提交(计划${slotName(r.slotId) ? ` · ${slotName(r.slotId)}` : ""}),进度见“下载与任务”`);
|
||||
toast.success(`已提交${slotName(r.slotId) ? `(${slotName(r.slotId)})` : ""},进度见“下载与任务”`);
|
||||
} else {
|
||||
setRejected(r.rejected);
|
||||
toast.warning("没有生成下载计划,原因见对话框");
|
||||
toast.warning("没有生成下载计划");
|
||||
}
|
||||
},
|
||||
onError: (e) => toast.error(errorMessage(e)),
|
||||
@@ -102,9 +102,7 @@ export function DownloadDialog({
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-meta text-muted-foreground">
|
||||
{release.entity
|
||||
? "该作品还没有版本目标(Slot),需要先在订阅里建目标才能提交。"
|
||||
: "资源尚未识别到本地作品,请先在“身份与元数据”指定作品。"}
|
||||
{release.entity ? "这个作品没有版本目标。先在订阅里新建。" : "资源未关联本地作品。先在“身份与元数据”指定。"}
|
||||
</p>
|
||||
)}
|
||||
{rejected ? (
|
||||
@@ -124,7 +122,7 @@ export function DownloadDialog({
|
||||
<p className="text-caption text-success">
|
||||
计划已生成。
|
||||
<Link to="/console/tasks" className="underline underline-offset-4">
|
||||
去“下载与任务”查看
|
||||
查看
|
||||
</Link>
|
||||
</p>
|
||||
) : null}
|
||||
|
||||
@@ -108,7 +108,7 @@ export function FeedFormDialog({
|
||||
if (!parsed.success) {
|
||||
const e = zodFieldErrors(parsed.error.issues);
|
||||
if (e.pollIntervalSec) e.pollMin = "轮询间隔至少 1 分钟";
|
||||
if (e.url) e.url = feed ? "URL 格式不对" : "需要完整的 Feed URL";
|
||||
if (e.url) e.url = feed ? "URL 格式不对" : "填写完整的 Feed URL";
|
||||
if (e.name) e.name = "名称不能为空";
|
||||
setErrors(e);
|
||||
return;
|
||||
@@ -116,7 +116,7 @@ export function FeedFormDialog({
|
||||
setErrors({});
|
||||
const done = {
|
||||
onSuccess: () => {
|
||||
toast.success(feed ? "已保存" : "已新建 Feed,会按轮询策略抓取");
|
||||
toast.success(feed ? "已保存" : "Feed 已创建");
|
||||
onOpenChange(false);
|
||||
},
|
||||
onError: (e: unknown) => toast.error(errorMessage(e)),
|
||||
@@ -130,7 +130,7 @@ export function FeedFormDialog({
|
||||
<DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-lg">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{feed ? "编辑 Feed" : "新建 Feed"}</DialogTitle>
|
||||
<DialogDescription>URL 可能含 passkey,只写入加密凭证,之后只显示脱敏地址。</DialogDescription>
|
||||
<DialogDescription>URL 加密保存,之后只显示脱敏地址。</DialogDescription>
|
||||
</DialogHeader>
|
||||
<form
|
||||
className="grid gap-1"
|
||||
@@ -248,7 +248,7 @@ export function FeedFormDialog({
|
||||
/>
|
||||
</FormField>
|
||||
<div className="flex items-center justify-between gap-3 py-1 text-caption text-foreground">
|
||||
<label htmlFor="feed-enabled">启用(关闭后停止轮询,历史观察保留)</label>
|
||||
<label htmlFor="feed-enabled">启用(关闭后停止轮询)</label>
|
||||
<Switch id="feed-enabled" checked={d.enabled} onCheckedChange={(v) => set("enabled", v)} />
|
||||
</div>
|
||||
<DialogFooter className="mt-2 gap-2">
|
||||
|
||||
@@ -33,9 +33,9 @@ function LocalInventory({ release, entry }: { release: WorkbenchRelease; entry:
|
||||
if (!release.entity) {
|
||||
return (
|
||||
<p className="text-caption text-muted-foreground">
|
||||
尚未识别到本地作品({release.resolutionStatus}),不显示库存推断。
|
||||
未关联本地作品({release.resolutionStatus})。
|
||||
<Link to="/console/identity" className="ml-1 underline underline-offset-4">
|
||||
去身份与元数据处理
|
||||
去指定作品
|
||||
</Link>
|
||||
</p>
|
||||
);
|
||||
@@ -100,7 +100,7 @@ function LocalInventory({ release, entry }: { release: WorkbenchRelease; entry:
|
||||
})}
|
||||
</ul>
|
||||
) : (
|
||||
<p className="text-meta text-muted-foreground">规则引擎还没评估过这条资源。</p>
|
||||
<p className="text-meta text-muted-foreground">这条资源还没有评估。</p>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@@ -177,8 +177,8 @@ export function ReleaseDetailSheet({
|
||||
{
|
||||
onSuccess: (d) =>
|
||||
d.refreshError
|
||||
? toast.warning(`复核失败,保留既有数据:${d.refreshError}`)
|
||||
: toast.success("已从站点复核详情"),
|
||||
? toast.warning(`复核失败,显示上次数据:${d.refreshError}`)
|
||||
: toast.success("已复核"),
|
||||
onError: (e) => toast.error(errorMessage(e)),
|
||||
},
|
||||
)
|
||||
@@ -197,7 +197,7 @@ export function ReleaseDetailSheet({
|
||||
<>
|
||||
{detail.data.refreshError ? (
|
||||
<p className="mb-2 rounded-lg border border-warning/40 bg-warning/10 px-3 py-2 text-caption text-warning">
|
||||
最近一次复核失败,以下为既有数据(已过期):{detail.data.refreshError}
|
||||
最近一次复核失败,以下是过期数据:{detail.data.refreshError}
|
||||
</p>
|
||||
) : null}
|
||||
<KvList
|
||||
@@ -211,9 +211,7 @@ export function ReleaseDetailSheet({
|
||||
{ label: "详情抓取于", value: formatDateTime(detail.data.volatile.detailFetchedAt) },
|
||||
]}
|
||||
/>
|
||||
<p className="mt-2 text-meta text-muted-foreground">
|
||||
缓存命中不代替下单前复核:提交下载时会再次核对免费与做种状态。
|
||||
</p>
|
||||
<p className="mt-2 text-meta text-muted-foreground">提交下载时会再次核对免费和做种状态。</p>
|
||||
</>
|
||||
) : null}
|
||||
</DetailSection>
|
||||
@@ -232,7 +230,7 @@ export function ReleaseDetailSheet({
|
||||
{ label: "首次发现", value: formatDateTime(r.firstSeenAt) },
|
||||
{ label: "最近确认", value: `${formatDateTime(r.dataUpdatedAt)}(${ORIGIN_LABEL[r.origin]})` },
|
||||
{ label: "Feed 观察次数", value: r.observedByFeeds },
|
||||
{ label: "站点资源 ID", value: r.siteReleaseId, mono: true },
|
||||
{ label: "站点 ID", value: r.siteReleaseId, mono: true },
|
||||
{ label: "infohash", value: r.infohashV1 ?? r.infohashV2, mono: true, wide: true },
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -64,7 +64,7 @@ export function SnapshotPanel({ site }: { site: Site }) {
|
||||
snap.mutate(
|
||||
{ id: site.id, maxPages: 2 },
|
||||
{
|
||||
onSuccess: () => toast.success(`${site.name}:已排队手动快照`),
|
||||
onSuccess: () => toast.success(`${site.name}:快照已排队`),
|
||||
onError: (e) => toast.error(errorMessage(e)),
|
||||
},
|
||||
)
|
||||
@@ -80,7 +80,7 @@ export function SnapshotPanel({ site }: { site: Site }) {
|
||||
) : snaps.error ? (
|
||||
<ErrorState plain error={snaps.error} onRetry={() => void snaps.refetch()} />
|
||||
) : !snaps.data.items.length ? (
|
||||
<p className="text-caption text-muted-foreground">还没有快照记录。</p>
|
||||
<p className="text-caption text-muted-foreground">还没有快照。</p>
|
||||
) : (
|
||||
<ul className="divide-y divide-border/60 text-caption">
|
||||
{snaps.data.items.map((s) => (
|
||||
|
||||
Reference in new issue
Block a user