Skip to content

Commit

Permalink
Merge pull request #770 from Workiva/FED-193-error-boundary-stack
Browse files Browse the repository at this point in the history
FED-193 Show Component Name in ErrorBoundary Stack
  • Loading branch information
rmconsole5-wk authored Aug 3, 2022
2 parents 18f49ae + dd5e987 commit c80c257
Show file tree
Hide file tree
Showing 121 changed files with 1,356 additions and 185 deletions.
2 changes: 2 additions & 0 deletions dart_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ presets:
- test/over_react_component_declaration_test.dart
- test/over_react_component_test.dart
- test/over_react_dom_test.dart
- test/over_react_prod_test.dart
- test/over_react_util_test.dart
- test/over_react_redux_test.dart

Expand All @@ -27,6 +28,7 @@ presets:
- test/over_react_component_declaration_test.dart
- test/over_react_component_test.dart
- test/over_react_dom_test.dart
- test/over_react_prod_test.dart
- test/over_react_util_test.dart
- test/over_react_redux_test.dart

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

127 changes: 127 additions & 0 deletions example/error_boundary/error_ui.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright 2022 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import 'package:over_react/components.dart';
import 'package:over_react/over_react.dart' hide ErrorBoundary;

part 'error_ui.over_react.g.dart';

UiFactory<ErrorUiProps> ErrorUi =
castUiFactory(_$ErrorUi); // ignore: undefined_identifier

mixin ErrorUiProps on UiProps {}

mixin ErrorUiState on UiState {
bool triggerError;
String stack;
}

class ErrorUiComponent
extends UiStatefulComponent2<ErrorUiProps, ErrorUiState> {
@override
get initialState => (newState()..triggerError = false);

@override
render() {
return (Dom.div()
..style = {
'margin': 16,
'paddingBottom': 16,
'borderBottom': '1px solid grey'
}
)(
(Dom.div()
..style = {
'height': 300,
}
)(
(ErrorBoundary()
..onComponentDidCatch = (e, i) {
if (state.stack == null) {
setState(newState()..stack = i.componentStack);
}

print(i.componentStack);
}
)(
state.triggerError ? (ThrowingComponent()()) : null,
),
),
Dom.div()(
(Dom.button()
..onClick = ((_) => setState(newState()..triggerError = true))
..disabled = state.triggerError
..style = {
'margin': '0 5px 0 5px',
}
)('Trigger Error'),
(Dom.button()
..onClick = ((_) => setState(newState()
..triggerError = false
..stack = null
))
..disabled = !state.triggerError
..style = {
'margin': '0 5px 0 5px',
}
)('Reset'),
),
state.stack != null
? (Dom.div()
..style = {
'border': '1px solid black',
'margin': 8,
'padding': 8,
}
)(
(Dom.div()
..style = {
'padding': 4,
'borderBottom': '1px solid grey',
'display': 'flex',
'justifyContent': 'space-between',
}
)(
Dom.div()('Stack'),
Dom.div()(
state.stack.contains('ThrowingComponent')
? 'Detected ThrowingComponent ✅'
: 'Failed to Find ThrowingComponent ❌',
),
),
(Dom.div()
..addProp('dangerouslySetInnerHTML', {
'__html': state.stack
.replaceAll('ThrowingComponent',
'<span style="color: green">ThrowingComponent</span>')
.replaceAll('at', '<br /><br />at')
})
)(),
)
: null,
);
}
}

UiFactory<ThrowingComponentProps> ThrowingComponent =
castUiFactory(_$ThrowingComponent); // ignore: undefined_identifier

mixin ThrowingComponentProps on UiProps {}

class ThrowingComponentComponent extends UiComponent2<ThrowingComponentProps> {
@override
render() {
throw StateError('Oh Dang');
}
}
41 changes: 41 additions & 0 deletions example/error_boundary/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!--
~ Copyright 2022 Workiva Inc.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<meta charset="utf-8">
<title>over_react Error Boundary example</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">

<!-- stylesheets -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">

<!-- javascript -->

</head>
<body>
<div id="content"></div>

<script src="packages/react/react_prod.js"></script>
<script src="packages/react/react_dom_prod.js"></script>

<script type="application/javascript" defer src="main.dart.js"></script>
</body>
</html>
27 changes: 27 additions & 0 deletions example/error_boundary/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2022 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import 'dart:html';

import 'package:react/react_dom.dart' as react_dom;

import 'error_ui.dart';

void main() {
render() {
react_dom.render(ErrorUi()(), querySelector('#content'));
}

render();
}
1 change: 1 addition & 0 deletions example/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ <h3><li>OverReact Redux Todo App
</li></h3>
<h3><li><a href="context/">Context Example</a></li></h3>
<h3><li><a href="hooks/">Hooks Example</a></li></h3>
<h3><li><a href="error_boundary/">Error Boundary Example</li></h3>
<h3><li><a href="builder/">Builder Testing <em>(for internal use only)</em></a></li></h3>
<h3><li><a href="boilerplate_versions/">Boilerplate Version Testing <em>(for internal use only)</em></a></li></h3>
</ul>
Expand Down
3 changes: 1 addition & 2 deletions lib/src/builder/codegen/component_factory_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,7 @@ class ComponentFactoryProxyGenerator extends BoilerplateDeclarationGenerator {
..writeln(' builderFactory: ${factoryNames.implName},')
..writeln(' componentClass: ${componentNames.consumerName},')
..writeln(' isWrapper: ${component.meta.isWrapper},')
..writeln(' parentType: $parentTypeParam,$parentTypeParamComment')
..writeln(' displayName: ${stringLiteral(factoryNames.consumerName)},');
..writeln(' parentType: $parentTypeParam,$parentTypeParamComment');

// If isComponent2 is true, we can safely assume the component class has a
// `@Component2()` (or no annotation), since other cases would fail validation.
Expand Down
12 changes: 12 additions & 0 deletions lib/src/builder/codegen/component_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ abstract class ComponentGenerator extends BoilerplateDeclarationGenerator {
TypedMapNames propsNames;
TypedMapNames stateNames;
ComponentNames componentNames;
FactoryNames factoryNames;

BoilerplateComponent get component;
bool get hasState;
Expand Down Expand Up @@ -122,6 +123,9 @@ abstract class ComponentGenerator extends BoilerplateDeclarationGenerator {
..writeln(' @override')
..writeln(' bool get \$isClassGenerated => true;')
..writeln()
..writeln(' @override')
..writeln(' String get displayName => \'${factoryNames.unprefixedConsumerName}\';')
..writeln()
..writeln(' $defaultConsumedPropsImpl');

_generateAdditionalComponentBody();
Expand All @@ -145,11 +149,15 @@ class _ComponentGenerator extends ComponentGenerator {
@override
final ComponentNames componentNames;

@override
final FactoryNames factoryNames;

_ComponentGenerator(this.declaration)
: this.propsNames = TypedMapNames(declaration.props.either.name.name),
this.stateNames =
declaration.state == null ? null : TypedMapNames(declaration.state.either.name.name),
this.componentNames = ComponentNames(declaration.component.name.name),
this.factoryNames = FactoryNames(declaration.factory.name.name),
super._();

@override
Expand Down Expand Up @@ -190,11 +198,15 @@ class _LegacyComponentGenerator extends ComponentGenerator {
@override
final ComponentNames componentNames;

@override
final FactoryNames factoryNames;

_LegacyComponentGenerator(this.declaration)
: this.propsNames = TypedMapNames(declaration.props.name.name),
this.stateNames =
declaration.state == null ? null : TypedMapNames(declaration.state.name.name),
this.componentNames = ComponentNames(declaration.component.name.name),
this.factoryNames = FactoryNames(declaration.factory.name.name),
super._();

@override
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion lib/src/component/dummy_component2.over_react.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit c80c257

Please sign in to comment.