-
-
Notifications
You must be signed in to change notification settings - Fork 239
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: add run process to layouting example
- Loading branch information
1 parent
0ae7502
commit 7bd2996
Showing
6 changed files
with
213 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,7 @@ import { IntersectionApp, IntersectionCSS } from './intersection' | |
import { SnapToHandleApp, SnappableConnectionLine } from './connection-radius' | ||
import { NodeResizerApp, ResizableNode } from './node-resizer' | ||
import { ToolbarApp, ToolbarNode } from './node-toolbar' | ||
import { LayoutApp, LayoutElements } from './layout' | ||
import { LayoutApp, LayoutElements, LayoutNode, LayoutScript } from './layout' | ||
|
||
export const exampleImports = { | ||
basic: { | ||
|
@@ -127,6 +127,8 @@ export const exampleImports = { | |
layout: { | ||
'App.vue': LayoutApp, | ||
'initial-elements.js': LayoutElements, | ||
'ProcessNode.vue': LayoutNode, | ||
'useRunProcess.js': LayoutScript, | ||
'additionalImports': { | ||
dagre: 'https://cdn.skypack.dev/pin/[email protected]/mode=imports,min/optimized/dagre.js', | ||
}, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
<script setup> | ||
import { toRef } from 'vue' | ||
import { Handle } from '@vue-flow/core' | ||
const props = defineProps({ | ||
data: { | ||
type: Object, | ||
required: true, | ||
}, | ||
sourcePosition: { | ||
type: String, | ||
}, | ||
targetPosition: { | ||
type: String, | ||
}, | ||
}) | ||
const bgColor = toRef(() => { | ||
if (props.data.hasError) { | ||
return '#f87171' | ||
} | ||
if (props.data.isFinished) { | ||
return '#10b981' | ||
} | ||
if (props.data.isRunning || props.data.isSkipped) { | ||
// pick me a lighter color please | ||
return '#6b7280' | ||
} | ||
return '#1a192b' | ||
}) | ||
</script> | ||
|
||
<template> | ||
<div class="process-node" :style="{ backgroundColor: bgColor }"> | ||
<Handle type="target" :position="targetPosition" /> | ||
<Handle type="source" :position="sourcePosition" /> | ||
|
||
<div style="display: flex; align-items: center; gap: 8px"> | ||
<div v-if="data.isRunning" class="spinner" /> | ||
<span v-else-if="data.hasError">❌</span> | ||
<span v-else-if="data.isSkipped">🚧</span> | ||
<span v-else>📦</span> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<style scoped> | ||
.process-node { | ||
padding: 10px; | ||
color: white; | ||
border: 1px solid #1a192b; | ||
border-radius: 99px; | ||
font-size: 10px; | ||
width: 15px; | ||
height: 15px; | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
} | ||
.spinner { | ||
border: 2px solid #f3f3f3; | ||
border-top: 2px solid #3498db; | ||
border-radius: 50%; | ||
width: 8px; | ||
height: 8px; | ||
animation: spin 1s linear infinite; | ||
} | ||
@keyframes spin { | ||
0% { | ||
transform: rotate(0deg); | ||
} | ||
100% { | ||
transform: rotate(360deg); | ||
} | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
export { default as LayoutApp } from './App.vue?raw' | ||
export { default as LayoutElements } from './initial-elements.js?raw' | ||
export { default as LayoutNode } from './ProcessNode.vue?raw' | ||
export { default as LayoutScript } from './useRunProcess.js?raw' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { ref } from 'vue' | ||
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, dagreGraph) { | ||
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) | ||
|
||
// 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, dagreGraph) { | ||
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) { | ||
for (const node of nodes) { | ||
updateNodeData(node.id, { isRunning: false, isFinished: false, hasError: false, isSkipped: false }) | ||
} | ||
} | ||
|
||
async function skipDescendants(nodeId, dagreGraph) { | ||
const children = dagreGraph.successors(nodeId) | ||
|
||
for (const child of children) { | ||
updateNodeData(child, { isRunning: false, isSkipped: true }) | ||
await skipDescendants(child, dagreGraph) | ||
} | ||
} | ||
|
||
return { run, running } | ||
} |