This commit is contained in:
2026-10-13 10:02:20 +02:00
parent a93f865e91
commit 80e595c02e
24 changed files with 2210 additions and 4310 deletions
+99 -127
View File
@@ -1,177 +1,149 @@
# The flow editor
The canvas is where most of the work happens. It floats its chrome over a
full-bleed graph, so what you are looking at is always the flow.
Build a flow by naming its messages and configuring its nodes. Fluksio draws
the connections and arranges the canvas for you.
## The canvas
Nodes are laid out for you, left to right on a desktop and top to bottom on a
phone, and the arrangement is recomputed as the graph changes. There is
nothing to drag and nothing to tidy.
The graph runs left to right on desktop and top to bottom on phones.
The edges come from message names, so there is no layout to store or to merge
when two people edit the same flow.
- **Nodes** show their execution status.
- **Edges** pulse when values pass through. Click one to inspect its payload.
- **Endpoints** show flow inputs, dashboard widgets and nodes in other flows
that exchange messages with this flow.
What is drawn:
- **Your nodes**, with a status dot — running, succeeded, failed, or nothing at
all when idle. Status is always named in words too, never colour alone.
- **Edges**, which pulse when a value goes down them. Click one to inspect it.
- **Endpoints** — anything wired into this flow that is not a node in it: a
dashboard control writing a message, a tile reading one, a node in another
flow on the far side of a dotted name. Drawn as labelled boxes at the
boundary, so a value never appears to come from nowhere.
Values are live. The editor holds a websocket to the engine, and the connection
banner tells you when it is not.
Values update over a websocket. A connection banner tells you when the editor
cannot reach the engine.
## Adding a node
**Add node** on the dock, or ⌘P / Ctrl-P for the command palette, which also
jumps between flows and offers your shared nodes. Pick a type and it appears on
the canvas with its panel open.
Choose **Add node** in the bottom dock, or use ⌘P / Ctrl-P. The command palette
also jumps between flows and offers reusable nodes. Select a type to add it
and open its settings.
## The node panel
Floats on the right; a full-screen sheet on a phone.
**Consumes** and **Provides** declare the node's ports. Each has a port name,
payload type, bound message and delivery interval. Outputs also have a
streaming toggle.
**Consumes** and **Provides** are the ports. Each port has two lines: its name
and payload type (a `list` also says what its items are), then the message it
is bound to, how often at most it is delivered, and, on an output, a
*streaming* toggle for ports that publish repeatedly during one execution. The
message field suggests messages already in the flow, which is usually how you
wire something: type the name that already exists.
Message fields suggest existing names. Matching an output's message is how
you connect an input.
A port is named after its message until you name it yourself. Its name field
then stays empty and shows the name it follows. A name typed there stays when
the message changes, which is how a port is bound to a message called
something else, as a [`wren`](../reference/node-types.md#wren) target is;
clear it to follow the message again. The name is what the node's code sees,
so it is letters, digits and `_`, not starting with a digit, and no two inputs
or two outputs of a node share one. The field keeps the name it had otherwise.
A blank port-name field follows the message's last segment. Set a port name
to keep the argument name fixed while changing its message binding. Names use
letters, digits and `_`, cannot start with a digit, and must be unique among
the node's inputs or outputs.
Renaming an output renames the message everywhere it is read. Inputs are not
renamed, because an input is more often re-pointed at a different message than
renamed.
Renaming an output's message updates its consumers in the flow. Changing an
input binding points that input at a different message.
**Settings** is generated from the node type's parameter schema, so an MQTT
node shows broker, topic and QoS, and an ntfy node shows server, topic and
priority. A field marked as a credential renders as a picker over your stored
[secrets](operations.md) instead of a text box. A setting holding JSON, such as
a Switch node's rules, shows one line of it; click it to edit the whole value
in a larger editor, which saves only once the text parses. Escape or Cancel
leaves the setting as it was. An inject's payload and a flow input's starting
value of type `json`, `record` or `list` open the same editor, which also holds
the shape (a `record` is an object, a `list` an array); emptying it leaves no
value.
### Settings
A Function node gets a second settings section where you add your own: a
setting is a constant of this node's code and arrives as an argument beside its
Built-in nodes show forms for their configuration. Credential fields offer
stored [secrets](operations.md#secrets). JSON settings open a larger editor
and save only when the value parses.
Function nodes also let you add settings passed as arguments alongside the
ports. See [Where a node's values come from](../concepts/values.md).
**Timeout** (Function nodes) is how many seconds the code may be *silent*
before it is stopped: it measures silence, not duration, so a node that yields
every few seconds can run for hours under a timeout of 300. Left empty there is
no limit, which is the default. Set one where a node going quiet means it is
stuck rather than working. A `0` says so explicitly.
**Timeout** on a Function node limits silence, not total duration. A node
yielding regularly can run longer than its timeout. Empty or `0` means no
limit, the default.
**Code** is the editor. It saves as you type and applies on ⌘S; the node
reloads without the flow stopping. A node file defines `process(...)`; if it
defines exactly one public function under another name, that one is used
instead.
**Resources** selects a shared worker pool, a named flavor or custom CPU,
memory and GPU requirements. Placement by `device` and `device_policy` is
configured through the API or flow JSON; see [Remote workers](../code/workers.md).
Code runs as the engine, so changing it is a superuser's. Anyone else sees the
editor read-only, a Command node's settings disabled, and no Function, Command
or reusable nodes to add.
### Code and reuse
**Shared** turns a node's code into a library entry other flows can reuse.
Editing a shared node edits the copy every flow using it runs, which is the
point and also the caution.
Define `process(...)` in **Code**. If the file instead contains exactly one
public function, Fluksio uses that function.
!!! note "Not in the panel yet"
Code saves as you type. ⌘S / Ctrl-S in the code editor saves immediately;
**Publish** applies ordinary node code to the running flow. Generated code
from `fluksio sync` is read-only: edit its source repository and sync again.
`device` and `device_policy`, which machine a node's code runs on, are set
through the API rather than the panel, with `PUT /flows/{name}`. See
[Remote workers](../code/workers.md).
Only superusers can add or edit code-running nodes. Other users can read code
and configure permitted built-in nodes.
**Reuse** shares node code as a library entry. Saving shared code takes effect
immediately in every flow using it, so check its users before changing it.
## The flow panel
Click the canvas title to open the flow's own settings.
Open **Flow settings** from the pencil button in the dock.
- **Running** — the switch that starts and stops the flow. Stopped means none
of its subscriptions, schedules or webhooks exist.
- **Mode** — `live` or `batch`. Live reacts to what arrives; batch only runs
when a run asks it to. See [Runs](../concepts/runs.md).
- **Inputs** — messages the flow takes from outside, with the value each starts
from. For a batch flow these are also the run's parameters.
- **Outputs** (batch only) — which messages a run reports as its result.
- **Contents** — a reminder that this flow's name namespaces every message
inside it.
| Setting | Purpose |
|---|---|
| **Running** | starts or stops the published live flow's subscriptions, schedules and webhooks |
| **Mode** | chooses continuous `live` operation or requested `batch` runs |
| **Inputs** | declares external messages and starting values; batch inputs become run parameters |
| **Result** | selects batch output messages |
| **Contents** | shows the node count and message namespace |
For live inputs, **Publish this value now** sends the starting value immediately.
Changing a stored starting value alone does not replace an existing message.
## Inspecting an edge
Click a wire. You get the last payload that went down it, when, and a sparkline
of its recent numeric history. You can also republish that value from the node
that produced it, which re-runs everything downstream. It is the fastest way to
test a change without waiting for the real sensor.
Click an edge to see its latest payload, timestamp and recent numeric history.
Republish its value from the producer to run downstream nodes without waiting
for the next sensor reading.
## The dock
Along the bottom, floating over the canvas.
| Control | What it does |
| Control | Action |
|---|---|
| **Add node** | opens the palette |
| **Fit** | returns to the view the flow opened with |
| **Run** | injects a value by hand; on a batch flow, opens the parameters dialog |
| **Pause / Resume** | holds messages instead of running them |
| **Step** | releases exactly one held message |
| **Publish** | puts the draft live |
| **Discard** | throws the draft away |
| **Issues** | what is stopping this flow from running, per node |
| **Logs** | what the nodes printed, filterable |
| **Add node** | opens the command palette |
| **Fit to screen** | fits the graph; desktop only |
| **Run** | executes the current live flow once; for batch flows, asks for run parameters |
| **Pause / Resume** | holds or releases pending work while values still arrive |
| **Step** | releases one held item while paused |
| **Flow settings** | opens the flow panel |
| **Publish** | puts the saved draft live |
| **Discard** | removes unpublished changes |
| **Issues** | lists problems by node |
| **Logs** | shows filterable node output |
Pause and step together are how you test a flow before it moves anything
physical: pause it, inject a value, step it through, watch the values appear on
the edges, then publish.
**Run** uses the current draft when one exists without publishing it. It
executes real node code, including device and network actions. To try a single
value in a live flow, publish it from a flow input or edge inspector.
Pause and step are useful for inspecting held work. They do not make a draft
run a simulation.
## Shortcuts
| Chord | Action |
Use ⌘ on macOS and Ctrl elsewhere.
| Shortcut | Action |
|---|---|
| ⌘P / Ctrl-P | command palette |
| ⌘S / Ctrl-S | publish the flow — or, with focus in the code editor, apply the code |
| ⌘Z / ⌘⇧Z | undo / redo (the flow; the code editor has its own) |
| ⌘C / ⌘V | copy and paste nodes, including between flows |
| ⌘S / Ctrl-S | publish the flow; inside the code editor, save code |
| ⌘Z / Ctrl-Z | undo a graph edit |
| ⌘⇧Z / Ctrl-Shift-Z | redo a graph edit |
| ⌘C / Ctrl-C | copy selected nodes |
| ⌘V / Ctrl-V | paste nodes, including into another flow |
## Drafts and publishing
Text fields and the code editor keep their own undo and clipboard behavior.
Saving writes a draft; the engine keeps running what was published. Publishing
promotes it and reloads.
## Drafts, conflicts and issues
If someone else saved the same flow while you were working, publishing answers
with a conflict rather than overwriting them. The Flows list offers **Publish
all changes** when several flows are sitting on drafts.
Edits are saved as drafts. The engine keeps running the published version until
you publish; shared code follows the exception above. **Discard** returns to
the published version. Delete a never-published flow to remove it.
## Issues
If another editor saved the same flow, a stale save or publish returns a
conflict. Reload and review their changes before retrying.
The canvas validates as you edit and marks the node each issue belongs to:
- a port that needs a message nothing in reach provides
- a message that exists but has never held a value
- a dependency cycle
- a node reading a message it also writes, with nothing to start it from
- code that did not load
- a webhook with no shared secret (advisory — it does not stop the flow)
- a node that loaded but reports itself down, such as a connector that cannot
reach its device
A flow with any of these except the last two does not run, and the health
summary on Home counts it. The last one clears on its own once the node reports
itself well again.
The canvas reports unconnected inputs, missing starting values, cycles and
code-load errors. These prevent the affected flow from running. Unauthenticated
webhooks are advisory; runtime node-health problems clear when the node
recovers. See [Flow issues](../concepts/flows.md#when-a-flow-needs-attention).
## See also
- [Flows, nodes and messages](../concepts/flows.md) — the model behind the canvas
- [Node types](../reference/node-types.md) — everything the palette offers
- [Writing node code](../code/nodes.md) — what goes in the editor
- [Flows, nodes and messages](../concepts/flows.md)
- [Node types](../reference/node-types.md)
- [Writing node code](../code/nodes.md)