feat(C): Phase C — Core UI prüfen, vervollständigen, testen
C-ERR-BOUNDARY: ErrorBoundary erweitert (trace_id, Fallback-UI, PluginErrorBoundary) C-NOTIF: NotificationDropdown mit System-Channel-Link C-DOCS: ApiDocs.tsx Seite (Swagger UI iframe) C-A11Y: aria-label, min-h-touch, focus-visible ergänzt C-FE-TEST: 29 neue Tests (ErrorBoundary, ApiDocs, PrintButton, themeStore, NotificationDropdown) C-DOC: ui-design-guidelines.md aktualisiert Verifiziert (keine Änderungen nötig): - C-TAGS, C-CF, C-FILTER, C-DEDUP, C-ONBOARD, C-THEME, C-PWA, C-PRINT TSC: 0 errors, Build: erfolgreich, Vitest: 29/29 passed
This commit is contained in:
@@ -511,7 +511,118 @@ function ContactForm({ open, onClose }) {
|
||||
|
||||
---
|
||||
|
||||
## 10. Datei-Struktur
|
||||
## 10. Error Boundaries & Plugin-Fehlerbehandlung
|
||||
|
||||
### ErrorBoundary (common)
|
||||
|
||||
Die zentrale `ErrorBoundary` in `components/common/ErrorBoundary.tsx` fängt React-Render-Fehler ab und zeigt eine Fallback-UI mit:
|
||||
|
||||
- **Trace-ID**: Jeder Fehler erhält eine eindeutige `trace_id` (Format: `err-<timestamp>-<random>`), die im Fehlerbuffer und im Backend-Log gespeichert wird
|
||||
- **Fehlerdetails**: Ausklappbare Details mit Fehlermeldung und Stack-Trace
|
||||
- **Retry-Button**: Setzt den Error-State zurück und versucht erneut zu rendern
|
||||
- **Neu laden-Button**: Lädt die Seite neu (`window.location.reload()`)
|
||||
- **ARIA**: `role="alert"` und `aria-live="assertive"` für Screenreader
|
||||
|
||||
```tsx
|
||||
import { ErrorBoundary } from '@/components/common/ErrorBoundary';
|
||||
|
||||
<ErrorBoundary>
|
||||
<MyComponent />
|
||||
</ErrorBoundary>
|
||||
|
||||
// Custom Fallback
|
||||
<ErrorBoundary fallback={(error, retry, traceId) => <CustomErrorUI error={error} retry={retry} traceId={traceId} />}>
|
||||
<MyComponent />
|
||||
</ErrorBoundary>
|
||||
```
|
||||
|
||||
### PluginErrorBoundary
|
||||
|
||||
Plugin-Seiten werden zusätzlich durch `PluginErrorBoundary` in `PluginLoader.tsx` umschlossen. Diese zeigt den Plugin-Namen im Fehlerfall und loggt den Fehler mit `pluginName` und `trace_id`.
|
||||
|
||||
### PluginRouteRenderer
|
||||
|
||||
Der `PluginRouteRenderer` (Catch-All Route) ist mit `ErrorBoundary` umschlossen, sodass Plugin-Seiten-Fehler nicht die gesamte App crashen.
|
||||
|
||||
---
|
||||
|
||||
## 11. Print & PDF-Export
|
||||
|
||||
### PrintButton
|
||||
|
||||
Die `PrintButton`-Komponente in `components/common/PrintButton.tsx` bietet ein Dropdown mit Druck- und PDF-Export-Funktionen:
|
||||
|
||||
- **Drucken**: Ruft `printElement(targetId)` oder `printCurrentPage()` auf
|
||||
- **Als PDF**: Ruft `exportToPDF(targetId, filename)` auf (Browser-Print-to-PDF)
|
||||
- **Print-CSS**: `public/print.css` mit `@media print` Regeln — versteckt Sidebars, TopBar, Buttons und formatiert Tabellen/Card für Druck
|
||||
|
||||
```tsx
|
||||
import { PrintButton } from '@/components/common/PrintButton';
|
||||
|
||||
<PrintButton targetId="contact-detail" filename="kontakt-john-doe" />
|
||||
```
|
||||
|
||||
Verwendung in: `ContactDetailPage`, `Reports`, `Calendar`.
|
||||
|
||||
---
|
||||
|
||||
## 12. API-Dokumentation (Swagger UI)
|
||||
|
||||
Die `ApiDocsPage` in `pages/ApiDocs.tsx` bettet die FastAPI Swagger UI in einem iframe ein:
|
||||
|
||||
- Route: `/api-docs` (erfordert `settings:read` Permission)
|
||||
- iframe src: `/docs` (FastAPI Swagger UI)
|
||||
- External-Link: Öffnet `/docs` in neuem Tab
|
||||
- Vollbild-iframe mit Header-Leiste
|
||||
|
||||
---
|
||||
|
||||
## 13. Notification-System
|
||||
|
||||
### NotificationBell + Dropdown
|
||||
|
||||
Die `NotificationBell` in `components/layout/NotificationBell.tsx` zeigt ungelesene Benachrichtigungen mit:
|
||||
|
||||
- **Unread-Badge**: Roter Zähler (max. 99+) mit 30s Polling
|
||||
- **Dropdown**: Liste der Benachrichtigungen, „Alle als gelesen"-Button
|
||||
- **System-Channel-Link**: Öffnet den Kommunikations-System-Channel unter `/communication?channel=system`
|
||||
- **Alle anzeigen**: Navigiert zu `/settings/notifications`
|
||||
|
||||
Das Backend delegiert `/notifications` an den Kommunikations-System-Channel (`post_system_message`).
|
||||
|
||||
---
|
||||
|
||||
## 14. Accessibility (A11Y) Patterns
|
||||
|
||||
### Verbindliche ARIA-Regeln
|
||||
|
||||
| Element | Attribut | Wert |
|
||||
|---|---|---|
|
||||
| Buttons | `aria-label` | Beschreibung der Aktion |
|
||||
| Icon-only Buttons | `aria-label` + `aria-hidden` auf Icon | Icon dekorativ |
|
||||
| Dropdowns | `aria-haspopup="menu"` + `aria-expanded` | true/false |
|
||||
| Menüs | `role="menu"` + `aria-label` | Menüname |
|
||||
| Error-Bereiche | `role="alert"` + `aria-live="assertive"` | Für Screenreader |
|
||||
| Navigation | `aria-label` auf `<nav>` und `<aside>` | „Hauptnavigation" etc. |
|
||||
| Skip-Link | `sr-only focus:not-sr-only` | „Zum Hauptinhalt springen" |
|
||||
|
||||
### Touch Targets
|
||||
|
||||
Alle interaktiven Elemente müssen `min-h-touch` (44px) und `min-w-touch` (44px) haben:
|
||||
|
||||
```tsx
|
||||
<button className="min-h-touch min-w-touch ...">Klick</button>
|
||||
```
|
||||
|
||||
### Focus-Management
|
||||
|
||||
- Sichtbarer Focus-Ring: `focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500`
|
||||
- Skip-Link in `App.tsx`: `sr-only focus:not-sr-only`
|
||||
- `main`-Element mit `tabIndex={-1}` für Tastatur-Fokus
|
||||
|
||||
---
|
||||
|
||||
## 15. Datei-Struktur
|
||||
|
||||
```
|
||||
frontend/src/
|
||||
|
||||
Reference in New Issue
Block a user