Errors thrown by Store can be dismissed in boundary (#21520)
Brian Vaughn committed
May 18, 2021 at 07:36 UTC
7bef382bf92e380f2b94e825cf35b8af58f8a2ec
3 files changed
+55
-5
packages/react-devtools-shared/src/devtools/views/ErrorBoundary/ErrorBoundary.js
+18
-2
@@ -21,6 +21,7 @@ type Props = {|
21
22
type State = {|
23
callStack: string | null,
24
+ canDismiss: boolean,
25
componentStack: string | null,
26
errorMessage: string | null,
27
hasError: boolean,
@@ -28,6 +29,7 @@ type State = {|
29
30
const InitialState: State = {
31
callStack: null,
32
+ canDismiss: false,
33
componentStack: null,
34
errorMessage: null,
35
hasError: false,
@@ -77,13 +79,20 @@ export default class ErrorBoundary extends Component<Props, State> {
79
80
render() {
81
const {children} = this.props;
80
- const {callStack, componentStack, errorMessage, hasError} = this.state;
82
+ const {
83
+ callStack,
84
+ canDismiss,
85
+ componentStack,
86
+ errorMessage,
87
+ hasError,
88
+ } = this.state;
89
90
if (hasError) {
91
return (
92
<ErrorView
93
callStack={callStack}
94
componentStack={componentStack}
95
+ dismissError={canDismiss ? this._dismissError : null}
96
errorMessage={errorMessage}>
97
<Suspense fallback={<SearchingGitHubIssues />}>
98
<SuspendingErrorView
@@ -99,9 +108,16 @@ export default class ErrorBoundary extends Component<Props, State> {
108
return children;
109
}
110
111
+ _dismissError = () => {
112
+ this.setState(InitialState);
113
+ };
114
+
115
_onStoreError = (error: Error) => {
116
if (!this.state.hasError) {
104
- this.setState(ErrorBoundary.getDerivedStateFromError(error));
117
+ this.setState({
118
+ ...ErrorBoundary.getDerivedStateFromError(error),
119
+ canDismiss: true,
120
+ });
121
}
122
};
123
}
packages/react-devtools-shared/src/devtools/views/ErrorBoundary/ErrorView.js
+14
-2
@@ -8,12 +8,15 @@
8
*/
9
10
import * as React from 'react';
11
+import Button from '../Button';
12
+import ButtonIcon from '../ButtonIcon';
13
import styles from './shared.css';
14
15
type Props = {|
16
callStack: string | null,
17
children: React$Node,
18
componentStack: string | null,
19
+ dismissError: Function | null,
20
errorMessage: string | null,
21
|};
22
@@ -21,14 +24,23 @@ export default function ErrorView({
24
callStack,
25
children,
26
componentStack,
27
+ dismissError = null,
28
errorMessage,
29
}: Props) {
30
return (
31
<div className={styles.ErrorBoundary}>
32
{children}
33
<div className={styles.ErrorInfo}>
30
- <div className={styles.Header}>
31
- Uncaught Error: {errorMessage || ''}
34
+ <div className={styles.HeaderRow}>
35
+ <div className={styles.Header}>
36
+ Uncaught Error: {errorMessage || ''}
37
+ </div>
38
+ {dismissError !== null && (
39
+ <Button className={styles.CloseButton} onClick={dismissError}>
40
+ Dismiss
41
+ <ButtonIcon className={styles.CloseButtonIcon} type="close" />
42
+ </Button>
43
+ )}
44
</div>
45
{!!callStack && (
46
<div className={styles.Stack}>
packages/react-devtools-shared/src/devtools/views/ErrorBoundary/shared.css
+23
-1
@@ -37,12 +37,22 @@
37
overflow: auto;
38
}
39
40
-.Header {
40
+.HeaderRow {
41
+ display: flex;
42
+ flex-direction: row;
43
font-size: var(--font-size-sans-large);
44
font-weight: bold;
45
color: var(--color-error-text);
46
}
47
48
+.Header {
49
+ flex: 1 1 auto;
50
+ overflow: hidden;
51
+ text-overflow: ellipsis;
52
+ white-space: nowrap;
53
+ min-width: 0;
54
+}
55
+
56
.Stack {
57
margin-top: 0.5rem;
58
white-space: pre-wrap;
@@ -75,9 +85,21 @@
85
.ReproSteps {
86
margin-left: 0.25rem;
87
color: var(--color-console-warning-text);
88
+ overflow: hidden;
89
+ text-overflow: ellipsis;
90
+ white-space: nowrap;
91
+ min-width: 0;
92
}
93
94
.UpdateExistingIssuePrompt {
95
margin-right: 0.25rem;
96
color: var(--color-console-warning-text);
97
+}
98
+
99
+.CloseButton {
100
+ font-weight: bold;
101
+}
102
+
103
+.CloseButtonIcon {
104
+ margin-left: 0.25rem;
105
}
\ No newline at end of file