diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 9ee1e83d7..429b03308 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -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 = () => ( -
+
Loading...
); @@ -29,17 +32,19 @@ export default function App() { return ( }> - - - - - - - - - - - + + + + + + + + + + + + + ); diff --git a/frontend/src/components/shared/ErrorBoundary.tsx b/frontend/src/components/shared/ErrorBoundary.tsx new file mode 100644 index 000000000..3dfd32d27 --- /dev/null +++ b/frontend/src/components/shared/ErrorBoundary.tsx @@ -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 { + 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 ; + } + + return ( + + Something went wrong + {process.env.NODE_ENV === 'development' && this.state.error && ( + + {this.state.error.message} + + )} + + + ); + } + + return this.props.children; + } +} \ No newline at end of file