Commit b113711a authored by StyleZhang's avatar StyleZhang

hooks

parent 68e95305
......@@ -8,79 +8,79 @@ const initialNodes = [
{
id: '1',
type: 'custom',
position: { x: 0, y: 0 },
position: { x: 180, y: 180 },
data: { type: 'start' },
},
{
id: '2',
type: 'custom',
position: { x: 0, y: 0 },
data: {
type: 'if-else',
branches: [
{
id: 'if-true',
name: 'IS TRUE',
},
{
id: 'if-false',
name: 'IS FALSE',
},
],
},
},
{
id: '3',
type: 'custom',
position: { x: 0, y: 0 },
data: { type: 'question-classifier', sortIndexInBranches: 0 },
},
{
id: '4',
type: 'custom',
position: { x: 0, y: 0 },
data: {
type: 'if-else',
sortIndexInBranches: 1,
branches: [
{
id: 'if-true',
name: 'IS TRUE',
},
{
id: 'if-false',
name: 'IS FALSE',
},
],
},
},
// {
// id: '2',
// type: 'custom',
// position: { x: 0, y: 0 },
// data: {
// type: 'if-else',
// branches: [
// {
// id: 'if-true',
// name: 'IS TRUE',
// },
// {
// id: 'if-false',
// name: 'IS FALSE',
// },
// ],
// },
// },
// {
// id: '3',
// type: 'custom',
// position: { x: 0, y: 0 },
// data: { type: 'question-classifier', sortIndexInBranches: 0 },
// },
// {
// id: '4',
// type: 'custom',
// position: { x: 0, y: 0 },
// data: {
// type: 'if-else',
// sortIndexInBranches: 1,
// branches: [
// {
// id: 'if-true',
// name: 'IS TRUE',
// },
// {
// id: 'if-false',
// name: 'IS FALSE',
// },
// ],
// },
// },
]
const initialEdges = [
{
id: '0',
type: 'custom',
source: '1',
sourceHandle: 'source',
target: '2',
targetHandle: 'target',
},
{
id: '1',
type: 'custom',
source: '2',
sourceHandle: 'if-true',
target: '3',
targetHandle: 'target',
},
{
id: '2',
type: 'custom',
source: '2',
sourceHandle: 'if-false',
target: '4',
targetHandle: 'target',
},
// {
// id: '0',
// type: 'custom',
// source: '1',
// sourceHandle: 'source',
// target: '2',
// targetHandle: 'target',
// },
// {
// id: '1',
// type: 'custom',
// source: '2',
// sourceHandle: 'if-true',
// target: '3',
// targetHandle: 'target',
// },
// {
// id: '2',
// type: 'custom',
// source: '2',
// sourceHandle: 'if-false',
// target: '4',
// targetHandle: 'target',
// },
]
const Page: FC = () => {
......
......@@ -34,7 +34,7 @@ export const NodeInitialData = {
retrieval_mode: 'single',
},
[BlockEnum.IfElse]: {
branches: [
targetBranches: [
{
id: 'if-true',
name: 'IS TRUE',
......
......@@ -2,6 +2,7 @@ import { useCallback } from 'react'
import produce from 'immer'
import type {
EdgeMouseHandler,
NodeDragHandler,
NodeMouseHandler,
OnConnect,
} from 'reactflow'
......@@ -17,6 +18,7 @@ import type {
} from './types'
import { NodeInitialData } from './constants'
import { getLayoutByDagre } from './utils'
import { useStore } from './store'
export const useWorkflow = () => {
const store = useStoreApi()
......@@ -42,7 +44,30 @@ export const useWorkflow = () => {
setNodes(newNodes)
}, [store])
const handleEnterNode = useCallback<NodeMouseHandler>((_, node) => {
const handleNodeDragStart = useCallback<NodeDragHandler>(() => {
useStore.getState().setIsDragging(true)
}, [])
const handleNodeDrag = useCallback<NodeDragHandler>((e, node: Node) => {
const {
getNodes,
setNodes,
} = store.getState()
e.stopPropagation()
const newNodes = produce(getNodes(), (draft) => {
const currentNode = draft.find(n => n.id === node.id)!
currentNode.position = node.position
})
setNodes(newNodes)
}, [store])
const handleNodeDragStop = useCallback<NodeDragHandler>(() => {
useStore.getState().setIsDragging(false)
}, [])
const handleNodeEnter = useCallback<NodeMouseHandler>((_, node) => {
const {
getNodes,
setNodes,
......@@ -67,7 +92,7 @@ export const useWorkflow = () => {
setEdges(newEdges)
}, [store])
const handleLeaveNode = useCallback<NodeMouseHandler>((_, node) => {
const handleNodeLeave = useCallback<NodeMouseHandler>((_, node) => {
const {
getNodes,
setNodes,
......@@ -81,34 +106,37 @@ export const useWorkflow = () => {
})
setNodes(newNodes)
const newEdges = produce(edges, (draft) => {
const connectedEdges = getConnectedEdges([node], edges)
connectedEdges.forEach((edge) => {
const currentEdge = draft.find(e => e.id === edge.id)
if (currentEdge)
currentEdge.data = { ...currentEdge.data, connectedNodeIsHovering: false }
draft.forEach((edge) => {
edge.data = { ...edge.data, connectedNodeIsHovering: false }
})
})
setEdges(newEdges)
}, [store])
const handleSelectNode = useCallback((nodeId: string, cancelSelection?: boolean) => {
const handleNodeSelect = useCallback((nodeId: string, cancelSelection?: boolean) => {
const {
getNodes,
setNodes,
} = store.getState()
const newNodes = produce(getNodes(), (draft) => {
draft.forEach(node => node.selected = false)
draft.forEach(node => node.data.selected = false)
const selectedNode = draft.find(node => node.id === nodeId)!
if (!cancelSelection)
selectedNode.selected = true
selectedNode.data.selected = true
})
setNodes(newNodes)
}, [store])
const handleConnectNode = useCallback<OnConnect>(({
const handleNodeClick = useCallback<NodeMouseHandler>((_, node) => {
if (useStore.getState().isDragging)
return
handleNodeSelect(node.id)
}, [handleNodeSelect])
const handleNodeConnect = useCallback<OnConnect>(({
source,
sourceHandle,
target,
......@@ -134,51 +162,31 @@ export const useWorkflow = () => {
return filtered
})
setEdges(newEdges)
handleLayout()
}, [store, handleLayout])
const handleEnterEdge = useCallback<EdgeMouseHandler>((_, edge) => {
const {
edges,
setEdges,
} = store.getState()
const newEdges = produce(edges, (draft) => {
const currentEdge = draft.find(e => e.id === edge.id)!
currentEdge.data = { ...currentEdge.data, hovering: true }
})
setEdges(newEdges)
}, [store])
const handleLeaveEdge = useCallback<EdgeMouseHandler>((_, edge) => {
const handleNodeDelete = useCallback((nodeId: string) => {
const {
getNodes,
setNodes,
edges,
setEdges,
} = store.getState()
const newEdges = produce(edges, (draft) => {
const currentEdge = draft.find(e => e.id === edge.id)!
currentEdge.data = { ...currentEdge.data, hovering: false }
})
setEdges(newEdges)
}, [store])
const handleDeleteEdge = useCallback(() => {
const {
edges,
setEdges,
} = store.getState()
const newEdges = produce(edges, (draft) => {
const index = draft.findIndex(edge => edge.selected)
const newNodes = produce(getNodes(), (draft) => {
const index = draft.findIndex(node => node.id === nodeId)
if (index > -1)
draft.splice(index, 1)
})
setNodes(newNodes)
const connectedEdges = getConnectedEdges([{ id: nodeId } as Node], edges)
const newEdges = produce(edges, (draft) => {
return draft.filter(edge => !connectedEdges.find(connectedEdge => connectedEdge.id === edge.id))
})
setEdges(newEdges)
handleLayout()
}, [store, handleLayout])
}, [store])
const handleUpdateNodeData = useCallback(({ id, data }: SelectedNode) => {
const handleNodeDataUpdate = useCallback(({ id, data }: SelectedNode) => {
const {
getNodes,
setNodes,
......@@ -191,7 +199,7 @@ export const useWorkflow = () => {
setNodes(newNodes)
}, [store])
const handleAddNextNode = useCallback((currentNodeId: string, nodeType: BlockEnum, sourceHandle: string) => {
const handleNodeAddNext = useCallback((currentNodeId: string, nodeType: BlockEnum, sourceHandle: string) => {
const {
getNodes,
setNodes,
......@@ -203,12 +211,14 @@ export const useWorkflow = () => {
const nextNode: Node = {
id: `${Date.now()}`,
type: 'custom',
data: NodeInitialData[nodeType],
data: {
...NodeInitialData[nodeType],
selected: true,
},
position: {
x: currentNode.position.x + 304,
y: currentNode.position.y,
},
selected: true,
}
const newEdge = {
id: `${currentNode.id}-${nextNode.id}`,
......@@ -220,7 +230,7 @@ export const useWorkflow = () => {
}
const newNodes = produce(nodes, (draft) => {
draft.forEach((node) => {
node.selected = false
node.data.selected = false
})
draft.push(nextNode)
})
......@@ -231,7 +241,7 @@ export const useWorkflow = () => {
setEdges(newEdges)
}, [store])
const handleChangeCurrentNode = useCallback((currentNodeId: string, nodeType: BlockEnum, sourceHandle?: string) => {
const handleNodeChange = useCallback((currentNodeId: string, nodeType: BlockEnum, sourceHandle?: string) => {
const {
getNodes,
setNodes,
......@@ -279,40 +289,64 @@ export const useWorkflow = () => {
}
}, [store])
const handleDeleteNode = useCallback((nodeId: string) => {
const handleEdgeEnter = useCallback<EdgeMouseHandler>((_, edge) => {
const {
getNodes,
setNodes,
edges,
setEdges,
} = store.getState()
const newEdges = produce(edges, (draft) => {
const currentEdge = draft.find(e => e.id === edge.id)!
const newNodes = produce(getNodes(), (draft) => {
const index = draft.findIndex(node => node.id === nodeId)
currentEdge.data = { ...currentEdge.data, hovering: true }
})
setEdges(newEdges)
}, [store])
if (index > -1)
draft.splice(index, 1)
const handleEdgeLeave = useCallback<EdgeMouseHandler>((_, edge) => {
const {
edges,
setEdges,
} = store.getState()
const newEdges = produce(edges, (draft) => {
const currentEdge = draft.find(e => e.id === edge.id)!
currentEdge.data = { ...currentEdge.data, hovering: false }
})
setNodes(newNodes)
const connectedEdges = getConnectedEdges([{ id: nodeId } as Node], edges)
setEdges(newEdges)
}, [store])
const handleEdgeDelete = useCallback(() => {
const {
edges,
setEdges,
} = store.getState()
const newEdges = produce(edges, (draft) => {
return draft.filter(edge => !connectedEdges.find(connectedEdge => connectedEdge.id === edge.id))
const index = draft.findIndex(edge => edge.selected)
if (index > -1)
draft.splice(index, 1)
})
setEdges(newEdges)
}, [store])
return {
handleEnterNode,
handleLeaveNode,
handleSelectNode,
handleEnterEdge,
handleLeaveEdge,
handleConnectNode,
handleDeleteEdge,
handleUpdateNodeData,
handleAddNextNode,
handleChangeCurrentNode,
handleDeleteNode,
handleLayout,
handleNodeDragStart,
handleNodeDrag,
handleNodeDragStop,
handleNodeEnter,
handleNodeLeave,
handleNodeSelect,
handleNodeClick,
handleNodeConnect,
handleNodeDelete,
handleNodeDataUpdate,
handleNodeAddNext,
handleNodeChange,
handleEdgeEnter,
handleEdgeLeave,
handleEdgeDelete,
}
}
import type { FC } from 'react'
import { memo, useEffect } from 'react'
import {
memo,
// useEffect,
} from 'react'
import { useKeyPress } from 'ahooks'
import ReactFlow, {
Background,
ReactFlowProvider,
useEdgesState,
useNodesInitialized,
// useNodesInitialized,
useNodesState,
} from 'reactflow'
import 'reactflow/dist/style.css'
import './style.css'
// import './style.css'
import type {
Edge,
Node,
......@@ -42,24 +45,32 @@ const Workflow: FC<WorkflowProps> = memo(({
const showFeaturesPanel = useStore(state => state.showFeaturesPanel)
const [nodes] = useNodesState(initialNodes)
const [edges, _, onEdgesChange] = useEdgesState(initialEdges)
const nodesInitialized = useNodesInitialized()
// const nodesInitialized = useNodesInitialized()
console.log(nodes)
const {
handleEnterNode,
handleLeaveNode,
handleConnectNode,
handleEnterEdge,
handleLeaveEdge,
handleDeleteEdge,
handleLayout,
// handleLayout,
handleNodeDragStart,
handleNodeDrag,
handleNodeDragStop,
handleNodeEnter,
handleNodeLeave,
handleNodeClick,
handleNodeConnect,
handleEdgeEnter,
handleEdgeLeave,
handleEdgeDelete,
} = useWorkflow()
useEffect(() => {
if (nodesInitialized)
handleLayout()
}, [nodesInitialized, handleLayout])
// useEffect(() => {
// if (nodesInitialized)
// handleLayout()
// }, [nodesInitialized, handleLayout])
useKeyPress('Backspace', handleDeleteEdge)
useKeyPress('Backspace', handleEdgeDelete)
return (
<div className='relative w-full h-full'>
......@@ -74,11 +85,15 @@ const Workflow: FC<WorkflowProps> = memo(({
edgeTypes={edgeTypes}
nodes={nodes}
edges={edges}
onConnect={handleConnectNode}
onNodeMouseEnter={handleEnterNode}
onNodeMouseLeave={handleLeaveNode}
onEdgeMouseEnter={handleEnterEdge}
onEdgeMouseLeave={handleLeaveEdge}
onNodeDragStart={handleNodeDragStart}
onNodeDrag={handleNodeDrag}
onNodeDragStop={handleNodeDragStop}
onNodeMouseEnter={handleNodeEnter}
onNodeMouseLeave={handleNodeLeave}
onNodeClick={handleNodeClick}
onConnect={handleNodeConnect}
onEdgeMouseEnter={handleEdgeEnter}
onEdgeMouseLeave={handleEdgeLeave}
onEdgesChange={onEdgesChange}
multiSelectionKeyCode={null}
connectionLineComponent={CustomConnectionLine}
......
......@@ -17,11 +17,11 @@ const Add = ({
sourceHandle,
branchName,
}: AddProps) => {
const { handleAddNextNode } = useWorkflow()
const { handleNodeAddNext } = useWorkflow()
const handleSelect = useCallback((type: BlockEnum) => {
handleAddNextNode(nodeId, type, sourceHandle)
}, [nodeId, sourceHandle, handleAddNextNode])
handleNodeAddNext(nodeId, type, sourceHandle)
}, [nodeId, sourceHandle, handleNodeAddNext])
const renderTrigger = useCallback((open: boolean) => {
return (
......
......@@ -18,7 +18,7 @@ const NextStep = ({
selectedNode,
}: NextStepProps) => {
const store = useStoreApi()
const branches = selectedNode?.data.branches
const branches = selectedNode?.data.targetBranches
const edges = useEdges()
const outgoers = getOutgoers(selectedNode as Node, store.getState().getNodes(), edges)
const connectedEdges = getConnectedEdges([selectedNode] as Node[], edges).filter(edge => edge.source === selectedNode!.id)
......
......@@ -23,10 +23,10 @@ const Item = ({
branchName,
data,
}: ItemProps) => {
const { handleChangeCurrentNode } = useWorkflow()
const { handleNodeChange } = useWorkflow()
const handleSelect = useCallback((type: BlockEnum) => {
handleChangeCurrentNode(nodeId, type, sourceHandle)
}, [nodeId, sourceHandle, handleChangeCurrentNode])
handleNodeChange(nodeId, type, sourceHandle)
}, [nodeId, sourceHandle, handleNodeChange])
const renderTrigger = useCallback((open: boolean) => {
return (
<Button
......
......@@ -88,7 +88,7 @@ export const NodeSourceHandle = ({
nodeSelectorClassName,
}: NodeHandleProps) => {
const [open, setOpen] = useState(false)
const { handleAddNextNode } = useWorkflow()
const { handleNodeAddNext } = useWorkflow()
const edges = useEdges()
const connectedEdges = getConnectedEdges([{ id } as Node], edges)
const connected = connectedEdges.find(edge => edge.sourceHandle === handleId && edge.source === id)
......@@ -101,8 +101,8 @@ export const NodeSourceHandle = ({
setOpen(v => !v)
}, [connected])
const handleSelect = useCallback((type: BlockEnum) => {
handleAddNextNode(id, type, handleId)
}, [handleAddNextNode, id, handleId])
handleNodeAddNext(id, type, handleId)
}, [handleNodeAddNext, id, handleId])
return (
<>
......
......@@ -12,11 +12,11 @@ type ChangeBlockProps = {
const ChangeBlock = ({
nodeId,
}: ChangeBlockProps) => {
const { handleChangeCurrentNode } = useWorkflow()
const { handleNodeChange } = useWorkflow()
const handleSelect = useCallback((type: BlockEnum) => {
handleChangeCurrentNode(nodeId, type)
}, [handleChangeCurrentNode, nodeId])
handleNodeChange(nodeId, type)
}, [handleNodeChange, nodeId])
const renderTrigger = useCallback(() => {
return (
......
......@@ -17,7 +17,7 @@ type PanelOperatorProps = {
const PanelOperator = ({
nodeId,
}: PanelOperatorProps) => {
const { handleDeleteNode } = useWorkflow()
const { handleNodeDelete } = useWorkflow()
const [open, setOpen] = useState(false)
return (
......@@ -51,7 +51,7 @@ const PanelOperator = ({
<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'
onClick={() => handleDeleteNode(nodeId)}
onClick={() => handleNodeDelete(nodeId)}
>
Delete
</div>
......
......@@ -8,7 +8,6 @@ import {
} from 'react'
import type { NodeProps } from 'reactflow'
import BlockIcon from '../../block-icon'
import { useWorkflow } from '../../hooks'
type BaseNodeProps = {
children: ReactElement
......@@ -17,19 +16,15 @@ type BaseNodeProps = {
const BaseNode: FC<BaseNodeProps> = ({
id,
data,
selected,
children,
}) => {
const { handleSelectNode } = useWorkflow()
return (
<div
className={`
group relative w-[240px] bg-[#fcfdff] rounded-2xl shadow-xs
hover:shadow-lg
${selected ? 'border-[2px] border-primary-600' : 'border border-white'}
${data.selected ? 'border-[2px] border-primary-600' : 'border border-white'}
`}
onClick={() => handleSelectNode(id)}
>
<div className='flex items-center px-3 pt-3 pb-2'>
<BlockIcon
......
......@@ -34,15 +34,15 @@ const BasePanel: FC<BasePanelProps> = ({
children,
}) => {
const {
handleSelectNode,
handleUpdateNodeData,
handleNodeSelect,
handleNodeDataUpdate,
} = useWorkflow()
const handleTitleChange = useCallback((title: string) => {
handleUpdateNodeData({ id, data: { ...data, title } })
}, [handleUpdateNodeData, id, data])
handleNodeDataUpdate({ id, data: { ...data, title } })
}, [handleNodeDataUpdate, id, data])
const handleDescriptionChange = useCallback((desc: string) => {
handleUpdateNodeData({ id, data: { ...data, desc } })
}, [handleUpdateNodeData, id, data])
handleNodeDataUpdate({ id, data: { ...data, desc } })
}, [handleNodeDataUpdate, id, data])
return (
<div className='mr-2 w-[420px] h-full bg-white shadow-lg border-[0.5px] border-gray-200 rounded-2xl overflow-y-auto'>
......@@ -73,7 +73,7 @@ const BasePanel: FC<BasePanelProps> = ({
<div className='mx-3 w-[1px] h-3.5 bg-gray-200' />
<div
className='flex items-center justify-center w-6 h-6 cursor-pointer'
onClick={() => handleSelectNode(id, true)}
onClick={() => handleNodeSelect(id, true)}
>
<XClose className='w-4 h-4' />
</div>
......
......@@ -16,7 +16,7 @@ const Panel: FC = () => {
const mode = useStore(state => state.mode)
const runStaus = useStore(state => state.runStaus)
const nodes = useNodes<CommonNodeType>()
const selectedNode = nodes.find(node => node.selected)
const selectedNode = nodes.find(node => node.data.selected)
const showRunHistory = useStore(state => state.showRunHistory)
const {
showWorkflowInfoPanel,
......
......@@ -5,12 +5,14 @@ type State = {
showRunHistory: boolean
showFeaturesPanel: boolean
runStaus: string
isDragging: boolean
}
type Action = {
setShowRunHistory: (showRunHistory: boolean) => void
setShowFeaturesPanel: (showFeaturesPanel: boolean) => void
setRunStaus: (runStaus: string) => void
setIsDragging: (isDragging: boolean) => void
}
export const useStore = create<State & Action>(set => ({
......@@ -21,4 +23,6 @@ export const useStore = create<State & Action>(set => ({
setShowFeaturesPanel: showFeaturesPanel => set(() => ({ showFeaturesPanel })),
runStaus: '',
setRunStaus: runStaus => set(() => ({ runStaus })),
isDragging: false,
setIsDragging: isDragging => set(() => ({ isDragging })),
}))
......@@ -28,6 +28,7 @@ export type CommonNodeType = {
x: number
y: number
}
selected?: boolean
hovering?: boolean
targetBranches?: Branch[]
title: string
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment