on master help sign in
Merge pull request #257 from urbit/feat/error-boundary

feat: error boundary mvp

commitda154dd22b8ca55264037bffef33df229f04c3f8 authorFang <Fang-@users.noreply.github.com> dateFri 27 Sep 2019, 13:12 (7 years ago) parente6e56e27f50d79
5 files changed+115−13
package-lock.json+5 package.json+1 src/Bridge.js+17−13 src/components/GlobalErrorBoundary.js+72 src/components/WithErrorBoundary.js+20
package-lock.json+5
@@ -12080,6 +12080,11 @@
1208012080 "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz",
1208112081 "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw=="
1208212082 },
12083+ "new-github-issue-url": {
12084+ "version": "0.2.1",
12085+ "resolved": "https://registry.npmjs.org/new-github-issue-url/-/new-github-issue-url-0.2.1.tgz",
12086+ "integrity": "sha512-md4cGoxuT4T4d/HDOXbrUHkTKrp/vp+m3aOA7XXVYwNsUNMK49g3SQicTSeV5GIz/5QVGAeYRAOlyp9OvlgsYA=="
12087+ },
1208312088 "next-tick": {
1208412089 "version": "1.0.0",
1208512090 "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
package.json+1
@@ -38,6 +38,7 @@
3838 "keythereum": "^1.0.4",
3939 "lodash": "^4.17.14",
4040 "more-entropy": "^0.0.7",
41+ "new-github-issue-url": "^0.2.1",
4142 "prop-types": "^15.6.2",
4243 "react": "^16.8.6",
4344 "react-dom": "^16.8.6",
src/Bridge.js+17−13
@@ -18,6 +18,8 @@ import useImpliedTicket from 'lib/useImpliedTicket';
1818import useHasDisclaimed from 'lib/useHasDisclaimed';
1919
2020import 'style/index.scss';
21+import WithErrorBoundary from 'components/WithErrorBoundary';
22+import GlobalErrorBoundary from 'components/GlobalErrorBoundary';
2123
2224const INITIAL_NETWORK_TYPE = isDevelopment
2325 ? NETWORK_TYPES.LOCAL
@@ -65,19 +67,21 @@ function Bridge() {
6567 const initialRoutes = useInitialRoutes();
6668
6769 return (
68− <Provider
69− views={ROUTES}
70− names={ROUTE_NAMES}
71− initialRoutes={initialRoutes}
72− initialNetworkType={INITIAL_NETWORK_TYPE}
73− initialWallet={INITIAL_WALLET}
74− initialMnemonic={INITIAL_MNEMONIC}
75− initialPointCursor={INITIAL_POINT_CURSOR}>
76− <Header />
77− <IndigoApp>
78− <Router />
79− </IndigoApp>
80− </Provider>
70+ <WithErrorBoundary render={error => <GlobalErrorBoundary error={error} />}>
71+ <Provider
72+ views={ROUTES}
73+ names={ROUTE_NAMES}
74+ initialRoutes={initialRoutes}
75+ initialNetworkType={INITIAL_NETWORK_TYPE}
76+ initialWallet={INITIAL_WALLET}
77+ initialMnemonic={INITIAL_MNEMONIC}
78+ initialPointCursor={INITIAL_POINT_CURSOR}>
79+ <Header />
80+ <IndigoApp>
81+ <Router />
82+ </IndigoApp>
83+ </Provider>
84+ </WithErrorBoundary>
8185 );
8286}
8387
src/components/GlobalErrorBoundary.jsnew file+72
@@ -0,0 +1,72 @@
1+import React, { useMemo } from 'react';
2+import newGithubIssueUrl from 'new-github-issue-url';
3+import { OutButton, RestartButton } from './Buttons';
4+
5+const buildTitle = error => `Error Report: ${error.message}`;
6+
7+const buildBody = error => `\n
8+<!-- Thanks for submitting this error! Can you help us identify the issue by providing additional context? -->
9+\n
10+## Context
11+\n
12+<!-- 1) What were you doing when you encountered this error? -->
13+\n
14+<!-- 2) Only if relevant (don't self-dox!), what point were you interacting with? -->
15+\n
16+## Error\n\n
17+\`\`\`
18+${error.stack}
19+\`\`\`
20+\n
21+`;
22+
23+/**
24+ * NOTE: we want to use as few normal components here as possible, since the
25+ * error might have originated from within those components, making this
26+ * whole error boundary useless.
27+ */
28+export default function GlobalErrorBoundary({ error }) {
29+ const url = useMemo(
30+ () =>
31+ newGithubIssueUrl({
32+ user: 'urbit',
33+ repo: 'bridge',
34+ labels: ['bug', 'error handling'],
35+ title: buildTitle(error),
36+ body: buildBody(error),
37+ }),
38+ [error]
39+ );
40+
41+ return (
42+ <div className="mw1 ph4">
43+ <h2 className="mt8">
44+ Bridge Error!{' '}
45+ <span role="img" aria-label="a bridge on fire">
46+ 🌉🔥
47+ </span>
48+ </h2>
49+ <p className="mt4 f5">
50+ We caught an error thrown by the Bridge application client-side code.
51+ <br />
52+ <b>Your points and assets are most likely safe.</b>
53+ </p>
54+ <p className="mt4">
55+ If you'd like to help us make Bridge better, you can submit the error
56+ and your description of events to our GitHub issue tracker.
57+ </p>
58+ <OutButton href={url} solid>
59+ Submit the Issue on GitHub
60+ </OutButton>
61+ <pre className="bg-gray1 mt4 p4 mono scroll-x">{error.stack}</pre>
62+ <p className="mt4">
63+ You can reload Bridge and retry the operation that caused an error. If
64+ the error persists, please submit a bug report and we'll work with you
65+ to resolve it!
66+ </p>
67+ <RestartButton onClick={() => document.location.reload()} solid success>
68+ Reload Bridge
69+ </RestartButton>
70+ </div>
71+ );
72+}
src/components/WithErrorBoundary.jsnew file+20
@@ -0,0 +1,20 @@
1+import React from 'react';
2+
3+export default class WithErrorBoundary extends React.Component {
4+ static getDerivedStateFromError(error) {
5+ return { error };
6+ }
7+ constructor(props) {
8+ super(props);
9+
10+ this.state = { error: null };
11+ }
12+
13+ render() {
14+ if (this.state.error) {
15+ return this.props.render(this.state.error);
16+ }
17+
18+ return this.props.children;
19+ }
20+}