Wizards overview
A wizard is a multi-step, guided data-entry flow. Where a form captures one record on one screen, a wizard walks the user through a graph of steps — collect some fields, branch on what they answered, run a bit of SQL, then finish — and can hand the result off to a workflow for review and approval.
Wizards are authored in *.wizard.xml as a node graph, edited visually in the in-app Wizard
Designer, and run by the React Wizard Runner at /wizard/{slug}.
Form or wizard?
Section titled “Form or wizard?”Reach for a plain view/form when the user edits one record on one screen. Reach for a wizard when the capture is inherently sequential or conditional:
- the input spans several logical steps and you want a progress bar + review screen;
- later steps depend on earlier answers (a Decision branch);
- you need to run intermediate SQL between steps (create a draft row, look something up);
- submission should start an approval workflow rather than just write a row.
The node-graph model
Section titled “The node-graph model”A wizard is a set of nodes connected by links (directed edges). The runner starts at the entry node and follows links, pausing only where it needs the user. There are five node types:
| Node | Purpose | Runner behaviour |
|---|---|---|
| Startup | Initialise global variables. | Auto-advances immediately. |
| Input | Collect user data via fields. | Renders a step and waits for Next. |
| Decision | Branch on the collected values. | Auto-advances down the first matching link. |
| Action | Side effect: alert, run SQL, or set a variable. | Auto-advances (an Alert pauses for acknowledgement). |
| Terminal | Finish, and optionally hand off to a workflow. | Submits the response and shows the outcome. |
Only Input and Terminal (and an Alert action) stop the runner; Startup, Decision and the
other Actions execute silently in an “auto-advance burst” between visible steps.
Variables
Section titled “Variables”Everything the wizard knows is a variable. Input fields become variables (keyed internally
as NodeId__FieldName, with a bare FieldName alias), Startup declares named globals, and an
Action can compute new ones. Variables flow into:
- Decision link expressions (which branch to take);
- SQL blocks, as
@FieldName/@VariableNamesubstitutions (plus session parameters like@SessionUserIdand@SessionCompanyId); - the saved response, and the workflow context on handoff.
Links and branching
Section titled “Links and branching”<Link From="a" To="b" /> is an edge. A Decision node’s outgoing links carry an
Expression; the first whose expression is true wins, with Expression="else" (or an
expression-less link) as the catch-all. Expressions use the same
expression engine as views.
Handoff to a workflow
Section titled “Handoff to a workflow”The most powerful thing a wizard does is finish into a workflow. When a Terminal node
declares a WorkflowName, submitting the wizard:
- saves a
WizardFormResponserow (the collected values as JSON); - optionally runs the Terminal’s SQL;
- starts the named workflow, bound to that response (
EntityType = "WizardFormResponse"), passing the wizard’s variables as the initial workflow context.
From there the workflow handles approvals, decisions and downstream actions independently. Editing and resubmitting a response can instead continue the existing workflow instance via a resubmission transition — see Runtime & designer.
A small annotated example
Section titled “A small annotated example”This is the shape of a wizard end to end — a Startup global, one Input step, an Action that creates a draft row, and a Terminal that starts an approval workflow:
┌───────────────────────────────┐│ Startup · Channel global │└───────────────┬───────────────┘ ▼┌───────────────────────────────┐│ Input · Product Details │└───────────────┬───────────────┘ ▼┌───────────────────────────────┐│ Action · Create Draft (SQL) │└───────────────┬───────────────┘ ▼┌───────────────────────────────┐│ Terminal · Submitted │└───────────────┬───────────────┘ ▼ starts on submit┌───────────────────────────────┐│ Workflow · ProductApproval │└───────────────────────────────┘<Wizard Name="NewProductRequest" Label="New Product Request" Slug="new-product-request" Schema="Inventory"> <!-- 1. Startup: seed a global, then auto-advance --> <Node Id="start" Type="Startup" Label="Start" X="-60" Y="38" Width="160" Height="60"> <Variables> <Variable Name="Channel" Type="String" Default="Wizard" /> </Variables> </Node>
<!-- 2. Input: collect fields (one is a SQL-backed Select) --> <Node Id="details" Type="Input" Label="Product Details" X="220" Y="-12" Width="200" Height="160"> <Fields> <Field Name="ProductName" Type="String" Label="Product Name" Required="true" /> <Field Name="CategoryId" Type="Select" Label="Category" Required="true" ControlType="Select2"> <OptionsSql>SELECT Id AS Value, Name AS Label FROM Inventory.Categories WHERE IsActive = 1</OptionsSql> </Field> <Field Name="UnitPrice" Type="Number" Label="Unit Price" Required="true" /> </Fields> </Node>
<!-- 3. Action: run SQL to create a draft, capture the new id into a variable --> <Node Id="register" Type="Action" Label="Create Draft" X="480" Y="30" ActionType="SetVariable"> <TargetVariable>ProductId</TargetVariable> <ValueSource>SQL</ValueSource> <SQL>INSERT INTO Inventory.Products (Name, CategoryId, UnitPrice, Status) VALUES (@ProductName, @CategoryId, @UnitPrice, 'Draft'); SELECT CAST(SCOPE_IDENTITY() AS BIGINT);</SQL> </Node>
<!-- 4. Terminal: finish and start the ProductApproval workflow --> <Node Id="done" Type="Terminal" Label="Submitted" X="740" Y="38" SubmissionStatus="Pending" WorkflowName="ProductApproval" ResubmissionTransition="Resubmitted"> <SuccessMessage>Your product request has been submitted for approval.</SuccessMessage> </Node>
<Link From="start" To="details" /> <Link From="details" To="register" /> <Link From="register" To="done" /></Wizard>The full reference (every node type, field type, SQL block and attribute) is in Authoring a wizard. How it executes and how the designer/runner work is in Runtime & designer.