Three flow-editor UX upgrades:
1. Wider deselect zone. A new translucent
Positioned.fill GestureDetector wraps the outermost
Stack (above the InteractiveViewer). Tapping the dark
area outside the canvas grid — which used to do
nothing — now closes the properties panel.
2. Edge selection. Click a wire → controller.selectEdge
stamps the edge key. Click again or click background →
deselects. Selection is mutually exclusive with step
selection, enforced inside the controller so the panel
never tries to render both. Selected edges highlight
with the same accent the hover state uses.
3. Properties panel grows an edge-info mode. When an
edge is selected, the panel shows:
- source qualified name (e.g. inputs.document or
summarize.response)
- target qualified name
- type colour swatch + name per endpoint (LabVIEW
palette)
- type-compatibility pill (green / red)
- Disconnect button that removes the edge in one click
l10n: 8 new edgeInfo* strings in EN + DE.
Editor tests still pass (20).
Signed-off-by: flemming-it <sf@flemming.it>
Four operator-visible improvements in one cut.
Port geometry (the "connection dots don't line up with the
labels" bug):
- Header now has a fixed two-line structure (title + 16-px
subtitle slot) regardless of node kind, so the body's
port-row Y-offsets are identical across step nodes and
endpoint nodes.
- NodeGeometry constants rewritten so the inline 8-px dot
inside each port row and the 16-px canvas-side dot both
compute to the same Y. Port rows now anchor where the
eye expects them.
Port type colours:
- Inputs endpoint labels carry `name: type` (e.g.
`doc: bytes`), so the FlowNode body parses the type and
tints the inline dot per type: text → primary,
bytes/file → tertiary, json → secondary, number → amber,
unknown → muted. Step input ports stay muted until a
future commit can read module manifests for type info.
Endpoint editor:
- Inputs and outputs nodes are now selectable. Selecting
opens a dedicated editor in the properties panel:
add / rename / retype / remove entries graphically
instead of forcing the operator into the text tab.
Inputs editor offers a Type dropdown
(text / bytes / json / file / number);
outputs editor exposes name + expression
(e.g. `$step.field`).
Unsaved badge:
- The toolbar's tiny 8-px dirty dot was easy to miss.
Replace it with a coloured "unsaved" / "ungespeichert"
chip + colour the file name itself in the primary accent
when dirty. Operators see at a glance that a flow has
unsaved changes, which matters because the Discard
confirmation prompt won't fire if they don't realise
they made changes.
Version 0.3.0 -> 0.4.0 — first new editor feature surface
since 0.3.
Signed-off-by: flemming-it <sf@flemming.it>
Full rewrite of the editor surface, layered on top of the
FlowGraph foundation. One in-memory flow drives three tabs
that the operator can flip between freely:
- Graph: a drag-and-drop canvas. Nodes are step cards with
port dots on their left (one per `with:` field) and a
combined output port on the right. Pinned inputs and
outputs pseudo-nodes sit at the left and right edges so
every flow has a visually obvious source and sink. Pan +
zoom via InteractiveViewer; drag a node by its body to
reposition it (positions persisted to a sidecar JSON file
under ~/.fai/data/flows/.layout/<name>.json — kept OUT of
the YAML so `fai run` stays byte-stable).
- Text: the existing YAML CodeField with expands:true so
line 1 anchors at the top edge. YAML-aware syntax
highlighting picks up the theme's primary / secondary /
tertiary palette for keys / strings / numbers.
- Run: an inputs form (text fields + file-pick), a Start
button that calls the host's FlowRunDriver, a live step
list driven by the driver's event stream (matches the
`fai run` CLI rendering — ◻ pending, · running, ✔ done +
duration, ✗ failed, ⏸ awaiting approval), and the typed
outputs once the run resolves.
Source of truth = the YAML text. Graph edits emit fresh YAML
into the shared CodeController; text edits re-parse the
graph on a 350 ms debounce. Layout sidecar persists drag
positions only.
New public API (lib/fai_studio_flow_editor.dart):
FlowEditorPage(
initialFlowName: ...,
locale: ...,
runDriver: FlowRunDriver?, // NEW — host bridge
availableCapabilities: List<String>, // NEW — for the
// capability picker
// dialog when adding
// a step
)
The host (Studio) implements FlowRunDriver to bridge the
hub's gRPC SDK into the editor's event vocabulary. The
StepStarted/Completed/Failed/AwaitingApproval events are
shared verbatim with the CLI's run_progress renderer so
both surfaces speak the same visual language.
Files in this commit:
- lib/src/editor_controller.dart — shared state +
debounced reparse loop
- lib/src/run_driver.dart — host bridge
interface + event types
- lib/src/widgets/flow_canvas.dart — pan / zoom / drag /
port-to-port connection drawing
- lib/src/widgets/flow_node.dart — node card primitive
(module / approval / inputs / outputs variants)
- lib/src/widgets/edge_painter.dart — single CustomPainter
for every edge + draft drag line, cubic bezier with
arrow-head caps
- lib/src/widgets/properties_panel.dart — right-side editor
when a step is selected (rename id, change capability, add
/ remove / rename with-fields, delete step)
- lib/src/widgets/capability_picker.dart — searchable list
dialog used by Add-step
- lib/src/widgets/run_tab.dart — inputs form +
live step progress + outputs renderer
- lib/src/flow_editor_page.dart — host scaffolding,
toolbar, file list, three-tab body, keyboard shortcuts
- lib/src/l10n.dart — EN + DE strings for
every new label
- lib/fai_studio_flow_editor.dart — exports the new
public types (FlowRunDriver, FlowRunEvent variants,
FlowOutputValue variants)
flutter analyze: 0 issues. flutter test: 7/7 green.
Signed-off-by: flemming-it <sf@flemming.it>