diff --git a/src/apps/dashboard/routes/routes.tsx b/src/apps/dashboard/routes/routes.tsx index 7bbeb3fc4e..16385ddf3e 100644 --- a/src/apps/dashboard/routes/routes.tsx +++ b/src/apps/dashboard/routes/routes.tsx @@ -7,6 +7,7 @@ import { toAsyncPageRoute } from 'components/router/AsyncRoute'; import { toViewManagerPageRoute } from 'components/router/LegacyRoute'; import { LEGACY_ADMIN_ROUTES } from './_legacyRoutes'; import ServerContentPage from 'components/ServerContentPage'; +import ErrorBoundary from '../../../components/router/ErrorBoundary'; export const DASHBOARD_APP_PATHS = { Dashboard: 'dashboard', @@ -26,7 +27,8 @@ export const DASHBOARD_APP_ROUTES: RouteObject[] = [ children: [ ...ASYNC_ADMIN_ROUTES.map(toAsyncPageRoute), ...LEGACY_ADMIN_ROUTES.map(toViewManagerPageRoute) - ] + ], + errorElement: }, /* NOTE: The metadata editor might deserve a dedicated app in the future */ diff --git a/src/apps/experimental/routes/routes.tsx b/src/apps/experimental/routes/routes.tsx index 47e0a9f7f5..c9e32899dc 100644 --- a/src/apps/experimental/routes/routes.tsx +++ b/src/apps/experimental/routes/routes.tsx @@ -6,6 +6,8 @@ import ConnectionRequired from 'components/ConnectionRequired'; import { toAsyncPageRoute } from 'components/router/AsyncRoute'; import { toViewManagerPageRoute } from 'components/router/LegacyRoute'; import { toRedirectRoute } from 'components/router/Redirect'; +import ErrorBoundary from 'components/router/ErrorBoundary'; + import AppLayout from '../AppLayout'; import { ASYNC_USER_ROUTES } from './asyncRoutes'; @@ -29,7 +31,8 @@ export const EXPERIMENTAL_APP_ROUTES: RouteObject[] = [ path: 'video', element: } - ] + ], + ErrorBoundary }, /* Public routes */ diff --git a/src/apps/stable/routes/routes.tsx b/src/apps/stable/routes/routes.tsx index 300092c9fe..e5f800d20b 100644 --- a/src/apps/stable/routes/routes.tsx +++ b/src/apps/stable/routes/routes.tsx @@ -5,6 +5,7 @@ import ConnectionRequired from 'components/ConnectionRequired'; import { toAsyncPageRoute } from 'components/router/AsyncRoute'; import { toViewManagerPageRoute } from 'components/router/LegacyRoute'; import { toRedirectRoute } from 'components/router/Redirect'; +import ErrorBoundary from 'components/router/ErrorBoundary'; import AppLayout from '../AppLayout'; @@ -23,7 +24,8 @@ export const STABLE_APP_ROUTES: RouteObject[] = [ children: [ ...ASYNC_USER_ROUTES.map(toAsyncPageRoute), ...LEGACY_USER_ROUTES.map(toViewManagerPageRoute) - ] + ], + ErrorBoundary }, /* Public routes */ diff --git a/src/components/router/ErrorBoundary.tsx b/src/components/router/ErrorBoundary.tsx new file mode 100644 index 0000000000..e195d2d989 --- /dev/null +++ b/src/components/router/ErrorBoundary.tsx @@ -0,0 +1,67 @@ +import Alert from '@mui/material/Alert/Alert'; +import AlertTitle from '@mui/material/AlertTitle/AlertTitle'; +import Box from '@mui/material/Box/Box'; +import Paper from '@mui/material/Paper/Paper'; +import Typography from '@mui/material/Typography/Typography'; +import classNames from 'classnames'; +import React, { type FC, useEffect } from 'react'; +import { useRouteError } from 'react-router-dom'; + +import loading from 'components/loading/loading'; +import Page from 'components/Page'; + +interface ErrorBoundaryParams { + pageClasses?: string[] +} + +const ErrorBoundary: FC = ({ + pageClasses = [ 'libraryPage' ] +}) => { + const error = useRouteError() as Error; + + useEffect(() => { + loading.hide(); + }, []); + + return ( + + + + + {error.name} + + + + {error.message} + + + {error.stack && ( + + + {error.stack} + + + )} + + + + ); +}; + +export default ErrorBoundary; diff --git a/src/themes/defaults.ts b/src/themes/defaults.ts index 31f85d79c3..7f92f0c4b2 100644 --- a/src/themes/defaults.ts +++ b/src/themes/defaults.ts @@ -41,6 +41,14 @@ export const DEFAULT_THEME_OPTIONS: ThemeOptions = { } }, components: { + MuiAlert: { + styleOverrides: { + message: { + // NOTE: This seems like a bug. Block content does not fill the container width. + flexGrow: 1 + } + } + }, MuiButton: { defaultProps: { variant: 'contained'