## Form Fields
- Form fields is template system add-on to the base ProcBlocks system.
- Form fields let you collect arbitrary user inputs at job-creation time by defining input fields and mapping them to an `assign` block.
- Form fields works by generating an `assign` block and saving it to JobFS at `input/prefix.yaml`. This appended to the job definition during processing.
## API Calls and Form Fields
API calls bypass the field input system but the API allows the user to upload the `input/prefix.yaml` directly. This allows field dependent templates to be added via API.
---
Each field is declared like:
```yaml
- field:
name: "my_field"
type: "input"
label: "Enter something:"
default: "foo"
placeholder: "Type here…"
filter: "trim;lower;maxlen(50)"
validate: "required;min(3);max(50);rematch('/^[a-z]+$/')"
error_message: "3–50 lowercase letters"
vars:
foo: "{value}" # map into a var named 'foo'
overrides:
- step: "resize"
section: "params"
key: "width"
```
---
## 1. Supported Field Types
| `type` | Component | Value shape |
| ---------- | ----------- | -------------------------------- |
| `label` | Text block | _n/a_ (display-only) |
| `input` | TextInput | `string` |
| `textarea` | Textarea | `string` |
| `number` | NumberInput | `number` |
| `checkbox` | Checkbox | `boolean` |
| `select` | Select | `string` (one of `options` keys) |
---
## 2. Field Definition Keys
| Key | Type | Req’d? | Notes |
| --------------- | ---------------------------- | :----: | -------------------------------------------------------------------- |
| `name` | `string` | Yes | Unique identifier; used in `vars` and your injected `assign` block |
| `type` | `string` | Yes | One of the types above |
| `label` | `string` | Yes | Shown as the field’s label |
| `default` | any | No | Initial value (string, number, boolean) |
| `options` | `Record` | No | For `select` only: key→label pairs |
| `required` | `boolean` | No | Defaults to `false`; when `true`, `validate` must include `required` |
| `placeholder` | `string` | No | Hint text for `input`/`textarea` |
| `description` | `string` | No | Not yet displayed, reserved for future |
| **`filter`** | `string` | No | Semicolon-delimited _filters_ (auto-correct) |
| **`validate`** | `string` | No | Semicolon-delimited _validation_ rules (errors, no auto-correct) |
| `error_message` | `string` | No | Custom message when _any_ validation rule fails |
| `vars` | `Record` | No | `{ varName: "{value}" }` → injected into your `assign` block |
| `init` | `Record` | No | Like `vars`, but only on first render (pre-submit initial `assign`) |
| `overrides` | `Array<{step,section?,key}>` | No | Structured override entries; `value` is implicitly `{field.value}` |
---
## 3. Filter Pipeline
Applied _before_ validation, never throws — only silently transforms.
Syntax:
```
filter: "trim;lower;upper;maxlen(50);int;float;min(0);max(100);refilter('/[^0-9]/g')"
```
| Filter | Meaning |
| ------------- | ------------------------------------------------------------------ |
| `trim` | Remove whitespace from both ends. Processed on blur |
| `lower` | → `.toLowerCase()` |
| `upper` | → `.toUpperCase()` |
| `maxlen(n)` | Truncate to at most _n_ characters (`maxlen` alias of `maxlength`) |
| `int` | Parse as `parseInt(v,10)` (→ `0` on failure) |
| `float` | Parse as `parseFloat(v)` (→ `0` on failure) |
| `min(n)` | Numeric clamp: `Math.max(v, n)` |
| `max(n)` | Numeric clamp: `Math.min(v, n)` |
| `refilter(r)` | `value.replace(RegExp(r), "")`, e.g. remove unwanted chars |
---
## 4. Validation Rules
Run _after_ filtering. Any failure records an error and blocks submit.
Syntax:
```
validate: "required;min(3);max(50);rematch('/^[a-z]+$/')"
```
| Rule | Meaning |
| ------------ | -------------------------------------------------------------------- |
| `required` | Must be non-empty (for strings) or `!== null/undefined` (for others) |
| `min(n)` | Numeric value ≥ _n_ |
| `max(n)` | Numeric value ≤ _n_ |
| `rematch(r)` | `RegExp(r).test(value)` must be `true` |
If _any_ rule fails, either your `error_message` or the concatenated per-rule messages will be shown under the field, and the overall submit is blocked.
---
> **Note:** whatever you put in `vars` / `init` / `overrides` will appear in the generated `input/prefix.yaml` assign block, so you can wire these field values directly into your processor parameters.
### Label (display‐only) with an `init` assignment
```yaml
- field:
name: "info_label"
type: "label"
label: "Configure your job below:"
```
---
### Text Input with `vars`, `init`, and `overrides`
```yaml
- field:
name: "username"
type: "input"
label: "Username"
default: "guest"
placeholder: "Enter your username"
filter: "trim;lower"
validate: "required;rematch('/^[a-z0-9_]{3,20}$/')"
error_message: "3–20 lowercase letters, digits or underscore"
vars: # every submission, set var `user_name`
user_name: "{value}"
random_code: "{random:1000,9999}"
init: # only on first render, set var `initial_user`
initial_user: "{value}"
overrides: # use this field’s value to override the pipeline’s width param
- step: "resize"
section: "params"
key: "width"
value: "{value}"
```
---
### Textarea with an `overrides`–only
```yaml
- field:
name: "notes"
type: "textarea"
label: "Additional Notes"
placeholder: "Any extra instructions…"
filter: "maxlen(500)"
validate: "maxlength(500)"
error_message: "Up to 500 characters only"
overrides: # inject this free-form text into your `assign` block’s `description` var
- step: "test"
section: "params"
key: "value"
value: "{value}"
```
---
### Number with all three assignment types
```yaml
- field:
name: "resize_width"
type: "number"
label: "Width (px)"
default: 800
filter: "min(100);max(1500)"
validate: "required;min(100);max(1500)"
error_message: "Enter a number between 100 and 1500"
vars:
w: "{value}" # each submit, set var `w`
random_offset: "{random:0,50}"
init:
initial_w: "{value}" # once, set var `initial_w`
overrides:
- section: "params"
key: "width"
value: "{value}" # override the `params.width` of the main processor
- step: "shadow"
section: "params"
key: "offset_x"
value: "{random_offset}" # use our generated random_offset
```
---
### Checkbox with `vars` + `overrides`
```yaml
- field:
name: "enable_watermark"
type: "checkbox"
label: "Enable watermark"
default: false
vars:
do_watermark: "{value}"
overrides:
- step: "composite"
section: "params"
key: "opacity"
value: "{value}" # if checked==true, set composite.opacity to "true" (truthy)
```
---
### Select with `vars`
```yaml
- field:
name: "quality"
type: "select"
label: "Image Quality"
options:
low: "Low"
medium: "Medium"
high: "High"
default: "medium"
required: true
error_message: "Please pick a quality level."
vars:
quality_choice: "{value}" # submit the chosen quality as var
```
A single job using all of those example fields will:
- Collect inputs on job‐creation.
- **Filter** & **validate** each value before submission.
- Pre–populate the pipeline with an `assign` block based on your fields.
- Write an `input/prefix.yaml` that might look like this:
```yaml
- assign:
vars:
user_name: "alice"
random_code: "3456"
initial_user: "guest"
w: "1024"
random_offset: "17"
do_watermark: "true"
quality_choice: "high"
overrides:
- step: "resize"
section: "params"
key: "width"
value: "1024"
- step: "shadow"
section: "params"
key: "offset_x"
value: "17"
- step: "resize"
section: "params"
key: "width"
value: "1024"
- step: "composite"
section: "params"
key: "opacity"
value: "true"
- step: "test"
section: "params"
key: "value"
value: "Here are my notes…"
```