Commit 0acb2db9 authored by StyleZhang's avatar StyleZhang

layout

parent 74d26764
...@@ -8,13 +8,13 @@ const initialNodes = [ ...@@ -8,13 +8,13 @@ const initialNodes = [
{ {
id: '1', id: '1',
type: 'custom', type: 'custom',
position: { x: 130, y: 130 }, position: { x: 0, y: 0 },
data: { type: 'start' }, data: { type: 'start' },
}, },
{ {
id: '2', id: '2',
type: 'custom', type: 'custom',
position: { x: 434, y: 130 }, position: { x: 0, y: 0 },
data: { data: {
type: 'if-else', type: 'if-else',
branches: [ branches: [
...@@ -32,21 +32,28 @@ const initialNodes = [ ...@@ -32,21 +32,28 @@ const initialNodes = [
{ {
id: '3', id: '3',
type: 'custom', type: 'custom',
position: { x: 738, y: 130 }, position: { x: 0, y: 0 },
data: { type: 'question-classifier', sortIndexInBranches: 0 }, data: { type: 'question-classifier', sortIndexInBranches: 0 },
}, },
{ {
id: '4', id: '4',
type: 'custom', type: 'custom',
position: { x: 738, y: 330 }, position: { x: 0, y: 0 },
data: { type: 'variable-assigner', sortIndexInBranches: 1 }, 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 = [ const initialEdges = [
...@@ -57,7 +64,6 @@ const initialEdges = [ ...@@ -57,7 +64,6 @@ const initialEdges = [
sourceHandle: 'source', sourceHandle: 'source',
target: '2', target: '2',
targetHandle: 'target', targetHandle: 'target',
deletable: false,
}, },
{ {
id: '1', id: '1',
......
...@@ -16,10 +16,32 @@ import type { ...@@ -16,10 +16,32 @@ import type {
SelectedNode, SelectedNode,
} from './types' } from './types'
import { NodeInitialData } from './constants' import { NodeInitialData } from './constants'
import { getLayoutByDagre } from './utils'
export const useWorkflow = () => { export const useWorkflow = () => {
const store = useStoreApi() 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 handleEnterNode = useCallback<NodeMouseHandler>((_, node) => {
const { const {
getNodes, getNodes,
...@@ -112,7 +134,8 @@ export const useWorkflow = () => { ...@@ -112,7 +134,8 @@ export const useWorkflow = () => {
return filtered return filtered
}) })
setEdges(newEdges) setEdges(newEdges)
}, [store]) handleLayout()
}, [store, handleLayout])
const handleEnterEdge = useCallback<EdgeMouseHandler>((_, edge) => { const handleEnterEdge = useCallback<EdgeMouseHandler>((_, edge) => {
const { const {
...@@ -152,7 +175,8 @@ export const useWorkflow = () => { ...@@ -152,7 +175,8 @@ export const useWorkflow = () => {
draft.splice(index, 1) draft.splice(index, 1)
}) })
setEdges(newEdges) setEdges(newEdges)
}, [store]) handleLayout()
}, [store, handleLayout])
const handleUpdateNodeData = useCallback(({ id, data }: SelectedNode) => { const handleUpdateNodeData = useCallback(({ id, data }: SelectedNode) => {
const { const {
...@@ -182,7 +206,7 @@ export const useWorkflow = () => { ...@@ -182,7 +206,7 @@ export const useWorkflow = () => {
data: NodeInitialData[nodeType], data: NodeInitialData[nodeType],
position: { position: {
x: currentNode.position.x + 304, x: currentNode.position.x + 304,
y: currentNode.position.y, y: 0,
}, },
selected: true, selected: true,
} }
...@@ -289,5 +313,6 @@ export const useWorkflow = () => { ...@@ -289,5 +313,6 @@ export const useWorkflow = () => {
handleAddNextNode, handleAddNextNode,
handleChangeCurrentNode, handleChangeCurrentNode,
handleDeleteNode, handleDeleteNode,
handleLayout,
} }
} }
...@@ -9,6 +9,7 @@ import ReactFlow, { ...@@ -9,6 +9,7 @@ import ReactFlow, {
useNodesState, useNodesState,
} from 'reactflow' } from 'reactflow'
import 'reactflow/dist/style.css' import 'reactflow/dist/style.css'
import './style.css'
import type { import type {
Edge, Edge,
Node, Node,
...@@ -41,11 +42,6 @@ const Workflow: FC<WorkflowProps> = memo(({ ...@@ -41,11 +42,6 @@ const Workflow: FC<WorkflowProps> = memo(({
const [edges, _, onEdgesChange] = useEdgesState(initialEdges) const [edges, _, onEdgesChange] = useEdgesState(initialEdges)
const nodesInitialized = useNodesInitialized() const nodesInitialized = useNodesInitialized()
useEffect(() => {
if (nodesInitialized)
console.log('initialed')
}, [nodesInitialized])
const { const {
handleEnterNode, handleEnterNode,
handleLeaveNode, handleLeaveNode,
...@@ -53,8 +49,14 @@ const Workflow: FC<WorkflowProps> = memo(({ ...@@ -53,8 +49,14 @@ const Workflow: FC<WorkflowProps> = memo(({
handleEnterEdge, handleEnterEdge,
handleLeaveEdge, handleLeaveEdge,
handleDeleteEdge, handleDeleteEdge,
handleLayout,
} = useWorkflow() } = useWorkflow()
useEffect(() => {
if (nodesInitialized)
handleLayout()
}, [nodesInitialized, handleLayout])
useKeyPress('Backspace', handleDeleteEdge) useKeyPress('Backspace', handleDeleteEdge)
return ( return (
......
.react-flow__node {
transition: transform 0.2s ease-in-out;
}
\ No newline at end of file
...@@ -3,6 +3,7 @@ import { ...@@ -3,6 +3,7 @@ import {
getConnectedEdges, getConnectedEdges,
getOutgoers, getOutgoers,
} from 'reactflow' } from 'reactflow'
import dagre from 'dagre'
import type { import type {
Edge, Edge,
Node, Node,
...@@ -118,3 +119,26 @@ export const getNodesPositionMap = (nodes: Node[], edges: Edge[]) => { ...@@ -118,3 +119,26 @@ export const getNodesPositionMap = (nodes: Node[], edges: Edge[]) => {
return positionMap 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
}
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
"classnames": "^2.3.2", "classnames": "^2.3.2",
"copy-to-clipboard": "^3.3.3", "copy-to-clipboard": "^3.3.3",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"dagre": "^0.8.5",
"dayjs": "^1.11.7", "dayjs": "^1.11.7",
"echarts": "^5.4.1", "echarts": "^5.4.1",
"echarts-for-react": "^3.0.2", "echarts-for-react": "^3.0.2",
...@@ -87,6 +88,7 @@ ...@@ -87,6 +88,7 @@
"@faker-js/faker": "^7.6.0", "@faker-js/faker": "^7.6.0",
"@rgrove/parse-xml": "^4.1.0", "@rgrove/parse-xml": "^4.1.0",
"@types/crypto-js": "^4.1.1", "@types/crypto-js": "^4.1.1",
"@types/dagre": "^0.7.52",
"@types/js-cookie": "^3.0.3", "@types/js-cookie": "^3.0.3",
"@types/lodash-es": "^4.17.7", "@types/lodash-es": "^4.17.7",
"@types/negotiator": "^0.6.1", "@types/negotiator": "^0.6.1",
......
...@@ -919,6 +919,11 @@ ...@@ -919,6 +919,11 @@
"@types/d3-transition" "*" "@types/d3-transition" "*"
"@types/d3-zoom" "*" "@types/d3-zoom" "*"
"@types/dagre@^0.7.52":
version "0.7.52"
resolved "https://registry.npmjs.org/@types/dagre/-/dagre-0.7.52.tgz"
integrity sha512-XKJdy+OClLk3hketHi9Qg6gTfe1F3y+UFnHxKA2rn9Dw+oXa4Gb378Ztz9HlMgZKSxpPmn4BNVh9wgkpvrK1uw==
"@types/debug@^4.0.0": "@types/debug@^4.0.0":
version "4.1.8" version "4.1.8"
resolved "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz" resolved "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz"
...@@ -2289,6 +2294,14 @@ dagre-d3-es@7.0.10: ...@@ -2289,6 +2294,14 @@ dagre-d3-es@7.0.10:
d3 "^7.8.2" d3 "^7.8.2"
lodash-es "^4.17.21" lodash-es "^4.17.21"
dagre@^0.8.5:
version "0.8.5"
resolved "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz"
integrity sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==
dependencies:
graphlib "^2.1.8"
lodash "^4.17.15"
damerau-levenshtein@^1.0.8: damerau-levenshtein@^1.0.8:
version "1.0.8" version "1.0.8"
resolved "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz" resolved "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz"
...@@ -3374,6 +3387,13 @@ graphemer@^1.4.0: ...@@ -3374,6 +3387,13 @@ graphemer@^1.4.0:
resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz" resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz"
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
graphlib@^2.1.8:
version "2.1.8"
resolved "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz"
integrity sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==
dependencies:
lodash "^4.17.15"
has-bigints@^1.0.1, has-bigints@^1.0.2: has-bigints@^1.0.1, has-bigints@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz" resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz"
...@@ -4384,7 +4404,7 @@ lodash.values@^4.3.0: ...@@ -4384,7 +4404,7 @@ lodash.values@^4.3.0:
resolved "https://registry.npmjs.org/lodash.values/-/lodash.values-4.3.0.tgz" resolved "https://registry.npmjs.org/lodash.values/-/lodash.values-4.3.0.tgz"
integrity sha512-r0RwvdCv8id9TUblb/O7rYPwVy6lerCbcawrfdo9iC/1t1wsNMJknO79WNBgwkH0hIeJ08jmvvESbFpNb4jH0Q== integrity sha512-r0RwvdCv8id9TUblb/O7rYPwVy6lerCbcawrfdo9iC/1t1wsNMJknO79WNBgwkH0hIeJ08jmvvESbFpNb4jH0Q==
lodash@^4.17.21: lodash@^4.17.15, lodash@^4.17.21:
version "4.17.21" version "4.17.21"
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
......
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