Added high level ErrorBoundary
This commit is contained in:
@@ -15,6 +15,7 @@ type Props = {
|
|||||||
readOnly: boolean,
|
readOnly: boolean,
|
||||||
component?: string,
|
component?: string,
|
||||||
attributes: Object,
|
attributes: Object,
|
||||||
|
className?: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
function Heading(props: Props) {
|
function Heading(props: Props) {
|
||||||
@@ -26,6 +27,7 @@ function Heading(props: Props) {
|
|||||||
readOnly,
|
readOnly,
|
||||||
children,
|
children,
|
||||||
component = 'h1',
|
component = 'h1',
|
||||||
|
className,
|
||||||
attributes,
|
attributes,
|
||||||
} = props;
|
} = props;
|
||||||
const parentIsDocument = parent instanceof Document;
|
const parentIsDocument = parent instanceof Document;
|
||||||
@@ -40,7 +42,7 @@ function Heading(props: Props) {
|
|||||||
emoji && title.match(new RegExp(`^${emoji}\\s`));
|
emoji && title.match(new RegExp(`^${emoji}\\s`));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Component {...attributes} id={slugish}>
|
<Component {...attributes} id={slugish} className={className}>
|
||||||
<Wrapper hasEmoji={startsWithEmojiAndSpace}>{children}</Wrapper>
|
<Wrapper hasEmoji={startsWithEmojiAndSpace}>{children}</Wrapper>
|
||||||
{showPlaceholder && (
|
{showPlaceholder && (
|
||||||
<Placeholder contentEditable={false}>
|
<Placeholder contentEditable={false}>
|
||||||
|
|||||||
42
app/components/ErrorBoundary/ErrorBoundary.js
Normal file
42
app/components/ErrorBoundary/ErrorBoundary.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// @flow
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import { observable } from 'mobx';
|
||||||
|
import CenteredContent from 'components/CenteredContent';
|
||||||
|
import PageTitle from 'components/PageTitle';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class ErrorBoundary extends Component {
|
||||||
|
@observable error: boolean = false;
|
||||||
|
|
||||||
|
componentDidCatch(error: Error, info: Object) {
|
||||||
|
this.error = true;
|
||||||
|
|
||||||
|
// Error handler is often blocked by the browser
|
||||||
|
if (window.Bugsnag) {
|
||||||
|
Bugsnag.notifyException(error, { react: info });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleReload = () => {
|
||||||
|
window.location.reload();
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.error) {
|
||||||
|
return (
|
||||||
|
<CenteredContent>
|
||||||
|
<PageTitle title="Unknown Error" />
|
||||||
|
<h1>Something went wrong</h1>
|
||||||
|
<p>
|
||||||
|
An unrecoverable error occurred. Please try{' '}
|
||||||
|
<a onClick={this.handleReload}>reloading</a>.
|
||||||
|
</p>
|
||||||
|
</CenteredContent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return this.props.children;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ErrorBoundary;
|
||||||
3
app/components/ErrorBoundary/index.js
Normal file
3
app/components/ErrorBoundary/index.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// @flow
|
||||||
|
import ErrorBoundary from './ErrorBoundary';
|
||||||
|
export default ErrorBoundary;
|
||||||
109
app/index.js
109
app/index.js
@@ -28,6 +28,7 @@ import Flatpage from 'scenes/Flatpage';
|
|||||||
import ErrorAuth from 'scenes/ErrorAuth';
|
import ErrorAuth from 'scenes/ErrorAuth';
|
||||||
import Error404 from 'scenes/Error404';
|
import Error404 from 'scenes/Error404';
|
||||||
|
|
||||||
|
import ErrorBoundary from 'components/ErrorBoundary';
|
||||||
import ScrollToTop from 'components/ScrollToTop';
|
import ScrollToTop from 'components/ScrollToTop';
|
||||||
import Layout from 'components/Layout';
|
import Layout from 'components/Layout';
|
||||||
import RouteSidebarHidden from 'components/RouteSidebarHidden';
|
import RouteSidebarHidden from 'components/RouteSidebarHidden';
|
||||||
@@ -101,62 +102,68 @@ globalStyles();
|
|||||||
|
|
||||||
render(
|
render(
|
||||||
<div style={{ display: 'flex', flex: 1, height: '100%' }}>
|
<div style={{ display: 'flex', flex: 1, height: '100%' }}>
|
||||||
<Provider {...stores}>
|
<ErrorBoundary>
|
||||||
<Router>
|
<Provider {...stores}>
|
||||||
<ScrollToTop>
|
<Router>
|
||||||
<Switch>
|
<ScrollToTop>
|
||||||
<Route exact path="/" component={Home} />
|
<Switch>
|
||||||
|
<Route exact path="/" component={Home} />
|
||||||
|
|
||||||
<Route exact path="/auth/slack" component={SlackAuth} />
|
<Route exact path="/auth/slack" component={SlackAuth} />
|
||||||
<Route exact path="/auth/slack/commands" component={SlackAuth} />
|
<Route exact path="/auth/slack/commands" component={SlackAuth} />
|
||||||
<Route exact path="/auth/error" component={ErrorAuth} />
|
<Route exact path="/auth/error" component={ErrorAuth} />
|
||||||
|
|
||||||
<Auth>
|
<Auth>
|
||||||
<Layout>
|
<Layout>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path="/dashboard" component={Dashboard} />
|
<Route exact path="/dashboard" component={Dashboard} />
|
||||||
<Route exact path="/starred" component={Starred} />
|
<Route exact path="/starred" component={Starred} />
|
||||||
<Route exact path="/collections/:id" component={Collection} />
|
<Route
|
||||||
<Route
|
exact
|
||||||
exact
|
path="/collections/:id"
|
||||||
path={`/d/${matchDocumentSlug}`}
|
component={Collection}
|
||||||
component={RedirectDocument}
|
/>
|
||||||
/>
|
<Route
|
||||||
<Route
|
exact
|
||||||
exact
|
path={`/d/${matchDocumentSlug}`}
|
||||||
path={`/doc/${matchDocumentSlug}`}
|
component={RedirectDocument}
|
||||||
component={Document}
|
/>
|
||||||
/>
|
<Route
|
||||||
<Route
|
exact
|
||||||
exact
|
path={`/doc/${matchDocumentSlug}`}
|
||||||
path={`/doc/${matchDocumentSlug}/move`}
|
component={Document}
|
||||||
component={Document}
|
/>
|
||||||
/>
|
<Route
|
||||||
|
exact
|
||||||
|
path={`/doc/${matchDocumentSlug}/move`}
|
||||||
|
component={Document}
|
||||||
|
/>
|
||||||
|
|
||||||
<Route exact path="/search" component={Search} />
|
<Route exact path="/search" component={Search} />
|
||||||
<Route exact path="/search/:query" component={Search} />
|
<Route exact path="/search/:query" component={Search} />
|
||||||
<Route exact path="/developers" component={Api} />
|
<Route exact path="/developers" component={Api} />
|
||||||
|
|
||||||
<Route path="/404" component={Error404} />
|
<Route path="/404" component={Error404} />
|
||||||
|
|
||||||
<RouteSidebarHidden
|
<RouteSidebarHidden
|
||||||
exact
|
exact
|
||||||
path={`/doc/${matchDocumentSlug}/edit`}
|
path={`/doc/${matchDocumentSlug}/edit`}
|
||||||
component={Document}
|
component={Document}
|
||||||
/>
|
/>
|
||||||
<RouteSidebarHidden
|
<RouteSidebarHidden
|
||||||
exact
|
exact
|
||||||
path="/collections/:id/new"
|
path="/collections/:id/new"
|
||||||
component={DocumentNew}
|
component={DocumentNew}
|
||||||
/>
|
/>
|
||||||
<Route component={notFoundSearch} />
|
<Route component={notFoundSearch} />
|
||||||
</Switch>
|
</Switch>
|
||||||
</Layout>
|
</Layout>
|
||||||
</Auth>
|
</Auth>
|
||||||
</Switch>
|
</Switch>
|
||||||
</ScrollToTop>
|
</ScrollToTop>
|
||||||
</Router>
|
</Router>
|
||||||
</Provider>
|
</Provider>
|
||||||
|
</ErrorBoundary>
|
||||||
{DevTools && <DevTools position={{ bottom: 0, right: 0 }} />}
|
{DevTools && <DevTools position={{ bottom: 0, right: 0 }} />}
|
||||||
</div>,
|
</div>,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
|
|||||||
Reference in New Issue
Block a user