mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-22 23:53:48 +01:00
Merge pull request #2551 from TheMas3212/feature-catch-errors-and-softreset-recovery
Add ErrorBoundary component to catch rendering error and redirect to recovery page
This commit is contained in:
commit
8d3c366e0e
29
src/ui/ErrorBoundary.tsx
Normal file
29
src/ui/ErrorBoundary.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import React, { ErrorInfo } from "react";
|
||||||
|
import { RecoveryRoot } from "./React/RecoveryRoot";
|
||||||
|
import { IRouter } from "./Router";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
router: IRouter;
|
||||||
|
softReset: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class ErrorBoundary extends React.Component<IProps> {
|
||||||
|
state: { hasError: boolean }
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = { hasError: false };
|
||||||
|
}
|
||||||
|
componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
|
||||||
|
console.error(error, errorInfo);
|
||||||
|
}
|
||||||
|
render(): React.ReactNode {
|
||||||
|
if (this.state.hasError) {
|
||||||
|
return <RecoveryRoot router={this.props.router} softReset={this.props.softReset} />;
|
||||||
|
}
|
||||||
|
return this.props.children;
|
||||||
|
}
|
||||||
|
static getDerivedStateFromError(): { hasError: true} {
|
||||||
|
return { hasError: true };
|
||||||
|
}
|
||||||
|
}
|
@ -77,6 +77,7 @@ import { enterBitNode } from "../RedPill";
|
|||||||
import { Context } from "./Context";
|
import { Context } from "./Context";
|
||||||
import { RecoveryMode, RecoveryRoot } from "./React/RecoveryRoot";
|
import { RecoveryMode, RecoveryRoot } from "./React/RecoveryRoot";
|
||||||
import { AchievementsRoot } from "../Achievements/AchievementsRoot";
|
import { AchievementsRoot } from "../Achievements/AchievementsRoot";
|
||||||
|
import { ErrorBoundary } from "./ErrorBoundary";
|
||||||
|
|
||||||
const htmlLocation = location;
|
const htmlLocation = location;
|
||||||
|
|
||||||
@ -218,6 +219,11 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
|
|||||||
throw new Error("Trying to go to a page without the proper setup");
|
throw new Error("Trying to go to a page without the proper setup");
|
||||||
|
|
||||||
const [cinematicText, setCinematicText] = useState("");
|
const [cinematicText, setCinematicText] = useState("");
|
||||||
|
const [errorBoundaryKey, setErrorBoundaryKey] = useState<number>(0);
|
||||||
|
|
||||||
|
function resetErrorBoundary(): void {
|
||||||
|
setErrorBoundaryKey(errorBoundaryKey+1);
|
||||||
|
}
|
||||||
|
|
||||||
function rerender(): void {
|
function rerender(): void {
|
||||||
setRerender((old) => old + 1);
|
setRerender((old) => old + 1);
|
||||||
@ -305,12 +311,19 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
|
|||||||
if (page !== Page.Terminal) window.scrollTo(0, 0);
|
if (page !== Page.Terminal) window.scrollTo(0, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function softReset(): void {
|
||||||
|
dialogBoxCreate("Soft Reset!");
|
||||||
|
prestigeAugmentation();
|
||||||
|
resetErrorBoundary();
|
||||||
|
Router.toTerminal();
|
||||||
|
}
|
||||||
|
|
||||||
let mainPage = <Typography>Cannot load</Typography>;
|
let mainPage = <Typography>Cannot load</Typography>;
|
||||||
let withSidebar = true;
|
let withSidebar = true;
|
||||||
let withPopups = true;
|
let withPopups = true;
|
||||||
switch (page) {
|
switch (page) {
|
||||||
case Page.Recovery: {
|
case Page.Recovery: {
|
||||||
mainPage = <RecoveryRoot router={Router} />;
|
mainPage = <RecoveryRoot router={Router} softReset={softReset} />;
|
||||||
withSidebar = false;
|
withSidebar = false;
|
||||||
withPopups = false;
|
withPopups = false;
|
||||||
break;
|
break;
|
||||||
@ -463,11 +476,7 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
|
|||||||
saveObject.exportGame();
|
saveObject.exportGame();
|
||||||
}}
|
}}
|
||||||
forceKill={killAllScripts}
|
forceKill={killAllScripts}
|
||||||
softReset={() => {
|
softReset={softReset}
|
||||||
dialogBoxCreate("Soft Reset!");
|
|
||||||
prestigeAugmentation();
|
|
||||||
Router.toTerminal();
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
@ -496,34 +505,27 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Context.Player.Provider value={player}>
|
<Context.Player.Provider value={player}>
|
||||||
<Context.Router.Provider value={Router}>
|
<Context.Router.Provider value={Router}>
|
||||||
|
<ErrorBoundary key={errorBoundaryKey} router={Router} softReset={softReset}>
|
||||||
<SnackbarProvider>
|
<SnackbarProvider>
|
||||||
<Overview mode={ITutorial.isRunning ? "tutorial" : "overview"}>
|
<Overview mode={ITutorial.isRunning ? "tutorial" : "overview"}>
|
||||||
{!ITutorial.isRunning ? (
|
{!ITutorial.isRunning ? (
|
||||||
<CharacterOverview save={() => saveObject.saveGame()} killScripts={killAllScripts} />
|
<CharacterOverview save={() => saveObject.saveGame()} killScripts={killAllScripts} />
|
||||||
) : (
|
) : (
|
||||||
<InteractiveTutorialRoot />
|
|
||||||
)}
|
|
||||||
</Overview>
|
|
||||||
{withSidebar ? (
|
|
||||||
<Box display="flex" flexDirection="row" width="100%">
|
|
||||||
<SidebarRoot player={player} router={Router} page={page} />
|
|
||||||
<Box className={classes.root}>{mainPage}</Box>
|
<Box className={classes.root}>{mainPage}</Box>
|
||||||
</Box>
|
)}
|
||||||
) : (
|
<Unclickable />
|
||||||
<Box className={classes.root}>{mainPage}</Box>
|
{withPopups && (
|
||||||
)}
|
<>
|
||||||
<Unclickable />
|
<LogBoxManager />
|
||||||
{withPopups && (
|
<AlertManager />
|
||||||
<>
|
<PromptManager />
|
||||||
<LogBoxManager />
|
<InvitationModal />
|
||||||
<AlertManager />
|
<Snackbar />
|
||||||
<PromptManager />
|
</>
|
||||||
<InvitationModal />
|
)}
|
||||||
<Snackbar />
|
</SnackbarProvider>
|
||||||
</>
|
</ErrorBoundary>
|
||||||
)}
|
|
||||||
</SnackbarProvider>
|
|
||||||
</Context.Router.Provider>
|
</Context.Router.Provider>
|
||||||
</Context.Player.Provider>
|
</Context.Player.Provider>
|
||||||
);
|
);
|
||||||
|
@ -15,9 +15,10 @@ export function ActivateRecoveryMode(): void {
|
|||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
router: IRouter;
|
router: IRouter;
|
||||||
|
softReset: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RecoveryRoot({ router }: IProps): React.ReactElement {
|
export function RecoveryRoot({ router, softReset }: IProps): React.ReactElement {
|
||||||
function recover(): void {
|
function recover(): void {
|
||||||
RecoveryMode = false;
|
RecoveryMode = false;
|
||||||
router.toTerminal();
|
router.toTerminal();
|
||||||
@ -48,6 +49,7 @@ export function RecoveryRoot({ router }: IProps): React.ReactElement {
|
|||||||
<br />
|
<br />
|
||||||
<Typography>You can disable recovery mode now. But chances are the game will not work correctly.</Typography>
|
<Typography>You can disable recovery mode now. But chances are the game will not work correctly.</Typography>
|
||||||
<Button onClick={recover}>DISABLE RECOVERY MODE</Button>
|
<Button onClick={recover}>DISABLE RECOVERY MODE</Button>
|
||||||
|
<Button onClick={softReset}>PERFORM SOFT RESET</Button>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user