diff --git a/package.json b/package.json index fd86623..6297cad 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "dependencies": { "@babel/polyfill": "^7.2.3", "@babel/runtime": "^7.1.5", + "@sentry/browser": "^4.4.2", "chart.js": "^2.7.3", "classnames": "^2.2.6", "history": "^4.7.2", diff --git a/src/components/ErrorBoundary.js b/src/components/ErrorBoundary.js new file mode 100644 index 0000000..a44ca92 --- /dev/null +++ b/src/components/ErrorBoundary.js @@ -0,0 +1,53 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { getSentry } from '../misc/sentry'; + +// XXX this is no Hook equivalents for componentDidCatch +// we have to use class for now + +class ErrorBoundary extends Component { + static propTypes = { + children: PropTypes.node + }; + + state = { error: null }; + + loadSentry = async () => { + if (this.sentry) return this.sentry; + const x = await getSentry(); + this.sentry = x; + return this.sentry; + }; + + componentDidMount() { + this.loadSentry(); + } + + componentDidCatch(error, errorInfo) { + this.setState({ error }); + this.loadSentry().then(Sentry => { + Sentry.withScope(scope => { + Object.keys(errorInfo).forEach(key => { + scope.setExtra(key, errorInfo[key]); + }); + Sentry.captureException(error); + }); + }); + } + + showReportDialog = () => { + this.loadSentry().then(Sentry => Sentry.showReportDialog()); + }; + + render() { + if (this.state.error) { + //render fallback UI + return Report feedback; + } else { + //when there's not an error, render children untouched + return this.props.children; + } + } +} + +export default ErrorBoundary; diff --git a/src/components/Root.js b/src/components/Root.js index a5f56e7..dc96e22 100644 --- a/src/components/Root.js +++ b/src/components/Root.js @@ -4,6 +4,7 @@ import { HashRouter as Router, Route } from 'react-router-dom'; // import { hot } from 'react-hot-loader'; // import createHistory from 'history/createHashHistory'; // import createHistory from 'history/createBrowserHistory'; +import ErrorBoundary from 'c/ErrorBoundary'; import SideBar from 'c/SideBar'; import Home from 'c/Home'; import Logs from 'c/Logs'; @@ -23,21 +24,23 @@ import s0 from './Root.module.scss'; window.store = store; const Root = () => ( - - -
- - } /> -
- } /> - } /> - } /> - } /> - } /> + + + +
+ + } /> +
+ } /> + } /> + } /> + } /> + } /> +
-
- - + + + ); // // diff --git a/src/misc/sentry.js b/src/misc/sentry.js new file mode 100644 index 0000000..435c41a --- /dev/null +++ b/src/misc/sentry.js @@ -0,0 +1,9 @@ +const dsn = 'https://7068a15928ae45cf884dd8398fe8649c@sentry.io/1359284'; +let Sentry; +export async function getSentry() { + if (Sentry) return Sentry; + const s = await import('@sentry/browser'); + s.init({ dsn }); + Sentry = s; + return Sentry; +} diff --git a/yarn.lock b/yarn.lock index ce87063..1399f2b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -831,6 +831,58 @@ dependencies: any-observable "^0.3.0" +"@sentry/browser@^4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-4.4.2.tgz#8d361778962ef8ab1540e4ebbf64d485903abdf1" + integrity sha512-km5p3hPz+aoY4UiEvYxAdRJAbIK30urZSuMs/3zAUVe+8Zij0IHjHmdi9JtrMqpn+rAcWCxtRmFSYlkiKjdSUg== + dependencies: + "@sentry/core" "4.4.2" + "@sentry/types" "4.4.2" + "@sentry/utils" "4.4.2" + tslib "^1.9.3" + +"@sentry/core@4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-4.4.2.tgz#562526bc634c087f04bbca68b09cedc4b41cc64d" + integrity sha512-hJyAodTCf4sZfVdf41Rtuzj4EsyzYq5rdMZ+zc2Vinwdf8D0/brHe91fHeO0CKXEb2P0wJsrjwMidG/ccq/M8A== + dependencies: + "@sentry/hub" "4.4.2" + "@sentry/minimal" "4.4.2" + "@sentry/types" "4.4.2" + "@sentry/utils" "4.4.2" + tslib "^1.9.3" + +"@sentry/hub@4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-4.4.2.tgz#1399556fda06fb83c4f186c4aa842725f520159c" + integrity sha512-oe9ytXkTWyD+QmOpVzHAqTbRV4Hc0ee2Nt6HvrDtRmlXzQxfvTWG2F8KYT6w8kzqg5klnuRpnsmgTTV3KuNBVQ== + dependencies: + "@sentry/types" "4.4.2" + "@sentry/utils" "4.4.2" + tslib "^1.9.3" + +"@sentry/minimal@4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-4.4.2.tgz#13fffc6b17a2401b6a79947838a637626ab80b10" + integrity sha512-GEZZiNvVgqFAESZhAe3vjwTInn13lI2bSI3ItQN4RUWKL/W4n/fwVoDJbkb1U8aWxanuMnRDEpKwyQv6zYTZfw== + dependencies: + "@sentry/hub" "4.4.2" + "@sentry/types" "4.4.2" + tslib "^1.9.3" + +"@sentry/types@4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-4.4.2.tgz#f38dd3bc671cd2f5983a85553aebeac9c2286b17" + integrity sha512-QyQd6PKKIyjJgaq/RQjsxPJEWbXcuiWZ9RvSnhBjS5jj53HEzkM1qkbAFqlYHJ1DTJJ1EuOM4+aTmGzHe93zuA== + +"@sentry/utils@4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-4.4.2.tgz#e05a47e135ecef29e63a996f59aee8c8f792c222" + integrity sha512-j/Ad8G1abHlJdD2q7aWWbSOSeWB5M5v1R1VKL8YPlwEbSvvmEQWePhBKFI0qlnKd2ObdUQsj86pHEXJRSFNfCw== + dependencies: + "@sentry/types" "4.4.2" + tslib "^1.9.3" + "@types/q@^1.5.1": version "1.5.1" resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.1.tgz#48fd98c1561fe718b61733daed46ff115b496e18" @@ -7731,7 +7783,7 @@ tryer@^1.0.0: resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== -tslib@^1.9.0: +tslib@^1.9.0, tslib@^1.9.3: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==