Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the App's crash page #411

Merged
merged 13 commits into from Aug 31, 2020
70 changes: 70 additions & 0 deletions desktop-app/app/components/CreateIssue/index.js
@@ -0,0 +1,70 @@
import React from 'react';
import {getEnvironmentInfo} from '../../utils/generalUtils';
import Button from '@material-ui/core/Button';

const {openNewGitHubIssue} = require('electron-util');

const {
appVersion,
electronVersion,
chromeVersion,
nodeVersion,
v8Version,
osInfo,
} = getEnvironmentInfo();

const reportBody = state => `Hi I'm reporting an app crash:
**PLEASE WRITE HERE ANY HINT THAT HELP US TO REPRODUCE THIS**

<details>
<summary>Environment</summary>

- Version: ${appVersion}
- Electron: ${electronVersion}
- Chrome: ${chromeVersion}
- Node.js: ${nodeVersion}
- V8: ${v8Version}
- OS: ${osInfo}
</details>

<details>
<summary>Error Info</summary>

\`\`\`json
${(state.error || '').split('\\n ').join('\n')}
\`\`\`
</details>

<details>
<summary>Stack Trace</summary>

\`\`\`json
${(state.errorInfo || '').split('\\n ').join('\n')}
\`\`\`
</details>

Hope you find the issue, regards`;

const createIssue = state => {
openNewGitHubIssue({
user: 'responsively-org',
repo: 'responsively-app',
body: reportBody(state),
title: 'App crash report',
});
};

export default function CreateIssue(props) {
return (
<div style={{textAlign: 'center'}}>
<p>Please create a new issue in the github repo sending this info</p>
<Button
variant="contained"
color="primary"
onClick={() => createIssue(props.state)}
>
Create issue
</Button>
</div>
);
}
75 changes: 50 additions & 25 deletions desktop-app/app/components/ErrorBoundary/index.js
@@ -1,17 +1,49 @@
import React, {Fragment} from 'react';
import React from 'react';
import TextAreaWithCopyButton from '../../utils/TextAreaWithCopyButton';
import CreateIssue from '../CreateIssue';
import {withStyles} from '@material-ui/core/styles';

export default class ErrorBoundary extends React.Component {
const styles = {
errorBoundaryContainer: {
overflowY: 'auto',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
height: '100%',
'& h1': {
textAlign: 'center',
},
},
errorsContainer: {
display: 'flex',
justifyContent: 'center',
},
errorContainer: {
textAlign: 'left',
justifyContent: 'center',
margin: '3rem 6rem',
width: '30vw',
},
};

class ErrorBoundary extends React.Component {
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return {hasError: true, error};
return {
hasError: true,
error: JSON.stringify(error, Object.getOwnPropertyNames(error)),
};
}

componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
this.setState({
err: error,
error: JSON.stringify(error, Object.getOwnPropertyNames(error)),
errorInfo,
errorInfo: JSON.stringify(
errorInfo,
Object.getOwnPropertyNames(errorInfo)
),
});
}

Expand All @@ -21,34 +53,27 @@ export default class ErrorBoundary extends React.Component {
}

render() {
const {classes} = this.props;
if (this.state.hasError) {
// You can render any custom fallback UI
return (
<Fragment>
<h1 style={{textAlign: 'center', marginTop: 100}}>
Something went wrong.
</h1>
<div style={{display: 'flex', justifyContent: 'center'}}>
<pre
style={{
overflow: 'scroll',
background: '#6d6d6d',
width: '80%',
userSelect: 'text',
}}
>
{JSON.stringify(this.state, null, 2)}
</pre>
<div className={classes.errorBoundaryContainer}>
<h1>😓 App has crashed!</h1>
<div className={classes.errorsContainer}>
<p className={classes.errorContainer}>
Stack Trace: <TextAreaWithCopyButton text={this.state.error} />
</p>
<p className={classes.errorContainer}>
Error Info: <TextAreaWithCopyButton text={this.state.errorInfo} />
</p>
</div>
<p style={{width: '80%', textAlign: 'center'}}>
Please copy the contents in the above box and create an issue in the
github repo:
https://github.com/responsively-org/responsively-app/issues
</p>
</Fragment>
<CreateIssue state={this.state} />
</div>
);
}

return this.props.children;
}
}

export default withStyles(styles)(ErrorBoundary);
50 changes: 50 additions & 0 deletions desktop-app/app/utils/TextAreaWithCopyButton.js
@@ -0,0 +1,50 @@
import React from 'react';
import CopyToClipBoard from 'react-copy-to-clipboard';
import Button from '@material-ui/core/Button';
import Box from '@material-ui/core/Box';
import {makeStyles} from '@material-ui/core/styles';

const useStyles = makeStyles(theme => ({
codeBoxContainer: {
overflow: 'auto',
width: '30vw',
height: '40vh',
marginBottom: '10px',
marginTop: '10px',
border: '1px white solid',
padding: '0 10px',
borderRadius: '4px',
},
codeBox: {
fontSize: '14px',
textAlign: 'left',
},
}));

const TextAreaWithCopyButton = props => {
const classes = useStyles();
return (
<Box>
<div className={classes.codeBoxContainer}>
<pre className={classes.codeBox}>
{(props.text || '').split('\\n ').map((line, idx) => {
if (idx === 0) return line;
return (
<>
<br />
{line}
</>
);
})}
</pre>
</div>
<CopyToClipBoard text={props.text}>
<Button size="small" variant="contained" color="primary">
Copy
</Button>
</CopyToClipBoard>
</Box>
);
};

export default TextAreaWithCopyButton;
13 changes: 8 additions & 5 deletions desktop-app/app/utils/generalUtils.js
Expand Up @@ -2,16 +2,19 @@ import {app} from 'electron';
import path from 'path';
import fs from 'fs';
import os from 'os';
import isRenderer from 'is-electron-renderer';

const getPackageJson = () => {
let appPath;
if (process.env.NODE_ENV === 'production') appPath = app.getAppPath();
else if (isRenderer) appPath = path.join(__dirname, '..');
else appPath = path.join(__dirname, '..', '..');
else appPath = process.cwd();

const pkgContent = fs.readFileSync(path.join(appPath, 'package.json'));
return JSON.parse(pkgContent);
const pkgPath = path.join(appPath, 'package.json');
if (fs.existsSync(pkgPath)) {
const pkgContent = fs.readFileSync(pkgPath);
return JSON.parse(pkgContent);
}
console.error(`cant find package.json in: '${appPath}'`);
return {};
};

export const pkg = getPackageJson();
Expand Down
2 changes: 2 additions & 0 deletions desktop-app/package.json
Expand Up @@ -293,6 +293,7 @@
"electron-notarize": "^0.3.0",
"electron-settings": "^3.2.0",
"electron-updater": "^4.3.1",
"electron-util": "^0.14.2",
"flwww": "^2.0.10",
"framer-motion": "^2.2.0",
"history": "^4.7.2",
Expand All @@ -307,6 +308,7 @@
"re-resizable": "^6.4.0",
"react": "^16.13.1",
"react-beautiful-dnd": "^11.0.5",
"react-copy-to-clipboard": "^5.0.2",
"react-dom": "^16.13.1",
"react-hot-loader": "^4.8",
"react-number-format": "^4.4.1",
Expand Down
23 changes: 22 additions & 1 deletion desktop-app/yarn.lock
Expand Up @@ -5394,7 +5394,7 @@ copy-descriptor@^0.1.0:
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=

copy-to-clipboard@^3.2.0:
copy-to-clipboard@^3, copy-to-clipboard@^3.2.0:
version "3.3.1"
resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae"
integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==
Expand Down Expand Up @@ -6510,6 +6510,14 @@ electron-updater@^4.3.1:
lodash.isequal "^4.5.0"
semver "^7.1.3"

electron-util@^0.14.2:
version "0.14.2"
resolved "https://registry.yarnpkg.com/electron-util/-/electron-util-0.14.2.tgz#793ebd61f75435363b0dbbba61dddb0f17812fb1"
integrity sha512-pnnRJiWajDcTtEAS33RgP3XVO+9cJjOlBA0BKk6cABjcPxihgCwiGWplCOHc0lH43f68ZJZweiunwomJC+TWng==
dependencies:
electron-is-dev "^1.1.0"
new-github-issue-url "^0.2.1"

electron@^9.1.1:
version "9.1.1"
resolved "https://registry.yarnpkg.com/electron/-/electron-9.1.1.tgz#d52c9873be4113287c3eb2b02f85bad6644b100e"
Expand Down Expand Up @@ -11363,6 +11371,11 @@ neo-async@^2.5.0, neo-async@^2.6.1:
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==

new-github-issue-url@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/new-github-issue-url/-/new-github-issue-url-0.2.1.tgz#e17be1f665a92de465926603e44b9f8685630c1d"
integrity sha512-md4cGoxuT4T4d/HDOXbrUHkTKrp/vp+m3aOA7XXVYwNsUNMK49g3SQicTSeV5GIz/5QVGAeYRAOlyp9OvlgsYA==

nice-try@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
Expand Down Expand Up @@ -13172,6 +13185,14 @@ react-beautiful-dnd@^11.0.5:
tiny-invariant "^1.0.4"
use-memo-one "^1.1.0"

react-copy-to-clipboard@^5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.2.tgz#d82a437e081e68dfca3761fbd57dbf2abdda1316"
integrity sha512-/2t5mLMMPuN5GmdXo6TebFa8IoFxZ+KTDDqYhcDm0PhkgEzSxVvIX26G20s1EB02A4h2UZgwtfymZ3lGJm0OLg==
dependencies:
copy-to-clipboard "^3"
prop-types "^15.5.8"

react-dom@^16.13.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f"
Expand Down