Skip to content

Commit

Permalink
Addressed some of David's comments.
Browse files Browse the repository at this point in the history
  • Loading branch information
fbarl committed Jun 6, 2017
1 parent 6a12f86 commit fcb76db
Show file tree
Hide file tree
Showing 12 changed files with 142 additions and 86 deletions.
24 changes: 13 additions & 11 deletions client/app/scripts/actions/app-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
doControlRequest,
getAllNodes,
getResourceViewNodesSnapshot,
updateNodesDeltaChannel,
updateWebsocketChannel,
getNodeDetails,
getTopologies,
deletePipe,
Expand Down Expand Up @@ -214,7 +214,7 @@ export function changeTopologyOption(option, value, topologyId, addOrRemove) {
resetUpdateBuffer();
const state = getState();
getTopologies(activeTopologyOptionsSelector(state), dispatch);
updateNodesDeltaChannel(state, dispatch);
updateWebsocketChannel(state, dispatch);
getNodeDetails(
state.get('topologyUrlsById'),
state.get('currentTopologyId'),
Expand Down Expand Up @@ -404,7 +404,7 @@ function updateTopology(dispatch, getState) {
// NOTE: This is currently not needed for our static resource
// view, but we'll need it here later and it's simpler to just
// keep it than to redo the nodes delta updating logic.
updateNodesDeltaChannel(state, dispatch);
updateWebsocketChannel(state, dispatch);
}

export function clickShowTopologyForNode(topologyId, nodeId) {
Expand Down Expand Up @@ -434,21 +434,23 @@ export function startMovingInTime() {
};
}

export function websocketQueryTimestamp(timestamp) {
export function websocketQueryTimestamp(queryTimestamp) {
const requestTimestamp = moment();
// If the timestamp stands for a time less than one second ago,
// assume we are actually interested in the current time.
if (timestamp && moment().diff(timestamp) >= 1000) {
timestamp = timestamp.toISOString();
if (requestTimestamp.diff(queryTimestamp) >= 1000) {
queryTimestamp = queryTimestamp.toISOString();
} else {
timestamp = null;
queryTimestamp = null;
}

return (dispatch, getState) => {
dispatch({
type: ActionTypes.WEBSOCKET_QUERY_TIMESTAMP,
timestamp,
requestTimestamp,
queryTimestamp,
});
updateNodesDeltaChannel(getState(), dispatch);
updateWebsocketChannel(getState(), dispatch);
// update all request workers with new options
resetUpdateBuffer();
};
Expand Down Expand Up @@ -641,7 +643,7 @@ export function receiveTopologies(topologies) {
topologies
});
const state = getState();
updateNodesDeltaChannel(state, dispatch);
updateWebsocketChannel(state, dispatch);
getNodeDetails(
state.get('topologyUrlsById'),
state.get('currentTopologyId'),
Expand Down Expand Up @@ -758,7 +760,7 @@ export function route(urlState) {
// update all request workers with new options
const state = getState();
getTopologies(activeTopologyOptionsSelector(state), dispatch);
updateNodesDeltaChannel(state, dispatch);
updateWebsocketChannel(state, dispatch);
getNodeDetails(
state.get('topologyUrlsById'),
state.get('currentTopologyId'),
Expand Down
2 changes: 1 addition & 1 deletion client/app/scripts/charts/nodes-layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ export function doLayout(immNodes, immEdges, opts) {
const cacheId = buildTopologyCacheId(options.topologyId, options.topologyOptions);

// one engine and node and edge caches per topology, to keep renderings similar
if (true || options.noCache || !topologyCaches[cacheId]) {
if (options.noCache || !topologyCaches[cacheId]) {
topologyCaches[cacheId] = {
nodeCache: makeMap(),
edgeCache: makeMap(),
Expand Down
10 changes: 6 additions & 4 deletions client/app/scripts/components/nodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ import {
import { TOPOLOGY_LOADER_DELAY } from '../constants/timer';


// TODO: The information that we already have available on the frontend should enable
// us to determine which of these cases exactly is preventing us from seeing the nodes.
const NODE_COUNT_ZERO_CAUSES = [
"We haven't received any reports from probes recently. Are the probes properly connected?",
"Containers view only: you're not running Docker, or you don't have any containers",
'We haven\'t received any reports from probes recently. Are the probes properly connected?',
'Containers view only: you\'re not running Docker, or you don\'t have any containers',
];

const NODES_DISPLAY_EMPTY_CAUSES = [
"There are nodes, but they're currently hidden. Check the view options in the bottom-left if they allow for showing hidden nodes.",
'There are nodes, but they\'re currently hidden. Check the view options in the bottom-left if they allow for showing hidden nodes.',
'There are no nodes for this particular moment in time. Use the timeline feature at the bottom-right corner to explore different times.',
];

const renderCauses = causes => (
Expand Down
34 changes: 0 additions & 34 deletions client/app/scripts/components/running-time.js

This file was deleted.

2 changes: 1 addition & 1 deletion client/app/scripts/components/status.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ function mapStateToProps(state) {
return {
errorUrl: state.get('errorUrl'),
filteredNodeCount: state.get('nodes').filter(node => node.get('filtered')).size,
showingCurrentState: !state.get('websocketQueryTimestamp'),
showingCurrentState: !state.get('websocketQueryPastAt'),
topologiesLoaded: state.get('topologiesLoaded'),
topology: state.get('currentTopology'),
websocketClosed: state.get('websocketClosed'),
Expand Down
24 changes: 13 additions & 11 deletions client/app/scripts/components/timeline-control.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import classNames from 'classnames';
import { connect } from 'react-redux';
import { debounce } from 'lodash';

import RunningTime from './running-time';
import TopologyTimestampInfo from './topology-timestamp-info';
import { getUpdateBufferSize } from '../utils/update-buffer-utils';
import {
clickPauseUpdate,
Expand Down Expand Up @@ -100,6 +100,13 @@ const sliderRanges = {
},
};

// <div className="column">
// {this.renderRangeOption(sliderRanges.yesterday)}
// {this.renderRangeOption(sliderRanges.previousWeek)}
// {this.renderRangeOption(sliderRanges.previousMonth)}
// {this.renderRangeOption(sliderRanges.previousYear)}
// </div>

class TimelineControl extends React.PureComponent {
constructor(props, context) {
super(props, context);
Expand Down Expand Up @@ -199,7 +206,7 @@ class TimelineControl extends React.PureComponent {
return (
<div className="timeline-control">
{showTimelinePanel && <div className="timeline-panel">
<strong>Move the slider to explore</strong>
<strong>Explore</strong>
<div className="options">
<div className="column">
{this.renderRangeOption(sliderRanges.last15Minutes)}
Expand All @@ -219,31 +226,26 @@ class TimelineControl extends React.PureComponent {
{this.renderRangeOption(sliderRanges.thisMonthSoFar)}
{this.renderRangeOption(sliderRanges.thisYearSoFar)}
</div>
<div className="column">
{this.renderRangeOption(sliderRanges.yesterday)}
{this.renderRangeOption(sliderRanges.previousWeek)}
{this.renderRangeOption(sliderRanges.previousMonth)}
{this.renderRangeOption(sliderRanges.previousYear)}
</div>
</div>
<strong>Move the slider to travel in time</strong>
<Slider
onChange={this.handleSliderChange}
value={rangeMilliseconds - offsetMilliseconds}
max={rangeMilliseconds}
/>
</div>}
<div className={timeStatusClassName}>
<RunningTime offsetMilliseconds={this.getTotalOffset()} />
<a className={toggleButtonClassName} onClick={this.toggleTimelinePanel}>
<TopologyTimestampInfo />
<span className="fa fa-clock-o" />
</a>
<a className="button" onClick={pauseAction} title={pauseTitle}>
{pauseLabel !== '' && <span>{pauseLabel}</span>}
{pauseLabel !== '' && <span className="pause-text">{pauseLabel}</span>}
<span className="fa fa-pause" />
</a>
{!showingCurrent && <a
className="button jump-to-now"
title="Jump to current state"
title="Jump to now"
onClick={this.jumpToNow}>
<span className="fa fa-step-forward" />
</a>}
Expand Down
71 changes: 71 additions & 0 deletions client/app/scripts/components/topology-timestamp-info.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React from 'react';
import moment from 'moment';
import { connect } from 'react-redux';


const TIMESTAMP_TICK_INTERVAL = 500;

class TopologyTimestampInfo extends React.PureComponent {
constructor(props, context) {
super(props, context);

this.state = this.getFreshState();
}

componentDidMount() {
this.timer = setInterval(() => {
if (!this.props.paused) {
this.setState(this.getFreshState());
}
}, TIMESTAMP_TICK_INTERVAL);
}

componentWillUnmount() {
clearInterval(this.timer);
}

getFreshState() {
const { updatePausedAt, websocketQueryPastAt, websocketQueryPastRequestMadeAt } = this.props;

let timestamp = updatePausedAt;
let showingCurrentState = false;

if (!updatePausedAt) {
timestamp = moment().utc();
showingCurrentState = true;

if (websocketQueryPastAt) {
const offset = moment(websocketQueryPastRequestMadeAt).diff(moment(websocketQueryPastAt));
timestamp = timestamp.subtract(offset);
showingCurrentState = false;
}
}
return { timestamp, showingCurrentState };
}

renderTimestamp() {
return (
<time>{this.state.timestamp.format('MMMM Do YYYY, h:mm:ss a')}</time>
);
}

render() {
const { showingCurrentState } = this.state;

return (
<span className="topology-timestamp-info">
{showingCurrentState ? 'now' : this.renderTimestamp()}
</span>
);
}
}

function mapStateToProps(state) {
return {
updatePausedAt: state.get('updatePausedAt'),
websocketQueryPastAt: state.get('websocketQueryPastAt'),
websocketQueryPastRequestMadeAt: state.get('websocketQueryPastRequestMadeAt'),
};
}

export default connect(mapStateToProps)(TopologyTimestampInfo);
9 changes: 9 additions & 0 deletions client/app/scripts/reducers/__tests__/root-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import expect from 'expect';
import { TABLE_VIEW_MODE } from '../../constants/naming';
// Root reducer test suite using Jasmine matchers
import { constructEdgeId } from '../../utils/layouter-utils';
// import { isResourceViewModeSelector } from '../../selectors/topology';

describe('RootReducer', () => {
const ActionTypes = require('../../constants/action-types').default;
Expand All @@ -15,6 +16,7 @@ describe('RootReducer', () => {
const activeTopologyOptionsSelector = topologySelectors.activeTopologyOptionsSelector;
const getAdjacentNodes = topologyUtils.getAdjacentNodes;
const isTopologyEmpty = topologyUtils.isTopologyEmpty;
const isNodesDisplayEmpty = topologyUtils.isNodesDisplayEmpty;
const getUrlState = require('../../utils/router-utils').getUrlState;

// fixtures
Expand Down Expand Up @@ -536,12 +538,19 @@ describe('RootReducer', () => {
let nextState = initialState;
nextState = reducer(nextState, ReceiveTopologiesAction);
nextState = reducer(nextState, ClickTopologyAction);
expect(isTopologyEmpty(nextState)).toBeTruthy();

nextState = reducer(nextState, ReceiveNodesDeltaAction);
expect(isTopologyEmpty(nextState)).toBeFalsy();

nextState = reducer(nextState, ClickTopology2Action);
nextState = reducer(nextState, ReceiveNodesDeltaAction);
expect(isTopologyEmpty(nextState)).toBeTruthy();

nextState = reducer(nextState, ClickTopologyAction);
expect(isTopologyEmpty(nextState)).toBeTruthy();

nextState = reducer(nextState, ReceiveNodesDeltaAction);
expect(isTopologyEmpty(nextState)).toBeFalsy();
});

Expand Down
10 changes: 7 additions & 3 deletions client/app/scripts/reducers/root.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable import/no-webpack-loader-syntax, import/no-unresolved */
import debug from 'debug';
import moment from 'moment';
import { size, each, includes, isEqual } from 'lodash';
import {
fromJS,
Expand Down Expand Up @@ -90,7 +91,8 @@ export const initialState = makeMap({
viewport: makeMap(),
websocketClosed: false,
websocketMovingInTime: false,
websocketQueryTimestamp: null,
websocketQueryPastAt: null,
websocketQueryPastRequestMadeAt: null,
zoomCache: makeMap(),
serviceImages: makeMap()
});
Expand Down Expand Up @@ -293,7 +295,7 @@ export function rootReducer(state = initialState, action) {
}

case ActionTypes.CLICK_PAUSE_UPDATE: {
return state.set('updatePausedAt', new Date());
return state.set('updatePausedAt', moment().utc());
}

case ActionTypes.CLICK_RELATIVE: {
Expand Down Expand Up @@ -353,7 +355,9 @@ export function rootReducer(state = initialState, action) {
}

case ActionTypes.WEBSOCKET_QUERY_TIMESTAMP: {
return state.set('websocketQueryTimestamp', action.timestamp);
const websocketPastRequestMadeAt = action.queryTimestamp ? action.requestTimestamp : null;
state = state.set('websocketQueryPastRequestMadeAt', websocketPastRequestMadeAt);
return state.set('websocketQueryPastAt', action.queryTimestamp);
}

case ActionTypes.CLOSE_WEBSOCKET: {
Expand Down
4 changes: 2 additions & 2 deletions client/app/scripts/utils/web-api-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,10 +236,10 @@ export function getTopologies(options, dispatch, initialPoll) {
});
}

export function updateNodesDeltaChannel(state, dispatch) {
export function updateWebsocketChannel(state, dispatch) {
const topologyUrl = getCurrentTopologyUrl(state);
const topologyOptions = activeTopologyOptionsSelector(state);
const queryTimestamp = state.get('websocketQueryTimestamp');
const queryTimestamp = state.get('websocketQueryPastAt');
const websocketUrl = buildWebsocketUrl(topologyUrl, topologyOptions, queryTimestamp);
// Only recreate websocket if url changed or if forced (weave cloud instance reload);
const isNewUrl = websocketUrl !== currentUrl;
Expand Down
Loading

0 comments on commit fcb76db

Please sign in to comment.