Moved highlighted nodes/edges info to selectors (#2584)

* Use selector for highlighted nodes.

* Use selector for highlighted edges.
This commit is contained in:
Filip Barl
2017-06-14 11:11:59 +02:00
committed by GitHub
parent 3ad629b797
commit 0869d26ec4
6 changed files with 91 additions and 58 deletions

View File

@@ -4,6 +4,7 @@ import { Map as makeMap } from 'immutable';
import { searchNodeMatchesSelector } from '../selectors/search';
import { selectedNetworkNodesIdsSelector } from '../selectors/node-networks';
import { highlightedEdgeIdsSelector } from '../selectors/graph-view/decorators';
import { hasSelectedNode as hasSelectedNodeFn } from '../utils/topology-utils';
import EdgeContainer from './edge-container';
@@ -82,8 +83,8 @@ export default connect(
hasSelectedNode: hasSelectedNodeFn(state),
searchNodeMatches: searchNodeMatchesSelector(state),
selectedNetworkNodesIds: selectedNetworkNodesIdsSelector(state),
highlightedEdgeIds: highlightedEdgeIdsSelector(state),
searchQuery: state.get('searchQuery'),
highlightedEdgeIds: state.get('highlightedEdgeIds'),
selectedNetwork: state.get('selectedNetwork'),
selectedNodeId: state.get('selectedNodeId'),
})

View File

@@ -4,6 +4,7 @@ import { Map as makeMap } from 'immutable';
import { nodeMetricSelector } from '../selectors/node-metric';
import { searchNodeMatchesSelector } from '../selectors/search';
import { highlightedNodeIdsSelector } from '../selectors/graph-view/decorators';
import { nodeNetworksSelector, selectedNetworkNodesIdsSelector } from '../selectors/node-networks';
import { getAdjacentNodes } from '../utils/topology-utils';
import NodeContainer from './node-container';
@@ -126,7 +127,7 @@ function mapStateToProps(state) {
searchNodeMatches: searchNodeMatchesSelector(state),
selectedNetworkNodesIds: selectedNetworkNodesIdsSelector(state),
neighborsOfSelectedNode: getAdjacentNodes(state),
highlightedNodeIds: state.get('highlightedNodeIds'),
highlightedNodeIds: highlightedNodeIdsSelector(state),
mouseOverNodeId: state.get('mouseOverNodeId'),
selectedNetwork: state.get('selectedNetwork'),
selectedNodeId: state.get('selectedNodeId'),

View File

@@ -3,6 +3,8 @@ import expect from 'expect';
import { TABLE_VIEW_MODE } from '../../constants/naming';
import { constructEdgeId } from '../../utils/layouter-utils';
import { highlightedEdgeIdsSelector } from '../../selectors/graph-view/decorators';
// Root reducer test suite using Jasmine matchers
describe('RootReducer', () => {
@@ -678,7 +680,7 @@ describe('RootReducer', () => {
edgeId: constructEdgeId('abc123', 'def456')
};
const nextState = reducer(initialState, action);
expect(nextState.get('highlightedEdgeIds').toJS()).toEqual([
expect(highlightedEdgeIdsSelector(nextState).toJS()).toEqual([
constructEdgeId('abc123', 'def456'),
constructEdgeId('def456', 'abc123')
]);

View File

@@ -8,12 +8,10 @@ import {
List as makeList,
Map as makeMap,
OrderedMap as makeOrderedMap,
Set as makeSet,
} from 'immutable';
import ActionTypes from '../constants/action-types';
import {
EDGE_ID_SEPARATOR,
GRAPH_VIEW_MODE,
TABLE_VIEW_MODE,
} from '../constants/naming';
@@ -26,7 +24,6 @@ import { consolidateNodesDeltas } from '../utils/nodes-delta-utils';
import { applyPinnedSearches } from '../utils/search-utils';
import {
findTopologyById,
getAdjacentNodes,
setTopologyUrlsById,
updateTopologyIds,
filterHiddenTopologies,
@@ -54,9 +51,6 @@ export const initialState = makeMap({
forceRelayout: false,
gridSortedBy: null,
gridSortedDesc: null,
// TODO: Calculate these sets from selectors instead.
highlightedEdgeIds: makeSet(),
highlightedNodeIds: makeSet(),
hostname: '...',
hoveredMetricType: null,
initialNodesLoaded: false,
@@ -468,64 +462,19 @@ export function rootReducer(state = initialState, action) {
}
case ActionTypes.ENTER_EDGE: {
// highlight adjacent nodes
state = state.update('highlightedNodeIds', (highlightedNodeIds) => {
highlightedNodeIds = highlightedNodeIds.clear();
return highlightedNodeIds.union(action.edgeId.split(EDGE_ID_SEPARATOR));
});
// highlight edge
state = state.update('highlightedEdgeIds', (highlightedEdgeIds) => {
highlightedEdgeIds = highlightedEdgeIds.clear();
highlightedEdgeIds = highlightedEdgeIds.add(action.edgeId);
const opposite = action.edgeId.split(EDGE_ID_SEPARATOR).reverse().join(EDGE_ID_SEPARATOR);
highlightedEdgeIds = highlightedEdgeIds.add(opposite);
return highlightedEdgeIds;
});
return state;
return state.set('mouseOverEdgeId', action.edgeId);
}
case ActionTypes.ENTER_NODE: {
const nodeId = action.nodeId;
const adjacentNodes = getAdjacentNodes(state, nodeId);
state = state.set('mouseOverNodeId', nodeId);
// highlight adjacent nodes
state = state.update('highlightedNodeIds', (highlightedNodeIds) => {
highlightedNodeIds = highlightedNodeIds.clear();
highlightedNodeIds = highlightedNodeIds.add(nodeId);
return highlightedNodeIds.union(adjacentNodes);
});
// highlight edge
state = state.update('highlightedEdgeIds', (highlightedEdgeIds) => {
highlightedEdgeIds = highlightedEdgeIds.clear();
if (adjacentNodes.size > 0) {
// all neighbour combinations because we dont know which direction exists
highlightedEdgeIds = highlightedEdgeIds.union(adjacentNodes.flatMap(adjacentId => [
[adjacentId, nodeId].join(EDGE_ID_SEPARATOR),
[nodeId, adjacentId].join(EDGE_ID_SEPARATOR)
]));
}
return highlightedEdgeIds;
});
return state;
return state.set('mouseOverNodeId', action.nodeId);
}
case ActionTypes.LEAVE_EDGE: {
state = state.update('highlightedEdgeIds', highlightedEdgeIds => highlightedEdgeIds.clear());
state = state.update('highlightedNodeIds', highlightedNodeIds => highlightedNodeIds.clear());
return state;
return state.set('mouseOverEdgeId', null);
}
case ActionTypes.LEAVE_NODE: {
state = state.set('mouseOverNodeId', null);
state = state.update('highlightedEdgeIds', highlightedEdgeIds => highlightedEdgeIds.clear());
state = state.update('highlightedNodeIds', highlightedNodeIds => highlightedNodeIds.clear());
return state;
return state.set('mouseOverNodeId', null);
}
case ActionTypes.DO_CONTROL_ERROR: {

View File

@@ -0,0 +1,76 @@
import { createSelector } from 'reselect';
import { Set as makeSet } from 'immutable';
import { constructEdgeId, getNodesFromEdgeId } from '../../utils/layouter-utils';
const adjacentToHoveredNodeIdsSelector = createSelector(
[
state => state.get('mouseOverNodeId'),
state => state.get('nodes'),
],
(mouseOverNodeId, nodes) => {
let nodeIds = makeSet();
if (mouseOverNodeId) {
nodeIds = makeSet(nodes.getIn([mouseOverNodeId, 'adjacency']));
// fill up set with reverse edges
nodes.forEach((node, id) => {
if (node.get('adjacency') && node.get('adjacency').includes(mouseOverNodeId)) {
nodeIds = nodeIds.add(id);
}
});
}
return nodeIds;
}
);
export const highlightedNodeIdsSelector = createSelector(
[
adjacentToHoveredNodeIdsSelector,
state => state.get('mouseOverNodeId'),
state => state.get('mouseOverEdgeId'),
],
(adjacentToHoveredNodeIds, mouseOverNodeId, mouseOverEdgeId) => {
let highlightedNodeIds = makeSet();
if (mouseOverEdgeId) {
highlightedNodeIds = highlightedNodeIds.union(getNodesFromEdgeId(mouseOverEdgeId));
}
if (mouseOverNodeId) {
highlightedNodeIds = highlightedNodeIds.add(mouseOverNodeId);
highlightedNodeIds = highlightedNodeIds.union(adjacentToHoveredNodeIds);
}
return highlightedNodeIds;
}
);
export const highlightedEdgeIdsSelector = createSelector(
[
adjacentToHoveredNodeIdsSelector,
state => state.get('mouseOverNodeId'),
state => state.get('mouseOverEdgeId'),
],
(adjacentToHoveredNodeIds, mouseOverNodeId, mouseOverEdgeId) => {
let highlightedEdgeIds = makeSet();
if (mouseOverEdgeId) {
const [sourceNode, targetNode] = getNodesFromEdgeId(mouseOverEdgeId);
highlightedEdgeIds = highlightedEdgeIds.add(constructEdgeId(sourceNode, targetNode));
highlightedEdgeIds = highlightedEdgeIds.add(constructEdgeId(targetNode, sourceNode));
}
if (mouseOverNodeId) {
// all neighbour combinations because we dont know which direction exists
highlightedEdgeIds = highlightedEdgeIds.union(adjacentToHoveredNodeIds.flatMap(adjacentId => [
constructEdgeId(adjacentId, mouseOverNodeId),
constructEdgeId(mouseOverNodeId, adjacentId),
]));
}
return highlightedEdgeIds;
}
);

View File

@@ -3,6 +3,10 @@ import { Map as makeMap } from 'immutable';
import { EDGE_ID_SEPARATOR } from '../constants/naming';
export function getNodesFromEdgeId(edgeId) {
return edgeId.split(EDGE_ID_SEPARATOR);
}
export function constructEdgeId(source, target) {
return [source, target].join(EDGE_ID_SEPARATOR);
}