-
Notifications
You must be signed in to change notification settings - Fork 28
/
Copy pathErrorBoundary.tsx
110 lines (93 loc) · 2.84 KB
/
ErrorBoundary.tsx
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
99
100
101
102
103
104
105
106
107
108
109
110
// SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates
// SPDX-FileCopyrightText: TNG Technology Consulting GmbH <https://www.tngtech.com>
// SPDX-FileCopyrightText: Nico Carl <nicocarl@protonmail.com>
//
// SPDX-License-Identifier: Apache-2.0
import MuiBox from '@mui/material/Box';
import { Action } from '@reduxjs/toolkit';
import { noop } from 'lodash';
import { Component, Dispatch, ErrorInfo, ReactNode } from 'react';
import { connect } from 'react-redux';
import { AllowedFrontendChannels } from '../../../shared/ipc-channels';
import { SendErrorInformationArgs } from '../../../shared/shared-types';
import { OpossumColors } from '../../shared-styles';
import { resetResourceState } from '../../state/actions/resource-actions/all-views-simple-actions';
import { resetViewState } from '../../state/actions/view-actions/view-actions';
const classes = {
root: {
background: OpossumColors.lightBlue,
width: '100vw',
height: '100vh',
},
};
// catches errors that are not thrown during render
// it's known to fire twice in dev mode: https://github.com/facebook/react/issues/19613
window.addEventListener('error', (event): void => {
if (event.error) {
sendErrorInfo(event.error, {
componentStack: event.error.stack,
});
}
});
interface ErrorBoundaryState {
hasError: boolean;
}
interface DispatchProps {
resetState(): void;
}
interface ErrorBoundaryProps extends DispatchProps {
children: ReactNode;
}
function sendErrorInfo(error: Error, errorInfo: ErrorInfo): void {
const sendErrorInformationArgs: SendErrorInformationArgs = {
error,
errorInfo,
};
window.electronAPI.sendErrorInformation(sendErrorInformationArgs);
}
class ProtoErrorBoundary extends Component<
ErrorBoundaryProps,
ErrorBoundaryState
> {
private removeListener: () => void = noop;
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false };
}
override componentDidMount(): void {
this.removeListener = window.electronAPI.on(
AllowedFrontendChannels.RestoreFrontend,
() => {
this.props.resetState();
this.setState({ hasError: false });
},
);
}
override componentWillUnmount(): void {
this.removeListener();
}
static getDerivedStateFromError(): ErrorBoundaryState {
return { hasError: true };
}
override componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
sendErrorInfo(error, errorInfo);
}
override render(): ReactNode {
if (this.state.hasError) {
return <MuiBox sx={classes.root} />;
}
return this.props.children;
}
}
function mapDispatchToProps(dispatch: Dispatch<Action>): DispatchProps {
return {
resetState: (): void => {
dispatch(resetResourceState());
dispatch(resetViewState());
},
};
}
export const ErrorBoundary = connect(
null,
mapDispatchToProps,
)(ProtoErrorBoundary);