diff --git a/client/app/scripts/components/status.js b/client/app/scripts/components/status.js
index d9c98677a8..fc0219a296 100644
--- a/client/app/scripts/components/status.js
+++ b/client/app/scripts/components/status.js
@@ -1,6 +1,8 @@
import React from 'react';
import { connect } from 'react-redux';
+import { isWebsocketQueryingCurrentSelector } from '../selectors/timeline';
+
class Status extends React.Component {
render() {
@@ -25,13 +27,9 @@ class Status extends React.Component {
showWarningIcon = true;
} else if (topology) {
const stats = topology.get('stats');
- if (showingCurrentState) {
- text = `${stats.get('node_count') - filteredNodeCount} nodes`;
- if (stats.get('filtered_nodes')) {
- text = `${text} (${stats.get('filtered_nodes') + filteredNodeCount} filtered)`;
- }
- } else {
- text = '';
+ text = `${stats.get('node_count') - filteredNodeCount} nodes`;
+ if (stats.get('filtered_nodes')) {
+ text = `${text} (${stats.get('filtered_nodes') + filteredNodeCount} filtered)`;
}
classNames += ' status-stats';
showWarningIcon = false;
@@ -40,7 +38,7 @@ class Status extends React.Component {
return (
{showWarningIcon && }
- {text}
+ {showingCurrentState && text}
);
}
@@ -50,7 +48,7 @@ function mapStateToProps(state) {
return {
errorUrl: state.get('errorUrl'),
filteredNodeCount: state.get('nodes').filter(node => node.get('filtered')).size,
- showingCurrentState: !state.get('websocketTimestampOffset'),
+ showingCurrentState: isWebsocketQueryingCurrentSelector(state),
topologiesLoaded: state.get('topologiesLoaded'),
topology: state.get('currentTopology'),
websocketClosed: state.get('websocketClosed'),
diff --git a/client/app/scripts/reducers/root.js b/client/app/scripts/reducers/root.js
index 4369f742ac..2503880e78 100644
--- a/client/app/scripts/reducers/root.js
+++ b/client/app/scripts/reducers/root.js
@@ -87,7 +87,7 @@ export const initialState = makeMap({
topologyOptions: makeOrderedMap(), // topologyId -> options
topologyUrlsById: makeOrderedMap(), // topologyId -> topologyUrl
topologyViewMode: GRAPH_VIEW_MODE,
- updatePausedAt: null, // moment.js timestamp
+ updatePausedAt: null,
version: '...',
versionUpdate: null,
viewport: makeMap(),
@@ -616,6 +616,10 @@ export function rootReducer(state = initialState, action) {
state = state.set('errorUrl', null);
+ // When moving in time, we will consider the transition complete
+ // only when the first batch of nodes delta has been received. We
+ // do that because we want to keep the previous state blurred instead
+ // of transitioning over an empty state like when switching topologies.
if (state.get('websocketTransitioning')) {
state = state.set('websocketTransitioning', false);
state = clearNodes(state);
diff --git a/client/app/scripts/selectors/timeline.js b/client/app/scripts/selectors/timeline.js
index 1bb7b801e3..ae84cb43d8 100644
--- a/client/app/scripts/selectors/timeline.js
+++ b/client/app/scripts/selectors/timeline.js
@@ -7,3 +7,10 @@ export const isPausedSelector = createSelector(
],
updatePausedAt => updatePausedAt !== null
);
+
+export const isWebsocketQueryingCurrentSelector = createSelector(
+ [
+ state => state.get('websocketQueryMillisecondsInPast')
+ ],
+ websocketQueryMillisecondsInPast => websocketQueryMillisecondsInPast === 0
+);
diff --git a/client/app/scripts/utils/topology-utils.js b/client/app/scripts/utils/topology-utils.js
index f829bcbe27..40020711f8 100644
--- a/client/app/scripts/utils/topology-utils.js
+++ b/client/app/scripts/utils/topology-utils.js
@@ -1,6 +1,7 @@
import { endsWith } from 'lodash';
import { Set as makeSet, List as makeList } from 'immutable';
+import { isWebsocketQueryingCurrentSelector } from '../selectors/timeline';
import { isResourceViewModeSelector } from '../selectors/topology';
import { pinnedMetricSelector } from '../selectors/node-metric';
@@ -134,7 +135,8 @@ export function getCurrentTopologyOptions(state) {
}
export function isTopologyNodeCountZero(state) {
- return state.getIn(['currentTopology', 'stats', 'node_count'], 0) === 0;
+ const nodeCount = state.getIn(['currentTopology', 'stats', 'node_count'], 0);
+ return nodeCount === 0 && isWebsocketQueryingCurrentSelector(state);
}
export function isNodesDisplayEmpty(state) {
diff --git a/client/app/scripts/utils/web-api-utils.js b/client/app/scripts/utils/web-api-utils.js
index 25d3c0ea03..bfc5784902 100644
--- a/client/app/scripts/utils/web-api-utils.js
+++ b/client/app/scripts/utils/web-api-utils.js
@@ -13,6 +13,7 @@ import { blurSearch, clearControlError, closeWebsocket, openWebsocket, receiveEr
import { getCurrentTopologyUrl } from '../utils/topology-utils';
import { layersTopologyIdsSelector } from '../selectors/resource-view/layout';
import { activeTopologyOptionsSelector } from '../selectors/topology';
+import { isWebsocketQueryingCurrentSelector } from '../selectors/timeline';
import { API_REFRESH_INTERVAL, TOPOLOGY_REFRESH_INTERVAL } from '../constants/timer';
const log = debug('scope:web-api-utils');
@@ -48,6 +49,7 @@ let continuePolling = true;
export function buildUrlQuery(params) {
if (!params) return '';
+ // Ignore the entries with values `null` or `undefined`.
return params.map((value, param) => {
if (value === undefined || value === null) return null;
if (List.isList(value)) {
@@ -238,10 +240,10 @@ export function getTopologies(options, dispatch, initialPoll) {
}
function getWebsocketQueryTimestamp(state) {
- const millisecondsInPast = state.get('websocketQueryMillisecondsInPast');
// The timestamp query parameter will be used only if it's in the past.
- if (millisecondsInPast === 0) return null;
+ if (isWebsocketQueryingCurrentSelector(state)) return null;
+ const millisecondsInPast = state.get('websocketQueryMillisecondsInPast');
return moment().utc().subtract(millisecondsInPast).toISOString();
}