<ErrorBoundary/> works 🎉

pull/768/head
Rick Carlino 2018-04-02 10:23:09 -05:00
parent 98a4f6cf58
commit 6736a3885d
7 changed files with 109 additions and 70 deletions

View File

@ -127,7 +127,7 @@ export const onSent = (client: Client) => () => !!client.connected ?
dispatchNetworkUp("user.mqtt") : dispatchNetworkDown("user.mqtt");
const LEGACY_META_KEY_NAMES: (keyof Log)[] = [
"type",
// "type",
"x",
"y",
"z",

View File

@ -0,0 +1,27 @@
import * as React from "react";
import { catchErrors } from "./util";
interface State { hasError?: boolean; }
interface Props { }
export class ErrorBoundary extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(error: Error) {
try {
this.setState({ hasError: true });
catchErrors(error);
} catch (e) {
this.setState({ hasError: true });
}
}
no = () => <h1>Something went wrong.</h1>;
ok = () => this.props.children;
render() { return (this.state.hasError ? this.no : this.ok)(); }
}

View File

@ -4,5 +4,7 @@ import { formatEnvKey } from "./translators";
/** Send a number to FBOS for storage on the device. */
export function envSave(key: WDENVKey, value: number) {
getDevice().setUserEnv({ [key]: JSON.stringify(formatEnvKey(key, value)) });
getDevice()
.setUserEnv({ [key]: JSON.stringify(formatEnvKey(key, value)) })
.then(() => { }, () => { });
}

View File

@ -16,6 +16,7 @@ import {
Position,
PopoverInteractionKind
} from "@blueprintjs/core/dist";
import { ErrorBoundary } from "../error_boundary";
export class NavBar extends React.Component<NavBarProps, Partial<NavBarState>> {
@ -60,47 +61,49 @@ export class NavBar extends React.Component<NavBarProps, Partial<NavBarState>> {
const { mobileMenuOpen, tickerListOpen, accountMenuOpen } = this.state;
const { logs, timeOffset } = this.props;
return <div className="nav-wrapper">
<nav role="navigation">
<Row>
<Col xs={12}>
<div>
<TickerList {...{ logs, tickerListOpen, toggle, timeOffset }} />
<div className="nav-group">
<div className="nav-left">
<i
className={menuIconClassNames.join(" ")}
onClick={this.toggle("mobileMenuOpen")} />
<span className="mobile-menu-container">
{MobileMenu({ close, mobileMenuOpen })}
</span>
<span className="top-menu-container">
{NavLinks({ close })}
</span>
</div>
<div className="nav-right">
<Popover
inline
interactionKind={PopoverInteractionKind.HOVER}
target={
<div className="nav-name"
onClick={this.toggle("accountMenuOpen")}>
{firstName}
</div>}
position={Position.BOTTOM_RIGHT}
content={AdditionalMenu({ logout: this.logout, close })}
isOpen={accountMenuOpen}
onClose={this.close("accountMenuOpen")} />
<EStopButton
bot={this.props.bot}
user={this.props.user} />
{this.syncButton()}
return <ErrorBoundary>
<div className="nav-wrapper">
<nav role="navigation">
<Row>
<Col xs={12}>
<div>
<TickerList {...{ logs, tickerListOpen, toggle, timeOffset }} />
<div className="nav-group">
<div className="nav-left">
<i
className={menuIconClassNames.join(" ")}
onClick={this.toggle("mobileMenuOpen")} />
<span className="mobile-menu-container">
{MobileMenu({ close, mobileMenuOpen })}
</span>
<span className="top-menu-container">
{NavLinks({ close })}
</span>
</div>
<div className="nav-right">
<Popover
inline
interactionKind={PopoverInteractionKind.HOVER}
target={
<div className="nav-name"
onClick={this.toggle("accountMenuOpen")}>
{firstName}
</div>}
position={Position.BOTTOM_RIGHT}
content={AdditionalMenu({ logout: this.logout, close })}
isOpen={accountMenuOpen}
onClose={this.close("accountMenuOpen")} />
<EStopButton
bot={this.props.bot}
user={this.props.user} />
{this.syncButton()}
</div>
</div>
</div>
</div>
</Col>
</Row>
</nav>
</div>;
</Col>
</Row>
</nav>
</div>
</ErrorBoundary>;
}
}

View File

@ -8,6 +8,7 @@ import { t } from "i18next";
import { formatLogTime } from "../logs/index";
import { Session, safeNumericSetting } from "../session";
import { isNumber } from "lodash";
import { ErrorBoundary } from "../error_boundary";
const logFilter = (log: Log): Log | undefined => {
const { type, verbosity } = log;
@ -64,27 +65,27 @@ const Ticker = (log: Log, index: number, timeOffset: number) => {
};
export let TickerList = (props: TickerListProps) => {
return <div
className="ticker-list"
onClick={props.toggle("tickerListOpen")} >
<div className="first-ticker">
{Ticker(getfirstTickerLog(props.logs), -1, props.timeOffset)}
return <ErrorBoundary>
<div className="ticker-list" onClick={props.toggle("tickerListOpen")} >
<div className="first-ticker">
{Ticker(getfirstTickerLog(props.logs), -1, props.timeOffset)}
</div>
<Collapse isOpen={props.tickerListOpen}>
{props
.logs
.filter((_, index) => index !== 0)
.filter((log) => logFilter(log))
.map((log: Log, index: number) => Ticker(log, index, props.timeOffset))}
</Collapse>
<Collapse isOpen={props.tickerListOpen}>
<Link to={"/app/logs"}>
<div className="logs-page-link">
<label>
{t("Filter logs")}
</label>
</div>
</Link>
</Collapse>
</div>
<Collapse isOpen={props.tickerListOpen}>
{props
.logs
.filter((_, index) => index !== 0)
.filter((log) => logFilter(log))
.map((log: Log, index: number) => Ticker(log, index, props.timeOffset))}
</Collapse>
<Collapse isOpen={props.tickerListOpen}>
<Link to={"/app/logs"}>
<div className="logs-page-link">
<label>
{t("Filter logs")}
</label>
</div>
</Link>
</Collapse>
</div>;
</ErrorBoundary>;
};

View File

@ -10,6 +10,7 @@ import { Session } from "./session";
import { attachToRoot } from "./util";
import { Callback } from "i18next";
import { topLevelRoutes } from "./route_config";
import { ErrorBoundary } from "./error_boundary";
interface RootComponentProps { store: Store; }
@ -26,10 +27,12 @@ export class RootComponent extends React.Component<RootComponentProps, {}> {
}
render() {
return <Provider store={_store}>
<Router history={history}>
{topLevelRoutes}
</Router>
</Provider>;
return <ErrorBoundary>
<Provider store={_store}>
<Router history={history}>
{topLevelRoutes}
</Router>
</Provider>
</ErrorBoundary>;
}
}

View File

@ -1,4 +1,5 @@
import * as React from "react";
import { ErrorBoundary } from "../error_boundary";
interface PageProps {
children?: React.ReactNode;
@ -9,6 +10,8 @@ export function Page(props: PageProps) {
let finalClassName = "all-content-wrapper";
if (props.className) { finalClassName += ` ${props.className}`; }
return <div className={finalClassName}>
{props.children}
<ErrorBoundary>
{props.children}
</ErrorBoundary>
</div>;
}