feat(studio): wire inline approval driver methods
Some checks failed
Security / Security check (push) Failing after 2s

StudioFlowRunDriver gains three new methods that satisfy the
editor 0.21.0 FlowRunDriver interface:

  - pendingApprovalIdForStep(flowName, stepId) — picks the
    newest pending approval row matching this (flow, step)
    pair from HubService.pendingApprovals().
  - approveApproval(approvalId, reviewer) — delegates to
    HubService.approve, same RPC the Approvals page uses.
  - rejectApproval(approvalId, reviewer, reason) — delegates
    to HubService.reject.

End result: when a flow run pauses on system.approval@^0,
the Run tab now renders a complete Approve / Reject form
directly under the awaiting step. Operator no longer needs
to switch tabs to make the decision; the standalone Approvals
page stays available for non-running approvals and history.

Studio bumped to 0.68.0; editor pin moves to 0.21.0.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-06-09 09:18:55 +02:00
parent 971196518c
commit 626404c5e4
4 changed files with 39 additions and 3 deletions

View file

@ -120,6 +120,42 @@ class StudioFlowRunDriver implements editor.FlowRunDriver {
return null;
}
@override
Future<String?> pendingApprovalIdForStep({
required String flowName,
required String stepId,
}) async {
try {
final pending = await HubService.instance.pendingApprovals();
// Match the newest approval for this (flow, step). The hub
// creates one approval row per step invocation; if multiple
// are pending we surface the most recent (operator can still
// navigate to the standalone Approvals page for the others).
final match = pending
.where((p) => p.flowName == flowName && p.stepId == stepId)
.toList()
..sort((a, b) => b.createdAt.compareTo(a.createdAt));
return match.isEmpty ? null : match.first.id;
} catch (_) {
return null;
}
}
@override
Future<void> approveApproval({
required String approvalId,
required String reviewer,
}) =>
HubService.instance.approve(approvalId, reviewer);
@override
Future<void> rejectApproval({
required String approvalId,
required String reviewer,
required String reason,
}) =>
HubService.instance.reject(approvalId, reviewer, reason);
/// Studio's FlowOutput hierarchy is gRPC-shaped (one class
/// per payload variant); the editor's is host-agnostic
/// (text / json / bytes only). File outputs degrade to

View file

@ -27,7 +27,7 @@ import 'widgets/widgets.dart';
/// Studio's own build version. Bump on every UI commit so the
/// running app self-identifies visible in the sidebar header
/// and quick-glance proof that you're seeing the current build.
const String kStudioVersion = '0.67.0';
const String kStudioVersion = '0.68.0';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();

View file

@ -126,7 +126,7 @@ packages:
path: "../fai_studio_flow_editor"
relative: true
source: path
version: "0.20.1"
version: "0.21.0"
fake_async:
dependency: transitive
description:

View file

@ -1,7 +1,7 @@
name: fai_studio
description: "F∆I Studio — desktop GUI for the F∆I hub"
publish_to: 'none'
version: 0.67.0
version: 0.68.0
environment:
sdk: ^3.11.0-200.1.beta