docs(editor): README + version bump to 0.2.1

Expands README to describe the three-tab UX, the source-of-
truth model (YAML + sidecar layout), the FlowRunDriver
contract, the folder layout, and how to swap the editor.

Version 0.2.0 -> 0.2.1 — picks up the live step status,
the empty-graph CTA, and the fit-to-screen button added
since the initial 0.2.0 commit.

Signed-off-by: flemming-it <sf@flemming.it>
This commit is contained in:
flemming-it 2026-06-01 01:53:29 +02:00
parent 9d21bd5318
commit cae5c94c4d
2 changed files with 113 additions and 41 deletions

152
README.md
View file

@ -1,42 +1,110 @@
# fai_studio_flow_editor
Swappable inline YAML editor for F∆I Studio flows.
Swappable in-Studio flow editor for the F∆I Platform. Hosts a
three-tab editing surface on top of one in-memory flow YAML:
- **Graph** — drag-and-drop WYSIWYG canvas of step nodes and
their input / output ports, edges derived live from
`$ref` expressions in the YAML.
- **Text** — full-screen YAML editor with line numbers and
syntax highlighting, anchored at the top of the viewport.
- **Run** — inputs form, Start button, live step-progress
list driven by the host's event stream, typed outputs once
the run resolves.
The package is intentionally host-agnostic. Studio depends
on it via a `git: ref: main` pubspec entry; replacing the
editor is one pubspec change and a rebuild.
## Public surface
```dart
import 'package:fai_studio_flow_editor/fai_studio_flow_editor.dart';
// Studio embeds the page as one of its destinations:
FlowEditorPage(
initialFlowName: 'hello', // optional
locale: FlowEditorLocale.de, // or .en
onRun: (name) => // optional callback
HubService.instance.runSavedFlow(name: name),
initialFlowName: String?, // preload this flow
locale: FlowEditorLocale, // en | de
runDriver: FlowRunDriver?, // host-supplied hub bridge
availableCapabilities: List<String>, // for the Add-step picker
)
```
- **`initialFlowName`** — when set, the page loads that flow
from `~/.fai/data/flows/<name>.yaml` on first build. Used
by Studio's Flows-page pencil → editor route push.
- **`locale`** — picks EN or DE for the editor's internal
string table. Studio passes its active locale through.
- **`onRun`** — async callback that runs the named flow
against the host hub and returns the typed outputs map.
When null, the Run button is disabled (e.g. when the
editor is embedded in a context without hub access).
Host implements `FlowRunDriver` to bridge the editor's
`runFlow` + `events` calls to whatever talks to the hub:
```dart
abstract class FlowRunDriver {
Future<Map<String, FlowOutputValue>> runFlow({
required String flowName,
required Map<String, String> textInputs,
required Map<String, Uint8List> fileInputs,
required Map<String, String> fileMimes,
});
Stream<FlowRunEvent> events();
}
```
Event types: `StepStarted`, `StepCompleted`, `StepFailed`,
`StepAwaitingApproval`. Output types: `FlowOutputText`,
`FlowOutputJson`, `FlowOutputBytes`.
## Source-of-truth model
YAML text is the canonical state. The graph view derives a
`FlowGraph` object from the YAML on every change (debounced
350 ms). Graph edits emit fresh YAML into the shared
`CodeController` via `FlowGraph.toYaml()`. The two tabs
cannot fall out of sync because both observe the same
`FlowEditorController`.
Node positions are the one piece NOT in the YAML — they
live in a per-flow sidecar JSON file at
`~/.fai/data/flows/.layout/<name>.json`. This keeps the
YAML byte-stable for the hub's audit log and avoids
spurious diffs in version control.
## Behaviour
- File browser (left, 240 px) lists `*.yaml` in
`~/.fai/data/flows/`.
- Code field (right) ships YAML syntax highlighting via
`flutter_code_editor` + the highlight package's yaml
grammar.
`~/.fai/data/flows/` with a FLOWS header + refresh icon.
- Graph tab: InteractiveViewer with pan + zoom; drag a
node body to reposition; drag an output port → drop on
an input port to create a `$source.field` reference; click
a node to open the properties panel on the right.
- Text tab: YAML with syntax highlighting, top-aligned via
`expands: true` on the underlying CodeField.
- Run tab: inputs form with text fields + file picks,
Start button, live step list driven by the driver's
event stream, typed outputs once the run resolves.
- Save writes directly to disk via `dart:io`; the hub picks
up the change on its next `ListFlows` / `RunSavedFlow`
call.
- Cmd+S / Ctrl+S — save. Cmd+Enter / Ctrl+Enter — run.
call. Cmd+S / Ctrl+S — save. Cmd+Enter / Ctrl+Enter —
jump to the Run tab.
## Folder layout
```
lib/
├── fai_studio_flow_editor.dart exports public API
└── src/
├── editor_controller.dart shared state + reparse loop
├── flow_editor_page.dart host scaffolding, tabs
├── l10n.dart EN/DE strings
├── run_driver.dart host bridge interface
├── tokens.dart spacing / radius / motion
├── widgets.dart FaiEmptyState + FaiErrorBox
├── model/
│ ├── flow_graph.dart parser + serializer
│ ├── auto_layout.dart topological column layout
│ └── layout_store.dart sidecar JSON I/O
└── widgets/
├── flow_canvas.dart InteractiveViewer + nodes + drag
├── flow_node.dart node card primitive
├── edge_painter.dart cubic bezier edges
├── properties_panel.dart selected-step editor
├── capability_picker.dart Add-step modal
└── run_tab.dart inputs + step progress + outputs
```
## Swap it
@ -55,24 +123,18 @@ To use a different editor:
1. Fork this repo (or write your own from scratch).
2. Keep the `FlowEditorPage` constructor signature
(`initialFlowName`, `locale`, `onRun`) — that's the
stable host contract.
3. Point Studio's pubspec at your fork (or local-path
during development):
```yaml
fai_studio_flow_editor:
git:
url: https://your-host/your/flow-editor
ref: main
```
4. Rebuild Studio. Done.
(`initialFlowName`, `locale`, `runDriver`,
`availableCapabilities`) — that's the stable host
contract.
3. Point Studio's pubspec at your fork.
4. Rebuild Studio.
The contract is intentionally minimal: a single page widget
with three parameters. The package brings its own tokens,
its own empty/error widgets, its own l10n table, so the
host doesn't have to share internals. The trade-off is
visual drift if Studio's design tokens change — that's the
deal you accept for a swappable module.
The contract is minimal: one page widget + a driver
interface. The package brings its own tokens, its own
empty/error widgets, its own l10n table, so the host
doesn't have to share internals. The trade-off is visual
drift if Studio's design tokens change — that's the deal
you accept for a swappable module.
## Develop
@ -82,8 +144,18 @@ flutter analyze
flutter test
```
The package's own widget tests live in `test/`. End-to-end
tests against a live hub stay in the host repo (Studio).
11 unit tests cover the parser (round-trip, edge detection,
approval flagging, leading-comment preservation) and the
controller (open / edit / dirty / select).
## Versioning
Semantic. Major bumps when the public `FlowEditorPage`
signature changes. Adding strings to `FlowEditorStrings` or
events to `FlowRunEvent` is a minor bump. Patch covers
visual + bug fixes inside the package.
Current: **0.2.1** — first WYSIWYG release.
## License