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:
parent
9d21bd5318
commit
cae5c94c4d
2 changed files with 113 additions and 41 deletions
152
README.md
152
README.md
|
|
@ -1,42 +1,110 @@
|
||||||
# fai_studio_flow_editor
|
# 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
|
## Public surface
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
import 'package:fai_studio_flow_editor/fai_studio_flow_editor.dart';
|
import 'package:fai_studio_flow_editor/fai_studio_flow_editor.dart';
|
||||||
|
|
||||||
// Studio embeds the page as one of its destinations:
|
|
||||||
FlowEditorPage(
|
FlowEditorPage(
|
||||||
initialFlowName: 'hello', // optional
|
initialFlowName: String?, // preload this flow
|
||||||
locale: FlowEditorLocale.de, // or .en
|
locale: FlowEditorLocale, // en | de
|
||||||
onRun: (name) => // optional callback
|
runDriver: FlowRunDriver?, // host-supplied hub bridge
|
||||||
HubService.instance.runSavedFlow(name: name),
|
availableCapabilities: List<String>, // for the Add-step picker
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
- **`initialFlowName`** — when set, the page loads that flow
|
Host implements `FlowRunDriver` to bridge the editor's
|
||||||
from `~/.fai/data/flows/<name>.yaml` on first build. Used
|
`runFlow` + `events` calls to whatever talks to the hub:
|
||||||
by Studio's Flows-page pencil → editor route push.
|
|
||||||
- **`locale`** — picks EN or DE for the editor's internal
|
```dart
|
||||||
string table. Studio passes its active locale through.
|
abstract class FlowRunDriver {
|
||||||
- **`onRun`** — async callback that runs the named flow
|
Future<Map<String, FlowOutputValue>> runFlow({
|
||||||
against the host hub and returns the typed outputs map.
|
required String flowName,
|
||||||
When null, the Run button is disabled (e.g. when the
|
required Map<String, String> textInputs,
|
||||||
editor is embedded in a context without hub access).
|
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
|
## Behaviour
|
||||||
|
|
||||||
- File browser (left, 240 px) lists `*.yaml` in
|
- File browser (left, 240 px) lists `*.yaml` in
|
||||||
`~/.fai/data/flows/`.
|
`~/.fai/data/flows/` with a FLOWS header + refresh icon.
|
||||||
- Code field (right) ships YAML syntax highlighting via
|
- Graph tab: InteractiveViewer with pan + zoom; drag a
|
||||||
`flutter_code_editor` + the highlight package's yaml
|
node body to reposition; drag an output port → drop on
|
||||||
grammar.
|
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
|
- Save writes directly to disk via `dart:io`; the hub picks
|
||||||
up the change on its next `ListFlows` / `RunSavedFlow`
|
up the change on its next `ListFlows` / `RunSavedFlow`
|
||||||
call.
|
call. Cmd+S / Ctrl+S — save. Cmd+Enter / Ctrl+Enter —
|
||||||
- Cmd+S / Ctrl+S — save. Cmd+Enter / Ctrl+Enter — run.
|
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
|
## Swap it
|
||||||
|
|
||||||
|
|
@ -55,24 +123,18 @@ To use a different editor:
|
||||||
|
|
||||||
1. Fork this repo (or write your own from scratch).
|
1. Fork this repo (or write your own from scratch).
|
||||||
2. Keep the `FlowEditorPage` constructor signature
|
2. Keep the `FlowEditorPage` constructor signature
|
||||||
(`initialFlowName`, `locale`, `onRun`) — that's the
|
(`initialFlowName`, `locale`, `runDriver`,
|
||||||
stable host contract.
|
`availableCapabilities`) — that's the stable host
|
||||||
3. Point Studio's pubspec at your fork (or local-path
|
contract.
|
||||||
during development):
|
3. Point Studio's pubspec at your fork.
|
||||||
```yaml
|
4. Rebuild Studio.
|
||||||
fai_studio_flow_editor:
|
|
||||||
git:
|
|
||||||
url: https://your-host/your/flow-editor
|
|
||||||
ref: main
|
|
||||||
```
|
|
||||||
4. Rebuild Studio. Done.
|
|
||||||
|
|
||||||
The contract is intentionally minimal: a single page widget
|
The contract is minimal: one page widget + a driver
|
||||||
with three parameters. The package brings its own tokens,
|
interface. The package brings its own tokens, its own
|
||||||
its own empty/error widgets, its own l10n table, so the
|
empty/error widgets, its own l10n table, so the host
|
||||||
host doesn't have to share internals. The trade-off is
|
doesn't have to share internals. The trade-off is visual
|
||||||
visual drift if Studio's design tokens change — that's the
|
drift if Studio's design tokens change — that's the deal
|
||||||
deal you accept for a swappable module.
|
you accept for a swappable module.
|
||||||
|
|
||||||
## Develop
|
## Develop
|
||||||
|
|
||||||
|
|
@ -82,8 +144,18 @@ flutter analyze
|
||||||
flutter test
|
flutter test
|
||||||
```
|
```
|
||||||
|
|
||||||
The package's own widget tests live in `test/`. End-to-end
|
11 unit tests cover the parser (round-trip, edge detection,
|
||||||
tests against a live hub stay in the host repo (Studio).
|
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
|
## License
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: fai_studio_flow_editor
|
name: fai_studio_flow_editor
|
||||||
description: Swappable inline YAML editor for F∆I Studio flows.
|
description: Swappable inline YAML editor for F∆I Studio flows.
|
||||||
version: 0.2.0
|
version: 0.2.1
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
repository: https://git.flemming.ai/fai/studio-flow-editor
|
repository: https://git.flemming.ai/fai/studio-flow-editor
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue