## 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…" ```