From 21a0093c0814705c050d516d5e8939e933bee0b2 Mon Sep 17 00:00:00 2001 From: Roland Schilter Date: Wed, 12 Jul 2017 16:41:46 +0200 Subject: [PATCH] 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 --- .../scripts/reducers/__tests__/root-test.js | 34 +++++++++++++++++++ client/app/scripts/reducers/root.js | 10 +++--- client/app/scripts/utils/topology-utils.js | 4 +-- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/client/app/scripts/reducers/__tests__/root-test.js b/client/app/scripts/reducers/__tests__/root-test.js index 4bb3d1a68..991c366c1 100644 --- a/client/app/scripts/reducers/__tests__/root-test.js +++ b/client/app/scripts/reducers/__tests__/root-test.js @@ -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 = { type: ActionTypes.ROUTE_TOPOLOGY, state: {} @@ -567,6 +586,21 @@ describe('RootReducer', () => { 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 it('keeps relatives as a stack', () => { diff --git a/client/app/scripts/reducers/root.js b/client/app/scripts/reducers/root.js index 81e6b6007..849157bb5 100644 --- a/client/app/scripts/reducers/root.js +++ b/client/app/scripts/reducers/root.js @@ -110,17 +110,17 @@ function calcSelectType(topology) { // adds ID field to topology (based on last part of URL path) and save urls in // map for easy lookup function processTopologies(state, nextTopologies) { + // add IDs to topology objects in-place + const topologiesWithId = updateTopologyIds(nextTopologies); // 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). const topologiesWithSelectType = visibleTopologies.map(calcSelectType); - // add IDs to topology objects in-place - const topologiesWithId = updateTopologyIds(topologiesWithSelectType); // cache URLs by ID 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); return state.set('topologies', immNextTopologies); } diff --git a/client/app/scripts/utils/topology-utils.js b/client/app/scripts/utils/topology-utils.js index efce0f6d1..fc2ba4d29 100644 --- a/client/app/scripts/utils/topology-utils.js +++ b/client/app/scripts/utils/topology-utils.js @@ -126,9 +126,9 @@ export function setTopologyUrlsById(topologyUrlsById, topologies) { return urlMap; } -export function filterHiddenTopologies(topologies) { +export function filterHiddenTopologies(topologies, currentTopologyId) { 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) {