1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

feat: frontend app error boundary (#2144)

* feat: frontend app error boundary

* fix: freeze added dependency

* update yarn lock
This commit is contained in:
Tymoteusz Czech 2022-10-10 12:18:37 +02:00 committed by GitHub
parent 5535a1769d
commit 879e1358ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 92 additions and 37 deletions

View File

@ -61,6 +61,7 @@
"date-fns": "2.29.3",
"debounce": "1.2.1",
"deep-diff": "1.0.2",
"dequal": "2.0.3",
"eslint": "8.23.0",
"eslint-config-react-app": "7.0.1",
"fast-json-patch": "3.1.1",
@ -76,6 +77,7 @@
"react": "17.0.2",
"react-chartjs-2": "4.3.1",
"react-dom": "17.0.2",
"react-error-boundary": "3.1.4",
"react-hooks-global-state": "2.0.0",
"react-router-dom": "6.3.0",
"react-table": "7.8.0",
@ -128,8 +130,5 @@
"ignorePatterns": [
"cypress"
]
},
"dependencies": {
"dequal": "2.0.3"
}
}

View File

@ -1,4 +1,7 @@
import { Suspense } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
import { ErrorBoundary } from 'react-error-boundary';
import { Error } from 'component/layout/Error/Error';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { FeedbackNPS } from 'component/feedback/FeedbackNPS/FeedbackNPS';
import { LayoutPicker } from 'component/layout/LayoutPicker/LayoutPicker';
@ -14,7 +17,6 @@ import { SplashPageRedirect } from 'component/splash/SplashPageRedirect/SplashPa
import { useStyles } from './App.styles';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { Suspense } from 'react';
export const App = () => {
const { classes: styles } = useStyles();
@ -29,40 +31,50 @@ export const App = () => {
: routes;
return (
<SWRProvider>
<Suspense fallback={<Loader />}>
<ConditionallyRender
condition={!hasFetchedAuth}
show={<Loader />}
elseShow={
<div className={styles.container}>
<ToastRenderer />
<LayoutPicker>
<Routes>
{availableRoutes.map(route => (
<ErrorBoundary FallbackComponent={Error}>
<SWRProvider>
<Suspense fallback={<Loader />}>
<ConditionallyRender
condition={!hasFetchedAuth}
show={<Loader />}
elseShow={
<div className={styles.container}>
<ToastRenderer />
<LayoutPicker>
<Routes>
{availableRoutes.map(route => (
<Route
key={route.path}
path={route.path}
element={
<ProtectedRoute
route={route}
/>
}
/>
))}
<Route
key={route.path}
path={route.path}
path="/"
element={
<ProtectedRoute route={route} />
<Navigate
to="/features"
replace
/>
}
/>
))}
<Route
path="/"
element={
<Navigate to="/features" replace />
}
/>
<Route path="*" element={<NotFound />} />
</Routes>
<FeedbackNPS openUrl="http://feedback.unleash.run" />
<SplashPageRedirect />
</LayoutPicker>
</div>
}
/>
</Suspense>
</SWRProvider>
<Route
path="*"
element={<NotFound />}
/>
</Routes>
<FeedbackNPS openUrl="http://feedback.unleash.run" />
<SplashPageRedirect />
</LayoutPicker>
</div>
}
/>
</Suspense>
</SWRProvider>
</ErrorBoundary>
);
};

View File

@ -0,0 +1,44 @@
import { VFC } from 'react';
import { useNavigate } from 'react-router-dom';
import { Box, Typography } from '@mui/material';
import { Dialogue } from 'component/common/Dialogue/Dialogue';
import { GO_BACK } from 'constants/navigate';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
interface IErrorProps {
error: Error;
}
export const Error: VFC<IErrorProps> = ({ error }) => {
const navigate = useNavigate();
return (
<Box sx={{ backgroundColor: 'neutral.light', height: '100%', p: 4 }}>
<Dialogue
open={true}
title="Something went wrong"
primaryButtonText="Go back"
onClick={() => {
navigate('/');
window?.location?.reload();
}}
secondaryButtonText="Reload this page"
onClose={() => {
window?.location?.reload();
}}
maxWidth="xl"
>
<Box component="pre" sx={{ color: 'error.main' }}>
{error.message}
</Box>
<ConditionallyRender
condition={Boolean(error.stack)}
show={
<Box component="pre" sx={{ color: 'error.main' }}>
{error.stack}
</Box>
}
/>
</Dialogue>
</Box>
);
};

View File

@ -22,7 +22,7 @@ export const useInviteTokens = (options: SWRConfiguration = {}) => {
return {
data: data
? { tokens: data.tokens.filter(token => token.enabled) }
? { tokens: data.tokens?.filter(token => token.enabled) }
: undefined,
error,
loading,

View File

@ -5920,7 +5920,7 @@ react-dom@17.0.2:
object-assign "^4.1.1"
scheduler "^0.20.2"
react-error-boundary@^3.1.0:
react-error-boundary@3.1.4, react-error-boundary@^3.1.0:
version "3.1.4"
resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-3.1.4.tgz#255db92b23197108757a888b01e5b729919abde0"
integrity sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==