Added high level ErrorBoundary
This commit is contained in:
parent
0909dc61ff
commit
ee89fb852b
|
@ -15,6 +15,7 @@ type Props = {
|
|||
readOnly: boolean,
|
||||
component?: string,
|
||||
attributes: Object,
|
||||
className?: string,
|
||||
};
|
||||
|
||||
function Heading(props: Props) {
|
||||
|
@ -26,6 +27,7 @@ function Heading(props: Props) {
|
|||
readOnly,
|
||||
children,
|
||||
component = 'h1',
|
||||
className,
|
||||
attributes,
|
||||
} = props;
|
||||
const parentIsDocument = parent instanceof Document;
|
||||
|
@ -40,7 +42,7 @@ function Heading(props: Props) {
|
|||
emoji && title.match(new RegExp(`^${emoji}\\s`));
|
||||
|
||||
return (
|
||||
<Component {...attributes} id={slugish}>
|
||||
<Component {...attributes} id={slugish} className={className}>
|
||||
<Wrapper hasEmoji={startsWithEmojiAndSpace}>{children}</Wrapper>
|
||||
{showPlaceholder && (
|
||||
<Placeholder contentEditable={false}>
|
||||
|
|
|
@ -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;
|
|
@ -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 Error404 from 'scenes/Error404';
|
||||
|
||||
import ErrorBoundary from 'components/ErrorBoundary';
|
||||
import ScrollToTop from 'components/ScrollToTop';
|
||||
import Layout from 'components/Layout';
|
||||
import RouteSidebarHidden from 'components/RouteSidebarHidden';
|
||||
|
@ -101,62 +102,68 @@ globalStyles();
|
|||
|
||||
render(
|
||||
<div style={{ display: 'flex', flex: 1, height: '100%' }}>
|
||||
<Provider {...stores}>
|
||||
<Router>
|
||||
<ScrollToTop>
|
||||
<Switch>
|
||||
<Route exact path="/" component={Home} />
|
||||
<ErrorBoundary>
|
||||
<Provider {...stores}>
|
||||
<Router>
|
||||
<ScrollToTop>
|
||||
<Switch>
|
||||
<Route exact path="/" component={Home} />
|
||||
|
||||
<Route exact path="/auth/slack" component={SlackAuth} />
|
||||
<Route exact path="/auth/slack/commands" component={SlackAuth} />
|
||||
<Route exact path="/auth/error" component={ErrorAuth} />
|
||||
<Route exact path="/auth/slack" component={SlackAuth} />
|
||||
<Route exact path="/auth/slack/commands" component={SlackAuth} />
|
||||
<Route exact path="/auth/error" component={ErrorAuth} />
|
||||
|
||||
<Auth>
|
||||
<Layout>
|
||||
<Switch>
|
||||
<Route exact path="/dashboard" component={Dashboard} />
|
||||
<Route exact path="/starred" component={Starred} />
|
||||
<Route exact path="/collections/:id" component={Collection} />
|
||||
<Route
|
||||
exact
|
||||
path={`/d/${matchDocumentSlug}`}
|
||||
component={RedirectDocument}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path={`/doc/${matchDocumentSlug}`}
|
||||
component={Document}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path={`/doc/${matchDocumentSlug}/move`}
|
||||
component={Document}
|
||||
/>
|
||||
<Auth>
|
||||
<Layout>
|
||||
<Switch>
|
||||
<Route exact path="/dashboard" component={Dashboard} />
|
||||
<Route exact path="/starred" component={Starred} />
|
||||
<Route
|
||||
exact
|
||||
path="/collections/:id"
|
||||
component={Collection}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path={`/d/${matchDocumentSlug}`}
|
||||
component={RedirectDocument}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path={`/doc/${matchDocumentSlug}`}
|
||||
component={Document}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path={`/doc/${matchDocumentSlug}/move`}
|
||||
component={Document}
|
||||
/>
|
||||
|
||||
<Route exact path="/search" component={Search} />
|
||||
<Route exact path="/search/:query" component={Search} />
|
||||
<Route exact path="/developers" component={Api} />
|
||||
<Route exact path="/search" component={Search} />
|
||||
<Route exact path="/search/:query" component={Search} />
|
||||
<Route exact path="/developers" component={Api} />
|
||||
|
||||
<Route path="/404" component={Error404} />
|
||||
<Route path="/404" component={Error404} />
|
||||
|
||||
<RouteSidebarHidden
|
||||
exact
|
||||
path={`/doc/${matchDocumentSlug}/edit`}
|
||||
component={Document}
|
||||
/>
|
||||
<RouteSidebarHidden
|
||||
exact
|
||||
path="/collections/:id/new"
|
||||
component={DocumentNew}
|
||||
/>
|
||||
<Route component={notFoundSearch} />
|
||||
</Switch>
|
||||
</Layout>
|
||||
</Auth>
|
||||
</Switch>
|
||||
</ScrollToTop>
|
||||
</Router>
|
||||
</Provider>
|
||||
<RouteSidebarHidden
|
||||
exact
|
||||
path={`/doc/${matchDocumentSlug}/edit`}
|
||||
component={Document}
|
||||
/>
|
||||
<RouteSidebarHidden
|
||||
exact
|
||||
path="/collections/:id/new"
|
||||
component={DocumentNew}
|
||||
/>
|
||||
<Route component={notFoundSearch} />
|
||||
</Switch>
|
||||
</Layout>
|
||||
</Auth>
|
||||
</Switch>
|
||||
</ScrollToTop>
|
||||
</Router>
|
||||
</Provider>
|
||||
</ErrorBoundary>
|
||||
{DevTools && <DevTools position={{ bottom: 0, right: 0 }} />}
|
||||
</div>,
|
||||
document.getElementById('root')
|
||||
|
|
Reference in New Issue