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:
parent
9e73036d0e
commit
ae09a55146
6 changed files with 52 additions and 6 deletions
|
|
@ -1,5 +1,13 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.23.0
|
||||||
|
|
||||||
|
- Run tab file inputs accept a host-injected native file picker
|
||||||
|
(`FlowEditorPage.onPickFile`, new `PickedFileData` /
|
||||||
|
`PickFileCallback` contract). The manual path-entry dialog remains
|
||||||
|
only as the no-host fallback — typing an absolute path by hand is
|
||||||
|
a last resort, not an input method.
|
||||||
|
|
||||||
All notable changes to `chain_studio_flow_editor` recorded here.
|
All notable changes to `chain_studio_flow_editor` recorded here.
|
||||||
Studio bumps its `pubspec.yaml` git ref to a specific release
|
Studio bumps its `pubspec.yaml` git ref to a specific release
|
||||||
of this package on every editor change.
|
of this package on every editor change.
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ export 'src/run_driver.dart'
|
||||||
show
|
show
|
||||||
FlowRunDriver,
|
FlowRunDriver,
|
||||||
FlowRunEvent,
|
FlowRunEvent,
|
||||||
|
PickedFileData,
|
||||||
|
PickFileCallback,
|
||||||
StepStarted,
|
StepStarted,
|
||||||
StepCompleted,
|
StepCompleted,
|
||||||
StepFailed,
|
StepFailed,
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,11 @@ class FlowEditorPage extends StatefulWidget {
|
||||||
/// silent — no install button offered.
|
/// silent — no install button offered.
|
||||||
final List<String> storeCapabilities;
|
final List<String> storeCapabilities;
|
||||||
|
|
||||||
|
/// Host-side native file picker for the Run tab's file inputs.
|
||||||
|
/// Studio passes a real file dialog; null keeps the manual
|
||||||
|
/// path-entry fallback.
|
||||||
|
final PickFileCallback? onPickFile;
|
||||||
|
|
||||||
/// The host's active workspace/project slug (empty = "all
|
/// The host's active workspace/project slug (empty = "all
|
||||||
/// projects", no active workspace). Used only to flag a
|
/// projects", no active workspace). Used only to flag a
|
||||||
/// mismatch when the open flow file declares a *different*
|
/// mismatch when the open flow file declares a *different*
|
||||||
|
|
@ -126,6 +131,7 @@ class FlowEditorPage extends StatefulWidget {
|
||||||
this.storeCapabilities = const [],
|
this.storeCapabilities = const [],
|
||||||
this.activeProject = '',
|
this.activeProject = '',
|
||||||
this.onSwitchToFileProject,
|
this.onSwitchToFileProject,
|
||||||
|
this.onPickFile,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -658,6 +664,7 @@ outputs:
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
strings: _l,
|
strings: _l,
|
||||||
driver: widget.runDriver,
|
driver: widget.runDriver,
|
||||||
|
onPickFile: widget.onPickFile,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,19 @@
|
||||||
|
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
/// A file chosen by the host's native picker for a flow file input.
|
||||||
|
class PickedFileData {
|
||||||
|
final String fileName;
|
||||||
|
final Uint8List bytes;
|
||||||
|
const PickedFileData({required this.fileName, required this.bytes});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Host-side native file picker. Returns null when the operator
|
||||||
|
/// cancels. When a host does not supply one, the Run tab falls back
|
||||||
|
/// to its manual path-entry dialog.
|
||||||
|
typedef PickFileCallback = Future<PickedFileData?> Function();
|
||||||
|
|
||||||
|
|
||||||
abstract class FlowRunDriver {
|
abstract class FlowRunDriver {
|
||||||
/// Trigger a run of [flowName] with the supplied inputs.
|
/// Trigger a run of [flowName] with the supplied inputs.
|
||||||
/// Text + file inputs come in separate maps so the host
|
/// Text + file inputs come in separate maps so the host
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,17 @@ class RunTab extends StatefulWidget {
|
||||||
final FlowEditorController controller;
|
final FlowEditorController controller;
|
||||||
final FlowEditorStrings strings;
|
final FlowEditorStrings strings;
|
||||||
final FlowRunDriver? driver;
|
final FlowRunDriver? driver;
|
||||||
|
|
||||||
|
/// Host-side native file picker; null keeps the manual
|
||||||
|
/// path-entry fallback dialog.
|
||||||
|
final PickFileCallback? onPickFile;
|
||||||
|
|
||||||
const RunTab({
|
const RunTab({
|
||||||
super.key,
|
super.key,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
required this.strings,
|
required this.strings,
|
||||||
this.driver,
|
this.driver,
|
||||||
|
this.onPickFile,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -469,11 +475,21 @@ class _RunTabState extends State<RunTab> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _pickFile(String name) async {
|
Future<void> _pickFile(String name) async {
|
||||||
// For 0.2.0 the editor relies on the host to inject a
|
// Host-injected native picker first — typing an absolute path
|
||||||
// file-picker via callback; minimal version uses
|
// by hand is a last resort, not an input method.
|
||||||
// dart:io directly for desktop. Studio uses file_picker;
|
final hostPick = widget.onPickFile;
|
||||||
// we fall back to a manual path entry dialog if no host
|
if (hostPick != null) {
|
||||||
// picker is available.
|
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 controller = TextEditingController();
|
||||||
final ctx = context;
|
final ctx = context;
|
||||||
final result = await showDialog<String>(
|
final result = await showDialog<String>(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: chain_studio_flow_editor
|
name: chain_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.22.0
|
version: 0.23.0
|
||||||
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