Skip to content

Flow Component Overview

The <flow-component> is a visual workflow editor built on top of VueFlow. It provides a drag-and-drop interface for creating and editing node-based workflows with custom action nodes.

The component is registered as a Custom Element:

import { defineCustomElement } from 'vue';
import FlowCe from '@/flow/view/Flow.ce.vue';
import { useCore } from './store/core';
// Expose hooks to browser context
window.$useFlowCore = useCore();
// Register custom element
customElements.define('flow-component', defineCustomElement(FlowCe));

Visual Editor

Drag-and-drop nodes from sidebar, connect with edges, zoom and pan canvas.

Custom Nodes

Configurable action nodes with forms, execution status, and error handling.

Real-time Updates

Visual feedback during execution with animated edges and status indicators.

SubFlows

Nested workflow support for modular flow composition.


<script setup lang="ts">
import { onMounted } from 'vue';
// Configure flow with available apps/actions
onMounted(() => {
const { configure, setFlow } = window.$useFlowCore;
// Register available action modules
configure('ion.action', [
{
module: 'ion.action.http',
label: 'HTTP Request',
icon: 'globe',
group: 'core',
spec: {
type: 'collection',
spec: [
{ type: 'select', name: 'method', label: 'Method', options: ['GET', 'POST', 'PUT', 'DELETE'] },
{ type: 'url', name: 'url', label: 'URL', required: true },
],
},
},
{
module: 'ion.action.email',
label: 'Send Email',
icon: 'mail',
group: 'core',
spec: {
type: 'collection',
spec: [
{ type: 'email', name: 'to', label: 'To', required: true },
{ type: 'text', name: 'subject', label: 'Subject', required: true },
{ type: 'text', name: 'body', label: 'Body', multiline: true },
],
},
},
]);
// Optionally load an existing flow
setFlow({
nodes: [],
edges: [],
variables: {},
});
});
function handleChange(change) {
console.log('Flow changed:', change);
// Auto-save or track changes
}
function handleAction(action, value, patch) {
console.log('Action triggered:', action.value);
// Handle custom actions from node forms
}
function handleRunNode(nodeId) {
console.log('Execute node:', nodeId);
// Trigger node execution on backend
}
</script>
<template>
<flow-component
@change="handleChange"
@action="handleAction"
@run-node="handleRunNode"
/>
</template>

The flow editor uses “apps” or “modules” to define available node types:

interface App {
module: string; // Unique identifier (e.g., "ion.action.http")
label: string; // Display name
icon?: string; // Icon identifier
group?: string; // Sidebar group
spec?: Field; // Form specification for node configuration
color?: string; // Node accent color
}
// Register apps
const { configure } = window.$useFlowCore;
configure('ion.action', [
{
module: 'ion.action.shopify.getOrders',
label: 'Get Orders',
icon: 'shopify',
group: 'shopify',
color: '#96bf48',
spec: {
type: 'collection',
spec: [
{ type: 'select', name: 'status', label: 'Status', options: ['open', 'closed', 'any'] },
{ type: 'number', name: 'limit', label: 'Limit', default: 50 },
],
},
},
]);

During workflow execution, the flow provides visual feedback:

const { pushingNode, pushNode, reset } = window.$useFlowCore;
// When a node starts executing
pushingNode({
node: 'node_123',
queue: {
edge_id: 'edge_456',
target: 'node_789',
data: { /* input data */ },
},
message: null, // or error message
});
// When a node completes
pushNode({
node: { id: 'node_123', data: { /* node data */ } },
status: 'success', // or 'error'
message: null,
edges: ['edge_456'],
outputs: [
{ data: { /* output data */ } }
],
});
// Reset all execution state
reset();
StateVisual Effect
ExecutingAnimated green edge, pointer indicator
SuccessGreen completed edge
ErrorRed node indicator, error message
ResetAll edges return to default gray

ShortcutAction
⌘/Ctrl + Shift + LToggle sidebar (add nodes)
EscapeClose sidebar
Delete/BackspaceRemove selected node/edge
⌘/Ctrl + ZUndo (if implemented)

interface WorkFlow {
nodes: Array<{
id: string;
type: string; // Module identifier
position: { x: number; y: number };
data: Record<string, any>;
}>;
edges: Array<{
id: string;
type: 'custom';
source: string;
target: string;
sourceHandle?: string;
targetHandle?: string;
label?: string;
data?: any;
}>;
variables?: Record<string, any>;
}

src/flow/
├── flow.ts # Custom element registration
├── components/
│ ├── Sidebar/ # Node picker sidebar
│ ├── ActionNode/ # Custom node component
│ ├── ActionNodeViewer/ # Read-only node (for FlowRaw)
│ ├── Edge/ # Custom edge component
│ └── FlowDrawer/ # Node configuration drawer
├── hooks/
│ └── useDnD.ts # Drag and drop handling
├── services/
│ └── ... # Flow services
├── store/
│ ├── core.ts # Browser hooks (window.$useFlowCore)
│ ├── workspace.ts # Flow state management
│ └── modules.ts # App/module registry
├── types/
│ ├── nodes.ts # Node type definitions
│ └── types.ts # General types
└── view/
└── Flow.ce.vue # Main component