From ee29b7b75228ab977714478ae0742ee196155d50 Mon Sep 17 00:00:00 2001 From: iven Date: Sun, 29 Mar 2026 23:51:55 +0800 Subject: [PATCH] =?UTF-8?q?fix(pipeline):=20BREAK-04=20=E6=8E=A5=E5=85=A5?= =?UTF-8?q?=20pipeline-complete=20=E4=BA=8B=E4=BB=B6=E7=9B=91=E5=90=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PipelinesPanel 新增 useEffect 订阅 PipelineClient.onComplete(), 处理用户导航离开后的后台 Pipeline 完成通知。 - 后台完成时 toast 提示成功/失败 - 跳过当前选中 pipeline 的重复通知(轮询路径已处理) - 组件卸载时自动清理监听器 --- desktop/src/components/PipelinesPanel.tsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/desktop/src/components/PipelinesPanel.tsx b/desktop/src/components/PipelinesPanel.tsx index 7c98bff..7419371 100644 --- a/desktop/src/components/PipelinesPanel.tsx +++ b/desktop/src/components/PipelinesPanel.tsx @@ -7,7 +7,7 @@ * Pipelines orchestrate Skills and Hands to accomplish complex tasks. */ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import { Play, RefreshCw, @@ -437,6 +437,22 @@ export function PipelinesPanel() { const [runResult, setRunResult] = useState<{ result: PipelineRunResponse; pipeline: PipelineInfo } | null>(null); const { toast } = useToast(); + // Subscribe to pipeline-complete push events (for background completion) + useEffect(() => { + let unlisten: (() => void) | undefined; + PipelineClient.onComplete((event) => { + // Only show notification if we're not already tracking this run + // (the polling path handles in-flight runs via handleRunComplete) + if (selectedPipeline?.id === event.pipelineId) return; + if (event.status === 'completed') { + toast(`Pipeline "${event.pipelineId}" 后台执行完成`, 'success'); + } else if (event.status === 'failed') { + toast(`Pipeline "${event.pipelineId}" 后台执行失败: ${event.error ?? ''}`, 'error'); + } + }).then((fn) => { unlisten = fn; }); + return () => { unlisten?.(); }; + }, [selectedPipeline, toast]); + // Fetch all pipelines without filtering const { pipelines, loading, error, refresh } = usePipelines({});