Skip to content

Commit 49645df

Browse files
SaerisCompuIves
authored andcommitted
✨ Feature: Add CodeSadbox Crash Reporter Error Boundary (codesandbox#2149)
* 🚧 WIP: Add ErrorBoundary, CodeSadbox Crash Report Page NOTE: Remove Demo route from Routes index. Demo available at http://localhost:3000/codesadbox * 🔧 Fix: Remove undefined theme fonts from CodeSadbox elements * 🚧 WIP: Add ErrorBoundary, CodeSadbox Crash Report Page NOTE: Remove Demo route from Routes index. Demo available at http://localhost:3000/codesadbox * 🔧 Fix: Remove undefined theme fonts from CodeSadbox elements * ⚡️ Update: Incorporate Navigation, Update Styles Still need to figure out why the fallback component can't observe changes to the global app state. This prevents checking login state and opening modals. Updated mobx related packages to latest versions. * 🧹 Remove Unused Actions Summary from Crash Report We're not currently recording and submitting a history of a user's actions, so removing this until we decide to add it later, likely after the Overmind refactor. * Fix modal showing I moved the error boundary lower so it doesn't swallow our modal component and notification component * Add option to go to dashboard * Import proper dashboard icon * Cleanup * 📝 Fix Sadbox Types, Ignore SVG Loader Import * 📰 Add CodeSadbox Announcement Post, Update Template Icons Dependency * 🧹 Remove CodeSadbox Test Route * 📰 Fix Typo * Update packages/app/src/app/pages/index.tsx Co-Authored-By: Michaël De Boey <[email protected]> * 🎨 Add CodeSadbox Blog Post Banner * 📰 Fix Gatsby Build Error Think I just needed to wrap the title in quotes. Gatsby now builds locally for me.
1 parent f783186 commit 49645df

File tree

20 files changed

+503
-86
lines changed

20 files changed

+503
-86
lines changed

packages/app/package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@
137137
"@cerebral/http": "^4.0.0",
138138
"@cerebral/mobx-state-tree": "^3.0.0",
139139
"@codesandbox/executors": "^0.1.0",
140-
"@codesandbox/template-icons": "^0.6.0",
140+
"@codesandbox/template-icons": "^0.6.1",
141141
"@emmetio/codemirror-plugin": "^0.3.5",
142142
"@svgr/core": "^2.4.1",
143143
"@vue/babel-preset-app": "^3.2.0",
@@ -165,6 +165,7 @@
165165
"babel-preset-stage-0": "^6.24.1",
166166
"babel-standalone": "^6.25.0",
167167
"base64-loader": "^1.0.0",
168+
"browser-detect": "^0.2.28",
168169
"browser-resolve": "CompuIves/node-browser-resolve",
169170
"cerebral": "^4.0.0",
170171
"circular-json": "^0.4.0",
@@ -212,10 +213,10 @@
212213
"lru-cache": "^4.1.3",
213214
"match-sorter": "^1.8.1",
214215
"memoize-one": "^4.0.0",
215-
"mobx": "^4.0.0",
216-
"mobx-react": "^5.2.3",
217-
"mobx-react-lite": "^1.3.2",
218-
"mobx-state-tree": "^3.3.0",
216+
"mobx": "^5.11.0",
217+
"mobx-react": "^6.1.1",
218+
"mobx-react-lite": "^1.4.1",
219+
"mobx-state-tree": "^3.14.0",
219220
"moment": "^2.18.1",
220221
"monaco-editor-textmate": "^2.0.0",
221222
"monaco-textmate": "^3.0.0",
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import React from 'react';
2+
import GoHome from 'react-icons/lib/go/home';
3+
import GoIssueOpened from 'react-icons/lib/go/issue-opened';
4+
import { observer } from 'mobx-react-lite';
5+
import { useStore } from 'app/store';
6+
import { Button } from '@codesandbox/common/lib/components/Button';
7+
import { dashboardUrl } from '@codesandbox/common/lib/utils/url-generator';
8+
// @ts-ignore
9+
import Dashboard from '-!svg-react-loader!@codesandbox/common/lib/icons/dashboard.svg';
10+
import Navigation from '../../Navigation';
11+
import { Sadbox } from './Sadbox';
12+
import { IFallbackComponentProps } from '../types';
13+
import { buildCrashReport } from './buildCrashReport';
14+
import {
15+
Container,
16+
Header,
17+
Nav,
18+
Content,
19+
Title,
20+
Subtitle,
21+
Actions,
22+
ButtonIcon,
23+
} from './elements';
24+
25+
export const CodeSadbox: React.FC<IFallbackComponentProps> = observer(
26+
({ error, trace }) => {
27+
const store = useStore();
28+
29+
return (
30+
<Container>
31+
<Header>
32+
<Nav>
33+
<Navigation title="CodeSadbox" />
34+
</Nav>
35+
</Header>
36+
<Content>
37+
<Title>Oh no! Something broke!</Title>
38+
<Sadbox scale={3} />
39+
<Subtitle>CodeSadbox</Subtitle>
40+
<Actions>
41+
{store.isLoggedIn ? (
42+
<Button small secondary href={dashboardUrl()}>
43+
<ButtonIcon>
44+
<Dashboard />
45+
</ButtonIcon>
46+
Go to Dashboard
47+
</Button>
48+
) : (
49+
<Button small secondary href="/">
50+
<ButtonIcon>
51+
<GoHome />
52+
</ButtonIcon>
53+
Back to Home
54+
</Button>
55+
)}
56+
{/*
57+
// @ts-ignore */}
58+
<Button
59+
small
60+
target="_blank"
61+
rel="noopener"
62+
href={buildCrashReport({ error, trace })}
63+
>
64+
<ButtonIcon>
65+
<GoIssueOpened />
66+
</ButtonIcon>
67+
Report Crash
68+
</Button>
69+
</Actions>
70+
</Content>
71+
</Container>
72+
);
73+
}
74+
);
75+
76+
CodeSadbox.displayName = `CodeSadbox`;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React from 'react';
2+
3+
interface ISadboxProps extends React.HTMLAttributes<SVGElement> {
4+
scale?: number;
5+
width?: number;
6+
height?: number;
7+
}
8+
9+
export const Sadbox: React.FC<ISadboxProps> = ({
10+
scale = 1,
11+
width = 64,
12+
height = 64,
13+
...props
14+
}) => (
15+
<svg
16+
width={width * scale}
17+
height={height * scale}
18+
viewBox="0 0 58 58"
19+
xmlns="http://www.w3.org/2000/svg"
20+
{...props}
21+
>
22+
<g fill="none" fillRule="evenodd">
23+
<path d="m48 0h-38l-10 16v42h58v-42z" fill="#a98258" />
24+
<path d="m10 0-10 16h58l-10-16z" fill="#daae86" />
25+
<path d="m33 54-4-4-4 4-2-2v6h12v-6z" fill="#d8b18b" />
26+
<path d="m23 0h12v16h-12z" fill="#f4d5bd" />
27+
<path d="m25 21 4 4 4-4 2 2v-7h-12v7z" fill="#d8b18b" />
28+
<g fill="#000" transform="translate(4 24)">
29+
<path
30+
d="m17.8181818 14.736842c.000495.8458946.1974848 1.6687015.5320707 2.4310874.5043535 1.1430876 1.3170604 2.1638595 2.3648684 2.9306664 1.0453333.7628771 2.3515048 1.2698245 3.7848784 1.2698245.9532727.0004912 1.8565554-.2254737 2.6573836-.6017544 1.2027272-.5663859 2.1847069-1.4569823 2.8875351-2.5013331.6993636-1.0453332 1.1334342-2.2586664 1.1368989-3.5284908 0-.8139649-.6647171-1.4736841-1.4848484-1.4736841-.8201312 0-1.4848483.6597192-1.4848483 1.4736841.0004949.3826666-.0935455.8183858-.2845959 1.2531226-.284596.6533333-.7899394 1.2899648-1.400707 1.7325613-.6137373.446035-1.3076564.6985262-2.026818.6985262-.4815858 0-.9458484-.112-1.3883332-.3192982-.6627373-.308-1.2675655-.8454034-1.6853028-1.4707367-.4216969-.6233683-.6419495-1.3214034-.6384848-1.8941752 0-.8139649-.6647171-1.4736841-1.4848483-1.4736841-.8201313 0-1.4848484.6597192-1.4848484 1.4736841"
31+
transform="matrix(1 0 0 -1 0 34.631578)"
32+
/>
33+
<g opacity=".2">
34+
<ellipse cx="2.227273" cy="11.789473" rx="2.227273" ry="2.210526" />
35+
<ellipse cx="46.772727" cy="11.789473" rx="2.227273" ry="2.210526" />
36+
</g>
37+
<ellipse cx="5.568182" cy="3.315789" rx="3.340909" ry="3.315789" />
38+
<ellipse cx="44.174243" cy="3.315789" rx="3.340909" ry="3.315789" />
39+
</g>
40+
</g>
41+
</svg>
42+
);
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import browser from 'browser-detect';
2+
3+
interface IbuildCrashReport {
4+
error?: Error;
5+
trace?: string;
6+
}
7+
8+
export const buildCrashReport = ({
9+
error,
10+
trace,
11+
}: IbuildCrashReport): string => {
12+
const { name, version, os } = browser();
13+
14+
const title = `💥 Crash Report: <Short Description of Crash Circumstances>`;
15+
16+
const body = `<h1>💥 Crash Report</h1>
17+
18+
<h2>What were you trying to accomplish when the crash occurred?</h2>
19+
20+
<h3>Link to sandbox: [link]() (optional)</h3>
21+
22+
<h3>Crash Details</h3>
23+
24+
<details>
25+
<summary>Environment</summary>
26+
27+
| Browser | Version | Operating System |
28+
| ------- | --------- | ---------------- |
29+
| ${name} | ${version} | ${os} |
30+
31+
</details>
32+
33+
<details>
34+
<summary>Error Message</summary>
35+
36+
${'```'}bash
37+
${error}
38+
${trace}
39+
${'```'}
40+
41+
</details>
42+
`;
43+
44+
return `https://github.com/codesandbox/codesandbox-client/issues/new?title=${encodeURI(
45+
title
46+
)}&body=${encodeURI(body)}`;
47+
};
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import styled, { css } from 'styled-components';
2+
3+
export const Container = styled.div`
4+
${({ theme }) => css`
5+
display: grid;
6+
grid-template-rows: min-content auto;
7+
width: 100%;
8+
height: 100vh;
9+
background-color: rgb(17, 21, 24);
10+
color: ${theme.white};
11+
`}
12+
`;
13+
14+
export const Header = styled.header`
15+
display: flex;
16+
justify-content: center;
17+
align-items: center;
18+
width: 100%;
19+
padding: 0px 2rem;
20+
box-sizing: border-box;
21+
`;
22+
23+
export const Nav = styled.nav`
24+
display: flex;
25+
width: 100%;
26+
max-width: 1280px;
27+
color: white;
28+
padding: 1rem 0px;
29+
30+
> div {
31+
width: 100%;
32+
}
33+
`;
34+
35+
export const Content = styled.div`
36+
display: flex;
37+
flex-direction: column;
38+
justify-content: center;
39+
align-items: center;
40+
align-self: start;
41+
justify-self: center;
42+
min-width: 320px;
43+
margin-top: 8rem;
44+
`;
45+
46+
export const Title = styled.h1`
47+
display: flex;
48+
justify-content: center;
49+
`;
50+
51+
export const Subtitle = styled.h2`
52+
display: flex;
53+
justify-content: center;
54+
`;
55+
56+
export const Actions = styled.section`
57+
display: flex;
58+
justify-content: center;
59+
padding: 0 1rem;
60+
61+
> a {
62+
display: inline-flex;
63+
align-items: center;
64+
65+
&:not(:first-child) {
66+
margin-left: 1rem;
67+
}
68+
}
69+
`;
70+
71+
export const ButtonIcon = styled.span`
72+
display: inline-flex;
73+
align-items: center;
74+
padding-right: 0.5rem;
75+
font-size: 16px;
76+
`;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { CodeSadbox } from './CodeSadbox';
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import React, { Component } from 'react';
2+
import { CodeSadbox } from './CodeSadbox';
3+
import { IErrorBoundaryProps, ErrorInfo, IErrorBoundaryState } from './types';
4+
5+
export class ErrorBoundary extends Component<
6+
IErrorBoundaryProps,
7+
IErrorBoundaryState
8+
> {
9+
static defaultProps = {
10+
FallbackComponent: CodeSadbox,
11+
};
12+
13+
static getDerivedStateFromError(error: Error) {
14+
return { error };
15+
}
16+
17+
static getDerivedStateFromProps(
18+
props: IErrorBoundaryProps,
19+
state: IErrorBoundaryState
20+
) {
21+
if (props.location !== state.previousLocation) {
22+
return {
23+
error: null,
24+
info: null,
25+
previousLocation: props.location,
26+
};
27+
}
28+
29+
return null;
30+
}
31+
32+
state = {
33+
error: null,
34+
info: null,
35+
previousLocation: null,
36+
};
37+
38+
componentDidCatch(error: Error, info: ErrorInfo): void {
39+
const { onError } = this.props;
40+
41+
if (typeof onError === 'function') {
42+
try {
43+
onError.call(this, error, info ? info.componentStack : '');
44+
} catch {} // eslint-disable-line
45+
}
46+
47+
this.setState({ info });
48+
}
49+
50+
render() {
51+
const { children, FallbackComponent } = this.props;
52+
const { error, info } = this.state;
53+
54+
return error !== null ? (
55+
<FallbackComponent
56+
error={error}
57+
trace={info ? info.componentStack : ''}
58+
/>
59+
) : (
60+
children || null
61+
);
62+
}
63+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { ErrorBoundary } from './ErrorBoundary';
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from 'react';
2+
import { Location } from 'history';
3+
4+
export type ErrorInfo = {
5+
componentStack: string;
6+
};
7+
8+
export interface IFallbackComponentProps {
9+
error?: Error;
10+
trace?: string;
11+
}
12+
13+
export interface IErrorBoundaryProps {
14+
children?: React.ReactNode;
15+
FallbackComponent: React.ComponentType<IFallbackComponentProps>;
16+
onError?: (error: Error, trace: string) => void;
17+
location?: Location;
18+
}
19+
20+
export interface IErrorBoundaryState {
21+
error?: Error;
22+
info?: ErrorInfo;
23+
previousLocation?: Location;
24+
}

packages/app/src/app/pages/elements.js

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)