add more error reporting #277

pull/304/head
Mikael Finstad 2020-04-10 22:04:19 +08:00
rodzic 4b80e358ce
commit 1d306e7073
5 zmienionych plików z 108 dodań i 53 usunięć

Wyświetl plik

@ -48,8 +48,9 @@ import { save as edlStoreSave, load as edlStoreLoad } from './edlStore';
import {
getOutPath, formatDuration, toast, errorToast, showFfmpegFail, setFileNameTitle,
promptTimeOffset, generateColor, getOutDir, withBlur, checkDirWriteAccess, dirExists,
openDirToast, askForHtml5ifySpeed,
openDirToast, askForHtml5ifySpeed, isMasBuild, isStoreBuild,
} from './util';
import { openSendReportDialog } from './reporting';
import loadingLottie from './7077-magic-flow.json';
@ -61,7 +62,6 @@ const trash = window.require('trash');
const { unlink, exists } = window.require('fs-extra');
const { extname } = window.require('path');
const { dialog, app } = electron.remote;
const ReactSwal = withReactContent(Swal);
@ -109,9 +109,6 @@ const calcShouldShowKeyframes = (zoomedDuration) => (zoomedDuration != null && z
const commonFormats = ['mov', 'mp4', 'matroska', 'mp3', 'ipod'];
const isMasBuild = window.process.mas;
const isStoreBuild = isMasBuild || window.process.windowsStore;
// TODO flex
const topBarHeight = 32;
const timelineHeight = 36;
@ -892,49 +889,20 @@ const App = memo(() => {
const outSegments = useMemo(() => (invertCutSegments ? inverseCutSegments : apparentCutSegments),
[invertCutSegments, inverseCutSegments, apparentCutSegments]);
const openSendReportDialog = useCallback(async (err) => {
const reportInstructions = isStoreBuild
? <p>Please send an email to <span style={{ fontWeight: 'bold' }} role="button" onClick={() => electron.shell.openExternal('mailto:losslesscut@yankee.no')}>losslesscut@yankee.no</span> where you describe what you were doing.</p>
: <p>Please create an issue at <span style={{ fontWeight: 'bold' }} role="button" onClick={() => electron.shell.openExternal('https://github.com/mifi/lossless-cut/issues')}>https://github.com/mifi/lossless-cut/issues</span> where you describe what you were doing.</p>;
const openSendReportDialogWithState = useCallback(async (err) => {
const state = {
filePath,
fileFormat,
externalStreamFiles,
mainStreams,
copyStreamIdsByFile,
cutSegments,
fileFormatData,
rotation,
shortestFlag,
};
ReactSwal.fire({
showCloseButton: true,
title: i18n.t('Send problem report'),
html: (
<div style={{ textAlign: 'left', overflow: 'auto', maxHeight: 300, overflowY: 'auto' }}>
{reportInstructions}
<p>Include the following text:</p>
<div style={{ fontWeight: 600, fontSize: 12, whiteSpace: 'pre-wrap' }} contentEditable suppressContentEditableWarning>
{`${err ? err.message : ''}\n\n${JSON.stringify({
err: err && {
code: err.code,
killed: err.killed,
failed: err.failed,
timedOut: err.timedOut,
isCanceled: err.isCanceled,
exitCode: err.exitCode,
signal: err.signal,
signalDescription: err.signalDescription,
},
state: {
filePath,
fileFormat,
externalStreamFiles,
mainStreams,
copyStreamIdsByFile,
cutSegments,
fileFormatData,
rotation,
shortestFlag,
},
}, null, 2)}`}
</div>
</div>
),
});
openSendReportDialog(err, state);
}, [copyStreamIdsByFile, cutSegments, externalStreamFiles, fileFormat, fileFormatData, filePath, mainStreams, rotation, shortestFlag]);
const handleCutFailed = useCallback(async (err) => {
@ -955,9 +923,9 @@ const App = memo(() => {
const { value } = await ReactSwal.fire({ title: i18n.t('Unable to export this file'), html, timer: null, showConfirmButton: true, showCancelButton: true, confirmButtonText: i18n.t('OK'), cancelButtonText: i18n.t('Report') });
if (!value) {
openSendReportDialog(err);
openSendReportDialogWithState(err);
}
}, [openSendReportDialog]);
}, [openSendReportDialogWithState]);
const cutClick = useCallback(async () => {
if (working) return;
@ -1519,7 +1487,7 @@ const App = memo(() => {
electron.ipcRenderer.on('openSettings', openSettings);
electron.ipcRenderer.on('openAbout', openAbout);
electron.ipcRenderer.on('batchConvertFriendlyFormat', batchConvertFriendlyFormat);
electron.ipcRenderer.on('openSendReportDialog', openSendReportDialog);
electron.ipcRenderer.on('openSendReportDialog', openSendReportDialogWithState);
return () => {
electron.ipcRenderer.removeListener('file-opened', fileOpened);
@ -1536,11 +1504,11 @@ const App = memo(() => {
electron.ipcRenderer.removeListener('openSettings', openSettings);
electron.ipcRenderer.removeListener('openAbout', openAbout);
electron.ipcRenderer.removeListener('batchConvertFriendlyFormat', batchConvertFriendlyFormat);
electron.ipcRenderer.removeListener('openSendReportDialog', openSendReportDialog);
electron.ipcRenderer.removeListener('openSendReportDialog', openSendReportDialogWithState);
};
}, [
mergeFiles, outputDir, filePath, isFileOpened, customOutDir, startTimeOffset, html5ifyCurrentFile,
createDummyVideo, resetState, extractAllStreams, userOpenFiles, cutSegmentsHistory, openSendReportDialog,
createDummyVideo, resetState, extractAllStreams, userOpenFiles, cutSegmentsHistory, openSendReportDialogWithState,
loadEdlFile, cutSegments, edlFilePath, askBeforeClose, toggleHelp, toggleSettings, assureOutDirAccess, html5ifyAndLoad, html5ifyInternal,
]);
@ -1673,6 +1641,8 @@ const App = memo(() => {
const { t } = useTranslation();
// throw new Error('Test');
return (
<div>
<div className="no-user-select" style={{ background: controlsBackground, height: topBarHeight, display: 'flex', alignItems: 'center', padding: '0 5px', justifyContent: 'space-between', flexWrap: 'wrap' }}>

Wyświetl plik

@ -0,0 +1,34 @@
import React, { Component } from 'react';
import { openSendReportDialog } from './reporting';
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { error: undefined };
}
static getDerivedStateFromError(error) {
return { error };
}
componentDidCatch(error, errorInfo) {
console.error('componentDidCatch', error, errorInfo);
}
render() {
const { error } = this.state;
if (error) {
return (
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
<h1>Something went wrong</h1>
<div style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}>{error.message}</div>
<p><button type="button" onClick={() => openSendReportDialog(error)} style={{ padding: 10, fontSize: 20 }}>Report error</button></p>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;

Wyświetl plik

@ -1,6 +1,7 @@
import React, { Suspense } from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import ErrorBoundary from './ErrorBoundary';
import './i18n';
import './fonts.css';
@ -11,4 +12,4 @@ const electron = window.require('electron');
console.log('Version', electron.remote.app.getVersion());
ReactDOM.render(<Suspense fallback={<div />}><App /></Suspense>, document.getElementById('root'));
ReactDOM.render(<ErrorBoundary><Suspense fallback={<div />}><App /></Suspense></ErrorBoundary>, document.getElementById('root'));

47
src/reporting.jsx 100644
Wyświetl plik

@ -0,0 +1,47 @@
import React from 'react';
import Swal from 'sweetalert2';
import withReactContent from 'sweetalert2-react-content';
import i18n from 'i18next';
import { isStoreBuild } from './util';
const electron = window.require('electron'); // eslint-disable-line
const ReactSwal = withReactContent(Swal);
// eslint-disable-next-line import/prefer-default-export
export function openSendReportDialog(err, state) {
const reportInstructions = isStoreBuild
? <p>Please send an email to <span style={{ fontWeight: 'bold' }} role="button" onClick={() => electron.shell.openExternal('mailto:losslesscut@yankee.no')}>losslesscut@yankee.no</span> where you describe what you were doing.</p>
: <p>Please create an issue at <span style={{ fontWeight: 'bold' }} role="button" onClick={() => electron.shell.openExternal('https://github.com/mifi/lossless-cut/issues')}>https://github.com/mifi/lossless-cut/issues</span> where you describe what you were doing.</p>;
ReactSwal.fire({
showCloseButton: true,
title: i18n.t('Send problem report'),
html: (
<div style={{ textAlign: 'left', overflow: 'auto', maxHeight: 300, overflowY: 'auto' }}>
{reportInstructions}
<p>Include the following text:</p>
<div style={{ fontWeight: 600, fontSize: 12, whiteSpace: 'pre-wrap' }} contentEditable suppressContentEditableWarning>
{`${err ? err.stack : ''}\n\n${JSON.stringify({
err: err && {
code: err.code,
killed: err.killed,
failed: err.failed,
timedOut: err.timedOut,
isCanceled: err.isCanceled,
exitCode: err.exitCode,
signal: err.signal,
signalDescription: err.signalDescription,
},
state,
}, null, 2)}`}
</div>
</div>
),
});
}

Wyświetl plik

@ -187,3 +187,6 @@ export async function askForHtml5ifySpeed(allowedOptions) {
return value;
}
export const isMasBuild = window.process.mas;
export const isStoreBuild = isMasBuild || window.process.windowsStore;