This commit is contained in:
yu 2026-10-28 14:38:57 +08:00
commit 12cf94da27
3 changed files with 50 additions and 6 deletions

View File

@ -258,7 +258,8 @@ export function App() {
onOpenEditor={(id) => void openEditor(id)}
onRun={(id) => void runTask(id)}
onDelete={(id) => void deleteTask(id)}
onRefresh={() => void refreshFlows()}
onRefresh={() => refreshFlows()}
onToast={showToast}
/>
)}
{page === "editor" && <EditorPage catalog={catalog} onToast={showToast} onBack={() => { setPage("tasks"); void refreshFlows(); }} />}

View File

@ -23,7 +23,8 @@ interface TasksPageProps {
onOpenEditor: (id: string) => void;
onRun: (id: string) => void;
onDelete: (id: string) => void;
onRefresh: () => void;
onRefresh: () => void | Promise<void>;
onToast: (message: string, kind?: "ok" | "error") => void;
}
function formatTime(value: string): string {
@ -45,9 +46,21 @@ function formatDuration(value?: number): string {
const RUN_LABEL = { succeeded: "成功", failed: "失败", cancelled: "已取消", never: "未运行" } as const;
export function TasksPage({ flows, onCreate, onCreateExamples, onOpenEditor, onRun, onDelete, onRefresh }: TasksPageProps) {
export function TasksPage({ flows, onCreate, onCreateExamples, onOpenEditor, onRun, onDelete, onRefresh, onToast }: TasksPageProps) {
const [query, setQuery] = useState("");
const [selectedId, setSelectedId] = useState<string | null>(flows[0]?.id || null);
const [refreshing, setRefreshing] = useState(false);
const handleRefresh = async () => {
if (refreshing) return;
setRefreshing(true);
try {
await onRefresh();
onToast("任务列表已刷新", "ok");
} finally {
setRefreshing(false);
}
};
useEffect(() => {
if (!flows.length) {
@ -76,9 +89,6 @@ export function TasksPage({ flows, onCreate, onCreateExamples, onOpenEditor, onR
<p>选择一个任务开始运行或编辑流程;组件库只在进入编辑时参与搭建。</p>
</div>
<div className="page-heading-actions">
<button type="button" className="icon-btn" title="刷新任务列表" onClick={onRefresh}>
<RefreshCw className="icon" />
</button>
<button type="button" className="btn" onClick={onCreateExamples}>
<PackagePlus className="icon" /> 安装示例任务
</button>
@ -106,6 +116,15 @@ export function TasksPage({ flows, onCreate, onCreateExamples, onOpenEditor, onR
<Search className="icon" />
<input value={query} onChange={(event) => setQuery(event.target.value)} placeholder="搜索任务" aria-label="搜索任务" />
</label>
<button
type="button"
className={`icon-btn refresh-btn${refreshing ? " refreshing" : ""}`}
title="刷新任务列表"
aria-label="刷新任务列表"
onClick={() => void handleRefresh()}
>
<RefreshCw className="icon" />
</button>
</div>
<div className="task-table-head" aria-hidden="true">

View File

@ -3294,3 +3294,27 @@ textarea:focus-visible {
overflow: hidden;
text-overflow: ellipsis;
}
/* 任务列表头部刷新按钮 */
.task-list-head {
gap: 10px;
}
.task-list-head .task-search {
margin-left: auto;
}
.icon-btn.refresh-btn {
width: 30px;
height: 30px;
flex: none;
color: var(--muted, #5b6474);
}
.icon-btn.refresh-btn:hover {
color: var(--accent, #2563eb);
}
.icon-btn.refresh-btn.refreshing .icon {
animation: spin 0.8s linear infinite;
}