diff --git a/client/app/scripts/components/time-travel-component.js b/client/app/scripts/components/time-travel-component.js new file mode 100644 index 000000000..a962eb7b0 --- /dev/null +++ b/client/app/scripts/components/time-travel-component.js @@ -0,0 +1,144 @@ +import React from 'react'; +import moment from 'moment'; +import classNames from 'classnames'; +import { connect } from 'react-redux'; +import { debounce } from 'lodash'; + +import TimeTravelTimeline from './time-travel-timeline'; +import { trackAnalyticsEvent } from '../utils/tracking-utils'; +import { clampToNowInSecondsPrecision } from '../utils/time-utils'; +import { + jumpToTime, + resumeTime, + timeTravelStartTransition, +} from '../actions/app-actions'; + +import { TIMELINE_DEBOUNCE_INTERVAL } from '../constants/timer'; + + +const getTimestampStates = (timestamp) => { + timestamp = timestamp || moment(); + return { + inputValue: moment(timestamp).utc().format(), + }; +}; + +class TimeTravelComponent extends React.Component { + constructor(props, context) { + super(props, context); + + this.state = getTimestampStates(props.timestamp); + + this.handleInputChange = this.handleInputChange.bind(this); + this.handleTimelinePan = this.handleTimelinePan.bind(this); + this.handleTimelinePanEnd = this.handleTimelinePanEnd.bind(this); + this.handleInstantJump = this.handleInstantJump.bind(this); + + this.trackTimestampEdit = this.trackTimestampEdit.bind(this); + this.trackTimelineClick = this.trackTimelineClick.bind(this); + this.trackTimelinePan = this.trackTimelinePan.bind(this); + + this.instantUpdateTimestamp = this.instantUpdateTimestamp.bind(this); + this.debouncedUpdateTimestamp = debounce( + this.instantUpdateTimestamp.bind(this), TIMELINE_DEBOUNCE_INTERVAL); + } + + componentWillReceiveProps(props) { + this.setState(getTimestampStates(props.timestamp)); + } + + handleInputChange(ev) { + const timestamp = moment(ev.target.value); + this.setState({ inputValue: ev.target.value }); + + if (timestamp.isValid()) { + const clampedTimestamp = clampToNowInSecondsPrecision(timestamp); + this.instantUpdateTimestamp(clampedTimestamp, this.trackTimestampEdit); + } + } + + handleTimelinePan(timestamp) { + this.setState(getTimestampStates(timestamp)); + this.debouncedUpdateTimestamp(timestamp); + } + + handleTimelinePanEnd(timestamp) { + this.instantUpdateTimestamp(timestamp, this.trackTimelinePan); + } + + handleInstantJump(timestamp) { + this.instantUpdateTimestamp(timestamp, this.trackTimelineClick); + } + + instantUpdateTimestamp(timestamp, callback) { + if (!timestamp.isSame(this.props.timestamp)) { + this.debouncedUpdateTimestamp.cancel(); + this.setState(getTimestampStates(timestamp)); + this.props.timeTravelStartTransition(); + this.props.jumpToTime(moment(timestamp)); + + // Used for tracking. + if (callback) callback(); + } + } + + trackTimestampEdit() { + trackAnalyticsEvent('scope.time.timestamp.edit', { + layout: this.props.topologyViewMode, + topologyId: this.props.currentTopology.get('id'), + parentTopologyId: this.props.currentTopology.get('parentId'), + }); + } + + trackTimelineClick() { + trackAnalyticsEvent('scope.time.timeline.click', { + layout: this.props.topologyViewMode, + topologyId: this.props.currentTopology.get('id'), + parentTopologyId: this.props.currentTopology.get('parentId'), + }); + } + + trackTimelinePan() { + trackAnalyticsEvent('scope.time.timeline.pan', { + layout: this.props.topologyViewMode, + topologyId: this.props.currentTopology.get('id'), + parentTopologyId: this.props.currentTopology.get('parentId'), + }); + } + + render() { + const { visible } = this.props; + + return ( +
+ +
+ UTC +
+
+ ); + } +} + +function mapStateToProps(state) { + return { + topologyViewMode: state.get('topologyViewMode'), + currentTopology: state.get('currentTopology'), + }; +} + +export default connect( + mapStateToProps, + { + jumpToTime, + resumeTime, + timeTravelStartTransition, + } +)(TimeTravelComponent); diff --git a/client/app/scripts/components/time-travel.js b/client/app/scripts/components/time-travel.js index 79528bb2a..672747c5b 100644 --- a/client/app/scripts/components/time-travel.js +++ b/client/app/scripts/components/time-travel.js @@ -1,144 +1,29 @@ import React from 'react'; -import moment from 'moment'; -import classNames from 'classnames'; import { connect } from 'react-redux'; -import { debounce } from 'lodash'; -import TimeTravelTimeline from './time-travel-timeline'; -import { trackAnalyticsEvent } from '../utils/tracking-utils'; -import { clampToNowInSecondsPrecision } from '../utils/time-utils'; -import { - jumpToTime, - resumeTime, - timeTravelStartTransition, -} from '../actions/app-actions'; +import TimeTravelComponent from './time-travel-component'; -import { TIMELINE_DEBOUNCE_INTERVAL } from '../constants/timer'; - - -const getTimestampStates = (timestamp) => { - timestamp = timestamp || moment(); - return { - inputValue: moment(timestamp).utc().format(), - }; -}; class TimeTravel extends React.Component { - constructor(props, context) { - super(props, context); - - this.state = getTimestampStates(props.pausedAt); - - this.handleInputChange = this.handleInputChange.bind(this); - this.handleTimelinePan = this.handleTimelinePan.bind(this); - this.handleTimelinePanEnd = this.handleTimelinePanEnd.bind(this); - this.handleInstantJump = this.handleInstantJump.bind(this); - - this.trackTimestampEdit = this.trackTimestampEdit.bind(this); - this.trackTimelineClick = this.trackTimelineClick.bind(this); - this.trackTimelinePan = this.trackTimelinePan.bind(this); - - this.instantUpdateTimestamp = this.instantUpdateTimestamp.bind(this); - this.debouncedUpdateTimestamp = debounce( - this.instantUpdateTimestamp.bind(this), TIMELINE_DEBOUNCE_INTERVAL); - } - - componentWillReceiveProps(props) { - this.setState(getTimestampStates(props.pausedAt)); - } - - handleInputChange(ev) { - const timestamp = moment(ev.target.value); - this.setState({ inputValue: ev.target.value }); - - if (timestamp.isValid()) { - const clampedTimestamp = clampToNowInSecondsPrecision(timestamp); - this.instantUpdateTimestamp(clampedTimestamp, this.trackTimestampEdit); - } - } - - handleTimelinePan(timestamp) { - this.setState(getTimestampStates(timestamp)); - this.debouncedUpdateTimestamp(timestamp); - } - - handleTimelinePanEnd(timestamp) { - this.instantUpdateTimestamp(timestamp, this.trackTimelinePan); - } - - handleInstantJump(timestamp) { - this.instantUpdateTimestamp(timestamp, this.trackTimelineClick); - } - - instantUpdateTimestamp(timestamp, callback) { - if (!timestamp.isSame(this.props.pausedAt)) { - this.debouncedUpdateTimestamp.cancel(); - this.setState(getTimestampStates(timestamp)); - this.props.timeTravelStartTransition(); - this.props.jumpToTime(moment(timestamp)); - - // Used for tracking. - if (callback) callback(); - } - } - - trackTimestampEdit() { - trackAnalyticsEvent('scope.time.timestamp.edit', { - layout: this.props.topologyViewMode, - topologyId: this.props.currentTopology.get('id'), - parentTopologyId: this.props.currentTopology.get('parentId'), - }); - } - - trackTimelineClick() { - trackAnalyticsEvent('scope.time.timeline.click', { - layout: this.props.topologyViewMode, - topologyId: this.props.currentTopology.get('id'), - parentTopologyId: this.props.currentTopology.get('parentId'), - }); - } - - trackTimelinePan() { - trackAnalyticsEvent('scope.time.timeline.pan', { - layout: this.props.topologyViewMode, - topologyId: this.props.currentTopology.get('id'), - parentTopologyId: this.props.currentTopology.get('parentId'), - }); - } - render() { + const { visible, timestamp } = this.props; + return ( -
- -
- UTC -
-
+ ); } } function mapStateToProps(state) { return { - showingTimeTravel: state.get('showingTimeTravel'), - topologyViewMode: state.get('topologyViewMode'), - currentTopology: state.get('currentTopology'), - pausedAt: state.get('pausedAt'), + visible: state.get('showingTimeTravel'), + // topologyViewMode: state.get('topologyViewMode'), + // currentTopology: state.get('currentTopology'), + timestamp: state.get('pausedAt'), }; } -export default connect( - mapStateToProps, - { - jumpToTime, - resumeTime, - timeTravelStartTransition, - } -)(TimeTravel); +export default connect(mapStateToProps)(TimeTravel);