2020-03-07 10:20:38 -05:00
|
|
|
|
import React from "react";
|
2020-03-31 09:37:51 +01:00
|
|
|
|
import * as Sentry from "@sentry/browser";
|
2023-12-12 11:32:51 +05:30
|
|
|
|
import { t } from "../../packages/excalidraw/i18n";
|
|
|
|
|
import Trans from "../../packages/excalidraw/components/Trans";
|
2020-03-07 10:20:38 -05:00
|
|
|
|
|
|
|
|
|
interface TopErrorBoundaryState {
|
|
|
|
|
hasError: boolean;
|
2020-03-31 09:37:51 +01:00
|
|
|
|
sentryEventId: string;
|
2020-03-07 10:20:38 -05:00
|
|
|
|
localStorage: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class TopErrorBoundary extends React.Component<
|
|
|
|
|
any,
|
|
|
|
|
TopErrorBoundaryState
|
|
|
|
|
> {
|
|
|
|
|
state: TopErrorBoundaryState = {
|
|
|
|
|
hasError: false,
|
2020-03-31 09:37:51 +01:00
|
|
|
|
sentryEventId: "",
|
2020-03-07 10:20:38 -05:00
|
|
|
|
localStorage: "",
|
|
|
|
|
};
|
|
|
|
|
|
2020-03-21 02:26:01 -07:00
|
|
|
|
render() {
|
|
|
|
|
return this.state.hasError ? this.errorSplash() : this.props.children;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-31 09:37:51 +01:00
|
|
|
|
componentDidCatch(error: Error, errorInfo: any) {
|
2020-03-07 10:20:38 -05:00
|
|
|
|
const _localStorage: any = {};
|
|
|
|
|
for (const [key, value] of Object.entries({ ...localStorage })) {
|
|
|
|
|
try {
|
|
|
|
|
_localStorage[key] = JSON.parse(value);
|
2021-11-02 14:24:16 +02:00
|
|
|
|
} catch (error: any) {
|
2020-03-07 10:20:38 -05:00
|
|
|
|
_localStorage[key] = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-31 09:37:51 +01:00
|
|
|
|
Sentry.withScope((scope) => {
|
|
|
|
|
scope.setExtras(errorInfo);
|
|
|
|
|
const eventId = Sentry.captureException(error);
|
2020-03-07 10:20:38 -05:00
|
|
|
|
|
2020-03-23 13:05:07 +02:00
|
|
|
|
this.setState((state) => ({
|
2020-03-31 09:37:51 +01:00
|
|
|
|
hasError: true,
|
|
|
|
|
sentryEventId: eventId,
|
|
|
|
|
localStorage: JSON.stringify(_localStorage),
|
2020-03-07 10:20:38 -05:00
|
|
|
|
}));
|
2020-03-31 09:37:51 +01:00
|
|
|
|
});
|
2020-03-07 10:20:38 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private selectTextArea(event: React.MouseEvent<HTMLTextAreaElement>) {
|
|
|
|
|
if (event.target !== document.activeElement) {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
(event.target as HTMLTextAreaElement).select();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async createGithubIssue() {
|
|
|
|
|
let body = "";
|
|
|
|
|
try {
|
2020-10-18 23:06:25 +05:30
|
|
|
|
const templateStrFn = (
|
|
|
|
|
await import(
|
|
|
|
|
/* webpackChunkName: "bug-issue-template" */ "../bug-issue-template"
|
|
|
|
|
)
|
|
|
|
|
).default;
|
2020-03-31 09:37:51 +01:00
|
|
|
|
body = encodeURIComponent(templateStrFn(this.state.sentryEventId));
|
2021-11-02 14:24:16 +02:00
|
|
|
|
} catch (error: any) {
|
2020-03-07 10:20:38 -05:00
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
window.open(
|
|
|
|
|
`https://github.com/excalidraw/excalidraw/issues/new?body=${body}`,
|
2024-08-23 15:54:59 +02:00
|
|
|
|
"_blank",
|
|
|
|
|
"noopener noreferrer",
|
2020-03-07 10:20:38 -05:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-21 02:26:01 -07:00
|
|
|
|
private errorSplash() {
|
|
|
|
|
return (
|
2020-10-28 20:52:53 +01:00
|
|
|
|
<div className="ErrorSplash excalidraw">
|
2020-03-21 02:26:01 -07:00
|
|
|
|
<div className="ErrorSplash-messageContainer">
|
|
|
|
|
<div className="ErrorSplash-paragraph bigger align-center">
|
2023-05-10 16:39:21 +08:00
|
|
|
|
<Trans
|
|
|
|
|
i18nKey="errorSplash.headingMain"
|
|
|
|
|
button={(el) => (
|
|
|
|
|
<button onClick={() => window.location.reload()}>{el}</button>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
2020-03-21 02:26:01 -07:00
|
|
|
|
</div>
|
|
|
|
|
<div className="ErrorSplash-paragraph align-center">
|
2023-05-10 16:39:21 +08:00
|
|
|
|
<Trans
|
|
|
|
|
i18nKey="errorSplash.clearCanvasMessage"
|
|
|
|
|
button={(el) => (
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => {
|
|
|
|
|
try {
|
|
|
|
|
localStorage.clear();
|
|
|
|
|
window.location.reload();
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{el}
|
|
|
|
|
</button>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
2020-03-21 02:26:01 -07:00
|
|
|
|
<br />
|
|
|
|
|
<div className="smaller">
|
|
|
|
|
<span role="img" aria-label="warning">
|
|
|
|
|
⚠️
|
|
|
|
|
</span>
|
|
|
|
|
{t("errorSplash.clearCanvasCaveat")}
|
|
|
|
|
<span role="img" aria-hidden="true">
|
|
|
|
|
⚠️
|
|
|
|
|
</span>
|
2020-03-07 10:20:38 -05:00
|
|
|
|
</div>
|
2020-03-21 02:26:01 -07:00
|
|
|
|
</div>
|
|
|
|
|
<div>
|
2020-03-31 09:37:51 +01:00
|
|
|
|
<div className="ErrorSplash-paragraph">
|
2023-05-10 16:39:21 +08:00
|
|
|
|
{t("errorSplash.trackedToSentry", {
|
|
|
|
|
eventId: this.state.sentryEventId,
|
|
|
|
|
})}
|
2020-03-31 09:37:51 +01:00
|
|
|
|
</div>
|
2020-03-21 02:26:01 -07:00
|
|
|
|
<div className="ErrorSplash-paragraph">
|
2023-05-10 16:39:21 +08:00
|
|
|
|
<Trans
|
|
|
|
|
i18nKey="errorSplash.openIssueMessage"
|
|
|
|
|
button={(el) => (
|
|
|
|
|
<button onClick={() => this.createGithubIssue()}>{el}</button>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
2020-03-07 10:20:38 -05:00
|
|
|
|
</div>
|
2020-03-21 02:26:01 -07:00
|
|
|
|
<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}
|
|
|
|
|
/>
|
2020-03-07 10:20:38 -05:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2020-03-21 02:26:01 -07:00
|
|
|
|
</div>
|
|
|
|
|
);
|
2020-03-07 10:20:38 -05:00
|
|
|
|
}
|
|
|
|
|
}
|