Workflow Addon

The WireFlow workflow addon exposes the AlpineFlow workflow addon to Livewire components. Use it to drive workflow runs from the server, sync run-state to nodes, and listen to execution events.

Installation

The workflow addon is opt-in — register it on the JS side alongside AlpineFlow:

import AlpineFlow from '@getartisanflow/alpineflow';
import AlpineFlowWorkflow from '@getartisanflow/alpineflow/workflow';

document.addEventListener('alpine:init', () => {
    window.Alpine.plugin(AlpineFlow);
    window.Alpine.plugin(AlpineFlowWorkflow);
});

If you're loading AlpineFlow from the bundled WireFlow dist, the workflow addon entry sits next to the core bundle:

import AlpineFlow from '../../vendor/getartisanflow/wireflow/dist/alpineflow.bundle.esm.js';
import AlpineFlowWorkflow from '../../vendor/getartisanflow/wireflow/dist/alpineflow-workflow.esm.js';

Once registered, every <x-flow> canvas gains the run/replay surface ($flow.run(), $flow.replayExecution(), $flow.executionLog) and the workflow node templates.

Components

Component Purpose
<x-flow-wait> Wait-node template — header (icon + label + formatted duration) plus top/bottom handles.
<x-flow-condition-node> Condition-node template — header + pretty-printed body + true/false handles + branch-taken decoration.
<x-flow-replay-controls> Duck-typed playback toolbar (Play/Pause/Restart/Speed + scrubber/progress).
<x-flow-execution-log> Dense reactive event viewer — filterable, click-to-highlight, XSS-safe.
<x-flow-run-button> Workflow run trigger that auto-disables during runs.
<x-flow-stop-button> Halts an active run; hidden when idle by default.
<x-flow-reset-button> Clears node runState and the execution log.

Server-side trait methods

These live on WithWireFlow — see Trait reference for the full method table.

Method Description
$this->flowRun(string $startId, array $options = []) Dispatch a flow:run event so the client-side workflow addon executes the workflow.
$this->flowSetNodeState(string|array $ids, string $state) Set runState on one or more nodes.
$this->flowResetStates() Clear runState from all nodes.

flowSetNodeState() valid states: pending, running, completed, failed, skipped.

Wire bridge events

The Livewire ↔ AlpineFlow bridge translates these dispatches into client-side calls on the workflow addon:

Dispatched event Payload Effect
flow:run { startId: string, options?: object } Calls $flow.run(startId, handlers, options) on the canvas.
flow:setNodeState { ids: string | string[], state: string } Updates runState on the matching nodes.
flow:resetStates (none) Clears every node's runState.

Pre-registering handlers

Workflow handlers (onEnter, onExit, pickBranch, …) are JavaScript callbacks; they can't be serialized from PHP. Pre-register them on the canvas with x-init so they're available when flowRun() dispatches:

<x-flow
    :nodes="$nodes"
    :edges="$edges"
    x-init="$el.runHandlers = {
        onEnter: async (node, ctx) => { /* ... */ },
        pickBranch: (node, edges, ctx) => edges[0].id,
    }"
/>

The forthcoming <x-flow-run-button> primitive reads from $el.runHandlers by default — see the upcoming UI-primitives release for the auto-wired flow.

Validation

The addon ships a pure helper that mirrors validateSchema():

const result = $flow.validateWorkflow();
// → { valid: boolean, issues: WorkflowValidationIssue[] }

Issue codes returned:

Severity Code Meaning
error dangling-edge Edge source or target node doesn't exist.
error duplicate-node-id Two nodes share an id.
error missing-condition A flow-condition node has neither condition nor evaluate.
error condition-missing-branch A flow-condition node is missing its true or false outgoing edge.
error unhandled-source-handle A flow-condition outgoing edge has a sourceHandle other than true / false.
error wait-missing-duration A flow-wait node has non-numeric or missing data.durationMs.
warning unreachable-node A node has no incoming and no outgoing edges.
warning cycle A directed cycle exists in the graph.

Use it from a server action via <x-flow-action> or wire a wire:click to a button that calls $flow.validateWorkflow() and posts the result back.

Quick start

<?php
use ArtisanFlow\WireFlow\Concerns\WithWireFlow;
use Livewire\Component;

class WorkflowEditor extends Component
{
    use WithWireFlow;

    public array $nodes = [
        ['id' => 'trigger', 'position' => ['x' => 0, 'y' => 0], 'data' => ['label' => 'Start']],
        ['id' => 'wait', 'type' => 'flow-wait', 'position' => ['x' => 200, 'y' => 0], 'data' => ['label' => 'Cooldown', 'durationMs' => 2000]],
    ];

    public array $edges = [
        ['id' => 'e1', 'source' => 'trigger', 'target' => 'wait'],
    ];

    public function startRun(): void
    {
        $this->flowRun('trigger');
    }

    public function render()
    {
        return view('livewire.workflow-editor');
    }
}
<x-flow :nodes="$nodes" :edges="$edges" x-init="$el.runHandlers = { onEnter: async () => {} }">
    <x-slot:node>
        <template x-if="node.type === 'flow-wait'">
            <x-flow-wait />
        </template>
    </x-slot:node>
</x-flow>

<button wire:click="startRun">Run workflow</button>