Merge pull request #3222 from weaveworks/2614-show-timeline-deployments

Show deployments in Time Travel
This commit is contained in:
Filip Barl
2018-06-12 17:47:16 +02:00
committed by GitHub
5 changed files with 87 additions and 29 deletions

View File

@@ -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,

View File

@@ -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 = '<all>';
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 (
<div className="tour-step-anchor time-travel-wrapper">
<TimeTravel
@@ -79,6 +120,9 @@ class TimeTravelWrapper extends React.Component {
timestamp={this.props.timestamp}
earliestTimestamp={this.props.earliestTimestamp}
onChangeTimestamp={this.props.jumpToTime}
deployments={visibleDeployments}
isLoading={this.state.isLoadingDeployments}
onUpdateVisibleRange={this.debouncedUpdateVisibleRange}
onTimestampInputEdit={this.trackTimestampEdit}
onTimelinePanButtonClick={this.trackTimelinePanButtonClick}
onTimelineLabelClick={this.trackTimelineLabelClick}
@@ -91,27 +135,36 @@ 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, FLUX_ALL_SERVICES],
[]
);
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'),
};
}
export default connect(
mapStateToProps,
{ jumpToTime, resumeTime, pauseTimeAtNow },
{
jumpToTime, resumeTime, pauseTimeAtNow, getFluxHistory
},
)(TimeTravelWrapper);

View File

@@ -208,8 +208,10 @@ a {
}
.header {
z-index: $layer-front;
padding: 15px 10px 0;
pointer-events: none;
position: relative;
width: 100%;
.selectors {
@@ -217,12 +219,9 @@ a {
position: relative;
> * {
z-index: $layer-front;
flex: 1 1;
}
.time-control { z-index: $layer-modal; }
.logo {
margin: -16px 0 0 8px;
height: 64px;

View File

@@ -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"
},

View File

@@ -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"