diff --git a/client/app/scripts/actions/app-actions.js b/client/app/scripts/actions/app-actions.js index afa805db3..67db35ee2 100644 --- a/client/app/scripts/actions/app-actions.js +++ b/client/app/scripts/actions/app-actions.js @@ -870,6 +870,12 @@ export function getImagesForService(orgId, serviceId) { }; } +export function getFluxHistory(...params) { + return (dispatch, getState, { actions }) => ( + dispatch(actions.getFluxHistory(...params)) + ); +} + export function setMonitorState(monitor) { return { type: ActionTypes.MONITOR_STATE, diff --git a/client/app/scripts/components/time-travel-wrapper.js b/client/app/scripts/components/time-travel-wrapper.js index 6572203d0..44737d837 100644 --- a/client/app/scripts/components/time-travel-wrapper.js +++ b/client/app/scripts/components/time-travel-wrapper.js @@ -2,25 +2,31 @@ import React from 'react'; import moment from 'moment'; import { connect } from 'react-redux'; import { TimeTravel } from 'weaveworks-ui-components'; +import { get, orderBy, debounce } from 'lodash'; import { trackAnalyticsEvent } from '../utils/tracking-utils'; -import { jumpToTime, resumeTime, pauseTimeAtNow } from '../actions/app-actions'; +import { jumpToTime, resumeTime, pauseTimeAtNow, getFluxHistory } from '../actions/app-actions'; +// Load deployments in timeline only on zoom levels up to this range. +const MAX_DEPLOYMENTS_RANGE_SECS = moment.duration(2, 'weeks').asSeconds(); + +// Reused from Service UI. +const FLUX_ALL_SERVICES = ''; class TimeTravelWrapper extends React.Component { - constructor(props, context) { - super(props, context); + constructor(props) { + super(props); - this.handleLiveModeChange = this.handleLiveModeChange.bind(this); + this.state = { + isLoadingDeployments: false, + visibleRangeStartAtSec: null, + visibleRangeEndAtSec: null, + }; - this.trackTimestampEdit = this.trackTimestampEdit.bind(this); - this.trackTimelinePanButtonClick = this.trackTimelinePanButtonClick.bind(this); - this.trackTimelineLabelClick = this.trackTimelineLabelClick.bind(this); - this.trackTimelineZoom = this.trackTimelineZoom.bind(this); - this.trackTimelinePan = this.trackTimelinePan.bind(this); + this.debouncedUpdateVisibleRange = debounce(this.updateVisibleRange, 500); } - trackTimestampEdit() { + trackTimestampEdit = () => { trackAnalyticsEvent('scope.time.timestamp.edit', { layout: this.props.topologyViewMode, topologyId: this.props.currentTopology.get('id'), @@ -28,7 +34,7 @@ class TimeTravelWrapper extends React.Component { }); } - trackTimelinePanButtonClick() { + trackTimelinePanButtonClick = () => { trackAnalyticsEvent('scope.time.timeline.pan.button.click', { layout: this.props.topologyViewMode, topologyId: this.props.currentTopology.get('id'), @@ -36,7 +42,7 @@ class TimeTravelWrapper extends React.Component { }); } - trackTimelineLabelClick() { + trackTimelineLabelClick = () => { trackAnalyticsEvent('scope.time.timeline.label.click', { layout: this.props.topologyViewMode, topologyId: this.props.currentTopology.get('id'), @@ -44,7 +50,7 @@ class TimeTravelWrapper extends React.Component { }); } - trackTimelinePan() { + trackTimelinePan = () => { trackAnalyticsEvent('scope.time.timeline.pan', { layout: this.props.topologyViewMode, topologyId: this.props.currentTopology.get('id'), @@ -52,7 +58,7 @@ class TimeTravelWrapper extends React.Component { }); } - trackTimelineZoom(zoomedPeriod) { + trackTimelineZoom = (zoomedPeriod) => { trackAnalyticsEvent('scope.time.timeline.zoom', { layout: this.props.topologyViewMode, topologyId: this.props.currentTopology.get('id'), @@ -61,7 +67,7 @@ class TimeTravelWrapper extends React.Component { }); } - handleLiveModeChange(showingLive) { + handleLiveModeChange = (showingLive) => { if (showingLive) { this.props.resumeTime(); } else { @@ -69,7 +75,42 @@ class TimeTravelWrapper extends React.Component { } } + + updateVisibleRange = ({ startAt, endAt }) => { + const { orgId } = this.props.params; + + const visibleRangeEndAtSec = moment(endAt).unix(); + const visibleRangeStartAtSec = moment(startAt).unix(); + this.setState({ visibleRangeStartAtSec, visibleRangeEndAtSec }); + + // Load deployment annotations only if not zoomed out too much. + // See https://github.com/weaveworks/service-ui/issues/1858. + const visibleRangeSec = visibleRangeEndAtSec - visibleRangeStartAtSec; + if (visibleRangeSec < MAX_DEPLOYMENTS_RANGE_SECS) { + this.setState({ isLoadingDeployments: true }); + this.props + .getFluxHistory(orgId, FLUX_ALL_SERVICES, null, endAt, true, startAt) + .then(() => { + this.setState({ isLoadingDeployments: false }); + }); + } + } + render() { + const { + visibleRangeStartAtSec, + visibleRangeEndAtSec, + } = this.state; + + // Don't pass any deployments that are outside of the timeline visible range. + const visibleDeployments = this.props.deployments.filter((deployment) => { + const deploymentAtSec = moment(deployment.Stamp).unix(); + return ( + visibleRangeStartAtSec <= deploymentAtSec && + deploymentAtSec <= visibleRangeEndAtSec + ); + }); + return (
* { - z-index: $layer-front; flex: 1 1; } - .time-control { z-index: $layer-modal; } - .logo { margin: -16px 0 0 8px; height: 64px; diff --git a/client/package.json b/client/package.json index 689c934e7..528e96235 100644 --- a/client/package.json +++ b/client/package.json @@ -44,7 +44,7 @@ "reselect": "3.0.1", "reselect-map": "1.0.3", "styled-components": "2.2.4", - "weaveworks-ui-components": "0.4.82", + "weaveworks-ui-components": "0.4.95", "whatwg-fetch": "2.0.3", "xterm": "3.3.0" }, diff --git a/client/yarn.lock b/client/yarn.lock index e169eb98d..78ccda3fd 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -8345,9 +8345,9 @@ wd@^0.4.0: underscore.string "~3.0.3" vargs "~0.1.0" -weaveworks-ui-components@0.4.82: - version "0.4.82" - resolved "https://registry.yarnpkg.com/weaveworks-ui-components/-/weaveworks-ui-components-0.4.82.tgz#c09cd529f59d553e2a3d426413e4f59f7e23d6d2" +weaveworks-ui-components@0.4.95: + version "0.4.95" + resolved "https://registry.yarnpkg.com/weaveworks-ui-components/-/weaveworks-ui-components-0.4.95.tgz#6f80f8e00e4fcef06033cadc377588bc3ed443fa" dependencies: classnames "2.2.5" d3-drag "1.2.1"