From 0ae75025b6e8744323bbea2b9d8b006a3e53f97b Mon Sep 17 00:00:00 2001
From: braks <78412429+bcakmakoglu@users.noreply.github.com>
Date: Tue, 6 Feb 2024 12:39:02 +0100
Subject: [PATCH] examples: add example for running a process tree
---
.../vite/src/Layouting/LayoutingExample.vue | 80 +++++++++++------
examples/vite/src/Layouting/ProcessNode.vue | 69 +++++++++++++++
.../vite/src/Layouting/initial-elements.ts | 58 ++++++------
examples/vite/src/Layouting/useRunProcess.ts | 88 +++++++++++++++++++
4 files changed, 239 insertions(+), 56 deletions(-)
create mode 100644 examples/vite/src/Layouting/ProcessNode.vue
create mode 100644 examples/vite/src/Layouting/useRunProcess.ts
diff --git a/examples/vite/src/Layouting/LayoutingExample.vue b/examples/vite/src/Layouting/LayoutingExample.vue
index f847e40d..d6707b0f 100644
--- a/examples/vite/src/Layouting/LayoutingExample.vue
+++ b/examples/vite/src/Layouting/LayoutingExample.vue
@@ -1,57 +1,79 @@
-
+
+
+
+
+
-
-
+
+
+
+
diff --git a/examples/vite/src/Layouting/ProcessNode.vue b/examples/vite/src/Layouting/ProcessNode.vue
new file mode 100644
index 00000000..d61941eb
--- /dev/null
+++ b/examples/vite/src/Layouting/ProcessNode.vue
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
diff --git a/examples/vite/src/Layouting/initial-elements.ts b/examples/vite/src/Layouting/initial-elements.ts
index 85018764..962746cc 100644
--- a/examples/vite/src/Layouting/initial-elements.ts
+++ b/examples/vite/src/Layouting/initial-elements.ts
@@ -1,71 +1,75 @@
-import type { Elements, XYPosition } from '@vue-flow/core'
+import type { Edge, Node } from '@vue-flow/core'
-const position: XYPosition = { x: 0, y: 0 }
+const position = { x: 0, y: 0 }
+const type: string = 'process'
-const elements: Elements = [
+export const initialNodes: Node[] = [
{
id: '1',
- type: 'input',
- label: 'input',
+ label: 'Start',
position,
+ type,
},
{
id: '2',
- label: 'node 2',
position,
+ type,
},
{
id: '2a',
- label: 'node 2a',
position,
+ type,
},
{
id: '2b',
- label: 'node 2b',
position,
+ type,
},
{
id: '2c',
- label: 'node 2c',
position,
+ type,
},
{
id: '2d',
- label: 'node 2d',
position,
+ type,
},
{
id: '3',
- label: 'node 3',
position,
+ type,
},
{
id: '4',
- label: 'node 4',
position,
+ type,
},
{
id: '5',
- label: 'node 5',
position,
+ type,
},
{
id: '6',
- type: 'output',
- label: 'output',
position,
+ type,
+ },
+ {
+ id: '7',
+ position,
+ type,
},
- { id: '7', type: 'output', label: 'output', position: { x: 400, y: 450 } },
- { id: 'e12', source: '1', target: '2', type: 'smoothstep', animated: true },
- { id: 'e13', source: '1', target: '3', type: 'smoothstep', animated: true },
- { id: 'e22a', source: '2', target: '2a', type: 'smoothstep', animated: true },
- { id: 'e22b', source: '2', target: '2b', type: 'smoothstep', animated: true },
- { id: 'e22c', source: '2', target: '2c', type: 'smoothstep', animated: true },
- { id: 'e2c2d', source: '2c', target: '2d', type: 'smoothstep', animated: true },
-
- { id: 'e45', source: '4', target: '5', type: 'smoothstep', animated: true },
- { id: 'e56', source: '5', target: '6', type: 'smoothstep', animated: true },
- { id: 'e57', source: '5', target: '7', type: 'smoothstep', animated: true },
]
-export default elements
+export const initialEdges: Edge[] = [
+ { id: 'e1-2', source: '1', target: '2', type: 'smoothstep', animated: true },
+ { id: 'e1-3', source: '1', target: '3', type: 'smoothstep', animated: true },
+ { id: 'e2-2a', source: '2', target: '2a', type: 'smoothstep', animated: true },
+ { id: 'e2-2b', source: '2', target: '2b', type: 'smoothstep', animated: true },
+ { id: 'e2-2c', source: '2', target: '2c', type: 'smoothstep', animated: true },
+ { id: 'e2c-2d', source: '2c', target: '2d', type: 'smoothstep', animated: true },
+ { id: 'e4-5', source: '4', target: '5', type: 'smoothstep', animated: true },
+ { id: 'e5-6', source: '5', target: '6', type: 'smoothstep', animated: true },
+ { id: 'e5-7', source: '5', target: '7', type: 'smoothstep', animated: true },
+]
diff --git a/examples/vite/src/Layouting/useRunProcess.ts b/examples/vite/src/Layouting/useRunProcess.ts
new file mode 100644
index 00000000..add31528
--- /dev/null
+++ b/examples/vite/src/Layouting/useRunProcess.ts
@@ -0,0 +1,88 @@
+import type { Node } from '@vue-flow/core'
+import { useVueFlow } from '@vue-flow/core'
+
+/**
+ * Composable to simulate running a process tree.
+ *
+ * It loops through each node, pretends to run an async process, and updates the node's data indicating whether the process has finished.
+ * When one node finishes, the next one starts.
+ *
+ * When a node has multiple descendants, it will run them in parallel.
+ */
+export function useRunProcess() {
+ const { updateNodeData } = useVueFlow()
+
+ const running = ref(false)
+ const executedNodes = new Set()
+
+ async function runNode(node: { id: string }, dagreGraph: dagre.graphlib.Graph) {
+ if (executedNodes.has(node.id)) {
+ return
+ }
+
+ executedNodes.add(node.id)
+
+ updateNodeData(node.id, { isRunning: true, isFinished: false, hasError: false })
+
+ // Simulate an async process with a random timeout between 1 and 3 seconds
+ const delay = Math.floor(Math.random() * 2000) + 1000
+ await new Promise((resolve) => setTimeout(resolve, delay))
+
+ const children = dagreGraph.successors(node.id) as unknown as string[]
+
+ // Randomly decide whether the node will throw an error
+ const willThrowError = Math.random() < 0.15
+
+ if (willThrowError) {
+ updateNodeData(node.id, { isRunning: false, hasError: true })
+
+ await skipDescendants(node.id, dagreGraph)
+ return
+ }
+
+ updateNodeData(node.id, { isRunning: false, isFinished: true })
+
+ // Run the process on the children in parallel
+ await Promise.all(
+ children.map((id) => {
+ return runNode({ id }, dagreGraph)
+ }),
+ )
+ }
+
+ async function run(nodes: Node[], dagreGraph: dagre.graphlib.Graph) {
+ if (running.value) {
+ return
+ }
+
+ reset(nodes)
+
+ running.value = true
+
+ // Get all starting nodes (nodes with no predecessors)
+ const startingNodes = nodes.filter((node) => dagreGraph.predecessors(node.id)?.length === 0)
+
+ // Run the process on all starting nodes in parallel
+ await Promise.all(startingNodes.map((node) => runNode(node, dagreGraph)))
+
+ running.value = false
+ executedNodes.clear()
+ }
+
+ function reset(nodes: Node[]) {
+ for (const node of nodes) {
+ updateNodeData(node.id, { isRunning: false, isFinished: false, hasError: false, isSkipped: false })
+ }
+ }
+
+ async function skipDescendants(nodeId: string, dagreGraph: dagre.graphlib.Graph) {
+ const children = dagreGraph.successors(nodeId) as unknown as string[]
+
+ for (const child of children) {
+ updateNodeData(child, { isRunning: false, isSkipped: true })
+ await skipDescendants(child, dagreGraph)
+ }
+ }
+
+ return { run, running }
+}