make error message more user-friendly (#812)

* make error message more user-friendly

* tweak aria

* override user-select for error splash screen

* localize messages

* fix naming

* log error

* include spaces in i18n
This commit is contained in:
David Luzar 2020-03-09 17:09:45 +01:00 committed by GitHub
parent 56a2f8f15f
commit 3bf3d96d9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 20 deletions

View File

@ -5,9 +5,9 @@ export default `
// paste stack trace here // paste stack trace here
\`\`\` \`\`\`
### localStorage ### Scene content
\`\`\` \`\`\`
// paste localStorage content here (if it doesn't contain sensitive data) // paste scene content here (if it doesn't contain sensitive data)
\`\`\` \`\`\`
`; `;

View File

@ -1,4 +1,6 @@
import React from "react"; import React from "react";
import { resetCursor } from "../utils";
import { t } from "../i18n";
interface TopErrorBoundaryState { interface TopErrorBoundaryState {
unresolvedError: Error[] | null; unresolvedError: Error[] | null;
@ -19,11 +21,12 @@ export class TopErrorBoundary extends React.Component<
}; };
componentDidCatch(error: Error) { componentDidCatch(error: Error) {
resetCursor();
const _localStorage: any = {}; const _localStorage: any = {};
for (const [key, value] of Object.entries({ ...localStorage })) { for (const [key, value] of Object.entries({ ...localStorage })) {
try { try {
_localStorage[key] = JSON.parse(value); _localStorage[key] = JSON.parse(value);
} catch { } catch (error) {
_localStorage[key] = value; _localStorage[key] = value;
} }
} }
@ -90,49 +93,55 @@ export class TopErrorBoundary extends React.Component<
return ( return (
<div className="ErrorSplash"> <div className="ErrorSplash">
<div className="ErrorSplash-messageContainer"> <div className="ErrorSplash-messageContainer">
<div className="ErrorSplash-paragraph bigger"> <div className="ErrorSplash-paragraph bigger align-center">
Encountered an error. Please{" "} {t("errorSplash.headingMain_pre")}
<button onClick={() => window.location.reload()}> <button onClick={() => window.location.reload()}>
reload the page {t("errorSplash.headingMain_button")}
</button> </button>
.
</div> </div>
<div className="ErrorSplash-paragraph"> <div className="ErrorSplash-paragraph align-center">
If reloading doesn't work. Try{" "} {t("errorSplash.clearCanvasMessage")}
<button <button
onClick={() => { onClick={() => {
localStorage.clear(); localStorage.clear();
window.location.reload(); window.location.reload();
}} }}
> >
clearing the canvas {t("errorSplash.clearCanvasMessage_button")}
</button> </button>
.<br /> <br />
<div className="smaller"> <div className="smaller">
(This will unfortunately result in loss of work.) <span role="img" aria-label="warning">
</span>
{t("errorSplash.clearCanvasCaveat")}
<span role="img" aria-hidden="true">
</span>
</div> </div>
</div> </div>
<div> <div>
<div className="ErrorSplash-paragraph"> <div className="ErrorSplash-paragraph">
Before doing so, we'd appreciate if you opened an issue on our{" "} {t("errorSplash.openIssueMessage_pre")}
<button onClick={this.createGithubIssue}>bug tracker</button>. <button onClick={this.createGithubIssue}>
Please include the following error stack trace & localStorage {t("errorSplash.openIssueMessage_button")}
content (provided it's not private): </button>
{t("errorSplash.openIssueMessage_post")}
</div> </div>
<div className="ErrorSplash-paragraph"> <div className="ErrorSplash-paragraph">
<div className="ErrorSplash-details"> <div className="ErrorSplash-details">
<label>Error stack trace:</label> <label>{t("errorSplash.errorStack")}</label>
<textarea <textarea
rows={10} rows={10}
onPointerDown={this.selectTextArea} onPointerDown={this.selectTextArea}
readOnly={true} readOnly={true}
value={ value={
this.state.unresolvedError this.state.unresolvedError
? "Loading data. please wait..." ? t("errorSplash.errorStack_loading")
: this.state.stack : this.state.stack
} }
/> />
<label>LocalStorage content:</label> <label>{t("errorSplash.sceneContent")}</label>
<textarea <textarea
rows={5} rows={5}
onPointerDown={this.selectTextArea} onPointerDown={this.selectTextArea}

View File

@ -92,5 +92,18 @@
"linearElement": "Click to start multiple points, drag for single line", "linearElement": "Click to start multiple points, drag for single line",
"linearElementMulti": "Press Escape or Enter to finish", "linearElementMulti": "Press Escape or Enter to finish",
"resize": "You can constraint proportions by holding SHIFT while resizing" "resize": "You can constraint proportions by holding SHIFT while resizing"
},
"errorSplash": {
"headingMain_pre": "Encountered an error. Try ",
"headingMain_button": "reloading the page.",
"clearCanvasMessage": "If reloading doesn't work, try ",
"clearCanvasMessage_button": "clearing the canvas.",
"clearCanvasCaveat": " This will result in loss of work ",
"openIssueMessage_pre": "Before doing so, we'd appreciate if you opened an issue on our ",
"openIssueMessage_button": "bug tracker.",
"openIssueMessage_post": " Please include the following error stack trace (and if it's not private, also the scene content):",
"errorStack": "Error stack trace:",
"errorStack_loading": "Loading data. please wait...",
"sceneContent": "Scene content:"
} }
} }

View File

@ -250,6 +250,7 @@ button,
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
user-select: text;
.ErrorSplash-messageContainer { .ErrorSplash-messageContainer {
display: flex; display: flex;
@ -264,8 +265,11 @@ button,
.ErrorSplash-paragraph { .ErrorSplash-paragraph {
margin: 15px 0; margin: 15px 0;
text-align: center;
max-width: 600px; max-width: 600px;
&.align-center {
text-align: center;
}
} }
.bigger, .bigger,