diff --git a/public/app/core/components/ErrorBoundary/ErrorBoundary.tsx b/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.tsx similarity index 50% rename from public/app/core/components/ErrorBoundary/ErrorBoundary.tsx rename to packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.tsx index 92d2f24979a..6e5299eadf3 100644 --- a/public/app/core/components/ErrorBoundary/ErrorBoundary.tsx +++ b/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.tsx @@ -1,13 +1,14 @@ import React, { PureComponent, ReactNode } from 'react'; -import { Alert } from '@grafana/ui'; +import { Alert } from '../Alert/Alert'; +import { css } from 'emotion'; interface ErrorInfo { componentStack: string; } interface RenderProps { - error: Error; - errorInfo: ErrorInfo; + error: Error | null; + errorInfo: ErrorInfo | null; } interface Props { @@ -15,8 +16,8 @@ interface Props { } interface State { - error: Error; - errorInfo: ErrorInfo; + error: Error | null; + errorInfo: ErrorInfo | null; } export class ErrorBoundary extends PureComponent { @@ -35,6 +36,7 @@ export class ErrorBoundary extends PureComponent { render() { const { children } = this.props; const { error, errorInfo } = this.state; + return children({ error, errorInfo, @@ -42,18 +44,28 @@ export class ErrorBoundary extends PureComponent { } } +function getAlertPageStyle() { + return css` + width: 500px; + margin: 64px auto; + `; +} + interface WithAlertBoxProps { title?: string; children: ReactNode; + style?: 'page' | 'alertbox'; } export class ErrorBoundaryAlert extends PureComponent { static defaultProps: Partial = { title: 'An unexpected error happened', + style: 'alertbox', }; render() { - const { title, children } = this.props; + const { title, children, style } = this.props; + return ( {({ error, errorInfo }) => { @@ -61,15 +73,28 @@ export class ErrorBoundaryAlert extends PureComponent { return children; } - return ( - -
- {error && error.toString()} -
- {errorInfo.componentStack} -
-
- ); + if (style === 'alertbox') { + return ( + +
+ {error && error.toString()} +
+ {errorInfo.componentStack} +
+
+ ); + } else { + return ( +
+

{title}

+
+ {error && error.toString()} +
+ {errorInfo.componentStack} +
+
+ ); + } }}
); diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts index f915b6ce681..7d8a1b7e5cf 100644 --- a/packages/grafana-ui/src/components/index.ts +++ b/packages/grafana-ui/src/components/index.ts @@ -78,3 +78,5 @@ export { VariableSuggestion, VariableOrigin } from './DataLinks/DataLinkSuggesti export { DataLinksEditor } from './DataLinks/DataLinksEditor'; export { DataLinksContextMenu } from './DataLinks/DataLinksContextMenu'; export { SeriesIcon } from './Legend/SeriesIcon'; + +export { ErrorBoundary, ErrorBoundaryAlert } from './ErrorBoundary/ErrorBoundary'; diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.tsx index afb0713cf83..d3550f6bad9 100644 --- a/public/app/features/dashboard/dashgrid/PanelChrome.tsx +++ b/public/app/features/dashboard/dashgrid/PanelChrome.tsx @@ -5,7 +5,7 @@ import { Unsubscribable } from 'rxjs'; // Components import { PanelHeader } from './PanelHeader/PanelHeader'; -import { ErrorBoundary } from 'app/core/components/ErrorBoundary/ErrorBoundary'; +import { ErrorBoundary } from '@grafana/ui'; // Utils & Services import { getTimeSrv, TimeSrv } from '../services/TimeSrv'; diff --git a/public/app/features/dashboard/panel_editor/QueryEditorRow.tsx b/public/app/features/dashboard/panel_editor/QueryEditorRow.tsx index 3ba17d0dd95..1e28832fa63 100644 --- a/public/app/features/dashboard/panel_editor/QueryEditorRow.tsx +++ b/public/app/features/dashboard/panel_editor/QueryEditorRow.tsx @@ -8,11 +8,10 @@ import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; import { AngularComponent, getAngularLoader } from '@grafana/runtime'; import { Emitter } from 'app/core/utils/emitter'; import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv'; -import { ErrorBoundaryAlert } from 'app/core/components/ErrorBoundary/ErrorBoundary'; // Types import { PanelModel } from '../state/PanelModel'; -import { DataQuery, DataSourceApi, PanelData, DataQueryRequest } from '@grafana/ui'; +import { DataQuery, DataSourceApi, PanelData, DataQueryRequest, ErrorBoundaryAlert } from '@grafana/ui'; import { TimeRange, LoadingState } from '@grafana/data'; import { DashboardModel } from '../state/DashboardModel'; @@ -259,7 +258,7 @@ export class QueryEditorRow extends PureComponent {
- {this.renderPluginEditor()} + {this.renderPluginEditor()}
); diff --git a/public/app/features/explore/ErrorBoundary.tsx b/public/app/features/explore/ErrorBoundary.tsx deleted file mode 100644 index 07b9eb1ea54..00000000000 --- a/public/app/features/explore/ErrorBoundary.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import React, { Component } from 'react'; - -export class ErrorBoundary extends Component<{}, any> { - constructor(props: {}) { - super(props); - this.state = { error: null, errorInfo: null }; - } - - componentDidCatch(error: any, errorInfo: any) { - // Catch errors in any components below and re-render with error message - this.setState({ - error, - errorInfo, - }); - } - - render() { - if (this.state.errorInfo) { - // Error path - return ( -
-

An unexpected error happened.

-
- {this.state.error && this.state.error.toString()} -
- {this.state.errorInfo.componentStack} -
-
- ); - } - // Normally, just render children - return this.props.children; - } -} diff --git a/public/app/features/explore/Explore.tsx b/public/app/features/explore/Explore.tsx index d4f966c152a..181e3712c24 100644 --- a/public/app/features/explore/Explore.tsx +++ b/public/app/features/explore/Explore.tsx @@ -9,8 +9,7 @@ import memoizeOne from 'memoize-one'; // Services & Utils import store from 'app/core/store'; // Components -import { Alert, DataQuery, ExploreStartPageProps, DataSourceApi, PanelData } from '@grafana/ui'; -import { ErrorBoundary } from './ErrorBoundary'; +import { Alert, ErrorBoundaryAlert, DataQuery, ExploreStartPageProps, DataSourceApi, PanelData } from '@grafana/ui'; import LogsContainer from './LogsContainer'; import QueryRows from './QueryRows'; import TableContainer from './TableContainer'; @@ -275,7 +274,7 @@ export class Explore extends React.PureComponent { return (
- + {showingStartPage && } {!showingStartPage && ( <> @@ -310,7 +309,7 @@ export class Explore extends React.PureComponent { )} )} - +
); }} diff --git a/public/app/features/explore/Wrapper.tsx b/public/app/features/explore/Wrapper.tsx index 7caa8e546f8..4677f336c24 100644 --- a/public/app/features/explore/Wrapper.tsx +++ b/public/app/features/explore/Wrapper.tsx @@ -5,9 +5,8 @@ import { connect } from 'react-redux'; import { StoreState } from 'app/types'; import { ExploreId } from 'app/types/explore'; -import { ErrorBoundary } from './ErrorBoundary'; import Explore from './Explore'; -import { CustomScrollbar } from '@grafana/ui'; +import { CustomScrollbar, ErrorBoundaryAlert } from '@grafana/ui'; import { resetExploreAction } from './state/actionTypes'; interface WrapperProps { @@ -27,13 +26,13 @@ export class Wrapper extends Component {
- + - + {split && ( - + - + )}
diff --git a/public/app/routes/ReactContainer.tsx b/public/app/routes/ReactContainer.tsx index 117df53b8b1..7cad6918133 100644 --- a/public/app/routes/ReactContainer.tsx +++ b/public/app/routes/ReactContainer.tsx @@ -8,11 +8,14 @@ import coreModule from 'app/core/core_module'; import { store } from 'app/store/store'; import { ContextSrv } from 'app/core/services/context_srv'; import { provideTheme } from 'app/core/utils/ConfigProvider'; +import { ErrorBoundaryAlert } from '@grafana/ui'; function WrapInProvider(store: any, Component: any, props: any) { return ( - + + + ); }