fix(approvals): usertest-panel hardening (0.81.0)

Panel findings against the reworked approvals page, fixed in place:

- Never fabricate the request time: ApprovalRecord.createdAt is
  nullable now; a missing created_at omits the line instead of
  rendering DateTime.now() (which drifted on refresh). Guard:
  approvals_origin_test pins the omit-on-null invariant.
- Copyable errors on approve/reject/batch via showChainErrorSnack
  (the hard project rule) — batch surfaces the first real cause.
- Reject requires a reason: ChainInlineHelp strip + confirm disabled
  while empty, no more silent close-and-nothing-happens.
- Batch approve applies the same no-data confirmation as the single
  path, naming how many selected requests carry no show: data.
- Plainer language: glossary "Vorgang (Flow)", history label FRAGE
  (was PROMPT), no-data hint drops developer jargon.
- One-click copy of the run id; history payload pretty-prints like
  the card.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-07-26 16:05:55 +02:00
parent 28f6fe1a9a
commit f7d7427d91
9 changed files with 411 additions and 122 deletions

View file

@ -2042,7 +2042,7 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get approvalsNoPayload =>
'No data was attached for review. The flow\'s approval step chooses what to show via its \"show:\" field — set it to surface the data behind this decision.';
'No data was attached to this approval. You are deciding without a detail view — when in doubt, ask whoever set up the process. (Technical: the approval step\'s \"show:\" field controls what appears here.)';
@override
String get approvalsNoDataConfirmTitle => 'Approve without review data?';
@ -2064,7 +2064,40 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get approvalsIntroHelp =>
'Paused flows waiting for your decision. Each card shows which flow is holding at which step and what data it puts in front of you — Approve resumes the flow, Reject stops it with your reason.';
'Paused processes (flows) waiting for your decision. Each card shows which process is holding at which step and what data it puts in front of you — Approve resumes it, Reject stops it with your reason.';
@override
String get approvalsRejectDialogHelp =>
'Rejecting stops the process at this step and is recorded with your reason in the audit trail.';
@override
String get approvalsRejectReasonHelper =>
'Required — recorded in the audit log.';
@override
String get approvalsBatchNoDataTitle => 'Approve without review data?';
@override
String approvalsBatchNoDataBody(num count, Object total) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other:
'$count of $total selected approvals have no review data. You are approving them without a detail view.',
one:
'1 of $total selected approvals has no review data. You are approving it without a detail view.',
);
return '$_temp0';
}
@override
String get approvalsCopyRun => 'Copy run id';
@override
String get approvalsRunCopied => 'Run id copied';
@override
String get approvalsUnknownReviewer => '(unknown)';
@override
String get approvalsOriginLabel => 'ORIGIN';
@ -2094,7 +2127,7 @@ class AppLocalizationsEn extends AppLocalizations {
String get approvalsRejectDialogTitle => 'Reject approval';
@override
String get approvalsRejectReasonLabel => 'Reason (recorded in audit log)';
String get approvalsRejectReasonLabel => 'Reason';
@override
String approvalsApprovedToast(String flow, String step) {
@ -2133,7 +2166,7 @@ class AppLocalizationsEn extends AppLocalizations {
String get approvalsDialogReason => 'reason';
@override
String get approvalsDialogPrompt => 'PROMPT';
String get approvalsDialogPrompt => 'QUESTION';
@override
String approvalsExpiresIn(int minutes) {