add top error boundary & reset localStorage on error (#493)

* add top error boundary & reset localStorage on error

* add issue tracker details and link

* add pointer cursor to buttons

* Update src/bug-issue-template.js

Co-Authored-By: Lipis <lipiridis@gmail.com>

* Update src/styles.scss

Co-Authored-By: Lipis <lipiridis@gmail.com>

* Update src/bug-issue-template.js

Co-Authored-By: Lipis <lipiridis@gmail.com>

* use open-color colors

* use Cascadia font

Co-authored-by: Lipis <lipiridis@gmail.com>
This commit is contained in:
David Luzar 2020-01-21 15:50:25 +01:00 committed by GitHub
parent 885b9c1483
commit 20cf1078fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 160 additions and 1 deletions

13
src/bug-issue-template.js Normal file
View File

@ -0,0 +1,13 @@
export default `
### Stack strace
\`\`\`
// paste stack trace here
\`\`\`
### localStorage
\`\`\`
// paste localStorage content here (if it doesn't contain sensitive data)
\`\`\`
`;

View File

@ -1371,4 +1371,100 @@ export class App extends React.Component<any, AppState> {
const AppWithTrans = withTranslation()(App);
const rootElement = document.getElementById("root");
ReactDOM.render(<AppWithTrans />, rootElement);
class TopErrorBoundary extends React.Component {
state = { hasError: false, stack: "", localStorage: "" };
static getDerivedStateFromError(error: any) {
console.error(error);
return {
hasError: true,
localStorage: JSON.stringify({ ...localStorage }),
stack: error.stack
};
}
private selectTextArea(event: React.MouseEvent<HTMLTextAreaElement>) {
(event.target as HTMLTextAreaElement).select();
}
private async createGithubIssue() {
let body = "";
try {
const templateStr = (await import("./bug-issue-template")).default;
if (typeof templateStr === "string") {
body = encodeURIComponent(templateStr);
}
} catch {}
window.open(
`https://github.com/excalidraw/excalidraw/issues/new?body=${body}`
);
}
render() {
if (this.state.hasError) {
return (
<div className="ErrorSplash">
<div className="ErrorSplash-messageContainer">
<div className="ErrorSplash-paragraph bigger">
Encountered an error. Please{" "}
<button onClick={() => window.location.reload()}>
reload the page
</button>
.
</div>
<div className="ErrorSplash-paragraph">
If reloading doesn't work. Try{" "}
<button
onClick={() => {
localStorage.clear();
window.location.reload();
}}
>
clearing the canvas
</button>
.<br />
<div className="smaller">
(This will unfortunately result in loss of work.)
</div>
</div>
<div>
<div className="ErrorSplash-paragraph">
Before doing so, we'd appreciate if you opened an issue on our{" "}
<button onClick={this.createGithubIssue}>bug tracker</button>.
Please include the following error stack trace & localStorage
content (provided it's not private):
</div>
<div className="ErrorSplash-paragraph">
<div className="ErrorSplash-details">
<label>Error stack trace:</label>
<textarea
rows={10}
onClick={this.selectTextArea}
defaultValue={this.state.stack}
/>
<label>LocalStorage content:</label>
<textarea
rows={5}
onClick={this.selectTextArea}
defaultValue={this.state.localStorage}
/>
</div>
</div>
</div>
</div>
</div>
);
}
return this.props.children;
}
}
ReactDOM.render(
<TopErrorBoundary>
<AppWithTrans />
</TopErrorBoundary>,
rootElement
);

View File

@ -73,6 +73,8 @@ button {
padding: 0.25rem;
outline: transparent;
cursor: pointer;
&:focus {
box-shadow: 0 0 0 2px #a5d8ff;
}
@ -133,3 +135,51 @@ button {
.App-right-menu {
width: 13.75rem;
}
.ErrorSplash {
min-height: 100vh;
padding: 20px 0;
overflow: auto;
display: flex;
align-items: center;
justify-content: center;
.ErrorSplash-messageContainer {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px;
background-color: #fff5f5;
border: 3px solid #c92a2a;
}
.ErrorSplash-paragraph {
margin: 15px 0;
text-align: center;
max-width: 600px;
}
.bigger,
.bigger button {
font-size: 1.1em;
}
.smaller,
.smaller button {
font-size: 0.9em;
}
.ErrorSplash-details {
display: flex;
flex-direction: column;
align-items: flex-start;
textarea {
width: 100%;
margin: 10px 0;
font-family: "Cascadia";
font-size: 0.8em;
}
}
}