Improve error boundary granularity with page and section level boundaries

Implement three-level error boundary strategy:
- Top-level (app shell): catches critical failures
- Page-level: preserves navigation when page crashes
- Section-level: graceful degradation for charts/tables

Create new components:
- PageErrorBoundary: wraps page routes
- SectionErrorBoundary: wraps data-heavy sections

Enhance ErrorBoundary with customizable titles, messages, and reload behavior.

Apply page boundaries to all route handlers in App.tsx.

Apply section boundaries to:
- DashboardPage: server status, ban trend, country charts, ban list
- JailsPage: jail overview, ban/unban form, IP lookup
- MapPage: world map, ban table
- ConfigPage: configuration editor
- HistoryPage: history table, IP detail view
- BlocklistsPage: sources, schedule, import log

Update Web-Development.md with error boundary strategy documentation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-04-28 08:33:39 +02:00
parent 42beb9cf3b
commit da6433b2cf
12 changed files with 453 additions and 143 deletions

View File

@@ -808,15 +808,82 @@ When an API request returns 401 or 403:
---
## 12. Error Handling
## 12. Error Handling & Resilience
### API Error Handling
- Wrap API calls in `try-catch` inside hooks — components should never see raw exceptions.
- **All hook catch blocks must use `handleFetchError` rather than directly calling `setError`.** This ensures auth errors (401/403) are routed to the global session-expiry flow instead of displaying confusing error text in the UI. Use the pattern: `handleFetchError(err, setError, "User-friendly fallback message")`.
- Display user-friendly error messages — never expose stack traces or raw server responses in the UI.
- Use an **error boundary** (`ErrorBoundary` component) at the page level to catch unexpected render errors.
- Log errors to the console (or a future logging service) with sufficient context for debugging.
- Always handle the **loading**, **error**, and **empty** states for every data-driven component.
### Error Boundaries — Granular Fallback Strategy
React error boundaries catch render-time exceptions and allow graceful fallback UI instead of a full white screen crash. BanGUI implements a **three-level error boundary strategy** to balance resilience with UX clarity:
#### Top-Level Boundary (`<ErrorBoundary>`)
- Wraps the entire application in `App.tsx`
- Catches critical failures in auth, theming, or routing infrastructure
- Shows a full-page fallback with reload button
- **Use case:** Rare catastrophic failures; most errors should be caught at lower levels
#### Page-Level Boundary (`<PageErrorBoundary>`)
- Wraps each route in `App.tsx` (Dashboard, Map, Jails, Config, History, Blocklists, etc.)
- Catches render errors in page components and their children
- Shows a page-level fallback but preserves app shell (sidebar navigation stays functional)
- User can still navigate away via the sidebar and retry the page
- **Use case:** Page component crashes (component tree errors, unhandled render-time exceptions)
**Example:**
```tsx
<Route
path="/jails"
element={
<PageErrorBoundary pageName="Jails">
<JailsPage />
</PageErrorBoundary>
}
/>
```
#### Section-Level Boundary (`<SectionErrorBoundary>`)
- Wraps individual data-heavy components within a page (charts, tables, forms)
- Examples: `BanTrendChart`, `TopCountriesBarChart`, `BanTable`, `JailOverviewSection`
- Shows a section-level fallback card but the rest of the page remains functional
- User can retry just that section or interact with other sections
- **Use case:** Component-specific data fetching errors, rendering issues in risky components
**Example:**
```tsx
<div className={styles.section}>
<div className={styles.sectionHeader}>
<Text as="h2" size={500} weight="semibold">Ban Trend</Text>
</div>
<SectionErrorBoundary sectionName="Ban Trend Chart">
<BanTrendChart timeRange={timeRange} origin={originFilter} source={source} />
</SectionErrorBoundary>
</div>
```
### When to Use Each Boundary
- **Page boundaries:** Always wrap page routes in `App.tsx` (`Dashboard`, `Map`, `Jails`, etc.)
- **Section boundaries:** Wrap risky components that fetch data or have complex side effects
- Data visualizations (charts)
- Data tables and lists
- Complex forms
- Components using external libraries (D3, Canvas, etc.)
- **Top-level boundary:** Leave as-is; only modify if auth/routing infrastructure changes
### Boundary Best Practices
- Do not over-use boundaries — too many nested boundaries can confuse error UX
- Ensure section fallback UI doesn't disrupt page layout (use consistent sizing/spacing)
- Provide meaningful error titles and messages (`pageName` and `sectionName` props)
- Retry buttons allow users to recover from transient failures without page reload
- Consider logging errors via `onError` callback for debugging and monitoring
---
## 13. Performance