feat(run): host-injected native file picker for flow file inputs

The Run tab asked the operator to type an absolute path into a text
field — with no file dialog anywhere. FlowEditorPage now accepts an
onPickFile callback (PickedFileData: name + bytes) that hosts wire
to their native picker; the path-entry dialog remains only as the
no-host fallback. 0.23.0.

Signed-off-by: flemming-it <sf@flemming.it>
This commit is contained in:
flemming-it 2026-07-17 01:04:40 +02:00
parent 9e73036d0e
commit ae09a55146
6 changed files with 52 additions and 6 deletions

View file

@ -36,11 +36,17 @@ class RunTab extends StatefulWidget {
final FlowEditorController controller;
final FlowEditorStrings strings;
final FlowRunDriver? driver;
/// Host-side native file picker; null keeps the manual
/// path-entry fallback dialog.
final PickFileCallback? onPickFile;
const RunTab({
super.key,
required this.controller,
required this.strings,
this.driver,
this.onPickFile,
});
@override
@ -469,11 +475,21 @@ class _RunTabState extends State<RunTab> {
}
Future<void> _pickFile(String name) async {
// For 0.2.0 the editor relies on the host to inject a
// file-picker via callback; minimal version uses
// dart:io directly for desktop. Studio uses file_picker;
// we fall back to a manual path entry dialog if no host
// picker is available.
// Host-injected native picker first typing an absolute path
// by hand is a last resort, not an input method.
final hostPick = widget.onPickFile;
if (hostPick != null) {
final picked = await hostPick();
if (picked == null || !mounted) return;
setState(() {
_fileInputs[name] = _FilePick(
fileName: picked.fileName,
bytes: picked.bytes,
);
});
return;
}
// Fallback without a host picker: manual path entry.
final controller = TextEditingController();
final ctx = context;
final result = await showDialog<String>(