mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Add top-level error page (#7889)
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.
This commit is contained in:
parent
86c6280bc3
commit
560be4b4e3
@ -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"
|
||||
},
|
||||
|
74
ui/app/pages/error/error.component.js
Normal file
74
ui/app/pages/error/error.component.js
Normal file
@ -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
ui/app/pages/error/index.js
Normal file
1
ui/app/pages/error/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './error.component'
|
41
ui/app/pages/error/index.scss
Normal file
41
ui/app/pages/error/index.scss
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -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 = {
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
@import 'add-token/index';
|
||||
|
||||
@import 'error/index';
|
||||
|
||||
@import 'send/send';
|
||||
|
||||
@import 'confirm-add-token/index';
|
||||
|
Loading…
Reference in New Issue
Block a user