Merge pull request #2664 from MartinFournier/feature/recovery

Add information to the recovery page
This commit is contained in:
hydroflame
2022-01-17 16:02:04 -05:00
committed by Olivier Gagnon
10 changed files with 346 additions and 95 deletions
+32
View File
@@ -0,0 +1,32 @@
import React, { useState } from 'react';
import { deleteGame } from "../../db";
import { ConfirmationModal } from "./ConfirmationModal";
import Button from "@mui/material/Button";
import { Tooltip } from '@mui/material';
import DeleteIcon from '@mui/icons-material/Delete';
interface IProps {
color?: "primary" | "warning" | "error";
}
export function DeleteGameButton({ color = "primary" }: IProps): React.ReactElement {
const [modalOpened, setModalOpened] = useState(false);
return (<>
<Tooltip title="This will permanently delete your local save game. Did you export it before?">
<Button startIcon={<DeleteIcon />} color={color} onClick={() => setModalOpened(true)}>Delete Save</Button>
</Tooltip>
<ConfirmationModal
onConfirm={() => {
setModalOpened(false);
deleteGame()
.then(() => setTimeout(() => location.reload(), 1000))
.catch((r) => console.error(`Could not delete game: ${r}`));
}}
open={modalOpened}
onClose={() => setModalOpened(false)}
confirmationText={"Really delete your game? (It's permanent!)"}
/>
</>)
}
+11 -43
View File
@@ -21,6 +21,7 @@ import TextField from "@mui/material/TextField";
import DownloadIcon from "@mui/icons-material/Download";
import UploadIcon from "@mui/icons-material/Upload";
import SaveIcon from '@mui/icons-material/Save';
import { FileDiagnosticModal } from "../../Diagnostic/FileDiagnosticModal";
import { dialogBoxCreate } from "./DialogBox";
@@ -31,9 +32,11 @@ import { StyleEditorModal } from "./StyleEditorModal";
import { SnackbarEvents } from "./Snackbar";
import { Settings } from "../../Settings/Settings";
import { save, deleteGame } from "../../db";
import { save } from "../../db";
import { formatTime } from "../../utils/helpers/formatTime";
import { OptionSwitch } from "./OptionSwitch";
import { DeleteGameButton } from "./DeleteGameButton";
import { SoftResetButton } from "./SoftResetButton";
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@@ -71,10 +74,8 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
const [timestampFormat, setTimestampFormat] = useState(Settings.TimestampsFormat);
const [locale, setLocale] = useState(Settings.Locale);
const [diagnosticOpen, setDiagnosticOpen] = useState(false);
const [deleteGameOpen, setDeleteOpen] = useState(false);
const [themeEditorOpen, setThemeEditorOpen] = useState(false);
const [styleEditorOpen, setStyleEditorOpen] = useState(false);
const [softResetOpen, setSoftResetOpen] = useState(false);
const [importSaveOpen, setImportSaveOpen] = useState(false);
const [importData, setImportData] = useState<ImportData | null>(null);
@@ -194,14 +195,6 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
});
}
function doSoftReset(): void {
if (!Settings.SuppressBuyAugmentationConfirmation) {
setSoftResetOpen(true);
} else {
props.softReset();
}
}
return (
<div className={classes.root} style={{ width: "90%" }}>
<Typography variant="h4" gutterBottom>
@@ -531,19 +524,19 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
</Grid>
<Box sx={{ display: 'grid', width: 'fit-content', height: 'fit-content' }}>
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr' }}>
<Button onClick={() => props.save()}>Save Game</Button>
<Button onClick={() => setDeleteOpen(true)}>Delete Game</Button>
<Button onClick={() => props.save()} startIcon={<SaveIcon />} >
Save Game
</Button>
<DeleteGameButton />
</Box>
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr' }}>
<Tooltip title={<Typography>Export your game to a text file.</Typography>}>
<Button onClick={() => props.export()}>
<DownloadIcon color="primary" />
<Button onClick={() => props.export()} startIcon={<DownloadIcon />}>
Export Game
</Button>
</Tooltip>
<Tooltip title={<Typography>Import your game from a text file.<br />This will <strong>overwrite</strong> your current game. Back it up first!</Typography>}>
<Button onClick={startImport}>
<UploadIcon color="primary" />
<Button onClick={startImport} startIcon={<UploadIcon />}>
Import Game
<input ref={importInput} id="import-game-file-selector" type="file" hidden onChange={onImport} />
</Button>
@@ -587,21 +580,7 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
</Tooltip>
</Box>
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr' }}>
<Tooltip
title={
<Typography>
Perform a soft reset. Resets everything as if you had just purchased an Augmentation.
</Typography>
}
>
<Button onClick={doSoftReset}>Soft Reset</Button>
</Tooltip>
<ConfirmationModal
open={softResetOpen}
onClose={() => setSoftResetOpen(false)}
onConfirm={props.softReset}
confirmationText={"This will perform the same action as installing Augmentations, are you sure?"}
/>
<SoftResetButton noConfirmation={Settings.SuppressBuyAugmentationConfirmation} onTriggered={props.softReset} />
<Tooltip
title={
<Typography>
@@ -640,17 +619,6 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
</Box>
</Grid>
<FileDiagnosticModal open={diagnosticOpen} onClose={() => setDiagnosticOpen(false)} />
<ConfirmationModal
onConfirm={() => {
setDeleteOpen(false);
deleteGame()
.then(() => setTimeout(() => location.reload(), 1000))
.catch((r) => console.error(`Could not delete game: ${r}`));
}}
open={deleteGameOpen}
onClose={() => setDeleteOpen(false)}
confirmationText={"Really delete your game? (It's permanent!)"}
/>
<ThemeEditorModal open={themeEditorOpen} onClose={() => setThemeEditorOpen(false)} />
<StyleEditorModal open={styleEditorOpen} onClose={() => setStyleEditorOpen(false)} />
</div>
+66 -22
View File
@@ -1,11 +1,16 @@
import React from "react";
import Typography from "@mui/material/Typography";
import Link from "@mui/material/Link";
import Button from "@mui/material/Button";
import React, { useEffect } from "react";
import { Typography, Link, Button, ButtonGroup, Tooltip, Box, Paper, TextField } from "@mui/material";
import { Settings } from "../../Settings/Settings";
import { load } from "../../db";
import { IRouter } from "../Router";
import { download } from "../../SaveObject";
import { IErrorData, newIssueUrl } from "../../utils/ErrorHelper";
import { DeleteGameButton } from "./DeleteGameButton";
import { SoftResetButton } from "./SoftResetButton";
import DirectionsRunIcon from '@mui/icons-material/DirectionsRun';
import GitHubIcon from "@mui/icons-material/GitHub";
export let RecoveryMode = false;
@@ -16,40 +21,79 @@ export function ActivateRecoveryMode(): void {
interface IProps {
router: IRouter;
softReset: () => void;
errorData?: IErrorData;
resetError?: () => void;
}
export function RecoveryRoot({ router, softReset }: IProps): React.ReactElement {
export function RecoveryRoot({ router, softReset, errorData, resetError }: IProps): React.ReactElement {
function recover(): void {
if (resetError) resetError();
RecoveryMode = false;
router.toTerminal();
}
Settings.AutosaveInterval = 0;
load().then((content) => {
download("RECOVERY.json", content);
});
useEffect(() => {
load().then((content) => {
const epochTime = Math.round(Date.now() / 1000);
const filename = `RECOVERY_BITBURNER_${epochTime}.json`;
download(filename, content);
});
}, []);
return (
<>
<Box sx={{ padding: "8px 16px", minHeight: "100vh", maxWidth: '1200px', boxSizing: "border-box",}}>
<Typography variant="h3">RECOVERY MODE ACTIVATED</Typography>
<Typography>
There was an error loading your save file and the game went into recovery mode. In this mode saving is disabled
There was an error with your save file and the game went into recovery mode. In this mode saving is disabled
and the game will automatically export your save file (to prevent corruption).
</Typography>
<Typography>At this point it is recommended to alert a developer.</Typography>
<Link href="https://github.com/danielyxie/bitburner/issues/new" target="_blank">
<Typography>File an issue on github</Typography>
</Link>
<Link href="https://www.reddit.com/r/Bitburner/" target="_blank">
<Typography>Make a reddit post</Typography>
</Link>
<Link href="https://discord.gg/TFc3hKD" target="_blank">
<Typography>Post in the #bug-report channel on Discord.</Typography>
</Link>
<Typography>
<Link href={errorData?.issueUrl ?? newIssueUrl} target="_blank">File an issue on github</Link>
</Typography>
<Typography>
<Link href="https://www.reddit.com/r/Bitburner/" target="_blank">Make a reddit post</Link>
</Typography>
<Typography>
<Link href="https://discord.gg/TFc3hKD" target="_blank">Post in the #bug-report channel on Discord.</Link>
</Typography>
<Typography>Please include your save file.</Typography>
<br />
<br />
<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={softReset}>PERFORM SOFT RESET</Button>
</>
<ButtonGroup sx={{ my: 2 }}>
<Tooltip title="Disables the recovery mode & attempt to head back to the terminal page. This may or may not work. Ensure you have saved the recovery file.">
<Button onClick={recover} startIcon={<DirectionsRunIcon />}>Disable Recovery Mode</Button>
</Tooltip>
<SoftResetButton color="warning" onTriggered={softReset} />
<DeleteGameButton color="error" />
</ButtonGroup>
{errorData && (
<Paper sx={{ px: 2, pt: 1, pb: 2, mt: 2}}>
<Typography variant="h5">
{errorData.title}
</Typography>
<Box sx={{ my: 2 }}>
<TextField
label="Bug Report Text"
value={errorData.body}
variant="outlined"
color="secondary"
multiline
fullWidth
rows={12}
sx={{ "& .MuiOutlinedInput-root": { color: Settings.theme.secondary }}} />
</Box>
<Tooltip title="Submitting an issue to GitHub really help us improve the game!">
<Button component={Link} startIcon={<GitHubIcon />} color="info" sx={{ px: 2 }}
href={errorData.issueUrl ?? newIssueUrl} target={"_blank"} >
Submit Issue to GitHub
</Button>
</Tooltip>
</Paper>
)}
</Box>
);
}
+36
View File
@@ -0,0 +1,36 @@
import React, { useState } from 'react';
import { ConfirmationModal } from "./ConfirmationModal";
import Button from "@mui/material/Button";
import { Tooltip } from '@mui/material';
import RestartAltIcon from '@mui/icons-material/RestartAlt';
interface IProps {
color?: "primary" | "warning" | "error";
noConfirmation?: boolean;
onTriggered: () => void;
}
export function SoftResetButton({ color = "primary", noConfirmation = false, onTriggered }: IProps): React.ReactElement {
const [modalOpened, setModalOpened] = useState(false);
function handleButtonClick(): void {
if (noConfirmation) {
onTriggered();
} else {
setModalOpened(true);
}
}
return (<>
<Tooltip title="Perform a soft reset. Resets everything as if you had just purchased an Augmentation.">
<Button startIcon={<RestartAltIcon />} color={color} onClick={handleButtonClick}>Soft Reset</Button>
</Tooltip>
<ConfirmationModal
onConfirm={onTriggered}
open={modalOpened}
onClose={() => setModalOpened(false)}
confirmationText={"This will perform the same action as installing Augmentations, are you sure?"}
/>
</>)
}