feat(FN-1286): add ErrorBoundary component with page-level, modal, and root-level wrapping

- Create ErrorBoundary and ModalErrorBoundary components with recovery actions (retry, reload)
- Add error boundary CSS styles with fallback UI styling
- Wrap main dashboard pages (Board, List, Settings, Agents) with PageErrorBoundary in App.tsx
- Wrap all key modals (task detail, planning, subtask breakdown, mission) with ModalErrorBoundary in AppModals.tsx
- Wrap entire App with RootErrorBoundary in main.tsx as final safety net
- Add 11 comprehensive ErrorBoundary tests covering all rendering and error scenarios
This commit is contained in:
gsxdsm
2026-04-08 20:04:23 -07:00
parent 2842088216
commit 47a035fde1
7 changed files with 538 additions and 143 deletions

View File

@@ -26690,3 +26690,75 @@ body[data-color-theme="terminal"][data-theme="light"]::before {
min-height: 44px;
}
}
/* === Error Boundary === */
.error-boundary {
display: flex;
flex-direction: column;
align-items: center;
padding: var(--space-xl);
background: var(--surface);
border-radius: var(--radius-lg);
border: 1px solid var(--color-error);
max-width: 480px;
margin: auto;
text-align: center;
color: var(--text-primary);
}
.error-boundary--root {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.error-boundary--page {
padding: var(--space-2xl) var(--space-xl);
}
.error-boundary--modal {
padding: var(--space-xl);
}
.error-boundary__icon {
color: var(--color-error);
margin-bottom: var(--space-md);
}
.error-boundary__icon svg {
width: 40px;
height: 40px;
}
.error-boundary__title {
font-size: 1.1rem;
font-weight: 600;
margin-bottom: var(--space-sm);
}
.error-boundary__message {
font-size: 0.85rem;
color: var(--text-secondary);
background: var(--bg);
padding: var(--space-sm) var(--space-md);
border-radius: var(--radius-sm);
margin: var(--space-md) 0;
overflow-x: auto;
text-align: left;
font-family: var(--font-mono);
white-space: pre-wrap;
word-break: break-word;
max-height: 120px;
overflow-y: auto;
width: 100%;
box-sizing: border-box;
}
.error-boundary__actions {
display: flex;
gap: var(--space-sm);
justify-content: center;
margin-top: var(--space-lg);
}