123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- import React from "react";
- import * as Sentry from "@sentry/browser";
- import { resetCursor } from "../utils";
- import { t } from "../i18n";
- interface TopErrorBoundaryState {
- hasError: boolean;
- sentryEventId: string;
- localStorage: string;
- }
- export class TopErrorBoundary extends React.Component<
- any,
- TopErrorBoundaryState
- > {
- state: TopErrorBoundaryState = {
- hasError: false,
- sentryEventId: "",
- localStorage: "",
- };
- render() {
- return this.state.hasError ? this.errorSplash() : this.props.children;
- }
- componentDidCatch(error: Error, errorInfo: any) {
- resetCursor();
- const _localStorage: any = {};
- for (const [key, value] of Object.entries({ ...localStorage })) {
- try {
- _localStorage[key] = JSON.parse(value);
- } catch (error) {
- _localStorage[key] = value;
- }
- }
- Sentry.withScope((scope) => {
- scope.setExtras(errorInfo);
- const eventId = Sentry.captureException(error);
- this.setState((state) => ({
- hasError: true,
- sentryEventId: eventId,
- localStorage: JSON.stringify(_localStorage),
- }));
- });
- }
- private selectTextArea(event: React.MouseEvent<HTMLTextAreaElement>) {
- if (event.target !== document.activeElement) {
- event.preventDefault();
- (event.target as HTMLTextAreaElement).select();
- }
- }
- private async createGithubIssue() {
- let body = "";
- try {
- const templateStrFn = (await import("../bug-issue-template")).default;
- body = encodeURIComponent(templateStrFn(this.state.sentryEventId));
- } catch (error) {
- console.error(error);
- }
- window.open(
- `https://github.com/excalidraw/excalidraw/issues/new?body=${body}`,
- );
- }
- private errorSplash() {
- return (
- <div className="ErrorSplash">
- <div className="ErrorSplash-messageContainer">
- <div className="ErrorSplash-paragraph bigger align-center">
- {t("errorSplash.headingMain_pre")}
- <button onClick={() => window.location.reload()}>
- {t("errorSplash.headingMain_button")}
- </button>
- </div>
- <div className="ErrorSplash-paragraph align-center">
- {t("errorSplash.clearCanvasMessage")}
- <button
- onClick={() => {
- try {
- localStorage.clear();
- window.location.reload();
- } catch (error) {
- console.error(error);
- }
- }}
- >
- {t("errorSplash.clearCanvasMessage_button")}
- </button>
- <br />
- <div className="smaller">
- <span role="img" aria-label="warning">
- ⚠️
- </span>
- {t("errorSplash.clearCanvasCaveat")}
- <span role="img" aria-hidden="true">
- ⚠️
- </span>
- </div>
- </div>
- <div>
- <div className="ErrorSplash-paragraph">
- {t("errorSplash.trackedToSentry_pre")}
- {this.state.sentryEventId}
- {t("errorSplash.trackedToSentry_post")}
- </div>
- <div className="ErrorSplash-paragraph">
- {t("errorSplash.openIssueMessage_pre")}
- <button onClick={() => this.createGithubIssue()}>
- {t("errorSplash.openIssueMessage_button")}
- </button>
- {t("errorSplash.openIssueMessage_post")}
- </div>
- <div className="ErrorSplash-paragraph">
- <div className="ErrorSplash-details">
- <label>{t("errorSplash.sceneContent")}</label>
- <textarea
- rows={5}
- onPointerDown={this.selectTextArea}
- readOnly={true}
- value={this.state.localStorage}
- />
- </div>
- </div>
- </div>
- </div>
- </div>
- );
- }
- }
|