diff --git a/web/app/components/workflow/header/view-workflow-history.tsx b/web/app/components/workflow/header/view-workflow-history.tsx index 9e8f5a5b32..37509d3d06 100644 --- a/web/app/components/workflow/header/view-workflow-history.tsx +++ b/web/app/components/workflow/header/view-workflow-history.tsx @@ -10,7 +10,6 @@ import { useState, } from 'react' import { useTranslation } from 'react-i18next' -import { useStoreApi } from 'reactflow' import { useShallow } from 'zustand/react/shallow' import { useStore as useAppStore } from '@/app/components/app/store' import { @@ -25,6 +24,7 @@ import { useNodesReadOnly, useWorkflowHistory, } from '../hooks' +import { useCollaborativeWorkflow } from '../hooks/use-collaborative-workflow' import TipPopup from '../operator/tip-popup' type ChangeHistoryEntry = { @@ -49,7 +49,7 @@ const ViewWorkflowHistory = () => { setCurrentLogItem: state.setCurrentLogItem, setShowMessageLogModal: state.setShowMessageLogModal, }))) - const reactFlowStore = useStoreApi() + const collaborativeWorkflow = useCollaborativeWorkflow() const { store, getHistoryLabel } = useWorkflowHistory() const { pastStates, futureStates, undo, redo, clear } = store.temporal.getState() @@ -61,7 +61,6 @@ const ViewWorkflowHistory = () => { }, [clear]) const handleSetState = useCallback(({ index }: ChangeHistoryEntry) => { - const { setEdges, setNodes } = reactFlowStore.getState() const diff = currentHistoryStateIndex + index if (diff === 0) return @@ -75,11 +74,13 @@ const ViewWorkflowHistory = () => { if (edges.length === 0 && nodes.length === 0) return - setEdges(edges) - setNodes(nodes) + const shouldBroadcast = collaborationManager.isConnected() + const { setEdges, setNodes } = collaborativeWorkflow.getState() + setEdges(edges, shouldBroadcast) + setNodes(nodes, shouldBroadcast, 'history:jump') if (collaborationManager.isConnected()) collaborationManager.emitHistoryAction('jump') - }, [currentHistoryStateIndex, reactFlowStore, redo, store, undo]) + }, [collaborativeWorkflow, currentHistoryStateIndex, redo, store, undo]) const calculateStepLabel = useCallback((index: number) => { if (!index) diff --git a/web/app/components/workflow/hooks/use-auto-generate-webhook-url.ts b/web/app/components/workflow/hooks/use-auto-generate-webhook-url.ts index a046346e6b..84dda1087d 100644 --- a/web/app/components/workflow/hooks/use-auto-generate-webhook-url.ts +++ b/web/app/components/workflow/hooks/use-auto-generate-webhook-url.ts @@ -1,20 +1,20 @@ import { produce } from 'immer' import { useCallback } from 'react' -import { useStoreApi } from 'reactflow' import { useStore as useAppStore } from '@/app/components/app/store' import { BlockEnum } from '@/app/components/workflow/types' import { fetchWebhookUrl } from '@/service/apps' +import { useCollaborativeWorkflow } from './use-collaborative-workflow' export const useAutoGenerateWebhookUrl = () => { - const reactFlowStore = useStoreApi() + const collaborativeWorkflow = useCollaborativeWorkflow() return useCallback(async (nodeId: string) => { const appId = useAppStore.getState().appDetail?.id if (!appId) return - const { getNodes } = reactFlowStore.getState() - const node = getNodes().find(n => n.id === nodeId) + const { nodes } = collaborativeWorkflow.getState() + const node = nodes.find(n => n.id === nodeId) if (!node || node.data.type !== BlockEnum.TriggerWebhook) return @@ -23,9 +23,9 @@ export const useAutoGenerateWebhookUrl = () => { try { const response = await fetchWebhookUrl({ appId, nodeId }) - const { getNodes: getLatestNodes, setNodes } = reactFlowStore.getState() + const { nodes: latestNodes, setNodes } = collaborativeWorkflow.getState() let hasUpdated = false - const updatedNodes = produce(getLatestNodes(), (draft) => { + const updatedNodes = produce(latestNodes, (draft) => { const targetNode = draft.find(n => n.id === nodeId) if (!targetNode || targetNode.data.type !== BlockEnum.TriggerWebhook) return @@ -44,5 +44,5 @@ export const useAutoGenerateWebhookUrl = () => { catch (error: unknown) { console.error('Failed to auto-generate webhook URL:', error) } - }, [reactFlowStore]) + }, [collaborativeWorkflow]) } diff --git a/web/app/components/workflow/hooks/use-workflow-organize.ts b/web/app/components/workflow/hooks/use-workflow-organize.ts index 1acaa07fbc..897963eca8 100644 --- a/web/app/components/workflow/hooks/use-workflow-organize.ts +++ b/web/app/components/workflow/hooks/use-workflow-organize.ts @@ -1,10 +1,11 @@ import { useCallback } from 'react' -import { useReactFlow, useStoreApi } from 'reactflow' +import { useReactFlow } from 'reactflow' import { useWorkflowStore } from '../store' import { getLayoutByELK, getLayoutForChildNodes, } from '../utils/elk-layout' +import { useCollaborativeWorkflow } from './use-collaborative-workflow' import { useNodesSyncDraft } from './use-nodes-sync-draft' import { useNodesReadOnly } from './use-workflow' import { useWorkflowHistory, WorkflowHistoryEvent } from './use-workflow-history' @@ -17,7 +18,7 @@ import { export const useWorkflowOrganize = () => { const workflowStore = useWorkflowStore() - const store = useStoreApi() + const collaborativeWorkflow = useCollaborativeWorkflow() const reactflow = useReactFlow() const { getNodesReadOnly } = useNodesReadOnly() const { saveStateToHistory } = useWorkflowHistory() @@ -29,11 +30,10 @@ export const useWorkflowOrganize = () => { workflowStore.setState({ nodeAnimation: true }) const { - getNodes, + nodes, edges, setNodes, - } = store.getState() - const nodes = getNodes() + } = collaborativeWorkflow.getState() const parentNodes = getLayoutContainerNodes(nodes) const childLayoutEntries = await Promise.all( @@ -63,7 +63,7 @@ export const useWorkflowOrganize = () => { setTimeout(() => { handleSyncWorkflowDraft() }) - }, [getNodesReadOnly, handleSyncWorkflowDraft, reactflow, saveStateToHistory, store, workflowStore]) + }, [getNodesReadOnly, handleSyncWorkflowDraft, reactflow, saveStateToHistory, collaborativeWorkflow, workflowStore]) return { handleLayout, diff --git a/web/app/components/workflow/nodes/data-source-empty/hooks.ts b/web/app/components/workflow/nodes/data-source-empty/hooks.ts index ffeb02788c..b3c33d699e 100644 --- a/web/app/components/workflow/nodes/data-source-empty/hooks.ts +++ b/web/app/components/workflow/nodes/data-source-empty/hooks.ts @@ -1,12 +1,12 @@ import type { OnSelectBlock } from '@/app/components/workflow/types' import { produce } from 'immer' import { useCallback } from 'react' -import { useStoreApi } from 'reactflow' import { useNodesMetaData } from '@/app/components/workflow/hooks' +import { useCollaborativeWorkflow } from '@/app/components/workflow/hooks/use-collaborative-workflow' import { generateNewNode } from '@/app/components/workflow/utils' export const useReplaceDataSourceNode = (id: string) => { - const store = useStoreApi() + const collaborativeWorkflow = useCollaborativeWorkflow() const { nodesMap: nodesMetaDataMap } = useNodesMetaData() const handleReplaceNode = useCallback(( @@ -14,10 +14,9 @@ export const useReplaceDataSourceNode = (id: string) => { pluginDefaultValue, ) => { const { - getNodes, + nodes, setNodes, - } = store.getState() - const nodes = getNodes() + } = collaborativeWorkflow.getState() const emptyNodeIndex = nodes.findIndex(node => node.id === id) if (emptyNodeIndex < 0) @@ -44,7 +43,7 @@ export const useReplaceDataSourceNode = (id: string) => { return draft.filter(node => !node.data._isTempNode) }) setNodes(newNodesWithoutTempNodes) - }, []) + }, [collaborativeWorkflow, id, nodesMetaDataMap]) return { handleReplaceNode, diff --git a/web/app/components/workflow/panel/env-panel/index.tsx b/web/app/components/workflow/panel/env-panel/index.tsx index f2d567f94b..b1d5ba9236 100644 --- a/web/app/components/workflow/panel/env-panel/index.tsx +++ b/web/app/components/workflow/panel/env-panel/index.tsx @@ -8,7 +8,7 @@ import { useState, } from 'react' import { useTranslation } from 'react-i18next' -import { useStoreApi } from 'reactflow' +import { useCollaborativeWorkflow } from '@/app/components/workflow/hooks/use-collaborative-workflow' import { useNodesSyncDraft } from '@/app/components/workflow/hooks/use-nodes-sync-draft' import RemoveEffectVarConfirm from '@/app/components/workflow/nodes/_base/components/remove-effect-var-confirm' import { findUsedVarNodes, updateNodeVars } from '@/app/components/workflow/nodes/_base/components/variable/utils' @@ -37,7 +37,7 @@ const removeSecretFromMap = (secretMap: Record, envId: string) = const EnvPanel = () => { const { t } = useTranslation() - const store = useStoreApi() + const collaborativeWorkflow = useCollaborativeWorkflow() const setShowEnvPanel = useStore(s => s.setShowEnvPanel) const envList = useStore(s => s.environmentVariables) as EnvironmentVariable[] const envSecrets = useStore(s => s.envSecrets) @@ -68,36 +68,36 @@ const EnvPanel = () => { }, [appId]) const getAffectedNodes = useCallback((env: EnvironmentVariable) => { - const allNodes = store.getState().getNodes() + const { nodes: allNodes } = collaborativeWorkflow.getState() return findUsedVarNodes( ['env', env.name], allNodes, ) - }, [store]) + }, [collaborativeWorkflow]) const removeUsedVarInNodes = useCallback((env: EnvironmentVariable) => { - const { getNodes, setNodes } = store.getState() + const { nodes, setNodes } = collaborativeWorkflow.getState() const affectedNodes = getAffectedNodes(env) - const newNodes = getNodes().map((node) => { + const newNodes = nodes.map((node) => { if (affectedNodes.find(n => n.id === node.id)) return updateNodeVars(node, ['env', env.name], []) return node }) setNodes(newNodes) - }, [getAffectedNodes, store]) + }, [collaborativeWorkflow, getAffectedNodes]) const renameUsedVarInNodes = useCallback((currentEnv: EnvironmentVariable, nextEnvName: string) => { - const { getNodes, setNodes } = store.getState() + const { nodes, setNodes } = collaborativeWorkflow.getState() const affectedNodes = getAffectedNodes(currentEnv) - const newNodes = getNodes().map((node) => { + const newNodes = nodes.map((node) => { if (affectedNodes.find(n => n.id === node.id)) return updateNodeVars(node, ['env', currentEnv.name], ['env', nextEnvName]) return node }) setNodes(newNodes) - }, [getAffectedNodes, store]) + }, [collaborativeWorkflow, getAffectedNodes]) const persistEnvironmentVariables = useCallback(async (nextEnvList: EnvironmentVariable[]) => { try {