From 1dddcf11942b70354d307e842fafff0e92ed0c28 Mon Sep 17 00:00:00 2001 From: lyzno1 <92089059+lyzno1@users.noreply.github.com> Date: Fri, 24 Oct 2025 12:33:14 +0800 Subject: [PATCH] fix(workflow): resolve occasional issues with syncing historical states or clearing DSL in draft mode (#27391) --- .../hooks/use-nodes-sync-draft.ts | 102 ++++++++---------- .../hooks/use-workflow-refresh-draft.ts | 52 ++++++--- .../workflow/hooks/use-nodes-sync-draft.ts | 8 +- 3 files changed, 81 insertions(+), 81 deletions(-) diff --git a/web/app/components/workflow-app/hooks/use-nodes-sync-draft.ts b/web/app/components/workflow-app/hooks/use-nodes-sync-draft.ts index f96bd3946e..41b43f5041 100644 --- a/web/app/components/workflow-app/hooks/use-nodes-sync-draft.ts +++ b/web/app/components/workflow-app/hooks/use-nodes-sync-draft.ts @@ -1,13 +1,8 @@ import { useCallback } from 'react' import { produce } from 'immer' import { useStoreApi } from 'reactflow' -import { useParams } from 'next/navigation' -import { - useWorkflowStore, -} from '@/app/components/workflow/store' -import { - useNodesReadOnly, -} from '@/app/components/workflow/hooks/use-workflow' +import { useWorkflowStore } from '@/app/components/workflow/store' +import { useNodesReadOnly } from '@/app/components/workflow/hooks/use-workflow' import { syncWorkflowDraft } from '@/service/workflow' import { useFeaturesStore } from '@/app/components/base/features/hooks' import { API_PREFIX } from '@/config' @@ -19,7 +14,6 @@ export const useNodesSyncDraft = () => { const featuresStore = useFeaturesStore() const { getNodesReadOnly } = useNodesReadOnly() const { handleRefreshWorkflowDraft } = useWorkflowRefreshDraft() - const params = useParams() const getPostParams = useCallback(() => { const { @@ -27,7 +21,7 @@ export const useNodesSyncDraft = () => { edges, transform, } = store.getState() - const nodes = getNodes() + const nodes = getNodes().filter(node => !node.data?._isTempNode) const [x, y, zoom] = transform const { appId, @@ -37,54 +31,50 @@ export const useNodesSyncDraft = () => { isWorkflowDataLoaded, } = workflowStore.getState() - if (appId) { - if (!isWorkflowDataLoaded) - return null + if (!appId || !isWorkflowDataLoaded) + return null - const features = featuresStore!.getState().features - const producedNodes = produce(nodes, (draft) => { - draft.forEach((node) => { - Object.keys(node.data).forEach((key) => { - if (key.startsWith('_')) - delete node.data[key] - }) + const features = featuresStore!.getState().features + const producedNodes = produce(nodes, (draft) => { + draft.forEach((node) => { + Object.keys(node.data).forEach((key) => { + if (key.startsWith('_')) + delete node.data[key] }) }) - const producedEdges = produce(edges.filter(edge => !edge.data?._isTemp), (draft) => { - draft.forEach((edge) => { - Object.keys(edge.data).forEach((key) => { - if (key.startsWith('_')) - delete edge.data[key] - }) + }) + const producedEdges = produce(edges.filter(edge => !edge.data?._isTemp), (draft) => { + draft.forEach((edge) => { + Object.keys(edge.data).forEach((key) => { + if (key.startsWith('_')) + delete edge.data[key] }) }) - return { - url: `/apps/${appId}/workflows/draft`, - params: { - graph: { - nodes: producedNodes, - edges: producedEdges, - viewport: { - x, - y, - zoom, - }, - }, - features: { - opening_statement: features.opening?.enabled ? (features.opening?.opening_statement || '') : '', - suggested_questions: features.opening?.enabled ? (features.opening?.suggested_questions || []) : [], - suggested_questions_after_answer: features.suggested, - text_to_speech: features.text2speech, - speech_to_text: features.speech2text, - retriever_resource: features.citation, - sensitive_word_avoidance: features.moderation, - file_upload: features.file, - }, - environment_variables: environmentVariables, - conversation_variables: conversationVariables, - hash: syncWorkflowDraftHash, + }) + const viewport = { x, y, zoom } + + return { + url: `/apps/${appId}/workflows/draft`, + params: { + graph: { + nodes: producedNodes, + edges: producedEdges, + viewport, }, - } + features: { + opening_statement: features.opening?.enabled ? (features.opening?.opening_statement || '') : '', + suggested_questions: features.opening?.enabled ? (features.opening?.suggested_questions || []) : [], + suggested_questions_after_answer: features.suggested, + text_to_speech: features.text2speech, + speech_to_text: features.speech2text, + retriever_resource: features.citation, + sensitive_word_avoidance: features.moderation, + file_upload: features.file, + }, + environment_variables: environmentVariables, + conversation_variables: conversationVariables, + hash: syncWorkflowDraftHash, + }, } }, [store, featuresStore, workflowStore]) @@ -93,13 +83,9 @@ export const useNodesSyncDraft = () => { return const postParams = getPostParams() - if (postParams) { - navigator.sendBeacon( - `${API_PREFIX}/apps/${params.appId}/workflows/draft`, - JSON.stringify(postParams.params), - ) - } - }, [getPostParams, params.appId, getNodesReadOnly]) + if (postParams) + navigator.sendBeacon(`${API_PREFIX}${postParams.url}`, JSON.stringify(postParams.params)) + }, [getPostParams, getNodesReadOnly]) const doSyncWorkflowDraft = useCallback(async ( notRefreshWhenSyncError?: boolean, diff --git a/web/app/components/workflow-app/hooks/use-workflow-refresh-draft.ts b/web/app/components/workflow-app/hooks/use-workflow-refresh-draft.ts index a4c36de814..910ddd4a8d 100644 --- a/web/app/components/workflow-app/hooks/use-workflow-refresh-draft.ts +++ b/web/app/components/workflow-app/hooks/use-workflow-refresh-draft.ts @@ -16,25 +16,43 @@ export const useWorkflowRefreshDraft = () => { setEnvironmentVariables, setEnvSecrets, setConversationVariables, + setIsWorkflowDataLoaded, + isWorkflowDataLoaded, + debouncedSyncWorkflowDraft, } = workflowStore.getState() + + if (debouncedSyncWorkflowDraft && typeof (debouncedSyncWorkflowDraft as any).cancel === 'function') + (debouncedSyncWorkflowDraft as any).cancel() + + const wasLoaded = isWorkflowDataLoaded + if (wasLoaded) + setIsWorkflowDataLoaded(false) setIsSyncingWorkflowDraft(true) - fetchWorkflowDraft(`/apps/${appId}/workflows/draft`).then((response) => { - // Ensure we have a valid workflow structure with viewport - const workflowData: WorkflowDataUpdater = { - nodes: response.graph?.nodes || [], - edges: response.graph?.edges || [], - viewport: response.graph?.viewport || { x: 0, y: 0, zoom: 1 }, - } - handleUpdateWorkflowCanvas(workflowData) - setSyncWorkflowDraftHash(response.hash) - setEnvSecrets((response.environment_variables || []).filter(env => env.value_type === 'secret').reduce((acc, env) => { - acc[env.id] = env.value - return acc - }, {} as Record)) - setEnvironmentVariables(response.environment_variables?.map(env => env.value_type === 'secret' ? { ...env, value: '[__HIDDEN__]' } : env) || []) - setConversationVariables(response.conversation_variables || []) - workflowStore.setState({ isWorkflowDataLoaded: true }) - }).finally(() => setIsSyncingWorkflowDraft(false)) + fetchWorkflowDraft(`/apps/${appId}/workflows/draft`) + .then((response) => { + // Ensure we have a valid workflow structure with viewport + const workflowData: WorkflowDataUpdater = { + nodes: response.graph?.nodes || [], + edges: response.graph?.edges || [], + viewport: response.graph?.viewport || { x: 0, y: 0, zoom: 1 }, + } + handleUpdateWorkflowCanvas(workflowData) + setSyncWorkflowDraftHash(response.hash) + setEnvSecrets((response.environment_variables || []).filter(env => env.value_type === 'secret').reduce((acc, env) => { + acc[env.id] = env.value + return acc + }, {} as Record)) + setEnvironmentVariables(response.environment_variables?.map(env => env.value_type === 'secret' ? { ...env, value: '[__HIDDEN__]' } : env) || []) + setConversationVariables(response.conversation_variables || []) + setIsWorkflowDataLoaded(true) + }) + .catch(() => { + if (wasLoaded) + setIsWorkflowDataLoaded(true) + }) + .finally(() => { + setIsSyncingWorkflowDraft(false) + }) }, [handleUpdateWorkflowCanvas, workflowStore]) return { diff --git a/web/app/components/workflow/hooks/use-nodes-sync-draft.ts b/web/app/components/workflow/hooks/use-nodes-sync-draft.ts index a3cf8dbe79..a4c9a45542 100644 --- a/web/app/components/workflow/hooks/use-nodes-sync-draft.ts +++ b/web/app/components/workflow/hooks/use-nodes-sync-draft.ts @@ -1,10 +1,6 @@ import { useCallback } from 'react' -import { - useStore, -} from '../store' -import { - useNodesReadOnly, -} from './use-workflow' +import { useStore } from '../store' +import { useNodesReadOnly } from './use-workflow' import { useHooksStore } from '@/app/components/workflow/hooks-store' export type SyncCallback = {