chain-studio/lib/pages/flows.dart
flemming-it 634fd52635
Some checks failed
Security / Security check (push) Failing after 1s
feat(studio): Flows page IS the editor — three-tab graph+text+run
Studio's Flows destination is now the swappable
fai_studio_flow_editor's full surface: a drag-and-drop
graph view, the raw YAML text editor, and the run tab
with inputs form + live step progress + outputs.

What's gone:
 - The old saved-flows list + per-row run dialog.
 - The separate "flow-editor" navigation destination (one
   icon, not two — operators reach the editor by clicking
   Flows, period).
 - _FlowEditorAdapter (no longer needed; FlowsPage hands
   the runDriver to the editor directly).

What's new:
 - lib/data/flow_run_driver.dart — StudioFlowRunDriver:
   adapter implementing the editor's FlowRunDriver. Maps
   runFlow() to HubService.runSavedFlow and events() to
   HubService.streamEvents filtered to step.* event types.
   Converts proto-shaped FlowOutput variants to the editor's
   host-agnostic FlowOutputValue family.
 - lib/pages/flows.dart — replaced with a 50-line wrapper
   that loads capabilities into the editor's picker dropdown
   and forwards the active locale.

Editor pinned to fai_studio_flow_editor 0.2.0 (commit
870cbc2). All editor state — file list, dirty tracking, tab
selection, graph layout sidecar, properties panel — lives in
the editor package now; Studio just supplies the hub bridge.

Version 0.51.10 -> 0.52.0 (minor bump — Flows-page contract
changed, separate flow-editor destination removed).

flutter analyze: 0 issues. flutter test: 12/12 green.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-06-01 00:52:23 +02:00

81 lines
2.6 KiB
Dart

// FlowsPage — Studio's flow surface. Thin host wrapper around
// the swappable fai_studio_flow_editor package: loads the
// hub's installed capabilities, hands them + a Studio-side
// FlowRunDriver to the editor, and lets the editor own
// everything else (file list, three-tab body, properties
// panel, run progress, …).
//
// Pre-0.52 versions split file-listing and run-dialog state
// across this page. v0.52 moves all of that into the editor
// package so a swap is one pubspec change — Studio doesn't
// need to know what's inside the editor any more.
import 'package:fai_studio_flow_editor/fai_studio_flow_editor.dart';
import 'package:flutter/material.dart';
import '../data/flow_run_driver.dart';
import '../data/hub.dart';
class FlowsPage extends StatefulWidget {
/// Pre-load this flow when the editor first builds. Studio
/// keeps the parameter so the Cmd+K palette + welcome page
/// can deep-link straight into a specific flow.
final String? initialFlowName;
const FlowsPage({super.key, this.initialFlowName});
@override
State<FlowsPage> createState() => _FlowsPageState();
}
class _FlowsPageState extends State<FlowsPage> {
late Future<List<String>> _capabilities;
late final StudioFlowRunDriver _driver;
@override
void initState() {
super.initState();
_driver = StudioFlowRunDriver();
_capabilities = _loadCapabilities();
}
/// Pulls the capability identifiers the picker dialog
/// offers when adding a step. `<capability>@<version>` so
/// the operator can see exactly what they'll be wiring in,
/// matching the format the `use:` field expects. Soft-fails
/// to an empty list if the hub is unreachable — the editor
/// falls back to a free-form text field in that case.
Future<List<String>> _loadCapabilities() async {
try {
final caps = await HubService.instance.allCapabilities();
final entries = caps
.map((c) => '${c.capability}@${c.version}')
.toSet()
.toList()
..sort();
return entries;
} catch (_) {
return const <String>[];
}
}
@override
Widget build(BuildContext context) {
final locale = Localizations.localeOf(context);
final editorLocale = locale.languageCode == 'de'
? FlowEditorLocale.de
: FlowEditorLocale.en;
return FutureBuilder<List<String>>(
future: _capabilities,
builder: (context, snap) {
final caps = snap.data ?? const <String>[];
return FlowEditorPage(
initialFlowName: widget.initialFlowName,
locale: editorLocale,
runDriver: _driver,
availableCapabilities: caps,
);
},
);
}
}