The 0.15.0 type-token coloring regex hunted for `type: <name>`,
but the F∆I YAML actually shapes types as `<fieldname>: <name>`
under `inputs:` / `outputs:` blocks. Real-world flows
(`hello.yaml`, `extract.yaml`) and module manifests (echo,
text-summarize, …) never produce the `type:` keyword unless
the operator hand-authors the long form.
Fix the regex to match an indented `KEY: VALUE` line where the
value is one of `text|json|bytes|file|number|integer`. Leading
whitespace is required so top-level keys (`name: foo`,
`version: 0.1.0`) can't false-match. This handles both
shapes — the implicit `pdf: bytes` and the explicit
`type: bytes` (used by module schema v2 inputs lists) —
because either way the pattern boils down to "key colon known
type token".
Analyzer also grows a type-token check: any inputs/outputs
field whose value isn't a known type lights up as a warning
("Unknown input type 'byes' …"), modulo `$ref` expressions
(flow outputs) and empty values (operator is mid-keystroke).
Adds `test/flow_analyzer_test.dart` with seven cases covering
empty, valid hello, unknown capability, unknown type, parse
error, version-bare matching, and the empty-installed-list
silence path.
Bumps the package to 0.15.1.
Signed-off-by: flemming-it <sf@flemming.it>
Two visible UX fixes:
1. Properties-panel toggle. Tap a step → opens. Tap the
same step again → closes (deselect via toggle). Tap the
canvas background → also closes. selectStep now returns
to null when called with the already-selected id; the
editor-controller test updated for the new semantics.
2. LabVIEW-style type colours on every port + wire.
_typeAccent now picks vibrant brightness-aware hues per
datatype:
text → magenta/pink (LabVIEW string)
json → amber/orange (cluster feel)
bytes → cyan/teal (raw binary)
file → green (file reference)
number → yellow/amber
Step-input dots, step-output dots, and outputs-endpoint
dots all switch from the generic theme.primary to the
field's declared type accent. Operators read the
payload from the dot alone.
Editor tests still pass (20).
Signed-off-by: flemming-it <sf@flemming.it>
Three changes:
1. Type-checked port connections. Drag from an output port
only highlights compatible-type input ports as drop
targets; incompatible drops are silently refused. Source
of truth: ModuleSpec for declared types. When either side
is unknown (no manifest, implicit YAML field) the check
degrades to 'compatible with anything' so a missing
manifest never blocks composition.
2. NodeGeometry.heightFor now adds a 2 px allowance for the
1 px AnimatedContainer border on top + bottom of the
card. Without this the last port-row's Column would
overflow by 2 px under tight layout constraints (caught
by the new widget tests; production canvas clipped it
silently inside InteractiveViewer).
3. Width parameter on FlowNode now actually drives the
outer SizedBox. The dynamic _stepWidth value from the
canvas finally reaches the card border rather than being
shadowed by NodeGeometry.width. Long labels
(model_endpoint, source_language) no longer ellipsis-clip.
Tests: 8 new widget + geometry tests covering width growth,
two-column body layout, port-tooltip attachment,
row-alignment between input and output sides, and the
existing kindForStep classifier. All 20 editor tests pass.
Bumps fai_studio_flow_editor to 0.11.0.
Signed-off-by: flemming-it <sf@flemming.it>
New test mirrors the most complex shipped example —
three-step chain with a system.approval gate in the middle,
multi-line prompts containing embedded \$step.field refs,
outputs that reference multiple steps. Verifies:
- step count + approval flagging
- edge detection (8 edges across inputs, steps, outputs)
- structural round-trip stability through toYaml() /
fromYaml()
If this test stays green, the editor is safe on every flow
currently shipped under flows/. 12/12 pass.
Signed-off-by: flemming-it <sf@flemming.it>
Step run events were previously visible only on the run tab.
Operators who triggered a run there and then switched to
the graph tab saw a static graph — the canvas had no idea
something was executing.
Wire the run events through the FlowEditorController so all
three tabs share the same status snapshot:
- New StepRunStatus enum on the controller
(idle / running / done / failed / awaiting).
- controller.stepStatuses exposes the live map.
- controller.updateStepStatus is called from the run tab's
event handler — one source of truth, both views read it.
- FlowCanvas drops its own stepStatuses parameter and
pulls from the controller instead, so the canvas now
shows the running pulse + done check + error cross + pause
icon in each step's header live, in lockstep with the
step list on the run tab.
When a fresh run starts (controller.running = true) the
status map is cleared so stale events from a previous run
don't paint the new one.
Signed-off-by: flemming-it <sf@flemming.it>
Four behaviour tests guarding the controller's contract with
the rest of the editor:
- openFlow seeds the graph + clears the dirty flag against
the freshly-captured baseline.
- graph edits re-emit YAML into the shared CodeController
so the text tab stays in lockstep.
- graph edits mark the buffer dirty against the baseline;
markSaved snaps it back to clean.
- selectStep is idempotent: re-selecting the same step
doesn't notify listeners (cheap rebuild guard for the
properties panel).
11/11 tests pass.
Signed-off-by: flemming-it <sf@flemming.it>
First piece of the v0.2.0 rewrite. The graph view, text view,
and run view will all share a single source of truth: the
YAML text. This commit introduces the parsing layer + the
sidecar that keeps layout metadata OUT of the YAML.
FlowGraph (lib/src/model/flow_graph.dart):
- Parses + emits the F-Delta-I flow YAML shape (inputs +
steps + outputs + leading comment block).
- Recognises both inputs shorthand (`name: text`) and the
expanded form (`name: { type: text, default: ..., hint: ... }`).
- Detects edges by scanning step.with + outputs for
$source.field references; understands both the short
$x.y form (canonical) and the long ${{ x.y }} form (legacy).
- Flags system.approval@ steps via FlowStep.isApproval so
the graph can paint them with the human-gate styling.
- Immutable update helpers (withStepUpdated, withStepAdded,
withStepRemoved) used by the property panel + add-step
button.
- tryParse returns null on YAML syntax errors so the text
tab can keep the last valid graph while the operator
types.
LayoutStore + FlowLayout (lib/src/model/layout_store.dart):
- Per-flow JSON sidecar at
~/.fai/data/flows/.layout/<name>.json. Atomic write via
tmp + rename so a crash mid-save leaves the previous
copy intact.
- The YAML stays byte-identical to what `fai run` consumes
— positions never bleed into the flow file.
AutoLayout (lib/src/model/auto_layout.dart):
- Deterministic topological column layout for flows that
have never been opened in the graph view before.
- Steps with no $step refs sit in column 0; steps whose
refs all point at column-0 steps sit in column 1; etc.
- Cycles + dangling refs collapse to column 0 so nothing
is ever invisible.
Tests (test/flow_graph_test.dart): 7 cases cover canonical
parsing, edge detection across both ref forms, approval-step
flagging, leading-comment round-trip, structural round-trip,
parser robustness on broken YAML, immutability invariant.
All pass.
Version 0.1.4 -> 0.2.0 (minor bump — significant new module
graph; public FlowEditorPage constructor API unchanged).
Signed-off-by: flemming-it <sf@flemming.it>