feat(t-paliad-154) commit 4/5: admin /admin/approval-policies page
New TSX page shell + client orchestration + admin-index card + CSS for the matrix + i18n keys (DE+EN). Page structure: - Section 1 'Partner-Unit-Standards': accordion list, each <details> block expandable into the 8-cell matrix for that partner unit. - Section 2 'Projekt-spezifisch': search-driven project picker → matrix showing the EFFECTIVE policy per cell with attribution chips (Projekt / Geerbt / Standard) per source. - Bulk-apply modal: 'Auf Unterprojekte anwenden' button per project; lists affected descendants; POST to /api/admin/approval-policies/apply-to-descendants. Cell semantics: - Select per cell with options: '— keine Regel —' (= DELETE), partner / of_counsel / associate / senior_pa / pa / 'Keine Genehmigung' (= 'none' sentinel, project-row only). - Change → PUT for any value, DELETE for empty. Re-fetch the affected scope so attribution chips reflect the new state. CSS: matrix grid on desktop (≥700px); two stacked sections (Fristen / Termine) below 700px via media query — both rendered in DOM, CSS toggles. All tokens are existing --color-* / --status-* / --hlc-*-rgb (no bare --surface / --text-muted / --bg-subtle). i18n: 42 new keys × 2 languages = 84 entries. Total i18n keys: 1924. Build: bun run build clean (i18n codegen updated, IIFE wrapping enforced).
This commit is contained in:
@@ -10,6 +10,7 @@ const ICON_LOG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" str
|
||||
const ICON_MAIL = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="14" rx="2"/><polyline points="3 7 12 13 21 7"/></svg>';
|
||||
const ICON_FLAG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" y1="22" x2="4" y2="15"/></svg>';
|
||||
const ICON_TABLE = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="3" y1="15" x2="21" y2="15"/><line x1="9" y1="3" x2="9" y2="21"/></svg>';
|
||||
const ICON_SHIELD = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="m9 12 2 2 4-4"/></svg>';
|
||||
|
||||
interface PlannedCard {
|
||||
icon: string;
|
||||
@@ -88,6 +89,11 @@ export function renderAdmin(): string {
|
||||
<h2 data-i18n="admin.card.broadcasts.title">Broadcasts</h2>
|
||||
<p data-i18n="admin.card.broadcasts.desc">Versendete Massen-E-Mails an Teamauswahlen einsehen.</p>
|
||||
</a>
|
||||
<a href="/admin/approval-policies" className="card card-link">
|
||||
<div className="card-icon" dangerouslySetInnerHTML={{ __html: ICON_SHIELD }} />
|
||||
<h2 data-i18n="admin.card.approval_policies.title">Genehmigungspflichten</h2>
|
||||
<p data-i18n="admin.card.approval_policies.desc">4-Augen-Prüfung pro Projekt und Partner Unit konfigurieren.</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<h3 className="section-heading admin-section-planned" data-i18n="admin.section.planned">Geplant</h3>
|
||||
|
||||
Reference in New Issue
Block a user