Moved the node layout metrics computation to selectors.

This commit is contained in:
Filip Barl
2017-02-09 18:53:06 +01:00
parent 2a54085c62
commit 3987e95465
8 changed files with 65 additions and 44 deletions

View File

@@ -152,10 +152,14 @@ class Node extends React.PureComponent {
}
}
export default connect(
state => ({
function mapStateToProps(state) {
return {
exportingGraph: state.get('exportingGraph'),
showingNetworks: state.get('showingNetworks'),
}),
};
}
export default connect(
mapStateToProps,
{ clickNode, enterNode, leaveNode }
)(Node);

View File

@@ -1,16 +1,17 @@
import React from 'react';
import { connect } from 'react-redux';
import { fromJS, List as makeList } from 'immutable';
import { List as makeList } from 'immutable';
import { nodeMetricsSelector } from '../selectors/metrics';
import { currentTopologySearchNodeMatchesSelector } from '../selectors/search';
import { getAdjacentNodes } from '../utils/topology-utils';
import NodeContainer from './node-container';
class NodesChartNodes extends React.Component {
render() {
const { adjacentNodes, highlightedNodeIds, layoutNodes, isAnimated, mouseOverNodeId,
selectedScale, searchQuery, selectedMetric, selectedNetwork, selectedNodeId,
topCardNode, searchNodeMatches } = this.props;
const { adjacentNodes, highlightedNodeIds, layoutNodes, isAnimated,
mouseOverNodeId, nodeMetrics, selectedScale, searchQuery, selectedNetwork,
selectedNodeId, searchNodeMatches } = this.props;
// highlighter functions
const setHighlighted = node => node.set('highlighted',
@@ -37,15 +38,6 @@ class NodesChartNodes extends React.Component {
return 1;
};
// TODO: think about pulling this up into the store.
const metric = (node) => {
const isHighlighted = topCardNode && topCardNode.details && topCardNode.id === node.get('id');
const sourceNode = isHighlighted ? fromJS(topCardNode.details) : node;
return sourceNode.get('metrics') && sourceNode.get('metrics')
.filter(m => m.get('id') === selectedMetric)
.first();
};
const nodesToRender = layoutNodes.toIndexedSeq()
.map(setHighlighted)
.map(setFocused)
@@ -67,7 +59,7 @@ class NodesChartNodes extends React.Component {
label={node.get('label')}
pseudo={node.get('pseudo')}
subLabel={node.get('subLabel')}
metric={metric(node)}
metric={nodeMetrics.get(node.get('id'))}
rank={node.get('rank')}
isAnimated={isAnimated}
scale={node.get('focused') ? selectedScale : 1}
@@ -79,16 +71,19 @@ class NodesChartNodes extends React.Component {
}
}
export default connect(
state => ({
function mapStateToProps(state) {
return {
adjacentNodes: getAdjacentNodes(state),
nodeMetrics: nodeMetricsSelector(state),
highlightedNodeIds: state.get('highlightedNodeIds'),
mouseOverNodeId: state.get('mouseOverNodeId'),
selectedMetric: state.get('selectedMetric'),
selectedNetwork: state.get('selectedNetwork'),
selectedNodeId: state.get('selectedNodeId'),
searchNodeMatches: currentTopologySearchNodeMatchesSelector(state),
searchQuery: state.get('searchQuery'),
topCardNode: state.get('nodeDetails').last()
})
};
}
export default connect(
mapStateToProps,
)(NodesChartNodes);

View File

@@ -6,7 +6,7 @@ import { Map as makeMap } from 'immutable';
import { event as d3Event, select } from 'd3-selection';
import { zoom, zoomIdentity } from 'd3-zoom';
import { nodeAdjacenciesSelector } from '../selectors/nodes-chart';
import { nodeAdjacenciesSelector } from '../selectors/nodes';
import { clickBackground } from '../actions/app-actions';
import Logo from '../components/logo';
import NodesChartElements from './nodes-chart-elements';

View File

@@ -5,7 +5,7 @@ import { connect } from 'react-redux';
import { List as makeList, Map as makeMap } from 'immutable';
import NodeDetailsTable from '../components/node-details/node-details-table';
import { clickNode, sortOrderChanged } from '../actions/app-actions';
import { nodesSelector } from '../selectors/nodes-chart';
import { shownNodesSelector } from '../selectors/nodes';
import { currentTopologySearchNodeMatchesSelector } from '../selectors/search';
import { getNodeColor } from '../utils/color-utils';
@@ -144,13 +144,12 @@ class NodesGrid extends React.Component {
function mapStateToProps(state) {
return {
nodes: nodesSelector(state),
nodes: shownNodesSelector(state),
gridSortedBy: state.get('gridSortedBy'),
gridSortedDesc: state.get('gridSortedDesc'),
currentTopology: state.get('currentTopology'),
currentTopologyId: state.get('currentTopologyId'),
searchNodeMatches: currentTopologySearchNodeMatchesSelector(state),
// searchNodeMatches: state.getIn(['searchNodeMatches', state.get('currentTopologyId')]),
searchQuery: state.get('searchQuery'),
selectedNodeId: state.get('selectedNodeId')
};

View File

@@ -67,7 +67,9 @@ function addMetrics(availableMetrics, node, v) {
]);
return Object.assign({}, node, {
metrics: metrics.map(m => Object.assign({}, m, {label: 'zing', max: 100, value: v})).toJS()
metrics: metrics.map(m => Object.assign({}, m, {
id: 'zing', label: 'zing', max: 100, value: v
})).toJS()
});
}

View File

@@ -0,0 +1,26 @@
import { createSelector } from 'reselect';
import { createMapSelector } from 'reselect-map';
import { fromJS } from 'immutable';
const topCardNodeSelector = createSelector(
[
state => state.get('nodeDetails')
],
nodeDetails => nodeDetails.last()
);
export const nodeMetricsSelector = createMapSelector(
[
state => state.get('nodes'),
state => state.get('selectedMetric'),
topCardNodeSelector,
],
(node, selectedMetric, topCardNode) => {
const isHighlighted = topCardNode && topCardNode.details && topCardNode.id === node.get('id');
const sourceNode = isHighlighted ? fromJS(topCardNode.details) : node;
return sourceNode.get('metrics') && sourceNode.get('metrics')
.filter(m => m.get('id') === selectedMetric)
.first();
}
);

View File

@@ -2,19 +2,16 @@ import { createSelector } from 'reselect';
import { Map as makeMap } from 'immutable';
const allNodesSelector = state => state.get('nodes');
export const nodesSelector = createSelector(
export const shownNodesSelector = createSelector(
[
allNodesSelector,
state => state.get('nodes'),
],
allNodes => allNodes.filter(node => !node.get('filtered'))
nodes => nodes.filter(node => !node.get('filtered'))
);
export const nodeAdjacenciesSelector = createSelector(
[
nodesSelector,
shownNodesSelector,
],
nodes => nodes.map(node => makeMap({
id: node.get('id'),

View File

@@ -5,37 +5,35 @@ import { Map as makeMap } from 'immutable';
import { parseQuery, searchTopology, getSearchableFields } from '../utils/search-utils';
const allNodesSelector = state => state.get('nodes');
const nodesByTopologySelector = state => state.get('nodesByTopology');
const currentTopologyIdSelector = state => state.get('currentTopologyId');
const searchQuerySelector = state => state.get('searchQuery');
const parsedSearchQuerySelector = createSelector(
[
searchQuerySelector
state => state.get('searchQuery')
],
searchQuery => parseQuery(searchQuery)
);
export const searchNodeMatchesSelector = createMapSelector(
[
nodesByTopologySelector,
state => state.get('nodesByTopology'),
parsedSearchQuerySelector,
],
// TODO: Bring map selectors one level deeper here so that `searchTopology` is
// not executed against all the topology nodes every time a small change occurs.
(nodes, parsed) => (parsed ? searchTopology(nodes, parsed) : makeMap())
);
export const currentTopologySearchNodeMatchesSelector = createSelector(
[
state => state.get('currentTopologyId'),
searchNodeMatchesSelector,
currentTopologyIdSelector,
],
(nodesByTopology, currentTopologyId) => nodesByTopology.get(currentTopologyId) || makeMap()
(currentTopologyId, nodesByTopology) => nodesByTopology.get(currentTopologyId) || makeMap()
);
export const searchableFieldsSelector = createSelector(
[
allNodesSelector,
state => state.get('nodes'),
],
// TODO: Bring this function in the selectors.
getSearchableFields
);