feat(editor): Fix-dialog from diagnostic strip + inline approval in Run tab

Two big operator-UX wins that the previous batch missed:

1. Diagnostic-strip header gets a 'Beheben' (Fix) button next
   to 'Copy all'. Clicking opens a focused modal listing every
   issue with its quick-fix actions plus an 'apply every quick
   fix' master button. Replaces the cramped expand-strip flow
   for operators who want a deliberate dialog instead of
   scrolling in a 200-px footer.

2. Run tab inlines the Approve / Reject form right under any
   step that the hub paused on system.approval@^0. The
   FlowRunDriver gains three new methods (host-implements
   them; defaults throw with a clear message):

     - pendingApprovalIdForStep(flowName, stepId) → String?
     - approveApproval(approvalId, reviewer) → Future<void>
     - rejectApproval(approvalId, reviewer, reason)

   The _InlineApprovalCard polls the driver for ~3s waiting for
   the hub to materialise the approval row (event-stream race
   against the hub's create), then renders the same form the
   Approvals page does — reviewer + optional reason + Approve /
   Reject buttons. After submit the hub picks up the decision
   on its next poll and emits step.approved / step.rejected,
   which the existing event stream already maps to the right
   step status.

   Closes the operator question 'wie soll das gehen dass da
   Freigaben landen?': they land in the Approvals page AND
   inline in the Run tab; the inline path is now the natural
   workflow.

All 36 editor tests + 24 Studio tests green. Bumped to 0.21.0.

Signed-off-by: flemming-it <sf@flemming.it>
This commit is contained in:
flemming-it 2026-06-09 09:18:17 +02:00
parent 8b38584555
commit 303e318ba8
5 changed files with 593 additions and 1 deletions

View file

@ -51,6 +51,40 @@ abstract class FlowRunDriver {
/// A real implementation hits the hub's ModuleInfo RPC and
/// maps the result to [ModuleSpec].
Future<ModuleSpec?> moduleInfo(String capability) async => null;
/// Resolve the pending approval id for `(flowName, stepId)`
/// when the flow is paused on a `system.approval@^0` step.
/// Default returns `null` so legacy hosts that didn't update
/// keep compiling the editor's Run tab then falls back to
/// directing the operator at the standalone Approvals page.
Future<String?> pendingApprovalIdForStep({
required String flowName,
required String stepId,
}) async =>
null;
/// Approve the named approval. `reviewer` is the audit-log
/// identity the host wants attributed (typically OS user +
/// '@studio'). Throws on hub-side failure; UI surfaces it.
Future<void> approveApproval({
required String approvalId,
required String reviewer,
}) async {
throw UnsupportedError(
'FlowRunDriver host did not implement approveApproval',
);
}
/// Reject the named approval with a free-form reason.
Future<void> rejectApproval({
required String approvalId,
required String reviewer,
required String reason,
}) async {
throw UnsupportedError(
'FlowRunDriver host did not implement rejectApproval',
);
}
}
/// Declared inputs + outputs of one installed module, as seen