bitburner-src/src/ui/ErrorBoundary.tsx
Martin Fournier 65964c84b2 Add information to the recovery page
Adds error & environment information to the recovery page when
available. The info will be displayed when the error boundary catches an error only.

Otherwise, does a few minor tweaks to the UI of the page.

- Add DevPage button to throw an uncaught error to go into recovery
- Add "Delete Save" button in recovery from Game Options (refactored into its own
component)
- Use "Soft Reset" button from Game Options (refactored into its own
component)
- The "Soft Reset" & "Delete Save" buttons now have confirmations
- Add tooltip on "Disable Recovery Mode" button
- Add timestamp to the RECOVERY.json filename
- Add textarea containing markdown with the current error details, if
available
  - Error
  - Page
  - Version
  - Environment
  - Platform
  - UserAgent
  - Features
  - Source
  - Stack Trace
- Change GitHub new issue link to contain default body & title, if possible
- Change links to not take the full width (they were clickable by mistake)
- Fix "Disable Recovery Mode" not resetting the ErrorBoundary's state,
making going back to terminal impossible
2022-01-16 09:07:53 -05:00

59 lines
1.5 KiB
TypeScript

import React, { ErrorInfo } from "react";
import { IErrorData, getErrorForDisplay } from "../utils/ErrorHelper";
import { RecoveryRoot } from "./React/RecoveryRoot";
import { IRouter, Page } from "./Router";
interface IProps {
router: IRouter;
softReset: () => void;
}
interface IState {
error?: Error;
errorInfo?: React.ErrorInfo;
page?: Page;
hasError: boolean;
}
export class ErrorBoundary extends React.Component<IProps, IState> {
state: IState
constructor(props: IProps) {
super(props);
this.state = { hasError: false } as IState;
}
reset(): void {
this.setState( { hasError: false } as IState);
}
componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
this.setState({
errorInfo,
page: this.props.router.page(),
});
console.error(error, errorInfo);
}
render(): React.ReactNode {
if (this.state.hasError) {
let errorData: IErrorData | undefined;
if (this.state.error) {
try {
// We don't want recursive errors, so in case this fails, it's in a try catch.
errorData = getErrorForDisplay(this.state.error, this.state.errorInfo, this.state.page);
} catch (ex) {
console.error(ex);
}
}
return <RecoveryRoot router={this.props.router} softReset={this.props.softReset}
errorData={errorData} resetError={() => this.reset()} />;
}
return this.props.children;
}
static getDerivedStateFromError(error: Error): IState {
return { hasError: true, error};
}
}