diff --git a/ui/src/data_explorer/components/Table.js b/ui/src/data_explorer/components/Table.js index 64d408911..8895cb6f4 100644 --- a/ui/src/data_explorer/components/Table.js +++ b/ui/src/data_explorer/components/Table.js @@ -86,14 +86,19 @@ const ChronoTable = React.createClass({ this.setState({isLoading: true}) // second param is db, we want to leave this blank try { - const results = await this.props.fetchTimeSeries(query.host, undefined, query) + const {results} = await this.props.fetchTimeSeries({source: query.host, query}) this.setState({isLoading: false}) if (!results) { return this.setState({cellData: emptyCells}) } - const cellData = _.get(results, ['series', '0'], {}) + const cellData = _.get(results, ['0', 'series', '0'], false) + + if (!cellData) { + return this.setState({cellData: emptyCells}) + } + this.setState({cellData}) } catch (error) { this.setState({ diff --git a/ui/src/shared/actions/timeSeries.js b/ui/src/shared/actions/timeSeries.js index 5e0e50911..169ab1533 100644 --- a/ui/src/shared/actions/timeSeries.js +++ b/ui/src/shared/actions/timeSeries.js @@ -2,35 +2,46 @@ import {proxy} from 'utils/queryUrlGenerator' import {editQueryStatus} from 'src/data_explorer/actions/view' import _ from 'lodash' -export const fetchTimeSeriesAsync = (source, db, query) => async (dispatch) => { +export const handleLoading = (query, dispatch) => { dispatch(editQueryStatus(query.id, {loading: true})) +} +// {results: [{}]} +export const handleSuccess = (data, query, dispatch) => { + const {results} = data + const error = _.get(results, ['0', 'error'], false) + const series = _.get(results, ['0', 'series'], false) + // 200 from server and no results = warn + if (!series && !error) { + dispatch(editQueryStatus(query.id, {warn: 'Your query is syntactically correct but returned no results'})) + return data + } + // 200 from chrono server but influx returns an "error" = warning + if (error) { + dispatch(editQueryStatus(query.id, {warn: error})) + return data + } + + // 200 from server and results contains data = success + dispatch(editQueryStatus(query.id, {success: 'Success!'})) + return data +} + +export const handleError = (error, query, dispatch) => { + const message = _.get(error, ['data', 'message'], error) + + // 400 from chrono server = fail + dispatch(editQueryStatus(query.id, {error: message})) + console.error(error) +} + +export const fetchTimeSeriesAsync = ({source, db, rp, query}) => async (dispatch) => { + handleLoading(query, dispatch) try { - const {data} = await proxy({source, db, query: query.text}) - const results = _.get(data, ['results', '0'], false) - const warn = _.get(results, 'error', false) - - // 200 from server and no results = warn - if (_.isEmpty(results)) { - dispatch(editQueryStatus(query.id, {warn: 'Your query is syntactically correct but returned no results'})) - return results - } - - // 200 from chrono server but influx returns an error = warning - if (warn) { - dispatch(editQueryStatus(query.id, {warn})) - return warn - } - - // 200 from server and results contains data = success - dispatch(editQueryStatus(query.id, {success: 'Success!'})) - return results + const {data} = await proxy({source, db, rp, query: query.text}) + return handleSuccess(data, query, dispatch) } catch (error) { - const message = _.get(error, ['data', 'message'], error) - - // 400 from chrono server = fail - dispatch(editQueryStatus(query.id, {error: message})) - console.error(error) + handleError(error, query, dispatch) throw error } } diff --git a/ui/src/shared/components/AutoRefresh.js b/ui/src/shared/components/AutoRefresh.js index 729980758..2fc68d160 100644 --- a/ui/src/shared/components/AutoRefresh.js +++ b/ui/src/shared/components/AutoRefresh.js @@ -1,21 +1,21 @@ import React, {PropTypes} from 'react' +import {connect} from 'react-redux' +import {bindActionCreators} from 'redux' import _ from 'lodash' -import {proxy} from 'utils/queryUrlGenerator' -function _fetchTimeSeries(source, db, rp, query) { - return proxy({source, db, rp, query}) -} +import {fetchTimeSeriesAsync} from 'shared/actions/timeSeries' const { - element, - number, arrayOf, - shape, + element, + func, + number, oneOfType, + shape, string, } = PropTypes -export default function AutoRefresh(ComposedComponent) { +const AutoRefresh = (ComposedComponent) => { const wrapper = React.createClass({ propTypes: { children: element, @@ -24,6 +24,7 @@ export default function AutoRefresh(ComposedComponent) { host: oneOfType([string, arrayOf(string)]), text: string, }).isRequired).isRequired, + fetchTimeSeries: func.isRequired, }, getInitialState() { return { @@ -58,7 +59,7 @@ export default function AutoRefresh(ComposedComponent) { const rightStrs = right.map((q) => `${q.host}${q.text}`) return _.difference(_.union(leftStrs, rightStrs), _.intersection(leftStrs, rightStrs)) }, - executeQueries(queries) { + async executeQueries(queries) { if (!queries.length) { this.setState({ timeSeries: [], @@ -69,20 +70,20 @@ export default function AutoRefresh(ComposedComponent) { this.setState({isFetching: true}) let count = 0 const newSeries = [] - queries.forEach(({host, database, rp, text}) => { - _fetchTimeSeries(host, database, rp, text).then((resp) => { - newSeries.push({response: resp.data}) - count += 1 - if (count === queries.length) { - const querySuccessful = !this._noResultsForQuery(newSeries) - this.setState({ - lastQuerySuccessful: querySuccessful, - isFetching: false, - timeSeries: newSeries, - }) - } - }) - }) + for (const query of queries) { + const {host, database, rp} = query + const response = await this.props.fetchTimeSeries({source: host, db: database, rp, query}) + newSeries.push({response}) + count += 1 + if (count === queries.length) { + const querySuccessful = !this._noResultsForQuery(newSeries) + this.setState({ + lastQuerySuccessful: querySuccessful, + isFetching: false, + timeSeries: newSeries, + }) + } + } }, componentWillUnmount() { clearInterval(this.intervalID) @@ -148,5 +149,11 @@ export default function AutoRefresh(ComposedComponent) { }, }) - return wrapper + const mapDispatchToProps = (dispatch) => ({ + fetchTimeSeries: bindActionCreators(fetchTimeSeriesAsync, dispatch), + }) + + return connect(null, mapDispatchToProps)(wrapper) } + +export default AutoRefresh