fix: improve error handling and stability - no logout on transient errors, add ErrorBoundary, global error logging

This commit is contained in:
Agent Zero
2026-07-26 12:18:52 +02:00
parent e12b85c2ce
commit 808da564f3
7 changed files with 344 additions and 8 deletions
@@ -0,0 +1,105 @@
import React, { Component, ErrorInfo, ReactNode } from 'react';
import { logError } from '@/utils/errorLogger';
interface ErrorBoundaryProps {
children: ReactNode;
/** Optional fallback render function; receives the error and a retry callback */
fallback?: (error: Error, retry: () => void) => ReactNode;
}
interface ErrorBoundaryState {
hasError: boolean;
error: Error | null;
}
/**
* React Error Boundary that catches JavaScript errors in the component tree.
* Shows a friendly error message with a Retry button.
* Logs errors via the global error logger.
* Only the affected subtree is broken — the rest of the app continues.
*/
export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
// Log to console + backend + sessionStorage buffer
logError(error, { componentStack: errorInfo.componentStack });
}
handleRetry = (): void => {
this.setState({ hasError: false, error: null });
};
render(): ReactNode {
if (this.state.hasError && this.state.error) {
// Custom fallback if provided
if (this.props.fallback) {
return this.props.fallback(this.state.error, this.handleRetry);
}
// Default fallback UI
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
minHeight: '300px',
padding: '2rem',
textAlign: 'center',
}}
>
<h2 style={{ marginBottom: '0.5rem', color: '#dc2626' }}>
Something went wrong
</h2>
<p style={{ marginBottom: '1rem', color: '#6b7280', maxWidth: '400px' }}>
An unexpected error occurred. You can try again or refresh the page.
</p>
<details style={{ marginBottom: '1rem', maxWidth: '600px', color: '#9ca3af' }}>
<summary style={{ cursor: 'pointer', fontSize: '0.875rem' }}>
Error details
</summary>
<pre
style={{
marginTop: '0.5rem',
fontSize: '0.75rem',
overflow: 'auto',
textAlign: 'left',
}}
>
{this.state.error.message}
{this.state.error.stack ? `\n\n${this.state.error.stack}` : ''}
</pre>
</details>
<button
onClick={this.handleRetry}
style={{
padding: '0.5rem 1.5rem',
backgroundColor: '#2563eb',
color: 'white',
border: 'none',
borderRadius: '0.375rem',
cursor: 'pointer',
fontSize: '0.875rem',
fontWeight: 500,
}}
>
Retry
</button>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;