From c20d096e6a251e1b84ac47b751d2eb065743dbc2 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Mar 2019 05:35:45 +0100 Subject: [PATCH] Show disappointed elephant if web UI crashes (#10275) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Do not crash the whole UI when loading an invalid column * Add error boundary component to catch Web UI crashes * Add stack trace on supported browsers * Add component stack info, pre-format everything for github * Make “Reload” a clickable link that calls window.location.reload() * Remove elephant friend from error boundary, make title stand out more * Simplify error boundary to only a graphic --- .../mastodon/components/error_boundary.js | 39 +++++++++++++++++++ .../mastodon/containers/mastodon.js | 5 ++- .../mastodon/features/ui/components/bundle.js | 5 +++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 app/javascript/mastodon/components/error_boundary.js diff --git a/app/javascript/mastodon/components/error_boundary.js b/app/javascript/mastodon/components/error_boundary.js new file mode 100644 index 000000000..d1ca5bf75 --- /dev/null +++ b/app/javascript/mastodon/components/error_boundary.js @@ -0,0 +1,39 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import illustration from '../../images/elephant_ui_disappointed.svg'; + +export default class ErrorBoundary extends React.PureComponent { + + static propTypes = { + children: PropTypes.node, + }; + + state = { + hasError: false, + stackTrace: undefined, + componentStack: undefined, + } + + componentDidCatch(error, info) { + this.setState({ + hasError: true, + stackTrace: error.stack, + componentStack: info && info.componentStack, + }); + } + + render() { + const { hasError } = this.state; + + if (!hasError) { + return this.props.children; + } + + return ( +
+ +
+ ); + } + +} diff --git a/app/javascript/mastodon/containers/mastodon.js b/app/javascript/mastodon/containers/mastodon.js index 2912540a0..542b68282 100644 --- a/app/javascript/mastodon/containers/mastodon.js +++ b/app/javascript/mastodon/containers/mastodon.js @@ -13,6 +13,7 @@ import { connectUserStream } from '../actions/streaming'; import { IntlProvider, addLocaleData } from 'react-intl'; import { getLocale } from '../locales'; import initialState from '../initial_state'; +import ErrorBoundary from '../components/error_boundary'; const { localeData, messages } = getLocale(); addLocaleData(localeData); @@ -75,7 +76,9 @@ export default class Mastodon extends React.PureComponent { return ( - + + + ); diff --git a/app/javascript/mastodon/features/ui/components/bundle.js b/app/javascript/mastodon/features/ui/components/bundle.js index e7d935251..a60ace35b 100644 --- a/app/javascript/mastodon/features/ui/components/bundle.js +++ b/app/javascript/mastodon/features/ui/components/bundle.js @@ -53,6 +53,11 @@ class Bundle extends React.PureComponent { const { fetchComponent, onFetch, onFetchSuccess, onFetchFail, renderDelay } = props || this.props; const cachedMod = Bundle.cache.get(fetchComponent); + if (fetchComponent === undefined) { + this.setState({ mod: null }); + return Promise.resolve(); + } + onFetch(); if (cachedMod) {