Workflows
The workflow designer draws approval and business processes the way people describe
them: steps in swimlanes, one lane for each role, and the actions that move work between them. Each action
can carry a condition written as a formula (=amount <= 1000), say who may take it, run by
itself, or need a comment. Steps set values as work enters them, hand events to your page, and escalate
when their time runs out.
A problems list checks the workflow as it is drawn, and Simulate runs it, acting as each role. The workflow engine runs the same JSON for real: a task card showing each person what is theirs to do, and the same engine for a Web Worker or a Node server, so your server can check every action. Nothing is stored; instances are plain JSON for your own database.
Expense claims
Claims of £1,000 or less go to a manager, larger ones straight to finance; the manager has 24 hours before finance takes over. Drag a step into another lane, drag from a selected step's handle to connect it, edit anything in the panel, then switch to Simulate and run a claim as each role.
Get the code
<script src="/assets/bmx-components.min.js"></script> <bmx-workflow-designer id="wf-design" style="inline-size: 100%; --bmx-workflow-designer-height: 26rem"></bmx-workflow-designer>
The task card
The same workflow, running. Each person sees the actions that are theirs; the others are shown closed, with the reason. Switch person to move the claim along — a comment is needed to send a claim back or reject it.
Get the code
<script src="/assets/bmx-components.min.js"></script> <bmx-workflow-engine id="wf-card" editable-values></bmx-workflow-engine>
From a blank page
A leave request, started from nothing but a start and an end. The problems list says what is missing as you go. Add an Approval from the palette while Request is selected and it is joined on; connect it to the end, and the workflow can run.
Get the code
<script src="/assets/bmx-components.min.js"></script> <bmx-workflow-designer id="wf-blank" style="inline-size: 100%; --bmx-workflow-designer-height: 20rem"></bmx-workflow-designer>
Your server has the last word
The card asks before it acts, and here the page sends every action to a stand-in for your server running the same engine, which keeps the real instance and adds a rule of its own: nobody approves their own claim. Mia, a manager, has submitted one; try approving it as Mia, then as Raj, another manager.
// Node 18 or later: the same engine, from the Gold package.
import { createWorkflowEngine, readInstance } from './dist/node/bmx-workflow.mjs';
const engine = createWorkflowEngine(await db.workflow('expenses'));
app.post('/claims/:id/actions', async (req, res) => {
const instance = readInstance(await db.claim(req.params.id));
const actor = { id: req.user.id, roles: req.user.roles };
if (req.body.action === 'approve' && instance.history[0].by === actor.id) {
return res.status(403).json({ error: 'Nobody approves their own claim.' });
}
const result = engine.fire(instance, req.body.action, { actor, comment: req.body.comment });
if (!result.ok) return res.status(409).json(result);
await db.saveClaim(req.params.id, result.instance);
res.json(result.instance);
});
Ten thousand claims
The engine from the top of the page, run over ten thousand claims the page makes up: each one started, routed by amount, and approved, sent back or rejected by a made-up person, with every rule checked.
Get the code
<script src="/assets/bmx-components.min.js"></script> <bmx-button id="wf-many" variant="soft">Run ten thousand claims</bmx-button>