From 35bcd28e81a9d1d8f0a15a1adba248f33670e6c5 Mon Sep 17 00:00:00 2001 From: Filip Barl Date: Tue, 12 Jun 2018 11:35:33 +0200 Subject: [PATCH 1/3] Show timeline deployments. --- .../scripts/components/time-travel-wrapper.js | 41 ++++++++----------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/client/app/scripts/components/time-travel-wrapper.js b/client/app/scripts/components/time-travel-wrapper.js index 6572203d0..20ad96b37 100644 --- a/client/app/scripts/components/time-travel-wrapper.js +++ b/client/app/scripts/components/time-travel-wrapper.js @@ -2,25 +2,14 @@ import React from 'react'; import moment from 'moment'; import { connect } from 'react-redux'; import { TimeTravel } from 'weaveworks-ui-components'; +import { get, orderBy } from 'lodash'; import { trackAnalyticsEvent } from '../utils/tracking-utils'; import { jumpToTime, resumeTime, pauseTimeAtNow } from '../actions/app-actions'; class TimeTravelWrapper extends React.Component { - constructor(props, context) { - super(props, context); - - this.handleLiveModeChange = this.handleLiveModeChange.bind(this); - - 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); - } - - trackTimestampEdit() { + trackTimestampEdit = () => { trackAnalyticsEvent('scope.time.timestamp.edit', { layout: this.props.topologyViewMode, topologyId: this.props.currentTopology.get('id'), @@ -28,7 +17,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 +25,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 +33,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 +41,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 +50,7 @@ class TimeTravelWrapper extends React.Component { }); } - handleLiveModeChange(showingLive) { + handleLiveModeChange = (showingLive) => { if (showingLive) { this.props.resumeTime(); } else { @@ -79,6 +68,7 @@ class TimeTravelWrapper extends React.Component { timestamp={this.props.timestamp} earliestTimestamp={this.props.earliestTimestamp} onChangeTimestamp={this.props.jumpToTime} + deployments={this.props.deployments} onTimestampInputEdit={this.trackTimestampEdit} onTimelinePanButtonClick={this.trackTimelinePanButtonClick} onTimelineLabelClick={this.trackTimelineLabelClick} @@ -91,23 +81,26 @@ class TimeTravelWrapper extends React.Component { } function mapStateToProps(state, { params }) { - const scopeState = state.scope || state; + const orgId = params && params.orgId; let firstSeenConnectedAt; // If we're in the Weave Cloud context, use firstSeeConnectedAt as the earliest timestamp. if (state.root && state.root.instances) { - const serviceInstance = state.root.instances[params && params.orgId]; + const serviceInstance = state.root.instances[orgId]; if (serviceInstance && serviceInstance.firstSeenConnectedAt) { firstSeenConnectedAt = moment(serviceInstance.firstSeenConnectedAt).utc().format(); } } + const unsortedDeployments = get(state, ['root', 'fluxInstanceHistory', orgId, ''], []); + return { - showingLive: !scopeState.get('pausedAt'), - topologyViewMode: scopeState.get('topologyViewMode'), - currentTopology: scopeState.get('currentTopology'), + showingLive: !state.scope.get('pausedAt'), + topologyViewMode: state.scope.get('topologyViewMode'), + currentTopology: state.scope.get('currentTopology'), + deployments: orderBy(unsortedDeployments, ['Stamp'], ['desc']), earliestTimestamp: firstSeenConnectedAt, - timestamp: scopeState.get('pausedAt'), + timestamp: state.scope.get('pausedAt'), }; } From a096f2f76a949167cdcacfc888de823466b4e205 Mon Sep 17 00:00:00 2001 From: Filip Barl Date: Tue, 12 Jun 2018 15:05:50 +0200 Subject: [PATCH 2/3] Reloading deployments in Time Travel. --- client/app/scripts/actions/app-actions.js | 6 ++ .../scripts/components/time-travel-wrapper.js | 70 +++++++++++++++++-- client/app/styles/_base.scss | 5 ++ client/package.json | 2 +- client/yarn.lock | 6 +- 5 files changed, 80 insertions(+), 9 deletions(-) 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 20ad96b37..44737d837 100644 --- a/client/app/scripts/components/time-travel-wrapper.js +++ b/client/app/scripts/components/time-travel-wrapper.js @@ -2,13 +2,30 @@ import React from 'react'; import moment from 'moment'; import { connect } from 'react-redux'; import { TimeTravel } from 'weaveworks-ui-components'; -import { get, orderBy } from 'lodash'; +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) { + super(props); + + this.state = { + isLoadingDeployments: false, + visibleRangeStartAtSec: null, + visibleRangeEndAtSec: null, + }; + + this.debouncedUpdateVisibleRange = debounce(this.updateVisibleRange, 500); + } + trackTimestampEdit = () => { trackAnalyticsEvent('scope.time.timestamp.edit', { layout: this.props.topologyViewMode, @@ -58,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 (
'], []); + const unsortedDeployments = get( + state, + ['root', 'fluxInstanceHistory', orgId, FLUX_ALL_SERVICES], + [] + ); return { showingLive: !state.scope.get('pausedAt'), @@ -106,5 +164,7 @@ function mapStateToProps(state, { params }) { export default connect( mapStateToProps, - { jumpToTime, resumeTime, pauseTimeAtNow }, + { + jumpToTime, resumeTime, pauseTimeAtNow, getFluxHistory + }, )(TimeTravelWrapper); diff --git a/client/app/styles/_base.scss b/client/app/styles/_base.scss index 3aa433bc6..5dbb1cb8d 100644 --- a/client/app/styles/_base.scss +++ b/client/app/styles/_base.scss @@ -212,6 +212,11 @@ a { pointer-events: none; width: 100%; + .time-travel-wrapper { + position: relative; + z-index: $layer-front; + } + .selectors { display: flex; position: relative; 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" From b9b8e5afd36436b66dc9fee8ef0a4bb2a298c7af Mon Sep 17 00:00:00 2001 From: Filip Barl Date: Tue, 12 Jun 2018 15:16:18 +0200 Subject: [PATCH 3/3] Fix z-index issues. --- client/app/styles/_base.scss | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/client/app/styles/_base.scss b/client/app/styles/_base.scss index 5dbb1cb8d..f47e356f2 100644 --- a/client/app/styles/_base.scss +++ b/client/app/styles/_base.scss @@ -208,26 +208,20 @@ a { } .header { + z-index: $layer-front; padding: 15px 10px 0; pointer-events: none; + position: relative; width: 100%; - .time-travel-wrapper { - position: relative; - z-index: $layer-front; - } - .selectors { display: flex; position: relative; > * { - z-index: $layer-front; flex: 1 1; } - .time-control { z-index: $layer-modal; } - .logo { margin: -16px 0 0 8px; height: 64px;