feat: bell-tower favicon, lfx-clean flows, branded HTML mail

This commit is contained in:
Jonas Miederer 2026-09-13 17:57:42 +02:00
parent 672faf3af8
commit df5c1e296c
15 changed files with 288 additions and 30 deletions

View file

@ -0,0 +1,58 @@
# Authoring web forms (CustomInputForm)
Flows that should render a web form start with a `CustomInputForm` node
(this package — the `kirche` category in the Langflow palette). The API
derives a JSON Schema + uiSchema from the node's template
(`app/flows/input_schema.py`) and the webapp renders it with RJSF.
## Adding a new form field
1. Open the Langflow authoring UI (http://localhost:7860) and load the
flow from `LANGFLOW_LOAD_FLOWS_PATH` (canonical files are preloaded).
2. Edit the `CustomInputForm` node: every entry in its `inputs` list is
one web-form field. Add an `lfx.io` input, e.g.
```python
from lfx.io import DropdownInput
DropdownInput(
name="room", # JSON-Schema property key
display_name="Room", # form label (title)
info="Where should it take place", # help text (description)
options=["Chapel", "Hall"], # dropdown choices (enum)
value="Chapel", # prefill (default)
required=True, # marks the field required
)
```
Supported input types → widgets: `StrInput`/`MessageTextInput` → text,
`MultilineInput` → textarea, `SecretStrInput` → password,
`IntInput` → integer, `FloatInput` → number, `BoolInput` → checkbox,
`DropdownInput` → select, `MultiselectInput` → multi-select,
`SliderInput` → slider (needs `range_spec`), `FileInput` → text stub
(real upload later).
3. Add the new field to `collect()` so it reaches the JSON output.
4. **Wire the envelope**: keep the `ChatInput → form_values` edge (hidden
input, `show=False`). Submitted web-form values arrive there as
`{"payload": {...}}` and are merged over the defaults. Never make form
fields required *with* an incoming edge — that's the envelope's job.
5. Export the flow (JSON) into `backend/flows/<name>.json` and commit.
The API watcher syncs + deploys it automatically; the form schema is
regenerated per version.
## Conventions the pipeline relies on
- `required=True` on a template field: `lfx validate --level 4` demands a
value or an edge, so the canonical-flow generator
(`backend/scripts/make_flow_fixtures.py`) writes a single-space
sentinel value for such fields. The form parser treats whitespace-only
values as "no default" — don't ship real whitespace defaults.
- Field key = `name` (stable); label = `display_name`; help = `info`.
- Unknown future input types degrade to a plain text field in the web
form (parser fallback), so adding exotic lfx inputs never breaks runs.
## Regenerating the bundled fixtures
After editing the component source (`form_inputs.py`), refresh the
canonical + test-fixture exports:
docker compose exec api /opt/venv/bin/python scripts/make_flow_fixtures.py
docker compose exec -T api uv run pytest tests/test_lfx_validate.py