Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | 690x 690x 50x 25x 25x 25x 2x 1x 1x 1256x 1256x 1256x 50x 4x 46x 1206x | import React, { Component, ReactNode } from 'react';
import ErrorMessage from './ErrorMessage';
import logger from '../../utils/logger';
/**
* Props for WidgetErrorBoundary component
*/
export interface WidgetErrorBoundaryProps {
/**
* Child components to wrap with error boundary
*/
children: ReactNode;
/**
* Optional custom fallback component to display on error
*/
fallback?: ReactNode;
/**
* Optional callback when an error is caught
*/
onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
/**
* Optional widget name for error messages
*/
widgetName?: string;
/**
* Optional test ID for automated testing
*/
testId?: string;
}
/**
* State for WidgetErrorBoundary component
*/
interface WidgetErrorBoundaryState {
hasError: boolean;
error?: Error;
}
/**
* Error boundary component for wrapping widgets
*
* ## Business Perspective
*
* Prevents widget failures from crashing the entire application, ensuring
* users can continue working even when individual components encounter errors.
* Critical for maintaining operational continuity and user trust. 🛡️
*
* ## Technical Perspective
*
* React Error Boundary that catches JavaScript errors in child components,
* logs them, and displays a fallback UI. Implements the error boundary
* lifecycle methods to gracefully handle rendering errors.
*
* Per React best practices, error boundaries catch errors during:
* - Rendering
* - Lifecycle methods
* - Constructors of child components
*
* They do NOT catch errors in:
* - Event handlers (use try-catch)
* - Asynchronous code (use try-catch)
* - Server-side rendering
* - Errors in the error boundary itself
*
* @example
* ```tsx
* // Basic usage
* <WidgetErrorBoundary>
* <SecurityMetricsWidget />
* </WidgetErrorBoundary>
*
* // With custom fallback
* <WidgetErrorBoundary fallback={<CustomErrorUI />}>
* <ComplianceWidget />
* </WidgetErrorBoundary>
*
* // With error callback and widget name
* <WidgetErrorBoundary
* widgetName="Security Metrics"
* onError={(error, info) => logError(error, info)}
* >
* <SecurityMetricsWidget />
* </WidgetErrorBoundary>
* ```
*/
export class WidgetErrorBoundary extends Component<
WidgetErrorBoundaryProps,
WidgetErrorBoundaryState
> {
constructor(props: WidgetErrorBoundaryProps) {
super(props);
this.state = { hasError: false };
}
/**
* Update state when an error is caught
*/
static getDerivedStateFromError(error: Error): WidgetErrorBoundaryState {
return { hasError: true, error };
}
/**
* Log error information and call optional callback
*/
componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
const { widgetName, onError } = this.props;
// Log using centralized logger for debugging
logger.error(
`WidgetErrorBoundary caught error${widgetName ? ` in ${widgetName}` : ''}`,
{ error, errorInfo }
);
// Call optional error callback
if (onError) {
onError(error, errorInfo);
}
}
/**
* Reset error state (for retry functionality)
*/
private resetError = (): void => {
this.setState({ hasError: false, error: undefined });
};
render(): ReactNode {
const { hasError, error } = this.state;
const { children, fallback, widgetName, testId = 'widget-error-boundary' } = this.props;
if (hasError) {
// Use custom fallback if provided
if (fallback) {
return fallback;
}
// Default error UI using ErrorMessage component
return (
<div data-testid={testId} className="p-4">
<ErrorMessage
title={widgetName ? `${widgetName} Error` : 'Widget Error'}
message={error?.message || 'An unexpected error occurred in this widget'}
retry={this.resetError}
testId={`${testId}-message`}
/>
</div>
);
}
return children;
}
}
export default WidgetErrorBoundary;
|