Skip to content

Commit

Permalink
fix: allow graceful error handling (opensearch-project#779)
Browse files Browse the repository at this point in the history
  • Loading branch information
nickofthyme committed Aug 18, 2020
1 parent 5c68eec commit b201445
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 5 deletions.
3 changes: 3 additions & 0 deletions packages/osd-charts/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ module.exports = {
'react/sort-comp': 0,
'react/jsx-one-expression-per-line': 0,
'react/jsx-curly-newline': 0,
'react/jsx-indent-props': 0,
'react/jsx-max-props-per-line': 0,
'react/jsx-first-prop-new-line': 0,
'react/jsx-indent': 0,
// Too restrictive: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/destructuring-assignment.md
'react/destructuring-assignment': 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* under the License.
*/

import { GracefulError } from '../../../components/error_boundary/errors';
import { ScaleContinuousType } from '../../../scales';
import { ScaleType } from '../../../scales/constants';
import { identity } from '../../../utils/commons';
Expand Down Expand Up @@ -141,7 +142,7 @@ function mergeYDomainForGroup(
domain = [newCustomDomain.min, newCustomDomain.max];
} else if (newCustomDomain && isLowerBound(newCustomDomain)) {
if (newCustomDomain.min > computedDomainMax) {
throw new Error(`custom yDomain for ${groupId} is invalid, custom min is greater than computed max`);
throw new GracefulError(`custom yDomain for ${groupId} is invalid, custom min is greater than computed max`);
}

domain = [newCustomDomain.min, computedDomainMax];
Expand Down
11 changes: 7 additions & 4 deletions packages/osd-charts/src/components/chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { ChartBackground } from './chart_background';
import { ChartContainer } from './chart_container';
import { ChartResizer } from './chart_resizer';
import { ChartStatus } from './chart_status';
import { ErrorBoundary } from './error_boundary';
import { Legend } from './legend/legend';

interface ChartProps {
Expand Down Expand Up @@ -179,10 +180,12 @@ export class Chart extends React.Component<ChartProps, ChartState> {
<ChartStatus />
<ChartResizer />
<Legend />
<SpecsParser>{this.props.children}</SpecsParser>
<div className="echContainer">
<ChartContainer getChartContainerRef={this.getChartContainerRef} forwardStageRef={this.chartStageRef} />
</div>
<ErrorBoundary>
<SpecsParser>{this.props.children}</SpecsParser>
<div className="echContainer">
<ChartContainer getChartContainerRef={this.getChartContainerRef} forwardStageRef={this.chartStageRef} />
</div>
</ErrorBoundary>
</div>
</Provider>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you 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 React, { Component, ReactNode } from 'react';

import { isGracefulError } from './errors';

type ErrorBoundaryProps = {
children: ReactNode;
};

interface ErrorBoundaryState {
hasError: boolean;
}

/**
* Error Boundary to catch and handle custom errors
* @internal
*/
export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
hasError = false;

componentDidUpdate() {
if (this.hasError) {
this.hasError = false;
}
}

componentDidCatch(error: Error) {
if (isGracefulError(error)) {
this.hasError = true;
this.forceUpdate();
}
}

render() {
if (this.hasError) {
return (
<div className="echReactiveChart_unavailable">
<p>No data to display</p>
</div>
);
}

return this.props.children;
}
}
37 changes: 37 additions & 0 deletions packages/osd-charts/src/components/error_boundary/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you 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 { $Values } from 'utility-types';

export const ErrorType = Object.freeze({
Graceful: 'graceful' as const,
});
/** @public */
export type ErrorType = $Values<typeof ErrorType>;

/**
* Error to used to gracefully render empty chart
*/
export class GracefulError extends Error {
type = ErrorType.Graceful;
}

export function isGracefulError(error: Error): error is GracefulError {
return (error as GracefulError)?.type === ErrorType.Graceful;
}
23 changes: 23 additions & 0 deletions packages/osd-charts/src/components/error_boundary/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you 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.
*/

/* @internal */
export { ErrorBoundary } from './error_boundary';
/* @internal */
export * from './errors';

0 comments on commit b201445

Please sign in to comment.