mirror of
https://github.com/langgenius/dify.git
synced 2024-11-16 11:42:29 +08:00
fix: workflow restore (#3711)
This commit is contained in:
parent
96160837d2
commit
83caffe000
|
@ -402,3 +402,5 @@ export const TOOL_OUTPUT_STRUCT: Var[] = [
|
|||
type: VarType.arrayFile,
|
||||
},
|
||||
]
|
||||
|
||||
export const WORKFLOW_DATA_UPDATE = 'WORKFLOW_DATA_UPDATE'
|
||||
|
|
|
@ -73,6 +73,7 @@ const Header: FC = () => {
|
|||
|
||||
const handleRestore = useCallback(() => {
|
||||
workflowStore.setState({ isRestoring: false })
|
||||
workflowStore.setState({ backupDraft: undefined })
|
||||
handleSyncWorkflowDraft(true)
|
||||
}, [handleSyncWorkflowDraft, workflowStore])
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import type {
|
|||
Viewport,
|
||||
} from 'reactflow'
|
||||
import {
|
||||
changeNodesAndEdgesId,
|
||||
getLayoutByDagre,
|
||||
initialEdges,
|
||||
initialNodes,
|
||||
|
@ -39,6 +40,7 @@ import {
|
|||
import {
|
||||
AUTO_LAYOUT_OFFSET,
|
||||
SUPPORT_OUTPUT_VARS_NODE,
|
||||
WORKFLOW_DATA_UPDATE,
|
||||
} from '../constants'
|
||||
import { findUsedVarNodes, getNodeOutputVars, updateNodeVars } from '../nodes/_base/components/variable/utils'
|
||||
import { useNodesExtraData } from './use-nodes-data'
|
||||
|
@ -56,6 +58,8 @@ import {
|
|||
fetchAllCustomTools,
|
||||
} from '@/service/tools'
|
||||
import I18n from '@/context/i18n'
|
||||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||
|
||||
export const useIsChatMode = () => {
|
||||
const appDetail = useAppStore(s => s.appDetail)
|
||||
|
||||
|
@ -69,6 +73,7 @@ export const useWorkflow = () => {
|
|||
const workflowStore = useWorkflowStore()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
||||
const { eventEmitter } = useEventEmitterContextContext()
|
||||
|
||||
const handleLayout = useCallback(async () => {
|
||||
workflowStore.setState({ nodeAnimation: true })
|
||||
|
@ -314,15 +319,21 @@ export const useWorkflow = () => {
|
|||
}, [locale])
|
||||
|
||||
const renderTreeFromRecord = useCallback((nodes: Node[], edges: Edge[], viewport?: Viewport) => {
|
||||
const { setNodes } = store.getState()
|
||||
const { setViewport, setEdges } = reactflow
|
||||
const { setViewport } = reactflow
|
||||
|
||||
setNodes(initialNodes(nodes, edges))
|
||||
setEdges(initialEdges(edges, nodes))
|
||||
const [newNodes, newEdges] = changeNodesAndEdgesId(nodes, edges)
|
||||
|
||||
eventEmitter?.emit({
|
||||
type: WORKFLOW_DATA_UPDATE,
|
||||
payload: {
|
||||
nodes: initialNodes(newNodes, newEdges),
|
||||
edges: initialEdges(newEdges, newNodes),
|
||||
},
|
||||
} as any)
|
||||
|
||||
if (viewport)
|
||||
setViewport(viewport)
|
||||
}, [store, reactflow])
|
||||
}, [reactflow, eventEmitter])
|
||||
|
||||
const getNode = useCallback((nodeId?: string) => {
|
||||
const { getNodes } = store.getState()
|
||||
|
|
|
@ -14,6 +14,8 @@ import {
|
|||
import ReactFlow, {
|
||||
Background,
|
||||
ReactFlowProvider,
|
||||
useEdgesState,
|
||||
useNodesState,
|
||||
useOnViewportChange,
|
||||
} from 'reactflow'
|
||||
import type { Viewport } from 'reactflow'
|
||||
|
@ -46,9 +48,11 @@ import {
|
|||
initialEdges,
|
||||
initialNodes,
|
||||
} from './utils'
|
||||
import { WORKFLOW_DATA_UPDATE } from './constants'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { FeaturesProvider } from '@/app/components/base/features'
|
||||
import type { Features as FeaturesData } from '@/app/components/base/features/types'
|
||||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||
|
||||
const nodeTypes = {
|
||||
custom: CustomNode,
|
||||
|
@ -63,10 +67,12 @@ type WorkflowProps = {
|
|||
viewport?: Viewport
|
||||
}
|
||||
const Workflow: FC<WorkflowProps> = memo(({
|
||||
nodes,
|
||||
edges,
|
||||
nodes: originalNodes,
|
||||
edges: originalEdges,
|
||||
viewport,
|
||||
}) => {
|
||||
const [nodes, setNodes] = useNodesState(originalNodes)
|
||||
const [edges, setEdges] = useEdgesState(originalEdges)
|
||||
const showFeaturesPanel = useStore(state => state.showFeaturesPanel)
|
||||
const nodeAnimation = useStore(s => s.nodeAnimation)
|
||||
const {
|
||||
|
@ -76,6 +82,15 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||
const { workflowReadOnly } = useWorkflowReadOnly()
|
||||
const { nodesReadOnly } = useNodesReadOnly()
|
||||
|
||||
const { eventEmitter } = useEventEmitterContextContext()
|
||||
|
||||
eventEmitter?.useSubscription((v: any) => {
|
||||
if (v.type === WORKFLOW_DATA_UPDATE) {
|
||||
setNodes(v.payload.nodes)
|
||||
setEdges(v.payload.edges)
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
setAutoFreeze(false)
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import type { ToolDefaultValue } from '../../../block-selector/types'
|
|||
import {
|
||||
useNodesExtraData,
|
||||
useNodesInteractions,
|
||||
useNodesReadOnly,
|
||||
} from '../../../hooks'
|
||||
import { useStore } from '../../../store'
|
||||
|
||||
|
@ -35,6 +36,7 @@ export const NodeTargetHandle = memo(({
|
|||
const [open, setOpen] = useState(false)
|
||||
const { handleNodeAdd } = useNodesInteractions()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const { getNodesReadOnly } = useNodesReadOnly()
|
||||
const connected = data._connectedTargetHandleIds?.includes(handleId)
|
||||
const availablePrevNodes = nodesExtraData[data.type].availablePrevNodes
|
||||
const isConnectable = !!availablePrevNodes.length
|
||||
|
@ -78,7 +80,7 @@ export const NodeTargetHandle = memo(({
|
|||
onClick={handleHandleClick}
|
||||
>
|
||||
{
|
||||
!connected && isConnectable && !data._isInvalidConnection && (
|
||||
!connected && isConnectable && !data._isInvalidConnection && !getNodesReadOnly() && (
|
||||
<BlockSelector
|
||||
open={open}
|
||||
onOpenChange={handleOpenChange}
|
||||
|
@ -113,6 +115,7 @@ export const NodeSourceHandle = memo(({
|
|||
const [open, setOpen] = useState(false)
|
||||
const { handleNodeAdd } = useNodesInteractions()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const { getNodesReadOnly } = useNodesReadOnly()
|
||||
const availableNextNodes = nodesExtraData[data.type].availableNextNodes
|
||||
const isConnectable = !!availableNextNodes.length
|
||||
const connected = data._connectedSourceHandleIds?.includes(handleId)
|
||||
|
@ -159,7 +162,7 @@ export const NodeSourceHandle = memo(({
|
|||
onClick={handleHandleClick}
|
||||
>
|
||||
{
|
||||
!connected && isConnectable && !data._isInvalidConnection && (
|
||||
!connected && isConnectable && !data._isInvalidConnection && !getNodesReadOnly() && (
|
||||
<BlockSelector
|
||||
open={open}
|
||||
onOpenChange={handleOpenChange}
|
||||
|
|
|
@ -58,7 +58,7 @@ const BaseNode: FC<BaseNodeProps> = ({
|
|||
`}
|
||||
>
|
||||
{
|
||||
data.type !== BlockEnum.VariableAssigner && !data._runningStatus && !nodesReadOnly && (
|
||||
data.type !== BlockEnum.VariableAssigner && !data._runningStatus && (
|
||||
<NodeTargetHandle
|
||||
id={id}
|
||||
data={data}
|
||||
|
@ -68,7 +68,7 @@ const BaseNode: FC<BaseNodeProps> = ({
|
|||
)
|
||||
}
|
||||
{
|
||||
data.type !== BlockEnum.IfElse && data.type !== BlockEnum.QuestionClassifier && !data._runningStatus && !nodesReadOnly && (
|
||||
data.type !== BlockEnum.IfElse && data.type !== BlockEnum.QuestionClassifier && !data._runningStatus && (
|
||||
<NodeSourceHandle
|
||||
id={id}
|
||||
data={data}
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
getOutgoers,
|
||||
} from 'reactflow'
|
||||
import dagre from 'dagre'
|
||||
import { v4 as uuid4 } from 'uuid'
|
||||
import {
|
||||
cloneDeep,
|
||||
uniqBy,
|
||||
|
@ -331,3 +332,28 @@ export const getToolCheckParams = (
|
|||
language,
|
||||
}
|
||||
}
|
||||
|
||||
export const changeNodesAndEdgesId = (nodes: Node[], edges: Edge[]) => {
|
||||
const idMap = nodes.reduce((acc, node) => {
|
||||
acc[node.id] = uuid4()
|
||||
|
||||
return acc
|
||||
}, {} as Record<string, string>)
|
||||
|
||||
const newNodes = nodes.map((node) => {
|
||||
return {
|
||||
...node,
|
||||
id: idMap[node.id],
|
||||
}
|
||||
})
|
||||
|
||||
const newEdges = edges.map((edge) => {
|
||||
return {
|
||||
...edge,
|
||||
source: idMap[edge.source],
|
||||
target: idMap[edge.target],
|
||||
}
|
||||
})
|
||||
|
||||
return [newNodes, newEdges] as [Node[], Edge[]]
|
||||
}
|
||||
|
|
|
@ -83,6 +83,7 @@
|
|||
"sortablejs": "^1.15.0",
|
||||
"swr": "^2.1.0",
|
||||
"use-context-selector": "^1.4.1",
|
||||
"uuid": "^9.0.1",
|
||||
"zustand": "^4.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -104,6 +105,7 @@
|
|||
"@types/react-window-infinite-loader": "^1.0.6",
|
||||
"@types/recordrtc": "^5.6.11",
|
||||
"@types/sortablejs": "^1.15.1",
|
||||
"@types/uuid": "^9.0.8",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.36.0",
|
||||
|
|
890
web/yarn.lock
890
web/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user