mirror of
https://github.com/langgenius/dify.git
synced 2026-04-29 12:37:20 +08:00
hooks
This commit is contained in:
parent
d2d6904c9b
commit
e8921787b3
@ -3,9 +3,11 @@ import produce from 'immer'
|
|||||||
import type {
|
import type {
|
||||||
EdgeMouseHandler,
|
EdgeMouseHandler,
|
||||||
NodeMouseHandler,
|
NodeMouseHandler,
|
||||||
|
OnConnect,
|
||||||
} from 'reactflow'
|
} from 'reactflow'
|
||||||
import {
|
import {
|
||||||
getConnectedEdges,
|
getConnectedEdges,
|
||||||
|
getIncomers,
|
||||||
useStoreApi,
|
useStoreApi,
|
||||||
} from 'reactflow'
|
} from 'reactflow'
|
||||||
import type {
|
import type {
|
||||||
@ -88,6 +90,33 @@ export const useWorkflow = () => {
|
|||||||
setNodes(newNodes)
|
setNodes(newNodes)
|
||||||
}, [store])
|
}, [store])
|
||||||
|
|
||||||
|
const handleConnectNode = useCallback<OnConnect>(({
|
||||||
|
source,
|
||||||
|
sourceHandle,
|
||||||
|
target,
|
||||||
|
targetHandle,
|
||||||
|
}) => {
|
||||||
|
const {
|
||||||
|
edges,
|
||||||
|
setEdges,
|
||||||
|
} = store.getState()
|
||||||
|
|
||||||
|
const newEdges = produce(edges, (draft) => {
|
||||||
|
const filtered = draft.filter(edge => edge.source !== source && edge.target !== target)
|
||||||
|
|
||||||
|
filtered.push({
|
||||||
|
id: `${source}-${target}`,
|
||||||
|
source: source!,
|
||||||
|
target: target!,
|
||||||
|
sourceHandle,
|
||||||
|
targetHandle,
|
||||||
|
})
|
||||||
|
|
||||||
|
return filtered
|
||||||
|
})
|
||||||
|
setEdges(newEdges)
|
||||||
|
}, [store])
|
||||||
|
|
||||||
const handleEnterEdge = useCallback<EdgeMouseHandler>((_, edge) => {
|
const handleEnterEdge = useCallback<EdgeMouseHandler>((_, edge) => {
|
||||||
const {
|
const {
|
||||||
edges,
|
edges,
|
||||||
@ -158,6 +187,7 @@ export const useWorkflow = () => {
|
|||||||
x: currentNode.position.x + 304,
|
x: currentNode.position.x + 304,
|
||||||
y: currentNode.position.y,
|
y: currentNode.position.y,
|
||||||
},
|
},
|
||||||
|
selected: true,
|
||||||
}
|
}
|
||||||
const newEdge = {
|
const newEdge = {
|
||||||
id: `${currentNode.id}-${nextNode.id}`,
|
id: `${currentNode.id}-${nextNode.id}`,
|
||||||
@ -169,7 +199,7 @@ export const useWorkflow = () => {
|
|||||||
}
|
}
|
||||||
const newNodes = produce(nodes, (draft) => {
|
const newNodes = produce(nodes, (draft) => {
|
||||||
draft.forEach((node) => {
|
draft.forEach((node) => {
|
||||||
node.data = { ...node.data, selected: false }
|
node.selected = false
|
||||||
})
|
})
|
||||||
draft.push(nextNode)
|
draft.push(nextNode)
|
||||||
})
|
})
|
||||||
@ -180,7 +210,7 @@ export const useWorkflow = () => {
|
|||||||
setEdges(newEdges)
|
setEdges(newEdges)
|
||||||
}, [store])
|
}, [store])
|
||||||
|
|
||||||
const handleChangeCurrentNode = useCallback((parentNodeId: string, currentNodeId: string, nodeType: BlockEnum, sourceHandle: string) => {
|
const handleChangeCurrentNode = useCallback((currentNodeId: string, nodeType: BlockEnum, sourceHandle?: string) => {
|
||||||
const {
|
const {
|
||||||
getNodes,
|
getNodes,
|
||||||
setNodes,
|
setNodes,
|
||||||
@ -189,6 +219,7 @@ export const useWorkflow = () => {
|
|||||||
} = store.getState()
|
} = store.getState()
|
||||||
const nodes = getNodes()
|
const nodes = getNodes()
|
||||||
const currentNode = nodes.find(node => node.id === currentNodeId)!
|
const currentNode = nodes.find(node => node.id === currentNodeId)!
|
||||||
|
const incomers = getIncomers(currentNode, nodes, edges)
|
||||||
const connectedEdges = getConnectedEdges([currentNode], edges)
|
const connectedEdges = getConnectedEdges([currentNode], edges)
|
||||||
const newCurrentNode: Node = {
|
const newCurrentNode: Node = {
|
||||||
id: `${Date.now()}`,
|
id: `${Date.now()}`,
|
||||||
@ -199,27 +230,32 @@ export const useWorkflow = () => {
|
|||||||
y: currentNode.position.y,
|
y: currentNode.position.y,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
const newEdge = {
|
|
||||||
id: `${parentNodeId}-${newCurrentNode.id}`,
|
|
||||||
type: 'custom',
|
|
||||||
source: parentNodeId,
|
|
||||||
sourceHandle,
|
|
||||||
target: newCurrentNode.id,
|
|
||||||
targetHandle: 'target',
|
|
||||||
}
|
|
||||||
const newNodes = produce(nodes, (draft) => {
|
const newNodes = produce(nodes, (draft) => {
|
||||||
const index = draft.findIndex(node => node.id === currentNodeId)
|
const index = draft.findIndex(node => node.id === currentNodeId)
|
||||||
|
|
||||||
draft.splice(index, 1, newCurrentNode)
|
draft.splice(index, 1, newCurrentNode)
|
||||||
})
|
})
|
||||||
setNodes(newNodes)
|
setNodes(newNodes)
|
||||||
const newEdges = produce(edges, (draft) => {
|
if (incomers.length === 1) {
|
||||||
const filtered = draft.filter(edge => !connectedEdges.find(connectedEdge => connectedEdge.id === edge.id))
|
const parentNodeId = incomers[0].id
|
||||||
filtered.push(newEdge)
|
|
||||||
|
|
||||||
return filtered
|
const newEdge = {
|
||||||
})
|
id: `${parentNodeId}-${newCurrentNode.id}`,
|
||||||
setEdges(newEdges)
|
type: 'custom',
|
||||||
|
source: parentNodeId,
|
||||||
|
sourceHandle: sourceHandle || 'source',
|
||||||
|
target: newCurrentNode.id,
|
||||||
|
targetHandle: 'target',
|
||||||
|
}
|
||||||
|
|
||||||
|
const newEdges = produce(edges, (draft) => {
|
||||||
|
const filtered = draft.filter(edge => !connectedEdges.find(connectedEdge => connectedEdge.id === edge.id))
|
||||||
|
filtered.push(newEdge)
|
||||||
|
|
||||||
|
return filtered
|
||||||
|
})
|
||||||
|
setEdges(newEdges)
|
||||||
|
}
|
||||||
}, [store])
|
}, [store])
|
||||||
|
|
||||||
const handleDeleteNode = useCallback((nodeId: string) => {
|
const handleDeleteNode = useCallback((nodeId: string) => {
|
||||||
@ -303,6 +339,7 @@ export const useWorkflow = () => {
|
|||||||
handleSelectNode,
|
handleSelectNode,
|
||||||
handleEnterEdge,
|
handleEnterEdge,
|
||||||
handleLeaveEdge,
|
handleLeaveEdge,
|
||||||
|
handleConnectNode,
|
||||||
handleDeleteEdge,
|
handleDeleteEdge,
|
||||||
handleUpdateNodeData,
|
handleUpdateNodeData,
|
||||||
handleAddNextNode,
|
handleAddNextNode,
|
||||||
|
|||||||
@ -41,6 +41,7 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||||||
const {
|
const {
|
||||||
handleEnterNode,
|
handleEnterNode,
|
||||||
handleLeaveNode,
|
handleLeaveNode,
|
||||||
|
handleConnectNode,
|
||||||
handleEnterEdge,
|
handleEnterEdge,
|
||||||
handleLeaveEdge,
|
handleLeaveEdge,
|
||||||
handleDeleteEdge,
|
handleDeleteEdge,
|
||||||
@ -58,6 +59,7 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||||||
edgeTypes={edgeTypes}
|
edgeTypes={edgeTypes}
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
edges={edges}
|
edges={edges}
|
||||||
|
onConnect={handleConnectNode}
|
||||||
onNodeMouseEnter={handleEnterNode}
|
onNodeMouseEnter={handleEnterNode}
|
||||||
onNodeMouseLeave={handleLeaveNode}
|
onNodeMouseLeave={handleLeaveNode}
|
||||||
onEdgeMouseEnter={handleEnterEdge}
|
onEdgeMouseEnter={handleEnterEdge}
|
||||||
|
|||||||
@ -33,9 +33,7 @@ const NextStep = ({
|
|||||||
{
|
{
|
||||||
!branches && !!outgoers.length && (
|
!branches && !!outgoers.length && (
|
||||||
<Item
|
<Item
|
||||||
parentNodeId={selectedNode!.id}
|
|
||||||
nodeId={outgoers[0].id}
|
nodeId={outgoers[0].id}
|
||||||
sourceHandle='source'
|
|
||||||
data={outgoers[0].data}
|
data={outgoers[0].data}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@ -63,7 +61,6 @@ const NextStep = ({
|
|||||||
connected && (
|
connected && (
|
||||||
<Item
|
<Item
|
||||||
data={target!.data!}
|
data={target!.data!}
|
||||||
parentNodeId={selectedNode!.id}
|
|
||||||
nodeId={target!.id}
|
nodeId={target!.id}
|
||||||
sourceHandle={branch.id}
|
sourceHandle={branch.id}
|
||||||
branchName={branch.name}
|
branchName={branch.name}
|
||||||
|
|||||||
@ -12,14 +12,12 @@ import { useWorkflow } from '../../../../hooks'
|
|||||||
import Button from '@/app/components/base/button'
|
import Button from '@/app/components/base/button'
|
||||||
|
|
||||||
type ItemProps = {
|
type ItemProps = {
|
||||||
parentNodeId: string
|
|
||||||
nodeId: string
|
nodeId: string
|
||||||
sourceHandle: string
|
sourceHandle?: string
|
||||||
branchName?: string
|
branchName?: string
|
||||||
data: CommonNodeType
|
data: CommonNodeType
|
||||||
}
|
}
|
||||||
const Item = ({
|
const Item = ({
|
||||||
parentNodeId,
|
|
||||||
nodeId,
|
nodeId,
|
||||||
sourceHandle,
|
sourceHandle,
|
||||||
branchName,
|
branchName,
|
||||||
@ -27,8 +25,8 @@ const Item = ({
|
|||||||
}: ItemProps) => {
|
}: ItemProps) => {
|
||||||
const { handleChangeCurrentNode } = useWorkflow()
|
const { handleChangeCurrentNode } = useWorkflow()
|
||||||
const handleSelect = useCallback((type: BlockEnum) => {
|
const handleSelect = useCallback((type: BlockEnum) => {
|
||||||
handleChangeCurrentNode(parentNodeId, nodeId, type, sourceHandle)
|
handleChangeCurrentNode(nodeId, type, sourceHandle)
|
||||||
}, [parentNodeId, nodeId, sourceHandle, handleChangeCurrentNode])
|
}, [nodeId, sourceHandle, handleChangeCurrentNode])
|
||||||
const renderTrigger = useCallback((open: boolean) => {
|
const renderTrigger = useCallback((open: boolean) => {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@ -0,0 +1,42 @@
|
|||||||
|
import {
|
||||||
|
memo,
|
||||||
|
useCallback,
|
||||||
|
} from 'react'
|
||||||
|
import BlockSelector from '../../../../block-selector'
|
||||||
|
import { useWorkflow } from '../../../../hooks'
|
||||||
|
import type { BlockEnum } from '../../../../types'
|
||||||
|
|
||||||
|
type ChangeBlockProps = {
|
||||||
|
nodeId: string
|
||||||
|
}
|
||||||
|
const ChangeBlock = ({
|
||||||
|
nodeId,
|
||||||
|
}: ChangeBlockProps) => {
|
||||||
|
const { handleChangeCurrentNode } = useWorkflow()
|
||||||
|
|
||||||
|
const handleSelect = useCallback((type: BlockEnum) => {
|
||||||
|
handleChangeCurrentNode(nodeId, type)
|
||||||
|
}, [handleChangeCurrentNode, nodeId])
|
||||||
|
|
||||||
|
const renderTrigger = useCallback(() => {
|
||||||
|
return (
|
||||||
|
<div className='flex items-center px-3 w-[232px] h-8 text-sm text-gray-700 rounded-lg cursor-pointer hover:bg-gray-50'>
|
||||||
|
Change Block
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BlockSelector
|
||||||
|
placement='bottom-end'
|
||||||
|
offset={{
|
||||||
|
mainAxis: -36,
|
||||||
|
crossAxis: 4,
|
||||||
|
}}
|
||||||
|
onSelect={handleSelect}
|
||||||
|
trigger={renderTrigger}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(ChangeBlock)
|
||||||
@ -2,7 +2,8 @@ import {
|
|||||||
memo,
|
memo,
|
||||||
useState,
|
useState,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import { useWorkflow } from '../../../hooks'
|
import { useWorkflow } from '../../../../hooks'
|
||||||
|
import ChangeBlock from './change-block'
|
||||||
import { DotsHorizontal } from '@/app/components/base/icons/src/vender/line/general'
|
import { DotsHorizontal } from '@/app/components/base/icons/src/vender/line/general'
|
||||||
import {
|
import {
|
||||||
PortalToFollowElem,
|
PortalToFollowElem,
|
||||||
@ -43,7 +44,7 @@ const PanelOperator = ({
|
|||||||
<PortalToFollowElemContent className='z-[11]'>
|
<PortalToFollowElemContent className='z-[11]'>
|
||||||
<div className='w-[240px] border-[0.5px] border-gray-200 rounded-2xl shadow-xl bg-white'>
|
<div className='w-[240px] border-[0.5px] border-gray-200 rounded-2xl shadow-xl bg-white'>
|
||||||
<div className='p-1'>
|
<div className='p-1'>
|
||||||
<div className='flex items-center px-3 h-8 text-sm text-gray-700 rounded-lg cursor-pointer hover:bg-gray-50'>Change Block</div>
|
<ChangeBlock nodeId={nodeId} />
|
||||||
<div className='flex items-center px-3 h-8 text-sm text-gray-700 rounded-lg cursor-pointer hover:bg-gray-50'>Help Link</div>
|
<div className='flex items-center px-3 h-8 text-sm text-gray-700 rounded-lg cursor-pointer hover:bg-gray-50'>Help Link</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='h-[1px] bg-gray-100'></div>
|
<div className='h-[1px] bg-gray-100'></div>
|
||||||
Loading…
Reference in New Issue
Block a user