engenty wizards
The wizard format

Pages and fields

A page step and its fields, the field kinds, and fields that show only when they fit.

v0.7.10

A page step asks the person. It holds at least one field, and a good page has at most five. cta is the button’s label.

{
  "id": "about", "type": "page", "title": "What is it about?", "cta": "Write it",
  "fields": [
    { "id": "topic", "label": "Topic", "kind": "textarea", "required": true,
      "placeholder": "e.g. We open our new studio on Friday", "help": "For the first line" },
    { "id": "tone", "label": "Tone", "kind": "select",
      "options": ["Casual", "Professional"], "default": "Casual" }
  ]
}

A field’s id is unique in the whole wizard, because later steps read the answer by it. Every field has a label and a kind, and may have required, placeholder, help and default.

Field kinds

KindWhat the person givesKeys of its own
text, textareaA line, or a few paragraphsscan (text): fill it from a QR code or barcode
number, date, email, urlA number, a date, an address, a link
select, multiselectOne or several of optionsoptionsFrom, cards
toggleYes or no
colorA colour
imagePhotos, taken or uploadedmultiple, min, max (up to 30)
fileDocuments, photos, recordingsmultiple, min, max, camera, video, listen
itemsLine items with totalscolumns, vat, currency
locationWhere they are, or an address they type
audioA voice note of up to 5 minutes, written down before the next step
signatureA signature drawn with the finger
slotOne appointment time, shown by dayoptions or optionsFrom, as ISO 8601 date-times
connectionConnects one of their accountsconnection: the id of a wizard connection
listChecks and corrects a stored listlist: the id of a wizard list

Uploads

The runtime checks each file an image or file field receives, from the run page or a runner plugin’s runs.upload, before it keeps it. A space’s files go through the same check. Up to 15 MB per file, 40 MB for a clip.

CheckWhat happens
NameFolders, control characters and direction overrides go. At most 120 characters
TypeThe first bytes must fit the declared type: a picture, a recording or clip, a PDF, an Office file, a font, text. Otherwise the upload is refused with 400. A picture is kept under the type its bytes show
SizeA picture of more than 50 megapixels or 16 384 pixels on a side is refused before it is decoded
PicturesPNG, JPEG, WebP and AVIF are decoded and encoded again in their own format, in a separate process: no EXIF, XMP or GPS, nothing after the picture’s end, upright as the EXIF orientation said. Animated pictures, GIF, HEIC, BMP and ICO keep their bytes
SVGWritten again from an allowlist of drawing elements. Scripts, foreignObject, animations, event handlers and references that don’t start with # go. A DOCTYPE or entity declaration is refused

A type the runtime doesn’t check (application/octet-stream, for example) is kept and served only as a download. The plan with what comes next is docs/plans/upload-checks.md.

Line items

An items field takes positions and computes the totals itself:

{ "id": "positions", "label": "Positions", "kind": "items", "currency": "EUR",
  "vat": { "rate": 20 },
  "columns": [
    { "id": "what", "label": "Service", "kind": "text" },
    { "id": "hours", "label": "Hours", "kind": "number" },
    { "id": "rate", "label": "Rate", "kind": "money" }
  ] }

A row’s amount is the product of its number and money columns. vat.field reads the rate from another field instead. Documents take the table with its totals from {{positions}}. See Templates.

Answers from earlier steps

  • prefill ("steps.<id>.<key>"): what the field starts with. An items field takes a table whose columns are its column ids, and the person corrects the rows.
  • optionsFrom: the choices of a select, multiselect or slot come from earlier data. It names a list output (steps.<id>.<key>), a column of a table output (steps.<id>.<key>.<column>) or a column of a stored list (lists.<id>.<column>). options stand in while that data is empty.
  • cards: with optionsFrom naming a table output, each row is a card. Its keys name the table’s columns: label, value (default: the label), image, subtitle, meta and link.

Fields that show only when they fit

when shows a field only while a condition holds. It reads a field of the same page, decided as the person types, or anything known before the page:

{ "id": "company", "label": "Company", "kind": "text",
  "when": { "field": "customerType", "op": "equals", "value": "Business" } }

A hidden field is not asked and not kept. Its template is empty. Conditions are described on Branches and loops.

Where no rule on one field can say it, a decision picks the fields as the run reaches the page:

  • ask on a field: a statement. The field shows when the decision finds it true of the run, for example “The complaint is about a damaged article”.
  • groups on the page and group on fields: of a group’s fields the decision shows one. With optional, it may show none.
"groups": [{ "id": "reach", "instructions": "How should we reach the person?" }],
"fields": [
  { "id": "phone", "label": "Phone", "kind": "text", "group": "reach" },
  { "id": "mail", "label": "Email", "kind": "email", "group": "reach" }
]

A page with decided fields holds up to 12 fields and shows at most 5. A field has ask or group, not both.

On this page