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 (
-
- +
+
+ +
{children}
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 ( ); } 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; }