feat(t-paliad-138): Verlauf rendering for approval lifecycle events

Commit 8 of 8. Bilingual (DE primary / EN secondary) translations for
the four approval event_types per entity that ApprovalService emits
into paliad.project_events:

  deadline_approval_requested / _approved / _rejected / _revoked
  appointment_approval_requested / _approved / _rejected / _revoked

Each gets:
- event.title.<event_type>          — full Verlauf-card heading
- event.description.<event_type>    — full-sentence localized description
- dashboard.action.short.<event_type> — verb-form for the dashboard activity feed

The existing translateEvent dispatch in i18n.ts handles these
automatically — it already keys off event.title.<event_type> for the
title, and the deadline_* / appointment_* prefix branch in
translateEventDescription falls through to event.description.<event_type>
when the stored body has no quoted title (which is true for the
approval-event descriptions emitted by ApprovalService).

Result: every project's Verlauf tab now renders the full 4-eye
lifecycle trail inline alongside the existing deadline_created /
deadline_updated / etc. rows. The /admin/audit-log timeline picks
them up too via the union path.

Pair-card rendering (request + decision side-by-side keyed by
metadata.approval_request_id) was a stretch goal in the design doc;
the current per-event row rendering already conveys the full story
chronologically without needing that pairing logic.
This commit is contained in:
m
2026-05-06 16:08:35 +02:00
parent deef5aaff5
commit 0d54da1d5b
2 changed files with 76 additions and 0 deletions

View File

@@ -821,6 +821,33 @@ const translations: Record<Lang, Record<string, string>> = {
"event.title.appointment_updated": "Termin ge\u00e4ndert",
"event.title.appointment_deleted": "Termin gel\u00f6scht",
"event.title.appointment_project_changed": "Termin verschoben",
// 4-eye approval lifecycle (t-paliad-138). Verlauf renders these as
// a paired card with the original lifecycle event (e.g.
// "Frist angelegt" + "Genehmigung erteilt von Bert").
"event.title.deadline_approval_requested": "Genehmigung beantragt",
"event.title.deadline_approval_approved": "Genehmigung erteilt",
"event.title.deadline_approval_rejected": "Genehmigung abgelehnt",
"event.title.deadline_approval_revoked": "Anfrage zurückgezogen",
"event.title.appointment_approval_requested": "Genehmigung beantragt",
"event.title.appointment_approval_approved": "Genehmigung erteilt",
"event.title.appointment_approval_rejected": "Genehmigung abgelehnt",
"event.title.appointment_approval_revoked": "Anfrage zurückgezogen",
"event.description.deadline_approval_requested": "4-Augen-Genehmigung für Frist beantragt",
"event.description.deadline_approval_approved": "Genehmigung für Frist erteilt",
"event.description.deadline_approval_rejected": "Genehmigung für Frist abgelehnt",
"event.description.deadline_approval_revoked": "Genehmigungsanfrage für Frist zurückgezogen",
"event.description.appointment_approval_requested": "4-Augen-Genehmigung für Termin beantragt",
"event.description.appointment_approval_approved": "Genehmigung für Termin erteilt",
"event.description.appointment_approval_rejected": "Genehmigung für Termin abgelehnt",
"event.description.appointment_approval_revoked": "Genehmigungsanfrage für Termin zurückgezogen",
"dashboard.action.short.deadline_approval_requested": "beantragte Genehmigung",
"dashboard.action.short.deadline_approval_approved": "genehmigte Frist",
"dashboard.action.short.deadline_approval_rejected": "lehnte Frist ab",
"dashboard.action.short.deadline_approval_revoked": "zog Anfrage zurück",
"dashboard.action.short.appointment_approval_requested": "beantragte Genehmigung",
"dashboard.action.short.appointment_approval_approved": "genehmigte Termin",
"dashboard.action.short.appointment_approval_rejected": "lehnte Termin ab",
"dashboard.action.short.appointment_approval_revoked": "zog Anfrage zurück",
"event.title.checklist_created": "Checkliste angelegt",
"event.title.checklist_renamed": "Checkliste umbenannt",
"event.title.checklist_linked": "Checkliste verkn\u00fcpft",
@@ -2472,6 +2499,31 @@ const translations: Record<Lang, Record<string, string>> = {
"event.title.appointment_updated": "Appointment updated",
"event.title.appointment_deleted": "Appointment deleted",
"event.title.appointment_project_changed": "Appointment moved",
// 4-eye approval lifecycle (t-paliad-138).
"event.title.deadline_approval_requested": "Approval requested",
"event.title.deadline_approval_approved": "Approval granted",
"event.title.deadline_approval_rejected": "Approval rejected",
"event.title.deadline_approval_revoked": "Request revoked",
"event.title.appointment_approval_requested": "Approval requested",
"event.title.appointment_approval_approved": "Approval granted",
"event.title.appointment_approval_rejected": "Approval rejected",
"event.title.appointment_approval_revoked": "Request revoked",
"event.description.deadline_approval_requested": "Four-eyes approval requested for deadline",
"event.description.deadline_approval_approved": "Deadline approval granted",
"event.description.deadline_approval_rejected": "Deadline approval rejected",
"event.description.deadline_approval_revoked": "Deadline approval request revoked",
"event.description.appointment_approval_requested": "Four-eyes approval requested for appointment",
"event.description.appointment_approval_approved": "Appointment approval granted",
"event.description.appointment_approval_rejected": "Appointment approval rejected",
"event.description.appointment_approval_revoked": "Appointment approval request revoked",
"dashboard.action.short.deadline_approval_requested": "requested approval",
"dashboard.action.short.deadline_approval_approved": "approved deadline",
"dashboard.action.short.deadline_approval_rejected": "rejected deadline",
"dashboard.action.short.deadline_approval_revoked": "revoked request",
"dashboard.action.short.appointment_approval_requested": "requested approval",
"dashboard.action.short.appointment_approval_approved": "approved appointment",
"dashboard.action.short.appointment_approval_rejected": "rejected appointment",
"dashboard.action.short.appointment_approval_revoked": "revoked request",
"event.title.checklist_created": "Checklist created",
"event.title.checklist_renamed": "Checklist renamed",
"event.title.checklist_linked": "Checklist linked",

View File

@@ -508,6 +508,10 @@ export type I18nKey =
| "common.cancel"
| "dashboard.action.short.akte_archived"
| "dashboard.action.short.akte_created"
| "dashboard.action.short.appointment_approval_approved"
| "dashboard.action.short.appointment_approval_rejected"
| "dashboard.action.short.appointment_approval_requested"
| "dashboard.action.short.appointment_approval_revoked"
| "dashboard.action.short.appointment_created"
| "dashboard.action.short.appointment_deleted"
| "dashboard.action.short.appointment_project_changed"
@@ -525,6 +529,10 @@ export type I18nKey =
| "dashboard.action.short.checkliste_reset"
| "dashboard.action.short.checkliste_unlinked"
| "dashboard.action.short.collaborators_updated"
| "dashboard.action.short.deadline_approval_approved"
| "dashboard.action.short.deadline_approval_rejected"
| "dashboard.action.short.deadline_approval_requested"
| "dashboard.action.short.deadline_approval_revoked"
| "dashboard.action.short.deadline_completed"
| "dashboard.action.short.deadline_created"
| "dashboard.action.short.deadline_deleted"
@@ -897,10 +905,18 @@ export type I18nKey =
| "einstellungen.tab.caldav"
| "einstellungen.tab.profil"
| "einstellungen.title"
| "event.description.appointment_approval_approved"
| "event.description.appointment_approval_rejected"
| "event.description.appointment_approval_requested"
| "event.description.appointment_approval_revoked"
| "event.description.appointment_created"
| "event.description.appointment_deleted"
| "event.description.appointment_project_changed"
| "event.description.appointment_updated"
| "event.description.deadline_approval_approved"
| "event.description.deadline_approval_rejected"
| "event.description.deadline_approval_requested"
| "event.description.deadline_approval_revoked"
| "event.description.deadline_completed"
| "event.description.deadline_created"
| "event.description.deadline_deleted"
@@ -912,6 +928,10 @@ export type I18nKey =
| "event.note.parent.appointment"
| "event.note.parent.deadline"
| "event.note.parent.project"
| "event.title.appointment_approval_approved"
| "event.title.appointment_approval_rejected"
| "event.title.appointment_approval_requested"
| "event.title.appointment_approval_revoked"
| "event.title.appointment_created"
| "event.title.appointment_deleted"
| "event.title.appointment_project_changed"
@@ -922,6 +942,10 @@ export type I18nKey =
| "event.title.checklist_renamed"
| "event.title.checklist_reset"
| "event.title.checklist_unlinked"
| "event.title.deadline_approval_approved"
| "event.title.deadline_approval_rejected"
| "event.title.deadline_approval_requested"
| "event.title.deadline_approval_revoked"
| "event.title.deadline_completed"
| "event.title.deadline_created"
| "event.title.deadline_deleted"