diff --git a/web/ui/react-app/src/Panel.tsx b/web/ui/react-app/src/Panel.tsx index b89f0db17b..6450eb1ee3 100644 --- a/web/ui/react-app/src/Panel.tsx +++ b/web/ui/react-app/src/Panel.tsx @@ -19,6 +19,7 @@ import GraphControls from './GraphControls'; import Graph from './Graph'; import DataTable from './DataTable'; import TimeInput from './TimeInput'; +import QueryStatsView, { QueryStats } from './QueryStatsView'; interface PanelProps { options: PanelOptions; @@ -36,7 +37,7 @@ interface PanelState { } | null; loading: boolean; error: string | null; - stats: null; // TODO: Stats. + stats: QueryStats | null, } export interface PanelOptions { @@ -100,6 +101,7 @@ class Panel extends Component { } executeQuery = (expr: string): void => { + const queryStart = Date.now(); if (this.props.options.expr !== expr) { this.setOptions({expr: expr}); } @@ -119,7 +121,6 @@ class Panel extends Component { const endTime = this.getEndTime().valueOf() / 1000; // TODO: shouldn't valueof only work when it's a moment? const startTime = endTime - this.props.options.range; const resolution = this.props.options.resolution || Math.max(Math.floor(this.props.options.range / 250), 1); - const url = new URL(window.location.href); const params: {[key: string]: string} = { 'query': expr, @@ -153,14 +154,29 @@ class Panel extends Component { throw new Error(json.error || 'invalid response JSON'); } + let resultSeries = 0; + if (json.data) { + const { resultType, result } = json.data; + if (resultType === "scalar") { + resultSeries = 1; + } else if (result && result.length > 0) { + resultSeries = result.length; + } + } + this.setState({ error: null, data: json.data, lastQueryParams: { - startTime: startTime, - endTime: endTime, - resolution: resolution, + startTime, + endTime, + resolution, }, + stats: { + loadTime: Date.now() - queryStart, + resolution, + resultSeries + }, loading: false, }); this.abortInFlightFetch = null; @@ -246,6 +262,10 @@ class Panel extends Component { Graph + { + (!this.state.loading && !this.state.error && this.state.stats) && + + } diff --git a/web/ui/react-app/src/QueryStatsView.css b/web/ui/react-app/src/QueryStatsView.css new file mode 100644 index 0000000000..d5d8dc7c96 --- /dev/null +++ b/web/ui/react-app/src/QueryStatsView.css @@ -0,0 +1,5 @@ +.query-stats{ + flex-grow: 1; + font-size: 9px; + color: #999; +} diff --git a/web/ui/react-app/src/QueryStatsView.tsx b/web/ui/react-app/src/QueryStatsView.tsx new file mode 100644 index 0000000000..a7cca4da81 --- /dev/null +++ b/web/ui/react-app/src/QueryStatsView.tsx @@ -0,0 +1,20 @@ +import React, { FC } from 'react'; +import './QueryStatsView.css'; + +export interface QueryStats { + loadTime: number; + resolution: number; + resultSeries: number; +} + +const QueryStatsView: FC = props => { + const {loadTime, resolution, resultSeries} = props; + + return ( +
+ Load time: {loadTime}ms   Resolution: {resolution}s   Result series: {resultSeries} +
+ ); +} + +export default QueryStatsView;