added basic error boundary

This commit is contained in:
Connor Yoh 2025-08-19 16:34:58 +01:00
parent 91ee707120
commit 03df9a260b
2 changed files with 90 additions and 29 deletions

View File

@ -1,26 +1,29 @@
import React, { Suspense } from 'react';
import { RainbowThemeProvider } from './components/shared/RainbowThemeProvider';
import { FileContextProvider } from './contexts/FileContext';
import { FilesModalProvider } from './contexts/FilesModalContext';
import { FileSelectionProvider } from './contexts/FileSelectionContext';
import { ToolWorkflowProvider } from './contexts/ToolWorkflowContext';
import { SidebarProvider } from './contexts/SidebarContext';
import HomePage from './pages/HomePage';
import React, { Suspense } from "react";
import { RainbowThemeProvider } from "./components/shared/RainbowThemeProvider";
import { FileContextProvider } from "./contexts/FileContext";
import { FilesModalProvider } from "./contexts/FilesModalContext";
import { FileSelectionProvider } from "./contexts/FileSelectionContext";
import { ToolWorkflowProvider } from "./contexts/ToolWorkflowContext";
import { SidebarProvider } from "./contexts/SidebarContext";
import ErrorBoundary from "./components/shared/ErrorBoundary";
import HomePage from "./pages/HomePage";
// Import global styles
import './styles/tailwind.css';
import './index.css';
import "./styles/tailwind.css";
import "./index.css";
// Loading component for i18next suspense
const LoadingFallback = () => (
<div style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
fontSize: '18px',
color: '#666'
}}>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100vh",
fontSize: "18px",
color: "#666",
}}
>
Loading...
</div>
);
@ -29,17 +32,19 @@ export default function App() {
return (
<Suspense fallback={<LoadingFallback />}>
<RainbowThemeProvider>
<FileContextProvider enableUrlSync={true} enablePersistence={true}>
<FilesModalProvider>
<FileSelectionProvider>
<ToolWorkflowProvider>
<SidebarProvider>
<HomePage />
</SidebarProvider>
</ToolWorkflowProvider>
</FileSelectionProvider>
</FilesModalProvider>
</FileContextProvider>
<ErrorBoundary>
<FileContextProvider enableUrlSync={true} enablePersistence={true}>
<FilesModalProvider>
<FileSelectionProvider>
<ToolWorkflowProvider>
<SidebarProvider>
<HomePage />
</SidebarProvider>
</ToolWorkflowProvider>
</FileSelectionProvider>
</FilesModalProvider>
</FileContextProvider>
</ErrorBoundary>
</RainbowThemeProvider>
</Suspense>
);

View File

@ -0,0 +1,56 @@
import React from 'react';
import { Text, Button, Stack } from '@mantine/core';
interface ErrorBoundaryState {
hasError: boolean;
error?: Error;
}
interface ErrorBoundaryProps {
children: React.ReactNode;
fallback?: React.ComponentType<{error?: Error; retry: () => void}>;
}
export default class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error('ErrorBoundary caught an error:', error, errorInfo);
}
retry = () => {
this.setState({ hasError: false, error: undefined });
};
render() {
if (this.state.hasError) {
if (this.props.fallback) {
const Fallback = this.props.fallback;
return <Fallback error={this.state.error} retry={this.retry} />;
}
return (
<Stack align="center" justify="center" style={{ minHeight: '200px', padding: '2rem' }}>
<Text size="lg" fw={500} c="red">Something went wrong</Text>
{process.env.NODE_ENV === 'development' && this.state.error && (
<Text size="sm" c="dimmed" style={{ textAlign: 'center', fontFamily: 'monospace' }}>
{this.state.error.message}
</Text>
)}
<Button onClick={this.retry} variant="light">
Try Again
</Button>
</Stack>
);
}
return this.props.children;
}
}