diff --git a/client/app/scripts/charts/nodes-error.js b/client/app/scripts/charts/nodes-error.js
index ba5cfbb6b..e6204bfb1 100644
--- a/client/app/scripts/charts/nodes-error.js
+++ b/client/app/scripts/charts/nodes-error.js
@@ -10,8 +10,10 @@ export default function NodesError({children, faIconClass, hidden,
return (
-
diff --git a/client/app/scripts/components/nodes.js b/client/app/scripts/components/nodes.js
index 9da9992b6..8b8c510eb 100644
--- a/client/app/scripts/components/nodes.js
+++ b/client/app/scripts/components/nodes.js
@@ -3,7 +3,7 @@ import { connect } from 'react-redux';
import NodesChart from '../charts/nodes-chart';
import NodesError from '../charts/nodes-error';
-import { isTopologyEmpty } from '../utils/topology-utils';
+import { findTopologyById, isTopologyEmpty } from '../utils/topology-utils';
const navbarHeight = 160;
const marginTop = 0;
@@ -27,6 +27,17 @@ function getLayoutPrecision(nodesCount) {
return precision;
}
+function getNodeType(topology, topologies) {
+ if (!topology || topologies.size === 0) {
+ return '';
+ }
+ if (topology.get('parentId')) {
+ const parentTopology = findTopologyById(topologies, topology.get('parentId'));
+ return parentTopology.get('name');
+ }
+ return topology.get('name');
+}
+
class Nodes extends React.Component {
constructor(props, context) {
super(props, context);
@@ -62,24 +73,26 @@ class Nodes extends React.Component {
);
}
- renderLoading(show) {
+ renderLoading(message, show) {
return (
- Loading Topologies
+ {message}
);
}
render() {
- const { nodes, selectedNodeId, topologyEmpty, topologiesLoaded } = this.props;
+ const { nodes, selectedNodeId, topologyEmpty, topologiesLoaded, nodesLoaded, topologies,
+ topology } = this.props;
const layoutPrecision = getLayoutPrecision(nodes.size);
const hasSelectedNode = selectedNodeId && nodes.has(selectedNodeId);
return (
- {!topologiesLoaded ?
- this.renderLoading(!topologiesLoaded) :
- (topologyEmpty && this.renderEmptyTopologyError(topologyEmpty))}
+ {this.renderLoading('Loading topologies...', !topologiesLoaded)}
+ {this.renderLoading(`Loading ${getNodeType(topology, topologies)}...`,
+ topologiesLoaded && !nodesLoaded)}
+ {this.renderEmptyTopologyError(topologiesLoaded && nodesLoaded && topologyEmpty)}
details
nodes: makeOrderedMap(), // nodeId -> node
+ nodesLoaded: false,
// nodes cache, infrequently updated, used for search
nodesByTopology: makeMap(), // topologyId -> nodes
pinnedMetric: null,
@@ -61,7 +62,7 @@ export const initialState = makeMap({
updatePausedAt: null, // Date
version: '...',
versionUpdate: null,
- websocketClosed: true,
+ websocketClosed: false,
exportingGraph: false
});
@@ -483,6 +484,7 @@ export function rootReducer(state = initialState, action) {
case ActionTypes.RECEIVE_NODES_DELTA: {
const emptyMessage = !action.delta.add && !action.delta.remove
&& !action.delta.update;
+ state = state.set('nodesLoaded', true);
if (!emptyMessage) {
log('RECEIVE_NODES_DELTA',
diff --git a/client/app/styles/main.less b/client/app/styles/main.less
index 72eb7511e..934743677 100644
--- a/client/app/styles/main.less
+++ b/client/app/styles/main.less
@@ -317,8 +317,11 @@ h2 {
}
}
+ &-loading &-error-icon-container {
+ animation: blinking 2.0s infinite @base-ease;
+ }
+
&-loading {
- animation: blinking 2s infinite @base-ease;
text-align: center;
}