Add error boundaries with fallback component to show any error (#471)
* add error boundaries with fallback component * use own ErrorBoundaries * fix build * simplistic implementation * Update packages/extension-ui/src/components/ErrorBoundary.tsx * keep fragments * at the root only * weird svg error * double click needed * remove trigger * demove errorDisplay and move goHome to class * cleanup and button * Update packages/extension-ui/src/Popup/ImportSeed.tsx * use trigger * remove intentionnal error * Update packages/extension-ui/src/Popup/index.tsx * Update packages/extension-ui/src/components/ErrorBoundary.tsx * fix build * Update packages/extension-ui/src/Popup/index.tsx Co-authored-by: Jaco Greeff <jacogr@gmail.com> Co-authored-by: Jaco Greeff <jacogr@gmail.com>
This commit is contained in:
parent
c9c2f6a366
commit
91cfad0c0e
2
.gitignore
vendored
2
.gitignore
vendored
@ -22,4 +22,4 @@ yarn-error.log*
|
||||
package-lock.json
|
||||
_book
|
||||
docs/html
|
||||
.idea
|
||||
.idea
|
||||
|
||||
@ -9,7 +9,7 @@ import { Route, Switch } from 'react-router';
|
||||
import uiSettings from '@polkadot/ui-settings';
|
||||
import { setSS58Format } from '@polkadot/util-crypto';
|
||||
|
||||
import { Loading } from '../components';
|
||||
import { Loading, ErrorBoundary } from '../components';
|
||||
import { AccountContext, ActionContext, AuthorizeReqContext, MediaContext, MetadataReqContext, SettingsContext, SigningReqContext } from '../components/contexts';
|
||||
import ToastProvider from '../components/Toast/ToastProvider';
|
||||
import { subscribeAccounts, subscribeAuthorizeRequests, subscribeMetadataRequests, subscribeSigningRequests } from '../messaging';
|
||||
@ -103,15 +103,19 @@ export default function Popup (): React.ReactElement {
|
||||
.catch(console.error);
|
||||
}, [cameraOn]);
|
||||
|
||||
function wrapWithErrorBoundary (component: React.ReactElement, trigger?: string): React.ReactElement {
|
||||
return <ErrorBoundary trigger={trigger}>{component}</ErrorBoundary>;
|
||||
}
|
||||
|
||||
const Root = isWelcomeDone
|
||||
? authRequests && authRequests.length
|
||||
? Authorize
|
||||
? wrapWithErrorBoundary(<Authorize />, 'authorize')
|
||||
: metaRequests && metaRequests.length
|
||||
? Metadata
|
||||
? wrapWithErrorBoundary(<Metadata />, 'metadata')
|
||||
: signRequests && signRequests.length
|
||||
? Signing
|
||||
: Accounts
|
||||
: Welcome;
|
||||
? wrapWithErrorBoundary(<Signing/>, 'signing')
|
||||
: wrapWithErrorBoundary(<Accounts/>, 'accounts')
|
||||
: wrapWithErrorBoundary(<Welcome />, 'welcome');
|
||||
|
||||
return (
|
||||
<Loading>{accounts && authRequests && metaRequests && signRequests && (
|
||||
@ -124,19 +128,19 @@ export default function Popup (): React.ReactElement {
|
||||
<SigningReqContext.Provider value={signRequests}>
|
||||
<ToastProvider>
|
||||
<Switch>
|
||||
<Route path='/account/create'><CreateAccount /></Route>
|
||||
<Route path='/account/forget/:address'><Forget /></Route>
|
||||
<Route path='/account/export/:address'><Export /></Route>
|
||||
<Route path='/account/import-qr'><ImportQr /></Route>
|
||||
<Route path='/account/import-seed'><ImportSeed /></Route>
|
||||
<Route path='/account/restore-json'><RestoreJson /></Route>
|
||||
<Route path='/account/derive/:address/locked'><Derive isLocked /></Route>
|
||||
<Route path='/account/derive/:address'><Derive /></Route>
|
||||
<Route path='/account/create'>{wrapWithErrorBoundary(<CreateAccount />, 'account-creation')}</Route>
|
||||
<Route path='/account/forget/:address'>{wrapWithErrorBoundary(<Forget />, 'forget-address')}</Route>
|
||||
<Route path='/account/export/:address'>{wrapWithErrorBoundary(<Export />, 'export-address')}</Route>
|
||||
<Route path='/account/import-qr'>{wrapWithErrorBoundary(<ImportQr />, 'import-qr')}</Route>
|
||||
<Route path='/account/import-seed'>{wrapWithErrorBoundary(<ImportSeed />, 'import-seed')}</Route>
|
||||
<Route path='/account/restore-json'>{wrapWithErrorBoundary(<RestoreJson />, 'restore-json')}</Route>
|
||||
<Route path='/account/derive/:address/locked'>{wrapWithErrorBoundary(<Derive isLocked />, 'derived-address-locked')}</Route>
|
||||
<Route path='/account/derive/:address'>{wrapWithErrorBoundary(<Derive />, 'derive-address')}</Route>
|
||||
<Route
|
||||
exact
|
||||
path='/'
|
||||
>
|
||||
<Root />
|
||||
{Root}
|
||||
</Route>
|
||||
</Switch>
|
||||
</ToastProvider>
|
||||
|
||||
74
packages/extension-ui/src/components/ErrorBoundary.tsx
Normal file
74
packages/extension-ui/src/components/ErrorBoundary.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright 2019-2020 @polkadot/extension-ui authors & contributor
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import ButtonArea from './ButtonArea';
|
||||
import Button from './Button';
|
||||
import VerticalSpace from './VerticalSpace';
|
||||
import Header from '../partials/Header';
|
||||
import translate from './translate';
|
||||
|
||||
interface Props extends WithTranslation {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
error?: Error | null;
|
||||
trigger?: string;
|
||||
}
|
||||
|
||||
interface State {
|
||||
error: Error | null;
|
||||
}
|
||||
|
||||
// NOTE: This is the only way to do an error boundary, via extend
|
||||
class ErrorBoundary extends React.Component<Props> {
|
||||
state: State = { error: null };
|
||||
|
||||
static getDerivedStateFromError (error: Error): Partial<State> {
|
||||
return { error };
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps: Props) {
|
||||
const { error } = this.state;
|
||||
const { trigger } = this.props;
|
||||
|
||||
if (error !== null && (prevProps.trigger !== trigger)) {
|
||||
this.setState({ error: null });
|
||||
}
|
||||
}
|
||||
|
||||
goHome = () => {
|
||||
this.setState({ error: null });
|
||||
window.location.hash = '/';
|
||||
};
|
||||
|
||||
public render (): React.ReactNode {
|
||||
const { children, t } = this.props;
|
||||
const { error } = this.state;
|
||||
|
||||
return error
|
||||
? (
|
||||
<>
|
||||
<Header text={t<string>('An error occured')} />
|
||||
<div>
|
||||
{t<string>('Something went wrong with the query and rendering of this component. {{message}}', {
|
||||
replace: { message: error.message }
|
||||
})}
|
||||
</div>
|
||||
<VerticalSpace/>
|
||||
<ButtonArea>
|
||||
<Button
|
||||
onClick={this.goHome}
|
||||
>
|
||||
{t<string>('Back to home')}
|
||||
</Button>
|
||||
</ButtonArea>
|
||||
</>
|
||||
)
|
||||
: children;
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(ErrorBoundary);
|
||||
@ -11,6 +11,7 @@ export { default as ButtonArea } from './ButtonArea';
|
||||
export { default as ButtonWithSubtitle } from './ButtonWithSubtitle';
|
||||
export { default as Checkbox } from './Checkbox';
|
||||
export { default as Dropdown } from './Dropdown';
|
||||
export { default as ErrorBoundary } from './ErrorBoundary';
|
||||
export { default as Fonts } from './Fonts';
|
||||
export { default as Icon } from './Icon';
|
||||
export { default as Identicon } from './Identicon';
|
||||
|
||||
10
packages/extension-ui/src/components/translate.ts
Normal file
10
packages/extension-ui/src/components/translate.ts
Normal file
@ -0,0 +1,10 @@
|
||||
// Copyright 2019-2020 @polkadot/extension-ui authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { useTranslation as useTranslationBase, UseTranslationResponse, withTranslation } from 'react-i18next';
|
||||
|
||||
export function useTranslation (): UseTranslationResponse {
|
||||
return useTranslationBase();
|
||||
}
|
||||
|
||||
export default withTranslation();
|
||||
@ -10,7 +10,8 @@ import ArrowLeftImage from '../assets/arrowLeft.svg';
|
||||
import gear from '../assets/gear.svg';
|
||||
import plus from '../assets/plus.svg';
|
||||
import logo from '../assets/pjs.svg';
|
||||
import { Link, Svg } from '../components';
|
||||
import Link from '../components/Link';
|
||||
import Svg from '../components/Svg';
|
||||
import useOutsideClick from '../hooks/useOutsideClick';
|
||||
import MenuAdd from './MenuAdd';
|
||||
import MenuSettings from './MenuSettings';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user