mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Prometheus: Fixed Prometheus query editor error (plus new ErrorBoundaryAlert component) (#18838)
* ErrorHandling: Fixed Prometheus query editor error and added error boundary * Update public/app/core/components/ErrorBoundary/ErrorBoundary.tsx Co-Authored-By: kay delaney <45561153+kaydelaney@users.noreply.github.com> * Fixed ts error
This commit is contained in:
parent
29ff8e6018
commit
fe658d7ac2
@ -1,15 +1,16 @@
|
|||||||
import React, { FC } from 'react';
|
import React, { FC, ReactNode } from 'react';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
message: any;
|
title: string;
|
||||||
button?: {
|
button?: {
|
||||||
text: string;
|
text: string;
|
||||||
onClick: (event: React.MouseEvent) => void;
|
onClick: (event: React.MouseEvent) => void;
|
||||||
};
|
};
|
||||||
|
children?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Alert: FC<Props> = props => {
|
export const Alert: FC<Props> = props => {
|
||||||
const { message, button } = props;
|
const { title, button, children } = props;
|
||||||
return (
|
return (
|
||||||
<div className="alert-container">
|
<div className="alert-container">
|
||||||
<div className="alert-error alert">
|
<div className="alert-error alert">
|
||||||
@ -17,7 +18,8 @@ export const Alert: FC<Props> = props => {
|
|||||||
<i className="fa fa-exclamation-triangle" />
|
<i className="fa fa-exclamation-triangle" />
|
||||||
</div>
|
</div>
|
||||||
<div className="alert-body">
|
<div className="alert-body">
|
||||||
<div className="alert-title">{message}</div>
|
<div className="alert-title">{title}</div>
|
||||||
|
{children && <div className="alert-text">{children}</div>}
|
||||||
</div>
|
</div>
|
||||||
{button && (
|
{button && (
|
||||||
<div className="alert-button">
|
<div className="alert-button">
|
||||||
|
@ -179,7 +179,7 @@ const LogRowContextGroup: React.FunctionComponent<LogRowContextGroupProps> = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{error && <Alert message={error} />}
|
{error && <Alert title={error} />}
|
||||||
</div>
|
</div>
|
||||||
</CustomScrollbar>
|
</CustomScrollbar>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Component } from 'react';
|
import React, { PureComponent, ReactNode } from 'react';
|
||||||
|
import { Alert } from '@grafana/ui';
|
||||||
|
|
||||||
interface ErrorInfo {
|
interface ErrorInfo {
|
||||||
componentStack: string;
|
componentStack: string;
|
||||||
@ -10,7 +11,7 @@ interface RenderProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children: (r: RenderProps) => JSX.Element;
|
children: (r: RenderProps) => ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
@ -18,7 +19,7 @@ interface State {
|
|||||||
errorInfo: ErrorInfo;
|
errorInfo: ErrorInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ErrorBoundary extends Component<Props, State> {
|
export class ErrorBoundary extends PureComponent<Props, State> {
|
||||||
readonly state: State = {
|
readonly state: State = {
|
||||||
error: null,
|
error: null,
|
||||||
errorInfo: null,
|
errorInfo: null,
|
||||||
@ -41,4 +42,36 @@ class ErrorBoundary extends Component<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ErrorBoundary;
|
interface WithAlertBoxProps {
|
||||||
|
title?: string;
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ErrorBoundaryAlert extends PureComponent<WithAlertBoxProps> {
|
||||||
|
static defaultProps: Partial<WithAlertBoxProps> = {
|
||||||
|
title: 'An unexpected error happened',
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { title, children } = this.props;
|
||||||
|
return (
|
||||||
|
<ErrorBoundary>
|
||||||
|
{({ error, errorInfo }) => {
|
||||||
|
if (!errorInfo) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Alert title={title}>
|
||||||
|
<details style={{ whiteSpace: 'pre-wrap' }}>
|
||||||
|
{error && error.toString()}
|
||||||
|
<br />
|
||||||
|
{errorInfo.componentStack}
|
||||||
|
</details>
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</ErrorBoundary>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,7 +5,7 @@ import { Unsubscribable } from 'rxjs';
|
|||||||
|
|
||||||
// Components
|
// Components
|
||||||
import { PanelHeader } from './PanelHeader/PanelHeader';
|
import { PanelHeader } from './PanelHeader/PanelHeader';
|
||||||
import ErrorBoundary from 'app/core/components/ErrorBoundary/ErrorBoundary';
|
import { ErrorBoundary } from 'app/core/components/ErrorBoundary/ErrorBoundary';
|
||||||
|
|
||||||
// Utils & Services
|
// Utils & Services
|
||||||
import { getTimeSrv, TimeSrv } from '../services/TimeSrv';
|
import { getTimeSrv, TimeSrv } from '../services/TimeSrv';
|
||||||
|
@ -8,6 +8,7 @@ import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
|||||||
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
|
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
|
||||||
import { Emitter } from 'app/core/utils/emitter';
|
import { Emitter } from 'app/core/utils/emitter';
|
||||||
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||||
|
import { ErrorBoundaryAlert } from 'app/core/components/ErrorBoundary/ErrorBoundary';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { PanelModel } from '../state/PanelModel';
|
import { PanelModel } from '../state/PanelModel';
|
||||||
@ -257,7 +258,9 @@ export class QueryEditorRow extends PureComponent<Props, State> {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={bodyClasses}>{this.renderPluginEditor()}</div>
|
<div className={bodyClasses}>
|
||||||
|
<ErrorBoundaryAlert title="Data source query editor failed">{this.renderPluginEditor()}</ErrorBoundaryAlert>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
export default class ErrorBoundary extends Component<{}, any> {
|
export class ErrorBoundary extends Component<{}, any> {
|
||||||
constructor(props: {}) {
|
constructor(props: {}) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = { error: null, errorInfo: null };
|
this.state = { error: null, errorInfo: null };
|
||||||
|
@ -12,7 +12,7 @@ import store from 'app/core/store';
|
|||||||
|
|
||||||
// Components
|
// Components
|
||||||
import { Alert } from '@grafana/ui';
|
import { Alert } from '@grafana/ui';
|
||||||
import ErrorBoundary from './ErrorBoundary';
|
import { ErrorBoundary } from './ErrorBoundary';
|
||||||
import LogsContainer from './LogsContainer';
|
import LogsContainer from './LogsContainer';
|
||||||
import QueryRows from './QueryRows';
|
import QueryRows from './QueryRows';
|
||||||
import TableContainer from './TableContainer';
|
import TableContainer from './TableContainer';
|
||||||
@ -263,7 +263,7 @@ export class Explore extends React.PureComponent<ExploreProps> {
|
|||||||
<FadeIn duration={datasourceError ? 150 : 5} in={datasourceError ? true : false}>
|
<FadeIn duration={datasourceError ? 150 : 5} in={datasourceError ? true : false}>
|
||||||
<div className="explore-container">
|
<div className="explore-container">
|
||||||
<Alert
|
<Alert
|
||||||
message={`Error connecting to datasource: ${datasourceError}`}
|
title={`Error connecting to datasource: ${datasourceError}`}
|
||||||
button={{ text: 'Reconnect', onClick: this.onReconnect }}
|
button={{ text: 'Reconnect', onClick: this.onReconnect }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,7 +5,7 @@ import { connect } from 'react-redux';
|
|||||||
import { StoreState } from 'app/types';
|
import { StoreState } from 'app/types';
|
||||||
import { ExploreId } from 'app/types/explore';
|
import { ExploreId } from 'app/types/explore';
|
||||||
|
|
||||||
import ErrorBoundary from './ErrorBoundary';
|
import { ErrorBoundary } from './ErrorBoundary';
|
||||||
import Explore from './Explore';
|
import Explore from './Explore';
|
||||||
import { CustomScrollbar } from '@grafana/ui';
|
import { CustomScrollbar } from '@grafana/ui';
|
||||||
import { resetExploreAction } from './state/actionTypes';
|
import { resetExploreAction } from './state/actionTypes';
|
||||||
|
@ -154,7 +154,8 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
|
|||||||
|
|
||||||
componentDidUpdate(prevProps: PromQueryFieldProps) {
|
componentDidUpdate(prevProps: PromQueryFieldProps) {
|
||||||
const { queryResponse } = this.props;
|
const { queryResponse } = this.props;
|
||||||
if (prevProps.queryResponse && prevProps.queryResponse.series !== queryResponse.series) {
|
|
||||||
|
if (queryResponse && prevProps.queryResponse && prevProps.queryResponse.series !== queryResponse.series) {
|
||||||
this.refreshHint();
|
this.refreshHint();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +178,7 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
|
|||||||
refreshHint = () => {
|
refreshHint = () => {
|
||||||
const { datasource, query, queryResponse } = this.props;
|
const { datasource, query, queryResponse } = this.props;
|
||||||
|
|
||||||
if (!queryResponse.series || queryResponse.series.length === 0) {
|
if (!queryResponse || queryResponse.series.length === 0) {
|
||||||
this.setState({ hint: null });
|
this.setState({ hint: null });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user