Просмотр исходного кода

fix: Remove the onRenderError prop and add an ErrorBoundary component

Johannes Schill 7 лет назад
Родитель
Сommit
f428db282c

+ 0 - 1
packages/grafana-ui/src/types/panel.ts

@@ -9,7 +9,6 @@ export interface PanelProps<T = any> {
   renderCounter: number;
   width: number;
   height: number;
-  onRenderError: () => void;
 }
 
 export interface PanelOptionsProps<T = any> {

+ 2 - 3
packages/grafana-ui/src/visualizations/Graph/Graph.tsx

@@ -13,7 +13,6 @@ interface GraphProps {
   showBars?: boolean;
   width: number;
   height: number;
-  onRenderError: () => void;
 }
 
 export class Graph extends PureComponent<GraphProps> {
@@ -38,7 +37,7 @@ export class Graph extends PureComponent<GraphProps> {
       return;
     }
 
-    const { width, timeSeries, timeRange, showLines, showBars, showPoints, onRenderError } = this.props;
+    const { width, timeSeries, timeRange, showLines, showBars, showPoints } = this.props;
 
     if (!width) {
       return;
@@ -99,7 +98,7 @@ export class Graph extends PureComponent<GraphProps> {
       $.plot(this.element, timeSeries, flotOptions);
     } catch (err) {
       console.log('Graph rendering error', err, flotOptions, timeSeries);
-      onRenderError();
+      throw new Error('Error rendering panel');
     }
   }
 

+ 47 - 0
public/app/core/components/ErrorBoundary/ErrorBoundary.tsx

@@ -0,0 +1,47 @@
+import React, { Component } from 'react';
+
+interface ErrorInfo {
+  componentStack: string;
+}
+
+interface RenderProps {
+  error: Error;
+  errorInfo: ErrorInfo;
+}
+
+interface Props {
+  children: (r: RenderProps) => JSX.Element;
+}
+
+interface State {
+  error: Error;
+  errorInfo: ErrorInfo;
+}
+
+class ErrorBoundary extends Component<Props, State> {
+  constructor(props) {
+    super(props);
+    this.state = { error: null, errorInfo: null };
+  }
+
+  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
+    this.setState({
+      error: error,
+      errorInfo: errorInfo
+    });
+  }
+
+  render() {
+    const { error, errorInfo } = this.state;
+    return (
+      <>
+        {this.props.children({
+          error,
+          errorInfo,
+        })}
+      </>
+    );
+  }
+}
+
+export default ErrorBoundary;

+ 19 - 10
public/app/features/dashboard/dashgrid/DataPanel.tsx

@@ -1,6 +1,7 @@
 // Library
 import React, { Component } from 'react';
 import Tooltip from 'app/core/components/Tooltip/Tooltip';
+import ErrorBoundary from 'app/core/components/ErrorBoundary/ErrorBoundary';
 
 // Services
 import { getDatasourceSrv, DatasourceSrv } from 'app/features/plugins/datasource_srv';
@@ -13,10 +14,11 @@ import { DataQueryOptions, DataQueryResponse } from 'app/types';
 import { TimeRange, TimeSeries, LoadingState } from '@grafana/ui';
 import { Themes } from 'app/core/components/Tooltip/Popper';
 
+const DEFAULT_PLUGIN_ERROR = 'Error in plugin';
+
 interface RenderProps {
   loading: LoadingState;
   timeSeries: TimeSeries[];
-  onRenderError: () => void;
 }
 
 export interface Props {
@@ -147,10 +149,6 @@ export class DataPanel extends Component<Props, State> {
     }
   }
 
-  onRenderError = () => {
-    this.onError('Error rendering panel');
-  }
-
   render() {
     const { queries } = this.props;
     const { response, loading, isFirstLoad } = this.state;
@@ -172,11 +170,22 @@ export class DataPanel extends Component<Props, State> {
     return (
       <>
         {this.renderLoadingStates()}
-        {this.props.children({
-          timeSeries,
-          loading,
-          onRenderError: this.onRenderError
-        })}
+        <ErrorBoundary>
+          {({error, errorInfo}) => {
+            if (errorInfo) {
+              this.onError(error.message || DEFAULT_PLUGIN_ERROR);
+              return null;
+            }
+            return (
+              <>
+                {this.props.children({
+                  timeSeries,
+                  loading,
+                })}
+              </>
+            );
+          }}
+        </ErrorBoundary>
       </>
     );
   }

+ 1 - 2
public/app/features/dashboard/dashgrid/PanelChrome.tsx

@@ -114,7 +114,7 @@ export class PanelChrome extends PureComponent<Props, State> {
                 widthPixels={width}
                 refreshCounter={refreshCounter}
               >
-                {({ loading, timeSeries, onRenderError }) => {
+                {({ loading, timeSeries }) => {
                   return (
                     <div className="panel-content">
                       <PanelComponent
@@ -125,7 +125,6 @@ export class PanelChrome extends PureComponent<Props, State> {
                         width={width}
                         height={height - PANEL_HEADER_HEIGHT}
                         renderCounter={renderCounter}
-                        onRenderError={onRenderError}
                       />
                     </div>
                   );

+ 2 - 3
public/app/plugins/panel/graph2/GraphPanel.tsx

@@ -10,12 +10,12 @@ import { Options } from './types';
 interface Props extends PanelProps<Options> {}
 
 export class GraphPanel extends PureComponent<Props> {
-  constructor(props) {
+  constructor(props: Props) {
     super(props);
   }
 
   render() {
-    const { timeSeries, timeRange, width, height, onRenderError } = this.props;
+    const { timeSeries, timeRange, width, height } = this.props;
     const { showLines, showBars, showPoints } = this.props.options;
 
     const vmSeries = processTimeSeries({
@@ -33,7 +33,6 @@ export class GraphPanel extends PureComponent<Props> {
         showBars={showBars}
         width={width}
         height={height}
-        onRenderError={onRenderError}
       />
     );
   }