Skip to content

Commit c80c257

Browse files
Merge pull request #770 from Workiva/FED-193-error-boundary-stack
FED-193 Show Component Name in ErrorBoundary Stack
2 parents 18f49ae + dd5e987 commit c80c257

File tree

121 files changed

+1356
-185
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

121 files changed

+1356
-185
lines changed

dart_test.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ presets:
1818
- test/over_react_component_declaration_test.dart
1919
- test/over_react_component_test.dart
2020
- test/over_react_dom_test.dart
21+
- test/over_react_prod_test.dart
2122
- test/over_react_util_test.dart
2223
- test/over_react_redux_test.dart
2324

@@ -27,6 +28,7 @@ presets:
2728
- test/over_react_component_declaration_test.dart
2829
- test/over_react_component_test.dart
2930
- test/over_react_dom_test.dart
31+
- test/over_react_prod_test.dart
3032
- test/over_react_util_test.dart
3133
- test/over_react_redux_test.dart
3234

example/boilerplate_versions/dart2_only/basic_component1.over_react.g.dart

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/boilerplate_versions/dart2_only/basic_component2.over_react.g.dart

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// Copyright 2022 Workiva Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import 'package:over_react/components.dart';
16+
import 'package:over_react/over_react.dart' hide ErrorBoundary;
17+
18+
part 'error_ui.over_react.g.dart';
19+
20+
UiFactory<ErrorUiProps> ErrorUi =
21+
castUiFactory(_$ErrorUi); // ignore: undefined_identifier
22+
23+
mixin ErrorUiProps on UiProps {}
24+
25+
mixin ErrorUiState on UiState {
26+
bool triggerError;
27+
String stack;
28+
}
29+
30+
class ErrorUiComponent
31+
extends UiStatefulComponent2<ErrorUiProps, ErrorUiState> {
32+
@override
33+
get initialState => (newState()..triggerError = false);
34+
35+
@override
36+
render() {
37+
return (Dom.div()
38+
..style = {
39+
'margin': 16,
40+
'paddingBottom': 16,
41+
'borderBottom': '1px solid grey'
42+
}
43+
)(
44+
(Dom.div()
45+
..style = {
46+
'height': 300,
47+
}
48+
)(
49+
(ErrorBoundary()
50+
..onComponentDidCatch = (e, i) {
51+
if (state.stack == null) {
52+
setState(newState()..stack = i.componentStack);
53+
}
54+
55+
print(i.componentStack);
56+
}
57+
)(
58+
state.triggerError ? (ThrowingComponent()()) : null,
59+
),
60+
),
61+
Dom.div()(
62+
(Dom.button()
63+
..onClick = ((_) => setState(newState()..triggerError = true))
64+
..disabled = state.triggerError
65+
..style = {
66+
'margin': '0 5px 0 5px',
67+
}
68+
)('Trigger Error'),
69+
(Dom.button()
70+
..onClick = ((_) => setState(newState()
71+
..triggerError = false
72+
..stack = null
73+
))
74+
..disabled = !state.triggerError
75+
..style = {
76+
'margin': '0 5px 0 5px',
77+
}
78+
)('Reset'),
79+
),
80+
state.stack != null
81+
? (Dom.div()
82+
..style = {
83+
'border': '1px solid black',
84+
'margin': 8,
85+
'padding': 8,
86+
}
87+
)(
88+
(Dom.div()
89+
..style = {
90+
'padding': 4,
91+
'borderBottom': '1px solid grey',
92+
'display': 'flex',
93+
'justifyContent': 'space-between',
94+
}
95+
)(
96+
Dom.div()('Stack'),
97+
Dom.div()(
98+
state.stack.contains('ThrowingComponent')
99+
? 'Detected ThrowingComponent ✅'
100+
: 'Failed to Find ThrowingComponent ❌',
101+
),
102+
),
103+
(Dom.div()
104+
..addProp('dangerouslySetInnerHTML', {
105+
'__html': state.stack
106+
.replaceAll('ThrowingComponent',
107+
'<span style="color: green">ThrowingComponent</span>')
108+
.replaceAll('at', '<br /><br />at')
109+
})
110+
)(),
111+
)
112+
: null,
113+
);
114+
}
115+
}
116+
117+
UiFactory<ThrowingComponentProps> ThrowingComponent =
118+
castUiFactory(_$ThrowingComponent); // ignore: undefined_identifier
119+
120+
mixin ThrowingComponentProps on UiProps {}
121+
122+
class ThrowingComponentComponent extends UiComponent2<ThrowingComponentProps> {
123+
@override
124+
render() {
125+
throw StateError('Oh Dang');
126+
}
127+
}

example/error_boundary/index.html

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<!--
2+
~ Copyright 2022 Workiva Inc.
3+
~
4+
~ Licensed under the Apache License, Version 2.0 (the "License");
5+
~ you may not use this file except in compliance with the License.
6+
~ You may obtain a copy of the License at
7+
~
8+
~ http://www.apache.org/licenses/LICENSE-2.0
9+
~
10+
~ Unless required by applicable law or agreed to in writing, software
11+
~ distributed under the License is distributed on an "AS IS" BASIS,
12+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
~ See the License for the specific language governing permissions and
14+
~ limitations under the License.
15+
-->
16+
17+
<!DOCTYPE html>
18+
<html lang="en">
19+
<head>
20+
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
21+
<meta charset="utf-8">
22+
<title>over_react Error Boundary example</title>
23+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
24+
<meta name="apple-mobile-web-app-capable" content="yes">
25+
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
26+
27+
<!-- stylesheets -->
28+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
29+
30+
<!-- javascript -->
31+
32+
</head>
33+
<body>
34+
<div id="content"></div>
35+
36+
<script src="packages/react/react_prod.js"></script>
37+
<script src="packages/react/react_dom_prod.js"></script>
38+
39+
<script type="application/javascript" defer src="main.dart.js"></script>
40+
</body>
41+
</html>

example/error_boundary/main.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2022 Workiva Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import 'dart:html';
16+
17+
import 'package:react/react_dom.dart' as react_dom;
18+
19+
import 'error_ui.dart';
20+
21+
void main() {
22+
render() {
23+
react_dom.render(ErrorUi()(), querySelector('#content'));
24+
}
25+
26+
render();
27+
}

example/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ <h3><li>OverReact Redux Todo App
4141
</li></h3>
4242
<h3><li><a href="context/">Context Example</a></li></h3>
4343
<h3><li><a href="hooks/">Hooks Example</a></li></h3>
44+
<h3><li><a href="error_boundary/">Error Boundary Example</li></h3>
4445
<h3><li><a href="builder/">Builder Testing <em>(for internal use only)</em></a></li></h3>
4546
<h3><li><a href="boilerplate_versions/">Boilerplate Version Testing <em>(for internal use only)</em></a></li></h3>
4647
</ul>

lib/src/builder/codegen/component_factory_generator.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,7 @@ class ComponentFactoryProxyGenerator extends BoilerplateDeclarationGenerator {
8989
..writeln(' builderFactory: ${factoryNames.implName},')
9090
..writeln(' componentClass: ${componentNames.consumerName},')
9191
..writeln(' isWrapper: ${component.meta.isWrapper},')
92-
..writeln(' parentType: $parentTypeParam,$parentTypeParamComment')
93-
..writeln(' displayName: ${stringLiteral(factoryNames.consumerName)},');
92+
..writeln(' parentType: $parentTypeParam,$parentTypeParamComment');
9493

9594
// If isComponent2 is true, we can safely assume the component class has a
9695
// `@Component2()` (or no annotation), since other cases would fail validation.

lib/src/builder/codegen/component_generator.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ abstract class ComponentGenerator extends BoilerplateDeclarationGenerator {
3131
TypedMapNames propsNames;
3232
TypedMapNames stateNames;
3333
ComponentNames componentNames;
34+
FactoryNames factoryNames;
3435

3536
BoilerplateComponent get component;
3637
bool get hasState;
@@ -122,6 +123,9 @@ abstract class ComponentGenerator extends BoilerplateDeclarationGenerator {
122123
..writeln(' @override')
123124
..writeln(' bool get \$isClassGenerated => true;')
124125
..writeln()
126+
..writeln(' @override')
127+
..writeln(' String get displayName => \'${factoryNames.unprefixedConsumerName}\';')
128+
..writeln()
125129
..writeln(' $defaultConsumedPropsImpl');
126130

127131
_generateAdditionalComponentBody();
@@ -145,11 +149,15 @@ class _ComponentGenerator extends ComponentGenerator {
145149
@override
146150
final ComponentNames componentNames;
147151

152+
@override
153+
final FactoryNames factoryNames;
154+
148155
_ComponentGenerator(this.declaration)
149156
: this.propsNames = TypedMapNames(declaration.props.either.name.name),
150157
this.stateNames =
151158
declaration.state == null ? null : TypedMapNames(declaration.state.either.name.name),
152159
this.componentNames = ComponentNames(declaration.component.name.name),
160+
this.factoryNames = FactoryNames(declaration.factory.name.name),
153161
super._();
154162

155163
@override
@@ -190,11 +198,15 @@ class _LegacyComponentGenerator extends ComponentGenerator {
190198
@override
191199
final ComponentNames componentNames;
192200

201+
@override
202+
final FactoryNames factoryNames;
203+
193204
_LegacyComponentGenerator(this.declaration)
194205
: this.propsNames = TypedMapNames(declaration.props.name.name),
195206
this.stateNames =
196207
declaration.state == null ? null : TypedMapNames(declaration.state.name.name),
197208
this.componentNames = ComponentNames(declaration.component.name.name),
209+
this.factoryNames = FactoryNames(declaration.factory.name.name),
198210
super._();
199211

200212
@override

lib/src/component/_deprecated/error_boundary.over_react.g.dart

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)