From c20d096e6a251e1b84ac47b751d2eb065743dbc2 Mon Sep 17 00:00:00 2001
From: Eugen Rochko <eugen@zeonfederated.com>
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 0000000000..d1ca5bf756
--- /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 (
+ <div>
+ <img src={illustration} alt='' />
+ </div>
+ );
+ }
+
+}
diff --git a/app/javascript/mastodon/containers/mastodon.js b/app/javascript/mastodon/containers/mastodon.js
index 2912540a00..542b682821 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 (
<IntlProvider locale={locale} messages={messages}>
<Provider store={store}>
- <MastodonMount />
+ <ErrorBoundary>
+ <MastodonMount />
+ </ErrorBoundary>
</Provider>
</IntlProvider>
);
diff --git a/app/javascript/mastodon/features/ui/components/bundle.js b/app/javascript/mastodon/features/ui/components/bundle.js
index e7d9352517..a60ace35ba 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) {
--
GitLab