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:
parent
f90d8cc7a7
commit
2002486828
13 changed files with 1215 additions and 64 deletions
|
|
@ -406,6 +406,50 @@
|
|||
"error": { "type": "String" }
|
||||
}
|
||||
},
|
||||
"flowsMissingModulesLabel": "Braucht:",
|
||||
"flowsRunDisabledTooltip": "Erst die fehlenden Module installieren.",
|
||||
"welcomeChecklistAllSetTitle": "Du bist eingerichtet.",
|
||||
"welcomeChecklistAllSetBody": "Drei Stränge, an denen du als nächstes ziehen kannst:",
|
||||
"welcomeChecklistNextAuditTitle": "Audit-Log lesen",
|
||||
"welcomeChecklistNextAuditBody": "Jede Installation, jeder Flow-Lauf, jede Freigabe landet im hash-verketteten Log. Im Protokoll-Tab siehst du, was dein Hub gemacht hat.",
|
||||
"welcomeChecklistNextAuditButton": "Protokoll öffnen",
|
||||
"welcomeChecklistNextTodayTitle": "Daily-Today-Story einrichten",
|
||||
"welcomeChecklistNextTodayBody": "tools/today/propose.sh per Cron laufen lassen und die Editorial-Karte im Store füllt sich mit operator-kuratierten Stories.",
|
||||
"welcomeChecklistNextTodayButton": "Today-Doku öffnen",
|
||||
"welcomeChecklistNextModuleTitle": "Eigenes Modul bauen",
|
||||
"welcomeChecklistNextModuleBody": "Mit `fai new module <name>` ein Rust+WASM-Scaffold erzeugen. Das module-sdk übernimmt die WIT-Plumbing; du schreibst nur ein typisiertes invoke.",
|
||||
"welcomeChecklistNextModuleButton": "Doku lesen",
|
||||
"auditGroupToday": "HEUTE",
|
||||
"auditGroupYesterday": "GESTERN",
|
||||
"auditGroupThisWeek": "DIESE WOCHE",
|
||||
"auditGroupOlder": "ÄLTER",
|
||||
"auditEventViewFlowRun": "Flow-Lauf ansehen",
|
||||
"auditFlowRunDialogTitle": "Flow-Lauf · {flow}",
|
||||
"@auditFlowRunDialogTitle": { "placeholders": { "flow": { "type": "String" } } },
|
||||
"auditFlowRunDialogSubtitle": "{n} {n, plural, =1{Ereignis} other{Ereignisse}} für Lauf {execution}",
|
||||
"@auditFlowRunDialogSubtitle": {
|
||||
"placeholders": {
|
||||
"n": { "type": "int" },
|
||||
"execution": { "type": "String" }
|
||||
}
|
||||
},
|
||||
"approvalsSelectAll": "Alle wählen",
|
||||
"approvalsClearSelection": "Auswahl aufheben",
|
||||
"approvalsBatchSelected": "{n} ausgewählt",
|
||||
"@approvalsBatchSelected": { "placeholders": { "n": { "type": "int" } } },
|
||||
"approvalsBatchApprove": "Alle freigeben",
|
||||
"approvalsBatchReject": "Alle ablehnen",
|
||||
"approvalsBatchApproveDoneToast": "{n} Freigaben erteilt.",
|
||||
"@approvalsBatchApproveDoneToast": { "placeholders": { "n": { "type": "int" } } },
|
||||
"approvalsBatchRejectDoneToast": "{n} Freigaben abgelehnt.",
|
||||
"@approvalsBatchRejectDoneToast": { "placeholders": { "n": { "type": "int" } } },
|
||||
"approvalsBatchPartialFailure": "{ok} erledigt, {failed} fehlgeschlagen.",
|
||||
"@approvalsBatchPartialFailure": {
|
||||
"placeholders": {
|
||||
"ok": { "type": "int" },
|
||||
"failed": { "type": "int" }
|
||||
}
|
||||
},
|
||||
"flowsRunButton": "Starten",
|
||||
"flowsRunningTitle": "{name} läuft",
|
||||
"@flowsRunningTitle": { "placeholders": { "name": { "type": "String" } } },
|
||||
|
|
|
|||
|
|
@ -407,6 +407,50 @@
|
|||
"error": { "type": "String" }
|
||||
}
|
||||
},
|
||||
"flowsMissingModulesLabel": "Needs:",
|
||||
"flowsRunDisabledTooltip": "Install the missing modules first.",
|
||||
"welcomeChecklistAllSetTitle": "You're set up.",
|
||||
"welcomeChecklistAllSetBody": "Three threads to pull on next:",
|
||||
"welcomeChecklistNextAuditTitle": "Read the audit log",
|
||||
"welcomeChecklistNextAuditBody": "Every install, flow run, and approval lives in the hash-chained log. Open the Audit tab to see what your hub has been up to.",
|
||||
"welcomeChecklistNextAuditButton": "Open Audit",
|
||||
"welcomeChecklistNextTodayTitle": "Set up the daily Today story",
|
||||
"welcomeChecklistNextTodayBody": "Run tools/today/propose.sh on a cron and the editorial card on the store auto-fills with operator-curated narratives.",
|
||||
"welcomeChecklistNextTodayButton": "Open Today docs",
|
||||
"welcomeChecklistNextModuleTitle": "Build your own module",
|
||||
"welcomeChecklistNextModuleBody": "Generate a Rust+WASM scaffold with `fai new module <name>`. The module-sdk handles the WIT plumbing; you write a typed invoke.",
|
||||
"welcomeChecklistNextModuleButton": "Read the docs",
|
||||
"auditGroupToday": "TODAY",
|
||||
"auditGroupYesterday": "YESTERDAY",
|
||||
"auditGroupThisWeek": "EARLIER THIS WEEK",
|
||||
"auditGroupOlder": "OLDER",
|
||||
"auditEventViewFlowRun": "View flow run",
|
||||
"auditFlowRunDialogTitle": "Flow run · {flow}",
|
||||
"@auditFlowRunDialogTitle": { "placeholders": { "flow": { "type": "String" } } },
|
||||
"auditFlowRunDialogSubtitle": "{n} {n, plural, =1{event} other{events}} for execution {execution}",
|
||||
"@auditFlowRunDialogSubtitle": {
|
||||
"placeholders": {
|
||||
"n": { "type": "int" },
|
||||
"execution": { "type": "String" }
|
||||
}
|
||||
},
|
||||
"approvalsSelectAll": "Select all",
|
||||
"approvalsClearSelection": "Clear",
|
||||
"approvalsBatchSelected": "{n} selected",
|
||||
"@approvalsBatchSelected": { "placeholders": { "n": { "type": "int" } } },
|
||||
"approvalsBatchApprove": "Approve all",
|
||||
"approvalsBatchReject": "Reject all",
|
||||
"approvalsBatchApproveDoneToast": "{n} approvals approved.",
|
||||
"@approvalsBatchApproveDoneToast": { "placeholders": { "n": { "type": "int" } } },
|
||||
"approvalsBatchRejectDoneToast": "{n} approvals rejected.",
|
||||
"@approvalsBatchRejectDoneToast": { "placeholders": { "n": { "type": "int" } } },
|
||||
"approvalsBatchPartialFailure": "{ok} done, {failed} failed.",
|
||||
"@approvalsBatchPartialFailure": {
|
||||
"placeholders": {
|
||||
"ok": { "type": "int" },
|
||||
"failed": { "type": "int" }
|
||||
}
|
||||
},
|
||||
"flowsRunButton": "Run",
|
||||
"flowsRunningTitle": "Running {name}",
|
||||
"@flowsRunningTitle": { "placeholders": { "name": { "type": "String" } } },
|
||||
|
|
|
|||
|
|
@ -1880,6 +1880,174 @@ abstract class AppLocalizations {
|
|||
/// **'Could not read \"{path}\": {error}'**
|
||||
String flowsFileReadFailed(String path, String error);
|
||||
|
||||
/// No description provided for @flowsMissingModulesLabel.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Needs:'**
|
||||
String get flowsMissingModulesLabel;
|
||||
|
||||
/// No description provided for @flowsRunDisabledTooltip.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Install the missing modules first.'**
|
||||
String get flowsRunDisabledTooltip;
|
||||
|
||||
/// No description provided for @welcomeChecklistAllSetTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'You\'re set up.'**
|
||||
String get welcomeChecklistAllSetTitle;
|
||||
|
||||
/// No description provided for @welcomeChecklistAllSetBody.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Three threads to pull on next:'**
|
||||
String get welcomeChecklistAllSetBody;
|
||||
|
||||
/// No description provided for @welcomeChecklistNextAuditTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Read the audit log'**
|
||||
String get welcomeChecklistNextAuditTitle;
|
||||
|
||||
/// No description provided for @welcomeChecklistNextAuditBody.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Every install, flow run, and approval lives in the hash-chained log. Open the Audit tab to see what your hub has been up to.'**
|
||||
String get welcomeChecklistNextAuditBody;
|
||||
|
||||
/// No description provided for @welcomeChecklistNextAuditButton.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Open Audit'**
|
||||
String get welcomeChecklistNextAuditButton;
|
||||
|
||||
/// No description provided for @welcomeChecklistNextTodayTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Set up the daily Today story'**
|
||||
String get welcomeChecklistNextTodayTitle;
|
||||
|
||||
/// No description provided for @welcomeChecklistNextTodayBody.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Run tools/today/propose.sh on a cron and the editorial card on the store auto-fills with operator-curated narratives.'**
|
||||
String get welcomeChecklistNextTodayBody;
|
||||
|
||||
/// No description provided for @welcomeChecklistNextTodayButton.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Open Today docs'**
|
||||
String get welcomeChecklistNextTodayButton;
|
||||
|
||||
/// No description provided for @welcomeChecklistNextModuleTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Build your own module'**
|
||||
String get welcomeChecklistNextModuleTitle;
|
||||
|
||||
/// No description provided for @welcomeChecklistNextModuleBody.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Generate a Rust+WASM scaffold with `fai new module <name>`. The module-sdk handles the WIT plumbing; you write a typed invoke.'**
|
||||
String get welcomeChecklistNextModuleBody;
|
||||
|
||||
/// No description provided for @welcomeChecklistNextModuleButton.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Read the docs'**
|
||||
String get welcomeChecklistNextModuleButton;
|
||||
|
||||
/// No description provided for @auditGroupToday.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'TODAY'**
|
||||
String get auditGroupToday;
|
||||
|
||||
/// No description provided for @auditGroupYesterday.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'YESTERDAY'**
|
||||
String get auditGroupYesterday;
|
||||
|
||||
/// No description provided for @auditGroupThisWeek.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'EARLIER THIS WEEK'**
|
||||
String get auditGroupThisWeek;
|
||||
|
||||
/// No description provided for @auditGroupOlder.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'OLDER'**
|
||||
String get auditGroupOlder;
|
||||
|
||||
/// No description provided for @auditEventViewFlowRun.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'View flow run'**
|
||||
String get auditEventViewFlowRun;
|
||||
|
||||
/// No description provided for @auditFlowRunDialogTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Flow run · {flow}'**
|
||||
String auditFlowRunDialogTitle(String flow);
|
||||
|
||||
/// No description provided for @auditFlowRunDialogSubtitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{n} {n, plural, =1{event} other{events}} for execution {execution}'**
|
||||
String auditFlowRunDialogSubtitle(int n, String execution);
|
||||
|
||||
/// No description provided for @approvalsSelectAll.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Select all'**
|
||||
String get approvalsSelectAll;
|
||||
|
||||
/// No description provided for @approvalsClearSelection.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Clear'**
|
||||
String get approvalsClearSelection;
|
||||
|
||||
/// No description provided for @approvalsBatchSelected.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{n} selected'**
|
||||
String approvalsBatchSelected(int n);
|
||||
|
||||
/// No description provided for @approvalsBatchApprove.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Approve all'**
|
||||
String get approvalsBatchApprove;
|
||||
|
||||
/// No description provided for @approvalsBatchReject.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Reject all'**
|
||||
String get approvalsBatchReject;
|
||||
|
||||
/// No description provided for @approvalsBatchApproveDoneToast.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{n} approvals approved.'**
|
||||
String approvalsBatchApproveDoneToast(int n);
|
||||
|
||||
/// No description provided for @approvalsBatchRejectDoneToast.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{n} approvals rejected.'**
|
||||
String approvalsBatchRejectDoneToast(int n);
|
||||
|
||||
/// No description provided for @approvalsBatchPartialFailure.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{ok} done, {failed} failed.'**
|
||||
String approvalsBatchPartialFailure(int ok, int failed);
|
||||
|
||||
/// No description provided for @flowsRunButton.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -1074,6 +1074,111 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
return 'Could not read \"$path\": $error';
|
||||
}
|
||||
|
||||
@override
|
||||
String get flowsMissingModulesLabel => 'Needs:';
|
||||
|
||||
@override
|
||||
String get flowsRunDisabledTooltip => 'Install the missing modules first.';
|
||||
|
||||
@override
|
||||
String get welcomeChecklistAllSetTitle => 'You\'re set up.';
|
||||
|
||||
@override
|
||||
String get welcomeChecklistAllSetBody => 'Three threads to pull on next:';
|
||||
|
||||
@override
|
||||
String get welcomeChecklistNextAuditTitle => 'Read the audit log';
|
||||
|
||||
@override
|
||||
String get welcomeChecklistNextAuditBody =>
|
||||
'Every install, flow run, and approval lives in the hash-chained log. Open the Audit tab to see what your hub has been up to.';
|
||||
|
||||
@override
|
||||
String get welcomeChecklistNextAuditButton => 'Open Audit';
|
||||
|
||||
@override
|
||||
String get welcomeChecklistNextTodayTitle => 'Set up the daily Today story';
|
||||
|
||||
@override
|
||||
String get welcomeChecklistNextTodayBody =>
|
||||
'Run tools/today/propose.sh on a cron and the editorial card on the store auto-fills with operator-curated narratives.';
|
||||
|
||||
@override
|
||||
String get welcomeChecklistNextTodayButton => 'Open Today docs';
|
||||
|
||||
@override
|
||||
String get welcomeChecklistNextModuleTitle => 'Build your own module';
|
||||
|
||||
@override
|
||||
String get welcomeChecklistNextModuleBody =>
|
||||
'Generate a Rust+WASM scaffold with `fai new module <name>`. The module-sdk handles the WIT plumbing; you write a typed invoke.';
|
||||
|
||||
@override
|
||||
String get welcomeChecklistNextModuleButton => 'Read the docs';
|
||||
|
||||
@override
|
||||
String get auditGroupToday => 'TODAY';
|
||||
|
||||
@override
|
||||
String get auditGroupYesterday => 'YESTERDAY';
|
||||
|
||||
@override
|
||||
String get auditGroupThisWeek => 'EARLIER THIS WEEK';
|
||||
|
||||
@override
|
||||
String get auditGroupOlder => 'OLDER';
|
||||
|
||||
@override
|
||||
String get auditEventViewFlowRun => 'View flow run';
|
||||
|
||||
@override
|
||||
String auditFlowRunDialogTitle(String flow) {
|
||||
return 'Flow run · $flow';
|
||||
}
|
||||
|
||||
@override
|
||||
String auditFlowRunDialogSubtitle(int n, String execution) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
n,
|
||||
locale: localeName,
|
||||
other: 'events',
|
||||
one: 'event',
|
||||
);
|
||||
return '$n $_temp0 for execution $execution';
|
||||
}
|
||||
|
||||
@override
|
||||
String get approvalsSelectAll => 'Select all';
|
||||
|
||||
@override
|
||||
String get approvalsClearSelection => 'Clear';
|
||||
|
||||
@override
|
||||
String approvalsBatchSelected(int n) {
|
||||
return '$n selected';
|
||||
}
|
||||
|
||||
@override
|
||||
String get approvalsBatchApprove => 'Approve all';
|
||||
|
||||
@override
|
||||
String get approvalsBatchReject => 'Reject all';
|
||||
|
||||
@override
|
||||
String approvalsBatchApproveDoneToast(int n) {
|
||||
return '$n approvals approved.';
|
||||
}
|
||||
|
||||
@override
|
||||
String approvalsBatchRejectDoneToast(int n) {
|
||||
return '$n approvals rejected.';
|
||||
}
|
||||
|
||||
@override
|
||||
String approvalsBatchPartialFailure(int ok, int failed) {
|
||||
return '$ok done, $failed failed.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get flowsRunButton => 'Run';
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue