From 83dd14bdbbe2a0cef277c661ad81e2d1c31c30de Mon Sep 17 00:00:00 2001 From: Christopher Henn Date: Wed, 13 Mar 2019 14:11:28 -0700 Subject: [PATCH] Hydrate in use variables before displaying the CEO --- ui/src/timeMachine/actions/index.ts | 38 +++++++++- ui/src/timeMachine/components/TimeMachine.tsx | 72 ++++++++++++++----- 2 files changed, 91 insertions(+), 19 deletions(-) diff --git a/ui/src/timeMachine/actions/index.ts b/ui/src/timeMachine/actions/index.ts index 93e1afe6f2..c3ad5decca 100644 --- a/ui/src/timeMachine/actions/index.ts +++ b/ui/src/timeMachine/actions/index.ts @@ -1,11 +1,21 @@ +// Libraries +import {get} from 'lodash' + // Actions import {loadBuckets} from 'src/timeMachine/actions/queryBuilder' +import {refreshVariableValues} from 'src/variables/actions' + +// Utils +import {getActiveTimeMachine} from 'src/timeMachine/selectors' +import {filterUnusedVars} from 'src/shared/utils/filterUnusedVars' +import {getVariablesForOrg} from 'src/variables/selectors' +import {getActiveOrg} from 'src/organizations/selectors' // Types import {Dispatch} from 'redux-thunk' import {TimeMachineState} from 'src/timeMachine/reducers' import {Action as QueryBuilderAction} from 'src/timeMachine/actions/queryBuilder' -import {TimeRange, ViewType} from 'src/types/v2' +import {TimeRange, ViewType, GetState} from 'src/types/v2' import { Axes, DecimalPlaces, @@ -541,3 +551,29 @@ export const setXAxisLabel = (xAxisLabel: string): SetXAxisLabelAction => ({ type: 'SET_X_AXIS_LABEL', payload: {xAxisLabel}, }) + +export const refreshTimeMachineVariableValues = () => async ( + dispatch, + getState: GetState +) => { + const contextID = getState().timeMachines.activeTimeMachineID + + // Find variables currently used by queries in the TimeMachine + const view = getActiveTimeMachine(getState()).view + const orgID = getActiveOrg(getState()).id + const variables = getVariablesForOrg(getState(), orgID) + const variablesInUse = filterUnusedVars(variables, [view]) + + // Find variables whose values have already been loaded by the TimeMachine + // (regardless of whether these variables are currently being used) + const existingVariableIDs = Object.keys( + get(getState(), `variables.values.${contextID}.values`, {}) + ) + + // Refresh values for all variables with existing values and in use variables + const variablesToRefresh = variables.filter( + v => variablesInUse.includes(v) || existingVariableIDs.includes(v.id) + ) + + await dispatch(refreshVariableValues(contextID, orgID, variablesToRefresh)) +} diff --git a/ui/src/timeMachine/components/TimeMachine.tsx b/ui/src/timeMachine/components/TimeMachine.tsx index 8892965b6b..fe6e86804f 100644 --- a/ui/src/timeMachine/components/TimeMachine.tsx +++ b/ui/src/timeMachine/components/TimeMachine.tsx @@ -5,19 +5,26 @@ import {get} from 'lodash' import classnames from 'classnames' // Components +import {SpinnerContainer, TechnoSpinner} from '@influxdata/clockface' import {DraggableResizer, Stack} from 'src/clockface' import TimeMachineBottom from 'src/timeMachine/components/TimeMachineBottom' import TimeMachineVis from 'src/timeMachine/components/Vis' import TimeSeries from 'src/shared/components/TimeSeries' import ViewOptions from 'src/timeMachine/components/view_options/ViewOptions' +// Actions +import {refreshTimeMachineVariableValues} from 'src/timeMachine/actions' + // Utils import {getActiveTimeMachine} from 'src/timeMachine/selectors' import {getTimeRangeVars} from 'src/variables/utils/getTimeRangeVars' +import {getVariableAssignments} from 'src/variables/selectors' // Types import {TimeMachineTab} from 'src/types/v2/timeMachine' import {AppState, DashboardQuery, TimeRange} from 'src/types/v2' +import {RemoteDataState} from 'src/types' +import {VariableAssignment} from 'src/types/ast' // Styles import 'src/timeMachine/components/TimeMachine.scss' @@ -29,35 +36,54 @@ interface StateProps { submitToken: number timeRange: TimeRange activeTab: TimeMachineTab + variableAssignments: VariableAssignment[] +} + +interface DispatchProps { + onRefreshVariableValues: () => Promise } interface State { resizerHandlePosition: number[] + initialLoadingStatus: RemoteDataState } -type Props = StateProps +type Props = StateProps & DispatchProps class TimeMachine extends Component { - constructor(props: Props) { - super(props) + public state: State = { + resizerHandlePosition: [INITIAL_RESIZER_HANDLE], + initialLoadingStatus: RemoteDataState.Loading, + } - this.state = { - resizerHandlePosition: [INITIAL_RESIZER_HANDLE], + public async componentDidMount() { + try { + await this.props.onRefreshVariableValues() + } catch (e) { + console.log(e) } + + // Even if refreshing the variable values fails, most of the `TimeMachine` + // can continue to function. So we set the status to `Done` whether or not + // the refresh is successful + this.setState({initialLoadingStatus: RemoteDataState.Done}) } public render() { - const {queries, submitToken, timeRange} = this.props - const {resizerHandlePosition} = this.state + const {queries, submitToken} = this.props + const {resizerHandlePosition, initialLoadingStatus} = this.state return ( - <> + } + >
{queriesState => ( {
{this.viewOptions} - +
) } @@ -90,8 +116,10 @@ class TimeMachine extends Component { } } - private handleResizerChange = (resizerHandlePosition: number[]): void => { - this.setState({resizerHandlePosition}) + private get variableAssignments(): VariableAssignment[] { + const {variableAssignments, timeRange} = this.props + + return [...variableAssignments, ...getTimeRangeVars(timeRange)] } private get containerClassName(): string { @@ -101,19 +129,27 @@ class TimeMachine extends Component { 'time-machine--split': activeTab === TimeMachineTab.Visualization, }) } + + private handleResizerChange = (resizerHandlePosition: number[]): void => { + this.setState({resizerHandlePosition}) + } } const mstp = (state: AppState) => { const timeMachine = getActiveTimeMachine(state) - const {activeTab} = getActiveTimeMachine(state) - const {timeRange} = timeMachine + const {activeTab, timeRange, submitToken} = timeMachine const queries = get(timeMachine, 'view.properties.queries', []) - const submitToken = timeMachine.submitToken + const {activeTimeMachineID} = state.timeMachines + const variableAssignments = getVariableAssignments(state, activeTimeMachineID) - return {queries, submitToken, timeRange, activeTab} + return {queries, submitToken, timeRange, activeTab, variableAssignments} } -export default connect( +const mdtp = { + onRefreshVariableValues: refreshTimeMachineVariableValues as any, +} + +export default connect( mstp, - null + mdtp )(TimeMachine)