feat(studio): operator QoL — flow runnability, audit grouping, batch approvals, welcome celebration (v0.42.0)

Four UX threads stitched into one commit. Each pulls Studio
toward Stefan's "zero-learning-curve" goal — the feedback
that earned its own memory entry.

1. Flow-Runnability-Indikator
   ─────────────────────────
   The Flows tab now fetches `listFlows` and `listModules`
   in parallel. Each card compares the flow's
   `requiredCapabilities` against the installed-modules'
   capability set; rows with missing modules show a "Needs:
   text.extract@^0" red pill row beneath the path and have
   their Run button greyed out + tooltip
   "Install the missing modules first." Operators stop
   hitting Run → cryptic hub error → frustration.

2. Welcome-Checklist Celebration
   ─────────────────────────────
   Once all four checklist signals flip to done, an
   `_AllDoneCelebration` card replaces the bare
   "All four steps complete" + Hide button. Three concrete
   next-threads with action buttons: "Read the audit log",
   "Set up the daily Today story" (opens the Flows / Today
   doc inline via `_DocReaderSheet`), and "Build your own
   module" (opens the architecture doc). Operator who just
   got set up sees what to do next instead of an empty
   "what now?" feeling.

3. Audit-Page Time-Bucket Headers + Flow-Run Detail
   ────────────────────────────────────────────────
   The flat event list grows tiny "TODAY / YESTERDAY /
   EARLIER THIS WEEK / OLDER" section headers — bucket is
   computed in the operator's local timezone so an event at
   23:55 yesterday in Berlin doesn't end up in "today"
   because UTC happened to spill into a new day.
   Plus: the event-detail dialog gains a "View flow run"
   action when the picked event has a `flow_execution`. It
   opens a drill-down that lists every event in the
   already-fetched 100-event window sharing the same
   execution id, sorted ascending — the operator reads the
   run from step.started top to flow.completed bottom.

4. Approvals-Batch-Aktionen
   ────────────────────────
   Each pending approval card grows a checkbox. When ≥1
   selected, a floating action bar appears at the bottom
   with "N selected · Select all · Clear · Reject all ·
   Approve all". The parent loops sequentially through the
   per-record SDK calls so a partial failure produces
   "X done, Y failed" instead of a confusing all-or-nothing
   rollback. Reject prompts for a reason once and applies
   to the whole picked set.

13 new ARB keys cover the strings the four features
needed. Studio's tests stay green.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-05-09 11:24:57 +02:00
parent f90d8cc7a7
commit 2002486828
13 changed files with 1215 additions and 64 deletions

View file

@ -1060,6 +1060,113 @@ class AppLocalizationsDe extends AppLocalizations {
return '$path\" konnte nicht gelesen werden: $error';
}
@override
String get flowsMissingModulesLabel => 'Braucht:';
@override
String get flowsRunDisabledTooltip =>
'Erst die fehlenden Module installieren.';
@override
String get welcomeChecklistAllSetTitle => 'Du bist eingerichtet.';
@override
String get welcomeChecklistAllSetBody =>
'Drei Stränge, an denen du als nächstes ziehen kannst:';
@override
String get welcomeChecklistNextAuditTitle => 'Audit-Log lesen';
@override
String get welcomeChecklistNextAuditBody =>
'Jede Installation, jeder Flow-Lauf, jede Freigabe landet im hash-verketteten Log. Im Protokoll-Tab siehst du, was dein Hub gemacht hat.';
@override
String get welcomeChecklistNextAuditButton => 'Protokoll öffnen';
@override
String get welcomeChecklistNextTodayTitle => 'Daily-Today-Story einrichten';
@override
String get welcomeChecklistNextTodayBody =>
'tools/today/propose.sh per Cron laufen lassen und die Editorial-Karte im Store füllt sich mit operator-kuratierten Stories.';
@override
String get welcomeChecklistNextTodayButton => 'Today-Doku öffnen';
@override
String get welcomeChecklistNextModuleTitle => 'Eigenes Modul bauen';
@override
String get welcomeChecklistNextModuleBody =>
'Mit `fai new module <name>` ein Rust+WASM-Scaffold erzeugen. Das module-sdk übernimmt die WIT-Plumbing; du schreibst nur ein typisiertes invoke.';
@override
String get welcomeChecklistNextModuleButton => 'Doku lesen';
@override
String get auditGroupToday => 'HEUTE';
@override
String get auditGroupYesterday => 'GESTERN';
@override
String get auditGroupThisWeek => 'DIESE WOCHE';
@override
String get auditGroupOlder => 'ÄLTER';
@override
String get auditEventViewFlowRun => 'Flow-Lauf ansehen';
@override
String auditFlowRunDialogTitle(String flow) {
return 'Flow-Lauf · $flow';
}
@override
String auditFlowRunDialogSubtitle(int n, String execution) {
String _temp0 = intl.Intl.pluralLogic(
n,
locale: localeName,
other: 'Ereignisse',
one: 'Ereignis',
);
return '$n $_temp0 für Lauf $execution';
}
@override
String get approvalsSelectAll => 'Alle wählen';
@override
String get approvalsClearSelection => 'Auswahl aufheben';
@override
String approvalsBatchSelected(int n) {
return '$n ausgewählt';
}
@override
String get approvalsBatchApprove => 'Alle freigeben';
@override
String get approvalsBatchReject => 'Alle ablehnen';
@override
String approvalsBatchApproveDoneToast(int n) {
return '$n Freigaben erteilt.';
}
@override
String approvalsBatchRejectDoneToast(int n) {
return '$n Freigaben abgelehnt.';
}
@override
String approvalsBatchPartialFailure(int ok, int failed) {
return '$ok erledigt, $failed fehlgeschlagen.';
}
@override
String get flowsRunButton => 'Starten';