<ErrorBoundary/> works 🎉
parent
98a4f6cf58
commit
6736a3885d
|
@ -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",
|
||||
|
|
|
@ -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)(); }
|
||||
}
|
|
@ -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(() => { }, () => { });
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue