sync nodes

This commit is contained in:
hjlarry 2025-09-25 16:31:46 +08:00
parent 2398ed6fe8
commit e240175116
6 changed files with 74 additions and 127 deletions

View File

@ -4,7 +4,6 @@ import {
import produce from 'immer' import produce from 'immer'
import { import {
useReactFlow, useReactFlow,
useStoreApi,
useViewport, useViewport,
} from 'reactflow' } from 'reactflow'
import { useEventListener } from 'ahooks' import { useEventListener } from 'ahooks'
@ -19,9 +18,9 @@ import CustomNode from './nodes'
import CustomNoteNode from './note-node' import CustomNoteNode from './note-node'
import { CUSTOM_NOTE_NODE } from './note-node/constants' import { CUSTOM_NOTE_NODE } from './note-node/constants'
import { BlockEnum } from './types' import { BlockEnum } from './types'
import { useCollaborativeWorkflow } from '@/app/components/workflow/hooks/use-collaborative-workflow'
const CandidateNode = () => { const CandidateNode = () => {
const store = useStoreApi()
const reactflow = useReactFlow() const reactflow = useReactFlow()
const workflowStore = useWorkflowStore() const workflowStore = useWorkflowStore()
const candidateNode = useStore(s => s.candidateNode) const candidateNode = useStore(s => s.candidateNode)
@ -29,18 +28,15 @@ const CandidateNode = () => {
const { zoom } = useViewport() const { zoom } = useViewport()
const { handleNodeSelect } = useNodesInteractions() const { handleNodeSelect } = useNodesInteractions()
const { saveStateToHistory } = useWorkflowHistory() const { saveStateToHistory } = useWorkflowHistory()
const collaborativeWorkflow = useCollaborativeWorkflow()
useEventListener('click', (e) => { useEventListener('click', (e) => {
const { candidateNode, mousePosition } = workflowStore.getState() const { candidateNode, mousePosition } = workflowStore.getState()
if (candidateNode) { if (candidateNode) {
e.preventDefault() e.preventDefault()
const { const { nodes, setNodes } = collaborativeWorkflow.getState()
getNodes,
setNodes,
} = store.getState()
const { screenToFlowPosition } = reactflow const { screenToFlowPosition } = reactflow
const nodes = getNodes()
const { x, y } = screenToFlowPosition({ x: mousePosition.pageX, y: mousePosition.pageY }) const { x, y } = screenToFlowPosition({ x: mousePosition.pageX, y: mousePosition.pageY })
const newNodes = produce(nodes, (draft) => { const newNodes = produce(nodes, (draft) => {
draft.push({ draft.push({

View File

@ -1,7 +1,7 @@
import { import {
useCallback, useCallback,
} from 'react' } from 'react'
import { useReactFlow, useStoreApi } from 'reactflow' import { useReactFlow } from 'reactflow'
import produce from 'immer' import produce from 'immer'
import { useStore, useWorkflowStore } from '../store' import { useStore, useWorkflowStore } from '../store'
import { import {
@ -28,6 +28,7 @@ import { useNodesInteractionsWithoutSync } from './use-nodes-interactions-withou
import { useNodesSyncDraft } from './use-nodes-sync-draft' import { useNodesSyncDraft } from './use-nodes-sync-draft'
import { WorkflowHistoryEvent, useWorkflowHistory } from './use-workflow-history' import { WorkflowHistoryEvent, useWorkflowHistory } from './use-workflow-history'
import { useEventEmitterContextContext } from '@/context/event-emitter' import { useEventEmitterContextContext } from '@/context/event-emitter'
import { useCollaborativeWorkflow } from '@/app/components/workflow/hooks/use-collaborative-workflow'
export const useWorkflowInteractions = () => { export const useWorkflowInteractions = () => {
const workflowStore = useWorkflowStore() const workflowStore = useWorkflowStore()
@ -87,23 +88,22 @@ export const useWorkflowMoveMode = () => {
export const useWorkflowOrganize = () => { export const useWorkflowOrganize = () => {
const workflowStore = useWorkflowStore() const workflowStore = useWorkflowStore()
const store = useStoreApi()
const reactflow = useReactFlow() const reactflow = useReactFlow()
const { getNodesReadOnly } = useNodesReadOnly() const { getNodesReadOnly } = useNodesReadOnly()
const { saveStateToHistory } = useWorkflowHistory() const { saveStateToHistory } = useWorkflowHistory()
const { handleSyncWorkflowDraft } = useNodesSyncDraft() const { handleSyncWorkflowDraft } = useNodesSyncDraft()
const collaborativeWorkflow = useCollaborativeWorkflow()
const handleLayout = useCallback(async () => { const handleLayout = useCallback(async () => {
if (getNodesReadOnly()) if (getNodesReadOnly())
return return
workflowStore.setState({ nodeAnimation: true }) workflowStore.setState({ nodeAnimation: true })
const { const {
getNodes, nodes,
edges, edges,
setNodes, setNodes,
} = store.getState() } = collaborativeWorkflow.getState()
const { setViewport } = reactflow const { setViewport } = reactflow
const nodes = getNodes()
const loopAndIterationNodes = nodes.filter( const loopAndIterationNodes = nodes.filter(
node => (node.data.type === BlockEnum.Loop || node.data.type === BlockEnum.Iteration) node => (node.data.type === BlockEnum.Loop || node.data.type === BlockEnum.Iteration)
@ -248,7 +248,7 @@ export const useWorkflowOrganize = () => {
setTimeout(() => { setTimeout(() => {
handleSyncWorkflowDraft() handleSyncWorkflowDraft()
}) })
}, [getNodesReadOnly, store, reactflow, workflowStore, handleSyncWorkflowDraft, saveStateToHistory]) }, [getNodesReadOnly, collaborativeWorkflow, reactflow, workflowStore, handleSyncWorkflowDraft, saveStateToHistory])
return { return {
handleLayout, handleLayout,

View File

@ -6,7 +6,6 @@ import { useTranslation } from 'react-i18next'
import { import {
getIncomers, getIncomers,
getOutgoers, getOutgoers,
useStoreApi,
} from 'reactflow' } from 'reactflow'
import type { import type {
Connection, Connection,
@ -35,6 +34,7 @@ import { CUSTOM_NOTE_NODE } from '../note-node/constants'
import { findUsedVarNodes, getNodeOutputVars, updateNodeVars } from '../nodes/_base/components/variable/utils' import { findUsedVarNodes, getNodeOutputVars, updateNodeVars } from '../nodes/_base/components/variable/utils'
import { useAvailableBlocks } from './use-available-blocks' import { useAvailableBlocks } from './use-available-blocks'
import { useStore as useAppStore } from '@/app/components/app/store' import { useStore as useAppStore } from '@/app/components/app/store'
import { useCollaborativeWorkflow } from '@/app/components/workflow/hooks/use-collaborative-workflow'
import { import {
fetchAllBuiltInTools, fetchAllBuiltInTools,
fetchAllCustomTools, fetchAllCustomTools,
@ -55,26 +55,19 @@ export const useIsChatMode = () => {
export const useWorkflow = () => { export const useWorkflow = () => {
const { t } = useTranslation() const { t } = useTranslation()
const store = useStoreApi() const collaborativeWorkflow = useCollaborativeWorkflow()
const workflowStore = useWorkflowStore() const workflowStore = useWorkflowStore()
const { getAvailableBlocks } = useAvailableBlocks() const { getAvailableBlocks } = useAvailableBlocks()
const { nodesMap } = useNodesMetaData() const { nodesMap } = useNodesMetaData()
const getNodeById = useCallback((nodeId: string) => { const getNodeById = useCallback((nodeId: string) => {
const { const { nodes } = collaborativeWorkflow.getState()
getNodes,
} = store.getState()
const nodes = getNodes()
const currentNode = nodes.find(node => node.id === nodeId) const currentNode = nodes.find(node => node.id === nodeId)
return currentNode return currentNode
}, [store]) }, [collaborativeWorkflow])
const getTreeLeafNodes = useCallback((nodeId: string) => { const getTreeLeafNodes = useCallback((nodeId: string) => {
const { const { nodes, edges } = collaborativeWorkflow.getState()
getNodes,
edges,
} = store.getState()
const nodes = getNodes()
const currentNode = nodes.find(node => node.id === nodeId) const currentNode = nodes.find(node => node.id === nodeId)
let startNodes = nodes.filter(node => nodesMap?.[node.data.type as BlockEnum]?.metaData.isStart) || [] let startNodes = nodes.filter(node => nodesMap?.[node.data.type as BlockEnum]?.metaData.isStart) || []
@ -117,14 +110,11 @@ export const useWorkflow = () => {
return uniqBy(list, 'id').filter((item: Node) => { return uniqBy(list, 'id').filter((item: Node) => {
return SUPPORT_OUTPUT_VARS_NODE.includes(item.data.type) return SUPPORT_OUTPUT_VARS_NODE.includes(item.data.type)
}) })
}, [store, nodesMap]) }, [collaborativeWorkflow, nodesMap])
const getBeforeNodesInSameBranch = useCallback((nodeId: string, newNodes?: Node[], newEdges?: Edge[]) => { const getBeforeNodesInSameBranch = useCallback((nodeId: string, newNodes?: Node[], newEdges?: Edge[]) => {
const { const { nodes: oldNodes, edges } = collaborativeWorkflow.getState()
getNodes, const nodes = newNodes || oldNodes
edges,
} = store.getState()
const nodes = newNodes || getNodes()
const currentNode = nodes.find(node => node.id === nodeId) const currentNode = nodes.find(node => node.id === nodeId)
const list: Node[] = [] const list: Node[] = []
@ -167,14 +157,11 @@ export const useWorkflow = () => {
} }
return [] return []
}, [store]) }, [collaborativeWorkflow])
const getBeforeNodesInSameBranchIncludeParent = useCallback((nodeId: string, newNodes?: Node[], newEdges?: Edge[]) => { const getBeforeNodesInSameBranchIncludeParent = useCallback((nodeId: string, newNodes?: Node[], newEdges?: Edge[]) => {
const nodes = getBeforeNodesInSameBranch(nodeId, newNodes, newEdges) const nodes = getBeforeNodesInSameBranch(nodeId, newNodes, newEdges)
const { const { nodes: allNodes } = collaborativeWorkflow.getState()
getNodes,
} = store.getState()
const allNodes = getNodes()
const node = allNodes.find(n => n.id === nodeId) const node = allNodes.find(n => n.id === nodeId)
const parentNodeId = node?.parentId const parentNodeId = node?.parentId
const parentNode = allNodes.find(n => n.id === parentNodeId) const parentNode = allNodes.find(n => n.id === parentNodeId)
@ -182,14 +169,10 @@ export const useWorkflow = () => {
nodes.push(parentNode) nodes.push(parentNode)
return nodes return nodes
}, [getBeforeNodesInSameBranch, store]) }, [getBeforeNodesInSameBranch, collaborativeWorkflow])
const getAfterNodesInSameBranch = useCallback((nodeId: string) => { const getAfterNodesInSameBranch = useCallback((nodeId: string) => {
const { const { nodes, edges } = collaborativeWorkflow.getState()
getNodes,
edges,
} = store.getState()
const nodes = getNodes()
const currentNode = nodes.find(node => node.id === nodeId)! const currentNode = nodes.find(node => node.id === nodeId)!
if (!currentNode) if (!currentNode)
@ -213,40 +196,29 @@ export const useWorkflow = () => {
}) })
return uniqBy(list, 'id') return uniqBy(list, 'id')
}, [store]) }, [collaborativeWorkflow])
const getBeforeNodeById = useCallback((nodeId: string) => { const getBeforeNodeById = useCallback((nodeId: string) => {
const { const { nodes, edges } = collaborativeWorkflow.getState()
getNodes,
edges,
} = store.getState()
const nodes = getNodes()
const node = nodes.find(node => node.id === nodeId)! const node = nodes.find(node => node.id === nodeId)!
return getIncomers(node, nodes, edges) return getIncomers(node, nodes, edges)
}, [store]) }, [collaborativeWorkflow])
const getIterationNodeChildren = useCallback((nodeId: string) => { const getIterationNodeChildren = useCallback((nodeId: string) => {
const { const { nodes } = collaborativeWorkflow.getState()
getNodes,
} = store.getState()
const nodes = getNodes()
return nodes.filter(node => node.parentId === nodeId) return nodes.filter(node => node.parentId === nodeId)
}, [store]) }, [collaborativeWorkflow])
const getLoopNodeChildren = useCallback((nodeId: string) => { const getLoopNodeChildren = useCallback((nodeId: string) => {
const { const { nodes } = collaborativeWorkflow.getState()
getNodes,
} = store.getState()
const nodes = getNodes()
return nodes.filter(node => node.parentId === nodeId) return nodes.filter(node => node.parentId === nodeId)
}, [store]) }, [collaborativeWorkflow])
const handleOutVarRenameChange = useCallback((nodeId: string, oldValeSelector: ValueSelector, newVarSelector: ValueSelector) => { const handleOutVarRenameChange = useCallback((nodeId: string, oldValeSelector: ValueSelector, newVarSelector: ValueSelector) => {
const { getNodes, setNodes } = store.getState() const { nodes: allNodes, setNodes } = collaborativeWorkflow.getState()
const allNodes = getNodes()
const affectedNodes = findUsedVarNodes(oldValeSelector, allNodes) const affectedNodes = findUsedVarNodes(oldValeSelector, allNodes)
if (affectedNodes.length > 0) { if (affectedNodes.length > 0) {
const newNodes = allNodes.map((node) => { const newNodes = allNodes.map((node) => {
@ -257,7 +229,7 @@ export const useWorkflow = () => {
}) })
setNodes(newNodes) setNodes(newNodes)
} }
}, [store]) }, [collaborativeWorkflow])
const isVarUsedInNodes = useCallback((varSelector: ValueSelector) => { const isVarUsedInNodes = useCallback((varSelector: ValueSelector) => {
const nodeId = varSelector[0] const nodeId = varSelector[0]
@ -268,11 +240,11 @@ export const useWorkflow = () => {
const removeUsedVarInNodes = useCallback((varSelector: ValueSelector) => { const removeUsedVarInNodes = useCallback((varSelector: ValueSelector) => {
const nodeId = varSelector[0] const nodeId = varSelector[0]
const { getNodes, setNodes } = store.getState() const { nodes, setNodes } = collaborativeWorkflow.getState()
const afterNodes = getAfterNodesInSameBranch(nodeId) const afterNodes = getAfterNodesInSameBranch(nodeId)
const effectNodes = findUsedVarNodes(varSelector, afterNodes) const effectNodes = findUsedVarNodes(varSelector, afterNodes)
if (effectNodes.length > 0) { if (effectNodes.length > 0) {
const newNodes = getNodes().map((node) => { const newNodes = nodes.map((node) => {
if (effectNodes.find(n => n.id === node.id)) if (effectNodes.find(n => n.id === node.id))
return updateNodeVars(node, varSelector, []) return updateNodeVars(node, varSelector, [])
@ -280,7 +252,7 @@ export const useWorkflow = () => {
}) })
setNodes(newNodes) setNodes(newNodes)
} }
}, [getAfterNodesInSameBranch, store]) }, [getAfterNodesInSameBranch, collaborativeWorkflow])
const isNodeVarsUsedInNodes = useCallback((node: Node, isChatMode: boolean) => { const isNodeVarsUsedInNodes = useCallback((node: Node, isChatMode: boolean) => {
const outputVars = getNodeOutputVars(node, isChatMode) const outputVars = getNodeOutputVars(node, isChatMode)
@ -291,9 +263,7 @@ export const useWorkflow = () => {
}, [isVarUsedInNodes]) }, [isVarUsedInNodes])
const checkParallelLimit = useCallback((nodeId: string, nodeHandle = 'source') => { const checkParallelLimit = useCallback((nodeId: string, nodeHandle = 'source') => {
const { const { edges } = collaborativeWorkflow.getState()
edges,
} = store.getState()
const connectedEdges = edges.filter(edge => edge.source === nodeId && edge.sourceHandle === nodeHandle) const connectedEdges = edges.filter(edge => edge.source === nodeId && edge.sourceHandle === nodeHandle)
if (connectedEdges.length > MAX_PARALLEL_LIMIT - 1) { if (connectedEdges.length > MAX_PARALLEL_LIMIT - 1) {
const { setShowTips } = workflowStore.getState() const { setShowTips } = workflowStore.getState()
@ -302,14 +272,10 @@ export const useWorkflow = () => {
} }
return true return true
}, [store, workflowStore, t]) }, [collaborativeWorkflow, workflowStore, t])
const getRootNodesById = useCallback((nodeId: string) => { const getRootNodesById = useCallback((nodeId: string) => {
const { const { nodes, edges } = collaborativeWorkflow.getState()
getNodes,
edges,
} = store.getState()
const nodes = getNodes()
const currentNode = nodes.find(node => node.id === nodeId) const currentNode = nodes.find(node => node.id === nodeId)
const rootNodes: Node[] = [] const rootNodes: Node[] = []
@ -349,7 +315,7 @@ export const useWorkflow = () => {
return uniqBy(rootNodes, 'id') return uniqBy(rootNodes, 'id')
return [] return []
}, [store]) }, [collaborativeWorkflow])
const getStartNodes = useCallback((nodes: Node[], currentNode?: Node) => { const getStartNodes = useCallback((nodes: Node[], currentNode?: Node) => {
const { id, parentId } = currentNode || {} const { id, parentId } = currentNode || {}
@ -402,11 +368,7 @@ export const useWorkflow = () => {
}, [t, workflowStore, getStartNodes]) }, [t, workflowStore, getStartNodes])
const isValidConnection = useCallback(({ source, sourceHandle, target }: Connection) => { const isValidConnection = useCallback(({ source, sourceHandle, target }: Connection) => {
const { const { nodes, edges } = collaborativeWorkflow.getState()
edges,
getNodes,
} = store.getState()
const nodes = getNodes()
const sourceNode: Node = nodes.find(node => node.id === source)! const sourceNode: Node = nodes.find(node => node.id === source)!
const targetNode: Node = nodes.find(node => node.id === target)! const targetNode: Node = nodes.find(node => node.id === target)!
@ -445,7 +407,7 @@ export const useWorkflow = () => {
} }
return !hasCycle(targetNode) return !hasCycle(targetNode)
}, [store, checkParallelLimit, getAvailableBlocks]) }, [collaborativeWorkflow, checkParallelLimit, getAvailableBlocks])
return { return {
getNodeById, getNodeById,
@ -550,13 +512,10 @@ export const useNodesReadOnly = () => {
} }
export const useIsNodeInIteration = (iterationId: string) => { export const useIsNodeInIteration = (iterationId: string) => {
const store = useStoreApi() const collaborativeWorkflow = useCollaborativeWorkflow()
const isNodeInIteration = useCallback((nodeId: string) => { const isNodeInIteration = useCallback((nodeId: string) => {
const { const { nodes } = collaborativeWorkflow.getState()
getNodes,
} = store.getState()
const nodes = getNodes()
const node = nodes.find(node => node.id === nodeId) const node = nodes.find(node => node.id === nodeId)
if (!node) if (!node)
@ -566,20 +525,17 @@ export const useIsNodeInIteration = (iterationId: string) => {
return true return true
return false return false
}, [iterationId, store]) }, [iterationId, collaborativeWorkflow])
return { return {
isNodeInIteration, isNodeInIteration,
} }
} }
export const useIsNodeInLoop = (loopId: string) => { export const useIsNodeInLoop = (loopId: string) => {
const store = useStoreApi() const collaborativeWorkflow = useCollaborativeWorkflow()
const isNodeInLoop = useCallback((nodeId: string) => { const isNodeInLoop = useCallback((nodeId: string) => {
const { const { nodes } = collaborativeWorkflow.getState()
getNodes,
} = store.getState()
const nodes = getNodes()
const node = nodes.find(node => node.id === nodeId) const node = nodes.find(node => node.id === nodeId)
if (!node) if (!node)
@ -589,7 +545,7 @@ export const useIsNodeInLoop = (loopId: string) => {
return true return true
return false return false
}, [loopId, store]) }, [loopId, collaborativeWorkflow])
return { return {
isNodeInLoop, isNodeInLoop,
} }

View File

@ -3,9 +3,6 @@ import {
useCallback, useCallback,
useState, useState,
} from 'react' } from 'react'
import {
useStoreApi,
} from 'reactflow'
import { RiBookOpenLine, RiCloseLine } from '@remixicon/react' import { RiBookOpenLine, RiCloseLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useStore } from '@/app/components/workflow/store' import { useStore } from '@/app/components/workflow/store'
@ -25,15 +22,15 @@ import { useDocLink } from '@/context/i18n'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import useInspectVarsCrud from '../../hooks/use-inspect-vars-crud' import useInspectVarsCrud from '../../hooks/use-inspect-vars-crud'
import { updateConversationVariables } from '@/service/workflow' import { updateConversationVariables } from '@/service/workflow'
import { useCollaborativeWorkflow } from '@/app/components/workflow/hooks/use-collaborative-workflow'
const ChatVariablePanel = () => { const ChatVariablePanel = () => {
const { t } = useTranslation() const { t } = useTranslation()
const docLink = useDocLink() const docLink = useDocLink()
const store = useStoreApi()
const setShowChatVariablePanel = useStore(s => s.setShowChatVariablePanel) const setShowChatVariablePanel = useStore(s => s.setShowChatVariablePanel)
const varList = useStore(s => s.conversationVariables) as ConversationVariable[] const varList = useStore(s => s.conversationVariables) as ConversationVariable[]
const updateChatVarList = useStore(s => s.setConversationVariables) const updateChatVarList = useStore(s => s.setConversationVariables)
const appId = useStore(s => s.appId) const appId = useStore(s => s.appId) as string
const { const {
invalidateConversationVarValues, invalidateConversationVarValues,
} = useInspectVarsCrud() } = useInspectVarsCrud()
@ -44,27 +41,27 @@ const ChatVariablePanel = () => {
const [showRemoveVarConfirm, setShowRemoveConfirm] = useState(false) const [showRemoveVarConfirm, setShowRemoveConfirm] = useState(false)
const [cacheForDelete, setCacheForDelete] = useState<ConversationVariable>() const [cacheForDelete, setCacheForDelete] = useState<ConversationVariable>()
const collaborativeWorkflow = useCollaborativeWorkflow()
const getEffectedNodes = useCallback((chatVar: ConversationVariable) => { const getEffectedNodes = useCallback((chatVar: ConversationVariable) => {
const { getNodes } = store.getState() const { nodes: allNodes } = collaborativeWorkflow.getState()
const allNodes = getNodes()
return findUsedVarNodes( return findUsedVarNodes(
['conversation', chatVar.name], ['conversation', chatVar.name],
allNodes, allNodes,
) )
}, [store]) }, [collaborativeWorkflow])
const removeUsedVarInNodes = useCallback((chatVar: ConversationVariable) => { const removeUsedVarInNodes = useCallback((chatVar: ConversationVariable) => {
const { getNodes, setNodes } = store.getState() const { nodes, setNodes } = collaborativeWorkflow.getState()
const effectedNodes = getEffectedNodes(chatVar) const effectedNodes = getEffectedNodes(chatVar)
const newNodes = getNodes().map((node) => { const newNodes = nodes.map((node) => {
if (effectedNodes.find(n => n.id === node.id)) if (effectedNodes.find(n => n.id === node.id))
return updateNodeVars(node, ['conversation', chatVar.name], []) return updateNodeVars(node, ['conversation', chatVar.name], [])
return node return node
}) })
setNodes(newNodes) setNodes(newNodes)
}, [getEffectedNodes, store]) }, [getEffectedNodes, collaborativeWorkflow])
const handleEdit = (chatVar: ConversationVariable) => { const handleEdit = (chatVar: ConversationVariable) => {
setCurrentVar(chatVar) setCurrentVar(chatVar)
@ -151,9 +148,9 @@ const ChatVariablePanel = () => {
// side effects of rename conversation variable // side effects of rename conversation variable
if (currentVar.name !== chatVar.name) { if (currentVar.name !== chatVar.name) {
const { getNodes, setNodes } = store.getState() const { nodes, setNodes } = collaborativeWorkflow.getState()
const effectedNodes = getEffectedNodes(currentVar) const effectedNodes = getEffectedNodes(currentVar)
const newNodes = getNodes().map((node) => { const newNodes = nodes.map((node) => {
if (effectedNodes.find(n => n.id === node.id)) if (effectedNodes.find(n => n.id === node.id))
return updateNodeVars(node, ['conversation', currentVar.name], ['conversation', chatVar.name]) return updateNodeVars(node, ['conversation', currentVar.name], ['conversation', chatVar.name])
@ -183,7 +180,7 @@ const ChatVariablePanel = () => {
// Revert local state on error // Revert local state on error
updateChatVarList(varList) updateChatVarList(varList)
} }
}, [currentVar, getEffectedNodes, store, updateChatVarList, varList, appId, invalidateConversationVarValues]) }, [currentVar, getEffectedNodes, collaborativeWorkflow, updateChatVarList, varList, appId, invalidateConversationVarValues])
return ( return (
<div <div

View File

@ -3,9 +3,6 @@ import {
useCallback, useCallback,
useState, useState,
} from 'react' } from 'react'
import {
useStoreApi,
} from 'reactflow'
import { RiCloseLine } from '@remixicon/react' import { RiCloseLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useStore } from '@/app/components/workflow/store' import { useStore } from '@/app/components/workflow/store'
@ -20,16 +17,17 @@ import cn from '@/utils/classnames'
import { webSocketClient } from '@/app/components/workflow/collaboration/core/websocket-manager' import { webSocketClient } from '@/app/components/workflow/collaboration/core/websocket-manager'
import { useStore as useWorkflowStore } from '@/app/components/workflow/store' import { useStore as useWorkflowStore } from '@/app/components/workflow/store'
import { updateEnvironmentVariables } from '@/service/workflow' import { updateEnvironmentVariables } from '@/service/workflow'
import { useCollaborativeWorkflow } from '@/app/components/workflow/hooks/use-collaborative-workflow'
const EnvPanel = () => { const EnvPanel = () => {
const { t } = useTranslation() const { t } = useTranslation()
const store = useStoreApi() const collaborativeWorkflow = useCollaborativeWorkflow()
const setShowEnvPanel = useStore(s => s.setShowEnvPanel) const setShowEnvPanel = useStore(s => s.setShowEnvPanel)
const envList = useStore(s => s.environmentVariables) as EnvironmentVariable[] const envList = useStore(s => s.environmentVariables) as EnvironmentVariable[]
const envSecrets = useStore(s => s.envSecrets) const envSecrets = useStore(s => s.envSecrets)
const updateEnvList = useStore(s => s.setEnvironmentVariables) const updateEnvList = useStore(s => s.setEnvironmentVariables)
const setEnvSecrets = useStore(s => s.setEnvSecrets) const setEnvSecrets = useStore(s => s.setEnvSecrets)
const appId = useWorkflowStore(s => s.appId) const appId = useWorkflowStore(s => s.appId) as string
const [showVariableModal, setShowVariableModal] = useState(false) const [showVariableModal, setShowVariableModal] = useState(false)
const [currentVar, setCurrentVar] = useState<EnvironmentVariable>() const [currentVar, setCurrentVar] = useState<EnvironmentVariable>()
@ -42,25 +40,24 @@ const EnvPanel = () => {
} }
const getEffectedNodes = useCallback((env: EnvironmentVariable) => { const getEffectedNodes = useCallback((env: EnvironmentVariable) => {
const { getNodes } = store.getState() const { nodes: allNodes } = collaborativeWorkflow.getState()
const allNodes = getNodes()
return findUsedVarNodes( return findUsedVarNodes(
['env', env.name], ['env', env.name],
allNodes, allNodes,
) )
}, [store]) }, [collaborativeWorkflow])
const removeUsedVarInNodes = useCallback((env: EnvironmentVariable) => { const removeUsedVarInNodes = useCallback((env: EnvironmentVariable) => {
const { getNodes, setNodes } = store.getState() const { nodes, setNodes } = collaborativeWorkflow.getState()
const effectedNodes = getEffectedNodes(env) const effectedNodes = getEffectedNodes(env)
const newNodes = getNodes().map((node) => { const newNodes = nodes.map((node) => {
if (effectedNodes.find(n => n.id === node.id)) if (effectedNodes.find(n => n.id === node.id))
return updateNodeVars(node, ['env', env.name], []) return updateNodeVars(node, ['env', env.name], [])
return node return node
}) })
setNodes(newNodes) setNodes(newNodes)
}, [getEffectedNodes, store]) }, [getEffectedNodes, collaborativeWorkflow])
const handleEdit = (env: EnvironmentVariable) => { const handleEdit = (env: EnvironmentVariable) => {
setCurrentVar(env) setCurrentVar(env)
@ -185,9 +182,9 @@ const EnvPanel = () => {
// side effects of rename env // side effects of rename env
if (currentVar.name !== env.name) { if (currentVar.name !== env.name) {
const { getNodes, setNodes } = store.getState() const { nodes, setNodes } = collaborativeWorkflow.getState()
const effectedNodes = getEffectedNodes(currentVar) const effectedNodes = getEffectedNodes(currentVar)
const newNodes = getNodes().map((node) => { const newNodes = nodes.map((node) => {
if (effectedNodes.find(n => n.id === node.id)) if (effectedNodes.find(n => n.id === node.id))
return updateNodeVars(node, ['env', currentVar.name], ['env', env.name]) return updateNodeVars(node, ['env', currentVar.name], ['env', env.name])
@ -218,7 +215,7 @@ const EnvPanel = () => {
// Revert local state on error // Revert local state on error
updateEnvList(envList) updateEnvList(envList)
} }
}, [currentVar, envList, envSecrets, getEffectedNodes, setEnvSecrets, store, updateEnvList, appId]) }, [currentVar, envList, envSecrets, getEffectedNodes, setEnvSecrets, collaborativeWorkflow, updateEnvList, appId])
return ( return (
<div <div

View File

@ -7,7 +7,7 @@ import {
} from 'react' } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useClickAway } from 'ahooks' import { useClickAway } from 'ahooks'
import { useStore as useReactFlowStore, useStoreApi } from 'reactflow' import { useStore as useReactFlowStore } from 'reactflow'
import { import {
RiAlignBottom, RiAlignBottom,
RiAlignCenter, RiAlignCenter,
@ -22,6 +22,7 @@ import { WorkflowHistoryEvent, useWorkflowHistory } from './hooks/use-workflow-h
import { useStore } from './store' import { useStore } from './store'
import { useSelectionInteractions } from './hooks/use-selection-interactions' import { useSelectionInteractions } from './hooks/use-selection-interactions'
import { useWorkflowStore } from './store' import { useWorkflowStore } from './store'
import { useCollaborativeWorkflow } from '@/app/components/workflow/hooks/use-collaborative-workflow'
enum AlignType { enum AlignType {
Left = 'left', Left = 'left',
@ -42,8 +43,8 @@ const SelectionContextmenu = () => {
const selectionMenu = useStore(s => s.selectionMenu) const selectionMenu = useStore(s => s.selectionMenu)
// Access React Flow methods // Access React Flow methods
const store = useStoreApi()
const workflowStore = useWorkflowStore() const workflowStore = useWorkflowStore()
const collaborativeWorkflow = useCollaborativeWorkflow()
// Get selected nodes for alignment logic // Get selected nodes for alignment logic
const selectedNodes = useReactFlowStore(state => const selectedNodes = useReactFlowStore(state =>
@ -256,7 +257,7 @@ const SelectionContextmenu = () => {
workflowStore.setState({ nodeAnimation: false }) workflowStore.setState({ nodeAnimation: false })
// Get all current nodes // Get all current nodes
const nodes = store.getState().getNodes() const { nodes, setNodes } = collaborativeWorkflow.getState()
// Get all selected nodes // Get all selected nodes
const selectedNodeIds = selectedNodes.map(node => node.id) const selectedNodeIds = selectedNodes.map(node => node.id)
@ -312,7 +313,7 @@ const SelectionContextmenu = () => {
const distributeNodes = handleDistributeNodes(nodesToAlign, nodes, alignType) const distributeNodes = handleDistributeNodes(nodesToAlign, nodes, alignType)
if (distributeNodes) { if (distributeNodes) {
// Apply node distribution updates // Apply node distribution updates
store.getState().setNodes(distributeNodes) setNodes(distributeNodes)
handleSelectionContextmenuCancel() handleSelectionContextmenuCancel()
// Clear guide lines // Clear guide lines
@ -347,7 +348,7 @@ const SelectionContextmenu = () => {
// Apply node position updates - consistent with handleNodeDrag and handleNodeDragStop // Apply node position updates - consistent with handleNodeDrag and handleNodeDragStop
try { try {
// Directly use setNodes to update nodes - consistent with handleNodeDrag // Directly use setNodes to update nodes - consistent with handleNodeDrag
store.getState().setNodes(newNodes) setNodes(newNodes)
// Close popup // Close popup
handleSelectionContextmenuCancel() handleSelectionContextmenuCancel()
@ -366,7 +367,7 @@ const SelectionContextmenu = () => {
catch (err) { catch (err) {
console.error('Failed to update nodes:', err) console.error('Failed to update nodes:', err)
} }
}, [store, workflowStore, selectedNodes, getNodesReadOnly, handleSyncWorkflowDraft, saveStateToHistory, handleSelectionContextmenuCancel, handleAlignNode, handleDistributeNodes]) }, [collaborativeWorkflow, workflowStore, selectedNodes, getNodesReadOnly, handleSyncWorkflowDraft, saveStateToHistory, handleSelectionContextmenuCancel, handleAlignNode, handleDistributeNodes])
if (!selectionMenu) if (!selectionMenu)
return null return null