-
-
Notifications
You must be signed in to change notification settings - Fork 746
/
global-error-handler.class.ts
98 lines (84 loc) · 3.26 KB
/
global-error-handler.class.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import {ErrorHandler, Injectable} from '@angular/core';
import {isObject} from '../../util/is-object';
import {getJiraResponseErrorTxt} from '../../util/get-jira-response-error-text';
import {HANDLED_ERROR_PROP_STR, IS_ELECTRON} from '../../app.constants';
import {ElectronService} from 'ngx-electron';
import {BannerService} from '../banner/banner.service';
let isWasErrorAlertCreated = false;
const _createErrorAlert = (eSvc: ElectronService, err: string, stackTrace: string) => {
if (isWasErrorAlertCreated) {
return;
}
const errorAlert = document.createElement('div');
errorAlert.classList.add('global-error-alert');
errorAlert.style.color = 'black';
errorAlert.innerHTML = `
<h2>Snap! A critical error occurred...<h2>
<p><a href="https://github.com/johannesjo/super-productivity/issues/new" target="_blank">! Please Report !</a></p>
<pre style="line-height: 1.3;">${err}</pre>
<pre style="line-height: 1.3; text-align: left; max-height: 240px; font-size: 12px; overflow: auto;">${stackTrace}</pre>
`;
const btnReload = document.createElement('BUTTON');
btnReload.innerText = 'Reload App';
btnReload.addEventListener('click', () => {
if (IS_ELECTRON) {
eSvc.remote.getCurrentWindow().webContents.reload();
} else {
window.location.reload();
}
});
errorAlert.append(btnReload);
document.body.append(errorAlert);
isWasErrorAlertCreated = true;
if (IS_ELECTRON) {
eSvc.remote.getCurrentWindow().webContents.openDevTools();
}
};
const isHandledError = (err): boolean => {
const errStr = (typeof err === 'string') ? err : err.toString();
// NOTE: for some unknown reason sometimes err is undefined while err.toString is not...
// this is why we also check the string value
return (err && err.hasOwnProperty(HANDLED_ERROR_PROP_STR)) || (errStr.match(HANDLED_ERROR_PROP_STR));
};
@Injectable()
export class GlobalErrorHandler implements ErrorHandler {
private _electronLogger: any;
constructor(
private _bannerService: BannerService,
private _electronService: ElectronService,
) {
if (IS_ELECTRON) {
this._electronLogger = this._electronService.remote.require('electron-log');
}
}
// TODO Cleanup this mess
handleError(err: any) {
const errStr = (typeof err === 'string') ? err : err.toString();
// tslint:disable-next-line
const stack = err && err.stack;
console.log(isHandledError(err), err[HANDLED_ERROR_PROP_STR], errStr);
// if not our custom error handler we have a critical error on our hands
if (!isHandledError(err)) {
const errorStr = this._getErrorStr(err) || errStr;
// NOTE: dom exceptions will break all rendering that's why
if (err.constructor && err.constructor === DOMException) {
_createErrorAlert(this._electronService, 'DOMException: ' + errorStr, stack);
} else {
_createErrorAlert(this._electronService, errorStr, stack);
}
}
console.error('GLOBAL_ERROR_HANDLER', err);
if (IS_ELECTRON) {
this._electronLogger.error('Frontend Error:', err, stack);
}
// NOTE: rethrow the error otherwise it gets swallowed
throw err;
}
private _getErrorStr(err: any): string {
if (isObject(err)) {
return getJiraResponseErrorTxt(err);
} else {
return err.toString();
}
}
}