feat(web): split plan page from tasks (FE-6)
- Nav overview group: 首页 / 任务 / 计划 / Agent 会话; tasks page drops the plan tab - /console/tasks?tab=plan[&job=] redirects to /console/schedules[?job=] - Plan page: 自动任务 compact grouped list (switch, interval preset/custom, last result, countdown, failure reason, run now/skip/run records) and Agent 巡检 cards (goal, allowlist, budget, upstream/model, trigger, cost per run, recent sessions); split stats - Home plan band: two counts linking to #auto / #checks - Docs: console-ia §7.4a, glossary, schedules runbook; smoke routes Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
c3aaf901ad
commit
baf2d6ea04
22 files changed
+1030
-417
No files matched your search
@@ -5,7 +5,6 @@ import { useEngineRun, useEngineStats } from "~/api/engine.ts";
|
||||
import { DetailSheet } from "~/components/console/detail-sheet.tsx";
|
||||
import { ErrorState, LoadingState } from "~/components/console/empty-state.tsx";
|
||||
import { PageHeader } from "~/components/console/page-header.tsx";
|
||||
import { ScheduleBoard } from "~/components/schedules/schedule-board.tsx";
|
||||
import { runTitle } from "~/components/tasks/labels.ts";
|
||||
import { RunActions, TaskDetailBody, TaskStatusLine } from "~/components/tasks/task-detail.tsx";
|
||||
import { type StreamFilters, type StreamTab, TaskStream } from "~/components/tasks/task-stream.tsx";
|
||||
@@ -16,11 +15,11 @@ import { legacyRedirectLoader } from "./redirects.ts";
|
||||
|
||||
export const meta = () => [{ title: "任务 · UHD 媒体自动化控制台" }];
|
||||
|
||||
// 旧的 ?tab=downloads / plans / business 跳到下载面板 / 下载计划 / 任务流
|
||||
// 旧的 ?tab=downloads / plans / business / plan 跳到下载面板 / 下载计划 / 任务流 / 计划页
|
||||
export const clientLoader = legacyRedirectLoader;
|
||||
|
||||
type Tab = StreamTab | "plan";
|
||||
const TABS: Tab[] = ["all", "active", "failed", "plan"];
|
||||
type Tab = StreamTab;
|
||||
const TABS: Tab[] = ["all", "active", "failed"];
|
||||
const FILTER_KEYS: (keyof StreamFilters)[] = ["status", "kind", "ref", "source", "since", "workflow"];
|
||||
|
||||
function Count({ n }: { n: number | undefined }) {
|
||||
@@ -102,14 +101,7 @@ export default function TasksPage() {
|
||||
title="任务"
|
||||
description="每次运行都是一条任务,不论定时、事件、手动还是 Agent 触发。"
|
||||
actions={
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
qc.invalidateQueries({ queryKey: qk.all("engine") });
|
||||
qc.invalidateQueries({ queryKey: qk.all("schedules") });
|
||||
}}
|
||||
>
|
||||
<Button variant="outline" size="sm" onClick={() => qc.invalidateQueries({ queryKey: qk.all("engine") })}>
|
||||
<RotateCw />
|
||||
刷新
|
||||
</Button>
|
||||
@@ -120,7 +112,6 @@ export default function TasksPage() {
|
||||
onValueChange={(v) =>
|
||||
update((p) => {
|
||||
p.set("tab", v);
|
||||
p.delete("job");
|
||||
if (v !== "all") p.delete("status");
|
||||
})
|
||||
}
|
||||
@@ -135,26 +126,21 @@ export default function TasksPage() {
|
||||
失败
|
||||
<Count n={by?.failed} />
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="plan">计划</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
<div className="mt-4">
|
||||
{tab === "plan" ? (
|
||||
<ScheduleBoard highlightJob={params.get("job") ?? undefined} />
|
||||
) : (
|
||||
<TaskStream
|
||||
tab={tab}
|
||||
filters={filters}
|
||||
setFilter={setFilter}
|
||||
resetFilters={() =>
|
||||
update((p) => {
|
||||
for (const k of FILTER_KEYS) p.delete(k);
|
||||
})
|
||||
}
|
||||
onOpen={(id) => update((p) => p.set("run", id))}
|
||||
selectedId={runId}
|
||||
/>
|
||||
)}
|
||||
<TaskStream
|
||||
tab={tab}
|
||||
filters={filters}
|
||||
setFilter={setFilter}
|
||||
resetFilters={() =>
|
||||
update((p) => {
|
||||
for (const k of FILTER_KEYS) p.delete(k);
|
||||
})
|
||||
}
|
||||
onOpen={(id) => update((p) => p.set("run", id))}
|
||||
selectedId={runId}
|
||||
/>
|
||||
</div>
|
||||
<RunSheet
|
||||
runId={runId}
|
||||
|
||||
Reference in new issue
Block a user