mirror of
https://github.com/langgenius/dify.git
synced 2026-05-04 17:38:04 +08:00
layout
This commit is contained in:
@ -8,13 +8,13 @@ const initialNodes = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'custom',
|
||||
position: { x: 130, y: 130 },
|
||||
position: { x: 0, y: 0 },
|
||||
data: { type: 'start' },
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'custom',
|
||||
position: { x: 434, y: 130 },
|
||||
position: { x: 0, y: 0 },
|
||||
data: {
|
||||
type: 'if-else',
|
||||
branches: [
|
||||
@ -32,21 +32,28 @@ const initialNodes = [
|
||||
{
|
||||
id: '3',
|
||||
type: 'custom',
|
||||
position: { x: 738, y: 130 },
|
||||
position: { x: 0, y: 0 },
|
||||
data: { type: 'question-classifier', sortIndexInBranches: 0 },
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
type: 'custom',
|
||||
position: { x: 738, y: 330 },
|
||||
data: { type: 'variable-assigner', sortIndexInBranches: 1 },
|
||||
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: '5',
|
||||
// type: 'custom',
|
||||
// position: { x: 1100, y: 130 },
|
||||
// data: { type: 'llm' },
|
||||
// },
|
||||
]
|
||||
|
||||
const initialEdges = [
|
||||
@ -57,7 +64,6 @@ const initialEdges = [
|
||||
sourceHandle: 'source',
|
||||
target: '2',
|
||||
targetHandle: 'target',
|
||||
deletable: false,
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
|
||||
@ -16,10 +16,32 @@ import type {
|
||||
SelectedNode,
|
||||
} from './types'
|
||||
import { NodeInitialData } from './constants'
|
||||
import { getLayoutByDagre } from './utils'
|
||||
|
||||
export const useWorkflow = () => {
|
||||
const store = useStoreApi()
|
||||
|
||||
const handleLayout = useCallback(async () => {
|
||||
const {
|
||||
getNodes,
|
||||
edges,
|
||||
setNodes,
|
||||
} = store.getState()
|
||||
|
||||
const layout = getLayoutByDagre(getNodes(), edges)
|
||||
|
||||
const newNodes = produce(getNodes(), (draft) => {
|
||||
draft.forEach((node) => {
|
||||
const nodeWithPosition = layout.node(node.id)
|
||||
node.position = {
|
||||
x: nodeWithPosition.x,
|
||||
y: nodeWithPosition.y,
|
||||
}
|
||||
})
|
||||
})
|
||||
setNodes(newNodes)
|
||||
}, [store])
|
||||
|
||||
const handleEnterNode = useCallback<NodeMouseHandler>((_, node) => {
|
||||
const {
|
||||
getNodes,
|
||||
@ -112,7 +134,8 @@ export const useWorkflow = () => {
|
||||
return filtered
|
||||
})
|
||||
setEdges(newEdges)
|
||||
}, [store])
|
||||
handleLayout()
|
||||
}, [store, handleLayout])
|
||||
|
||||
const handleEnterEdge = useCallback<EdgeMouseHandler>((_, edge) => {
|
||||
const {
|
||||
@ -152,7 +175,8 @@ export const useWorkflow = () => {
|
||||
draft.splice(index, 1)
|
||||
})
|
||||
setEdges(newEdges)
|
||||
}, [store])
|
||||
handleLayout()
|
||||
}, [store, handleLayout])
|
||||
|
||||
const handleUpdateNodeData = useCallback(({ id, data }: SelectedNode) => {
|
||||
const {
|
||||
@ -182,7 +206,7 @@ export const useWorkflow = () => {
|
||||
data: NodeInitialData[nodeType],
|
||||
position: {
|
||||
x: currentNode.position.x + 304,
|
||||
y: currentNode.position.y,
|
||||
y: 0,
|
||||
},
|
||||
selected: true,
|
||||
}
|
||||
@ -289,5 +313,6 @@ export const useWorkflow = () => {
|
||||
handleAddNextNode,
|
||||
handleChangeCurrentNode,
|
||||
handleDeleteNode,
|
||||
handleLayout,
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import ReactFlow, {
|
||||
useNodesState,
|
||||
} from 'reactflow'
|
||||
import 'reactflow/dist/style.css'
|
||||
import './style.css'
|
||||
import type {
|
||||
Edge,
|
||||
Node,
|
||||
@ -41,11 +42,6 @@ const Workflow: FC<WorkflowProps> = memo(({
|
||||
const [edges, _, onEdgesChange] = useEdgesState(initialEdges)
|
||||
const nodesInitialized = useNodesInitialized()
|
||||
|
||||
useEffect(() => {
|
||||
if (nodesInitialized)
|
||||
console.log('initialed')
|
||||
}, [nodesInitialized])
|
||||
|
||||
const {
|
||||
handleEnterNode,
|
||||
handleLeaveNode,
|
||||
@ -53,8 +49,14 @@ const Workflow: FC<WorkflowProps> = memo(({
|
||||
handleEnterEdge,
|
||||
handleLeaveEdge,
|
||||
handleDeleteEdge,
|
||||
handleLayout,
|
||||
} = useWorkflow()
|
||||
|
||||
useEffect(() => {
|
||||
if (nodesInitialized)
|
||||
handleLayout()
|
||||
}, [nodesInitialized, handleLayout])
|
||||
|
||||
useKeyPress('Backspace', handleDeleteEdge)
|
||||
|
||||
return (
|
||||
|
||||
3
web/app/components/workflow/style.css
Normal file
3
web/app/components/workflow/style.css
Normal file
@ -0,0 +1,3 @@
|
||||
.react-flow__node {
|
||||
transition: transform 0.2s ease-in-out;
|
||||
}
|
||||
@ -3,6 +3,7 @@ import {
|
||||
getConnectedEdges,
|
||||
getOutgoers,
|
||||
} from 'reactflow'
|
||||
import dagre from 'dagre'
|
||||
import type {
|
||||
Edge,
|
||||
Node,
|
||||
@ -118,3 +119,26 @@ export const getNodesPositionMap = (nodes: Node[], edges: Edge[]) => {
|
||||
|
||||
return positionMap
|
||||
}
|
||||
|
||||
export const getLayoutByDagre = (nodes: Node[], edges: Edge[]) => {
|
||||
const dagreGraph = new dagre.graphlib.Graph()
|
||||
dagreGraph.setGraph({
|
||||
rankdir: 'LR',
|
||||
align: 'UL',
|
||||
nodesep: 40,
|
||||
ranksep: 64,
|
||||
})
|
||||
nodes.forEach((node) => {
|
||||
dagreGraph.setNode(node.id, { width: node.width, height: node.height })
|
||||
})
|
||||
|
||||
edges.forEach((edge) => {
|
||||
dagreGraph.setEdge(edge.source, edge.target, {
|
||||
weight: edge?.data?.weight || 1,
|
||||
})
|
||||
})
|
||||
|
||||
dagre.layout(dagreGraph)
|
||||
|
||||
return dagreGraph
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user