excalidraw/excalidraw-app/components/TopErrorBoundary.tsx
Aakansha Doshi f14ad61bd0
build: move build process and excalidraw-app dependencies in its own package.json (#7021)
* build: move build process and excalidraw-app dependencies in its own package.json

* fix

* fix public path

* move bug-issue-template to excalidraw-app

* make env vars accessible in excalidraw app

* update build script

* install when building

* add ts ignore

* fix build-version script

* update config in vercel.json

* add vercel config for example

* fix vercel config

* update install script in vercel

* update install script in lint.yml

* update install script in test workflows

* push locales to locales folder pwa

* add favicons to manifest

* move react to peer deps in editor

* fix ts

* Enable vite intellisense

* add global.d.ts for excalidraw-app

* remove console.log

* remove react, react-dom and vite from excalidraw-app deps

* increase size limit
2023-12-07 16:39:11 +05:30

145 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React from "react";
import * as Sentry from "@sentry/browser";
import { t } from "../../src/i18n";
import Trans from "../../src/components/Trans";
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) {
const _localStorage: any = {};
for (const [key, value] of Object.entries({ ...localStorage })) {
try {
_localStorage[key] = JSON.parse(value);
} catch (error: any) {
_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(
/* webpackChunkName: "bug-issue-template" */ "../bug-issue-template"
)
).default;
body = encodeURIComponent(templateStrFn(this.state.sentryEventId));
} catch (error: any) {
console.error(error);
}
window.open(
`https://github.com/excalidraw/excalidraw/issues/new?body=${body}`,
);
}
private errorSplash() {
return (
<div className="ErrorSplash excalidraw">
<div className="ErrorSplash-messageContainer">
<div className="ErrorSplash-paragraph bigger align-center">
<Trans
i18nKey="errorSplash.headingMain"
button={(el) => (
<button onClick={() => window.location.reload()}>{el}</button>
)}
/>
</div>
<div className="ErrorSplash-paragraph align-center">
<Trans
i18nKey="errorSplash.clearCanvasMessage"
button={(el) => (
<button
onClick={() => {
try {
localStorage.clear();
window.location.reload();
} catch (error: any) {
console.error(error);
}
}}
>
{el}
</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", {
eventId: this.state.sentryEventId,
})}
</div>
<div className="ErrorSplash-paragraph">
<Trans
i18nKey="errorSplash.openIssueMessage"
button={(el) => (
<button onClick={() => this.createGithubIssue()}>{el}</button>
)}
/>
</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>
);
}
}