Keep topology nav visible if selected

If the scope-app API unexpectedly restarts, it has no report
at hand (until it gets one from the probe) and sends node
count 0 to the frontend for all topologies. Once the report
arrives, it will send the proper count.

What happened was the frontend did hide Processes for a short
time till the node count recovered. This moved the topology
selection to the always visible Containers (hide_if_empty == false)
while keeping the graph as is.

Once the node count recovers, Processes comes back but the
selection is still at Containers.

We now keep the selected topology visible at all time even if
the API returns a node count of 0. This recovers nicely when
the correct node counts come in. Once the user selects a different
topology while and a backend response arrives, it disappears.

Fixes #2646
This commit is contained in:
Roland Schilter
2017-07-12 16:41:46 +02:00
parent 4355f73226
commit 21a0093c08
3 changed files with 41 additions and 7 deletions

View File

@@ -280,6 +280,25 @@ describe('RootReducer', () => {
}] }]
}; };
const ReceiveTopologiesHiddenAction = {
type: ActionTypes.RECEIVE_TOPOLOGIES,
topologies: [{
url: '/topo1',
name: 'Topo1',
stats: {
node_count: 1
}
}, {
hide_if_empty: true,
url: '/topo2',
name: 'Topo2',
stats: {
node_count: 0,
filtered_nodes: 0
}
}]
};
const RouteAction = { const RouteAction = {
type: ActionTypes.ROUTE_TOPOLOGY, type: ActionTypes.ROUTE_TOPOLOGY,
state: {} state: {}
@@ -567,6 +586,21 @@ describe('RootReducer', () => {
expect(isTopologyNodeCountZero(nextState)).toBeFalsy(); expect(isTopologyNodeCountZero(nextState)).toBeFalsy();
}); });
it('keeps hidden topology visible if selected', () => {
let nextState = initialState;
nextState = reducer(nextState, ClickTopology2Action);
nextState = reducer(nextState, ReceiveTopologiesHiddenAction);
expect(nextState.get('currentTopologyId')).toEqual('topo2');
expect(nextState.get('topologies').toJS().length).toEqual(2);
});
it('keeps hidden topology hidden if not selected', () => {
let nextState = initialState;
nextState = reducer(nextState, ClickTopologyAction);
nextState = reducer(nextState, ReceiveTopologiesHiddenAction);
expect(nextState.get('topologies').toJS().length).toEqual(1);
});
// selection of relatives // selection of relatives
it('keeps relatives as a stack', () => { it('keeps relatives as a stack', () => {

View File

@@ -110,17 +110,17 @@ function calcSelectType(topology) {
// adds ID field to topology (based on last part of URL path) and save urls in // adds ID field to topology (based on last part of URL path) and save urls in
// map for easy lookup // map for easy lookup
function processTopologies(state, nextTopologies) { function processTopologies(state, nextTopologies) {
// add IDs to topology objects in-place
const topologiesWithId = updateTopologyIds(nextTopologies);
// filter out hidden topos // filter out hidden topos
const visibleTopologies = filterHiddenTopologies(nextTopologies); const visibleTopologies = filterHiddenTopologies(topologiesWithId, state.get('currentTopologyId'));
// set `selectType` field for topology and sub_topologies options (recursive). // set `selectType` field for topology and sub_topologies options (recursive).
const topologiesWithSelectType = visibleTopologies.map(calcSelectType); const topologiesWithSelectType = visibleTopologies.map(calcSelectType);
// add IDs to topology objects in-place
const topologiesWithId = updateTopologyIds(topologiesWithSelectType);
// cache URLs by ID // cache URLs by ID
state = state.set('topologyUrlsById', state = state.set('topologyUrlsById',
setTopologyUrlsById(state.get('topologyUrlsById'), topologiesWithId)); setTopologyUrlsById(state.get('topologyUrlsById'), topologiesWithSelectType));
const topologiesWithFullnames = addTopologyFullname(topologiesWithId); const topologiesWithFullnames = addTopologyFullname(topologiesWithSelectType);
const immNextTopologies = fromJS(topologiesWithFullnames).sortBy(topologySorter); const immNextTopologies = fromJS(topologiesWithFullnames).sortBy(topologySorter);
return state.set('topologies', immNextTopologies); return state.set('topologies', immNextTopologies);
} }

View File

@@ -126,9 +126,9 @@ export function setTopologyUrlsById(topologyUrlsById, topologies) {
return urlMap; return urlMap;
} }
export function filterHiddenTopologies(topologies) { export function filterHiddenTopologies(topologies, currentTopologyId) {
return topologies.filter(t => (!t.hide_if_empty || t.stats.node_count > 0 || return topologies.filter(t => (!t.hide_if_empty || t.stats.node_count > 0 ||
t.stats.filtered_nodes > 0)); t.stats.filtered_nodes > 0 || t.id === currentTopologyId));
} }
export function getCurrentTopologyOptions(state) { export function getCurrentTopologyOptions(state) {