// Library import React, { Component } from 'react'; import Tooltip from 'app/core/components/Tooltip/Tooltip'; // Services import { getDatasourceSrv, DatasourceSrv } from 'app/features/plugins/datasource_srv'; // Utils import kbn from 'app/core/utils/kbn'; // Types import { DataQueryOptions, DataQueryResponse } from 'app/types'; import { TimeRange, TimeSeries, LoadingState } from '@grafana/ui'; import { Themes } from 'app/core/components/Tooltip/Popper'; interface RenderProps { loading: LoadingState; timeSeries: TimeSeries[]; onRenderError: () => void; } export interface Props { datasource: string | null; queries: any[]; panelId?: number; dashboardId?: number; isVisible?: boolean; timeRange?: TimeRange; widthPixels: number; refreshCounter: number; minInterval?: string; maxDataPoints?: number; children: (r: RenderProps) => JSX.Element; } export interface State { isFirstLoad: boolean; loading: LoadingState; errorMessage: string; response: DataQueryResponse; } export class DataPanel extends Component { static defaultProps = { isVisible: true, panelId: 1, dashboardId: 1, }; dataSourceSrv: DatasourceSrv = getDatasourceSrv(); isUnmounted = false; constructor(props: Props) { super(props); this.state = { loading: LoadingState.NotStarted, errorMessage: '', response: { data: [], }, isFirstLoad: true, }; } componentDidMount() { this.issueQueries(); } componentWillUnmount() { this.isUnmounted = true; } async componentDidUpdate(prevProps: Props) { if (!this.hasPropsChanged(prevProps)) { return; } this.issueQueries(); } hasPropsChanged(prevProps: Props) { return this.props.refreshCounter !== prevProps.refreshCounter; } private issueQueries = async () => { const { isVisible, queries, datasource, panelId, dashboardId, timeRange, widthPixels, maxDataPoints } = this.props; if (!isVisible) { return; } if (!queries.length) { this.setState({ loading: LoadingState.Done }); return; } this.setState({ loading: LoadingState.Loading, errorMessage: '' }); try { const ds = await this.dataSourceSrv.get(datasource); // TODO interpolate variables const minInterval = this.props.minInterval || ds.interval; const intervalRes = kbn.calculateInterval(timeRange, widthPixels, minInterval); const queryOptions: DataQueryOptions = { timezone: 'browser', panelId: panelId, dashboardId: dashboardId, range: timeRange, rangeRaw: timeRange.raw, interval: intervalRes.interval, intervalMs: intervalRes.intervalMs, targets: queries, maxDataPoints: maxDataPoints || widthPixels, scopedVars: {}, cacheTimeout: null, }; console.log('Issuing DataPanel query', queryOptions); const resp = await ds.query(queryOptions); console.log('Issuing DataPanel query Resp', resp); if (this.isUnmounted) { return; } this.setState({ loading: LoadingState.Done, response: resp, isFirstLoad: false, }); } catch (err) { console.log('Loading error', err); this.onError('Request Error'); } }; onError = (errorMessage: string) => { if (this.state.loading !== LoadingState.Error || this.state.errorMessage !== errorMessage) { this.setState({ loading: LoadingState.Error, isFirstLoad: false, errorMessage: errorMessage }); } } onRenderError = () => { this.onError('Error rendering panel'); } render() { const { queries } = this.props; const { response, loading, isFirstLoad } = this.state; const timeSeries = response.data; if (isFirstLoad && loading === LoadingState.Loading) { return this.renderLoadingStates(); } if (!queries.length) { return (

Add a query to get some data!

); } return ( <> {this.renderLoadingStates()} {this.props.children({ timeSeries, loading, onRenderError: this.onRenderError })} ); } private renderLoadingStates(): JSX.Element { const { loading, errorMessage } = this.state; if (loading === LoadingState.Loading) { return (
); } else if (loading === LoadingState.Error) { return ( ); } return null; } }