Skip to content

Commit

Permalink
Add top-level error page
Browse files Browse the repository at this point in the history
Any error caught during a React component render or lifecycle method
will now be caught by the top-level error boundary, which shows the
user this new error page. The error page will display a simple error
message, and will show the details of the error in a collapsible
section.

The caught error is also reported to Sentry.

In development the error will be re-thrown to make it easier to see on
the console, but it is not re-thrown in production.
  • Loading branch information
Gudahtt committed Jan 24, 2020
1 parent 86c6280 commit ebf647e
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 12 deletions.
32 changes: 32 additions & 0 deletions app/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,38 @@
"enterPasswordContinue": {
"message": "Enter password to continue"
},
"errorCode": {
"message": "Code: $1",
"description": "Displayed error code for debugging purposes. $1 is the error code"
},
"errorDetails": {
"message": "Error Details",
"description": "Title for collapsible section that displays error details for debugging purposes"
},
"errorMessage": {
"message": "Message: $1",
"description": "Displayed error message for debugging purposes. $1 is the error message"
},
"errorName": {
"message": "Code: $1",
"description": "Displayed error name for debugging purposes. $1 is the error name"
},
"errorPageTitle": {
"message": "MetaMask encountered an error",
"description": "Title of generic error page"
},
"errorPageMessage": {
"message": "Try again by reloading the page, or contact support at support@metamask.io",
"description": "Message displayed on generic error page in the fullscreen or notification UI"
},
"errorPagePopupMessage": {
"message": "Try again by closing and reopening the popup, or contact support at support@metamask.io",
"description": "Message displayed on generic error page in the popup UI"
},
"errorStack": {
"message": "Stack:",
"description": "Title for error stack, which is displayed for debugging purposes"
},
"ethereumPublicAddress": {
"message": "Ethereum Public Address"
},
Expand Down
74 changes: 74 additions & 0 deletions ui/app/pages/error/error.component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import { getEnvironmentType } from '../../../../app/scripts/lib/util'
import { ENVIRONMENT_TYPE_POPUP } from '../../../../app/scripts/lib/enums'

class ErrorPage extends PureComponent {
static contextTypes = {
t: PropTypes.func.isRequired,
}

static propTypes = {
error: PropTypes.object.isRequired,
}

renderErrorDetail (content) {
return (
<li>
<p>
{content}
</p>
</li>
)
}

renderErrorStack (title, stack) {
return (
<li>
<span>
{title}
</span>
<pre className="error-page__stack">
{stack}
</pre>
</li>
)
}

render () {
const { error } = this.props
const { t } = this.context

const isPopup = getEnvironmentType() === ENVIRONMENT_TYPE_POPUP

return (
<section className="error-page">
<h1 className="error-page__header">
{t('errorPageTitle')}
</h1>
<h2 className="error-page__subheader">
{
isPopup
? t('errorPagePopupMessage')
: t('errorPageMessage')
}
</h2>
<section className="error-page__details">
<details>
<summary>
{t('errorDetails')}
</summary>
<ul>
{ error.message ? this.renderErrorDetail(t('errorMessage', [error.message])) : null }
{ error.code ? this.renderErrorDetail(t('errorCode', [error.code])) : null }
{ error.name ? this.renderErrorDetail(t('errorName', [error.name])) : null }
{ error.stack ? this.renderErrorStack(t('errorStack'), error.stack) : null }
</ul>
</details>
</section>
</section>
)
}
}

export default ErrorPage
1 change: 1 addition & 0 deletions ui/app/pages/error/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './error.component'
41 changes: 41 additions & 0 deletions ui/app/pages/error/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
.error-page {
display: flex;
flex-flow: column nowrap;
align-items: center;

font-family: Roboto;
font-style: normal;
font-weight: normal;

padding: 35px 10px 10px 10px;
height: 100%;

&__header {
display: flex;
justify-content: center;
font-size: 42px;
padding: 10px 0;
text-align: center;
}

&__subheader {
font-size: 19px;
padding: 10px 0;
width: 100%;
max-width: 720px;
text-align: center;
}

&__details {
font-size: 18px;
overflow-y: auto;
width: 100%;
max-width: 720px;
padding-top: 10px;
}

&__stack {
overflow-x: auto;
background-color: #eee;
}
}
52 changes: 40 additions & 12 deletions ui/app/pages/index.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,53 @@
import React from 'react'
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import { Provider } from 'react-redux'
import { HashRouter } from 'react-router-dom'
import * as Sentry from '@sentry/browser'
import ErrorPage from './error'
import Routes from './routes'
import I18nProvider from '../helpers/higher-order-components/i18n-provider'
import MetaMetricsProvider from '../helpers/higher-order-components/metametrics/metametrics.provider'

const Index = props => {
const { store } = props
class Index extends PureComponent {
state = {}

return (
<Provider store={store}>
<HashRouter hashType="noslash">
<MetaMetricsProvider>
static getDerivedStateFromError (error) {
return { error }
}

componentDidCatch (error) {
Sentry.captureException(error)
}

render () {
const { error, errorId } = this.state
const { store } = this.props

if (error) {
return (
<Provider store={store}>
<I18nProvider>
<Routes />
<ErrorPage
error={error}
errorId={errorId}
/>
</I18nProvider>
</MetaMetricsProvider>
</HashRouter>
</Provider>
)
</Provider>
)
}

return (
<Provider store={store}>
<HashRouter hashType="noslash">
<MetaMetricsProvider>
<I18nProvider>
<Routes />
</I18nProvider>
</MetaMetricsProvider>
</HashRouter>
</Provider>
)
}
}

Index.propTypes = {
Expand Down
2 changes: 2 additions & 0 deletions ui/app/pages/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

@import 'add-token/index';

@import 'error/index';

@import 'send/send';

@import 'confirm-add-token/index';
Expand Down

0 comments on commit ebf647e

Please sign in to comment.