diff --git a/client/app/scripts/charts/edge-container.js b/client/app/scripts/charts/edge-container.js index ac1db00a0..8253ec536 100644 --- a/client/app/scripts/charts/edge-container.js +++ b/client/app/scripts/charts/edge-container.js @@ -1,5 +1,4 @@ import React from 'react'; -import { connect } from 'react-redux'; import { Motion, spring } from 'react-motion'; import { Map as makeMap } from 'immutable'; import { line, curveBasis } from 'd3-shape'; @@ -37,7 +36,7 @@ const waypointsMapToArray = (waypointsMap) => { }; -class EdgeContainer extends React.PureComponent { +export default class EdgeContainer extends React.PureComponent { constructor(props, context) { super(props, context); this.state = { waypointsMap: makeMap() }; @@ -102,5 +101,3 @@ class EdgeContainer extends React.PureComponent { this.setState({ waypointsMap }); } } - -export default connect()(EdgeContainer); diff --git a/client/app/scripts/charts/node-container.js b/client/app/scripts/charts/node-container.js index ca4ba8d65..9b36c57c8 100644 --- a/client/app/scripts/charts/node-container.js +++ b/client/app/scripts/charts/node-container.js @@ -1,12 +1,14 @@ import React from 'react'; import { omit } from 'lodash'; -import { connect } from 'react-redux'; import { Motion, spring } from 'react-motion'; import { NODES_SPRING_ANIMATION_CONFIG } from '../constants/animation'; -import { NODE_BLUR_OPACITY } from '../constants/styles'; +import { isContrastMode } from '../utils/contrast-utils'; import Node from './node'; + +const nodeBlurOpacity = isContrastMode() ? 0.6 : 0.25; + const transformedNode = (otherProps, { x, y, k, opacity }) => ( // NOTE: Controlling blurring and transform from here seems to re-render // faster than adding a CSS class and controlling it from there. @@ -15,11 +17,11 @@ const transformedNode = (otherProps, { x, y, k, opacity }) => ( ); -class NodeContainer extends React.PureComponent { +export default class NodeContainer extends React.PureComponent { render() { const { dx, dy, isAnimated, scale, blurred } = this.props; const forwardedProps = omit(this.props, 'dx', 'dy', 'isAnimated', 'scale', 'blurred'); - const opacity = blurred ? NODE_BLUR_OPACITY : 1; + const opacity = blurred ? nodeBlurOpacity : 1; if (!isAnimated) { // Show static node for optimized rendering @@ -40,5 +42,3 @@ class NodeContainer extends React.PureComponent { ); } } - -export default connect()(NodeContainer); diff --git a/client/app/scripts/charts/node.js b/client/app/scripts/charts/node.js index accbf6058..3252a7133 100644 --- a/client/app/scripts/charts/node.js +++ b/client/app/scripts/charts/node.js @@ -41,7 +41,7 @@ function getNodeShape({ shape, stack }) { } -class Node extends React.PureComponent { +class Node extends React.Component { constructor(props, context) { super(props, context); this.state = { @@ -93,8 +93,8 @@ class Node extends React.PureComponent { } render() { - const { focused, highlighted, networks, pseudo, rank, label, - transform, exportingGraph, showingNetworks, stack, id, metric } = this.props; + const { focused, highlighted, networks, pseudo, rank, label, transform, + exportingGraph, showingNetworks, stack, id, metric, matches = makeMap() } = this.props; const { hovered } = this.state; const color = getNodeColor(rank, label, pseudo); @@ -102,6 +102,9 @@ class Node extends React.PureComponent { const labelOffsetY = (showingNetworks && networks) ? 40 : 28; const nodeClassName = classnames('node', { + // NOTE: Having a CSS animation here might not be the best idea. + // See https://github.com/weaveworks/scope/issues/2255 + matched: !matches.isEmpty(), highlighted, hovered, pseudo diff --git a/client/app/scripts/charts/nodes-chart-elements.js b/client/app/scripts/charts/nodes-chart-elements.js index 728ce4448..fdd65823a 100644 --- a/client/app/scripts/charts/nodes-chart-elements.js +++ b/client/app/scripts/charts/nodes-chart-elements.js @@ -1,25 +1,22 @@ import React from 'react'; -import { connect } from 'react-redux'; import NodesChartEdges from './nodes-chart-edges'; import NodesChartNodes from './nodes-chart-nodes'; -class NodesChartElements extends React.Component { +export default class NodesChartElements extends React.PureComponent { render() { - const props = this.props; + const { transform, layoutEdges, layoutNodes, selectedScale, isAnimated } = this.props; return ( - + + layoutEdges={layoutEdges} + selectedScale={selectedScale} + isAnimated={isAnimated} /> + layoutNodes={layoutNodes} + selectedScale={selectedScale} + isAnimated={isAnimated} /> ); } } - -export default connect()(NodesChartElements); diff --git a/client/app/scripts/charts/nodes-chart.js b/client/app/scripts/charts/nodes-chart.js index 9c4898110..2c9288b0c 100644 --- a/client/app/scripts/charts/nodes-chart.js +++ b/client/app/scripts/charts/nodes-chart.js @@ -17,7 +17,7 @@ import { layoutWithSelectedNode } from '../selectors/nodes-chart-focus'; import { graphLayout } from '../selectors/nodes-chart-layout'; -const GRAPH_COMPLEXITY_NODES_TRESHOLD = 150; +const GRAPH_COMPLEXITY_NODES_TRESHOLD = 100; const ZOOM_CACHE_FIELDS = [ 'panTranslateX', 'panTranslateY', 'zoomScale', 'minZoomScale', 'maxZoomScale' diff --git a/client/app/scripts/components/matched-results.js b/client/app/scripts/components/matched-results.js index ef1a170f3..295d9820f 100644 --- a/client/app/scripts/components/matched-results.js +++ b/client/app/scripts/components/matched-results.js @@ -1,5 +1,4 @@ import React from 'react'; -import { connect } from 'react-redux'; import MatchedText from './matched-text'; @@ -21,7 +20,7 @@ const Match = match => ( ); -class MatchedResults extends React.Component { +export default class MatchedResults extends React.PureComponent { render() { const { matches, style } = this.props; @@ -49,5 +48,3 @@ class MatchedResults extends React.Component { ); } } - -export default connect()(MatchedResults); diff --git a/client/app/scripts/components/matched-text.js b/client/app/scripts/components/matched-text.js index 7aaa07d49..e1e91cd0c 100644 --- a/client/app/scripts/components/matched-text.js +++ b/client/app/scripts/components/matched-text.js @@ -1,5 +1,4 @@ import React from 'react'; -import { connect } from 'react-redux'; const TRUNCATE_CONTEXT = 6; const TRUNCATE_ELLIPSIS = '…'; @@ -79,8 +78,7 @@ function truncateChunks(chunks, text, maxLength) { * `match` is a text match object of shape `{start, length}` * that delimit text matches in `text`. `label` shows the origin of the text. */ -class MatchedText extends React.Component { - +export default class MatchedText extends React.PureComponent { render() { const { match, text, truncate, maxLength } = this.props; @@ -109,5 +107,3 @@ class MatchedText extends React.Component { ); } } - -export default connect()(MatchedText); diff --git a/client/app/scripts/components/node-details/node-details-control-button.js b/client/app/scripts/components/node-details/node-details-control-button.js index 36c414ae6..1c01c96aa 100644 --- a/client/app/scripts/components/node-details/node-details-control-button.js +++ b/client/app/scripts/components/node-details/node-details-control-button.js @@ -1,9 +1,8 @@ import React from 'react'; -import { connect } from 'react-redux'; import { doControl } from '../../actions/app-actions'; -class NodeDetailsControlButton extends React.Component { +export default class NodeDetailsControlButton extends React.PureComponent { constructor(props, context) { super(props, context); this.handleClick = this.handleClick.bind(this); @@ -24,5 +23,3 @@ class NodeDetailsControlButton extends React.Component { this.props.dispatch(doControl(this.props.nodeId, this.props.control)); } } - -export default connect()(NodeDetailsControlButton); diff --git a/client/app/scripts/components/node-details/node-details-relatives-link.js b/client/app/scripts/components/node-details/node-details-relatives-link.js index 30d254a60..587cd228f 100644 --- a/client/app/scripts/components/node-details/node-details-relatives-link.js +++ b/client/app/scripts/components/node-details/node-details-relatives-link.js @@ -1,11 +1,9 @@ import React from 'react'; -import { connect } from 'react-redux'; import { clickRelative } from '../../actions/app-actions'; import MatchedText from '../matched-text'; -class NodeDetailsRelativesLink extends React.Component { - +export default class NodeDetailsRelativesLink extends React.PureComponent { constructor(props, context) { super(props, context); this.handleClick = this.handleClick.bind(this); @@ -37,5 +35,3 @@ class NodeDetailsRelativesLink extends React.Component { ); } } - -export default connect()(NodeDetailsRelativesLink); diff --git a/client/app/scripts/components/node-details/node-details-table-node-link.js b/client/app/scripts/components/node-details/node-details-table-node-link.js index 3eef941ef..d2b87441d 100644 --- a/client/app/scripts/components/node-details/node-details-table-node-link.js +++ b/client/app/scripts/components/node-details/node-details-table-node-link.js @@ -1,10 +1,8 @@ import React from 'react'; -import { connect } from 'react-redux'; import { clickRelative } from '../../actions/app-actions'; -class NodeDetailsTableNodeLink extends React.Component { - +export default class NodeDetailsTableNodeLink extends React.PureComponent { constructor(props, context) { super(props, context); this.handleClick = this.handleClick.bind(this); @@ -45,5 +43,3 @@ class NodeDetailsTableNodeLink extends React.Component { ); } } - -export default connect()(NodeDetailsTableNodeLink); diff --git a/client/app/scripts/components/show-more.js b/client/app/scripts/components/show-more.js index 5578cf5ff..e22f97abc 100644 --- a/client/app/scripts/components/show-more.js +++ b/client/app/scripts/components/show-more.js @@ -1,8 +1,6 @@ import React from 'react'; -import { connect } from 'react-redux'; - -class ShowMore extends React.Component { +export default class ShowMore extends React.PureComponent { constructor(props, context) { super(props, context); this.handleClick = this.handleClick.bind(this); @@ -29,5 +27,3 @@ class ShowMore extends React.Component { ); } } - -export default connect()(ShowMore); diff --git a/client/app/scripts/constants/styles.js b/client/app/scripts/constants/styles.js index 3a68e0564..361afcd56 100644 --- a/client/app/scripts/constants/styles.js +++ b/client/app/scripts/constants/styles.js @@ -21,7 +21,6 @@ export const NODE_SHAPE_HIGHLIGHT_RADIUS = 70; export const NODE_SHAPE_BORDER_RADIUS = 50; export const NODE_SHAPE_SHADOW_RADIUS = 45; export const NODE_SHAPE_DOT_RADIUS = 10; -export const NODE_BLUR_OPACITY = 0.2; // NOTE: This value represents the node unit radius (in pixels). Since zooming is // controlled at the top level now, this renormalization would be obsolete (i.e. // value 1 could be used instead), if it wasn't for the following factors: diff --git a/client/app/scripts/reducers/root.js b/client/app/scripts/reducers/root.js index be34fc7be..0f499c394 100644 --- a/client/app/scripts/reducers/root.js +++ b/client/app/scripts/reducers/root.js @@ -38,6 +38,7 @@ export const initialState = makeMap({ gridMode: false, gridSortedBy: null, gridSortedDesc: null, + // TODO: Calculate these sets from selectors instead. highlightedEdgeIds: makeSet(), highlightedNodeIds: makeSet(), hostname: '...', @@ -560,6 +561,9 @@ export function rootReducer(state = initialState, action) { // update existing nodes each(action.delta.update, (node) => { if (state.hasIn(['nodes', node.id])) { + // TODO: Implement a manual deep update here, as it might bring a great benefit + // to our nodes selectors (e.g. layout engine would be completely bypassed if the + // adjacencies would stay the same but the metrics would get updated). state = state.setIn(['nodes', node.id], fromJS(node)); } }); diff --git a/client/app/scripts/selectors/nodes-chart-layout.js b/client/app/scripts/selectors/nodes-chart-layout.js index 604b81dfd..4670fab28 100644 --- a/client/app/scripts/selectors/nodes-chart-layout.js +++ b/client/app/scripts/selectors/nodes-chart-layout.js @@ -51,6 +51,20 @@ const layoutOptionsSelector = createStructuredSelector({ export const graphLayout = createSelector( [ + // TODO: Instead of sending the nodes with all the information (metrics, metadata, etc...) + // to the layout engine, it would suffice to forward it just the nodes adjacencies map, which + // we could get with another selector like: + // + // const nodesAdjacenciesSelector = createMapSelector( + // [ (_, props) => props.nodes ], + // node => node.get('adjacency') || makeList() + // ); + // + // That would enable us to use smarter caching, so that the layout doesn't get recalculated + // if adjacencies don't change but e.g. metrics gets updated. We also don't need to init + // edges here as the adjacencies data is enough to reconstruct them in the layout engine (this + // might enable us to simplify the caching system there since we really only need to cache + // the adjacencies map in that case and not nodes and edges). (_, props) => props.nodes, layoutOptionsSelector, ], diff --git a/client/app/styles/_base.scss b/client/app/styles/_base.scss index d820c3f8b..63408881a 100644 --- a/client/app/styles/_base.scss +++ b/client/app/styles/_base.scss @@ -388,10 +388,6 @@ } } - &.blurred { - opacity: $node-opacity-blurred; - } - &.matched .shape { animation: throb 0.5s $base-ease; } diff --git a/client/app/styles/_contrast-overrides.scss b/client/app/styles/_contrast-overrides.scss index 1ae13c32b..9685d363b 100644 --- a/client/app/styles/_contrast-overrides.scss +++ b/client/app/styles/_contrast-overrides.scss @@ -11,7 +11,6 @@ $border-light-color: lighten($text-color, 50%); $text-darker-color: darken($text-color, 20%); $white: white; -$node-opacity-blurred: 0.6; $node-highlight-fill-opacity: 0.3; $node-highlight-stroke-opacity: 0.5; $node-highlight-stroke-width: 8; @@ -19,7 +18,6 @@ $node-border-stroke-width: 10; $node-pseudo-opacity: 1; $edge-highlight-opacity: 0.3; $edge-opacity-blurred: 0; -$edge-opacity: 0.5; $btn-opacity-default: 1; $btn-opacity-hover: 1; diff --git a/client/app/styles/_variables.scss b/client/app/styles/_variables.scss index 778322088..9c3c5fdff 100644 --- a/client/app/styles/_variables.scss +++ b/client/app/styles/_variables.scss @@ -30,7 +30,6 @@ $border-radius: 4px; $terminal-header-height: 44px; -$node-opacity-blurred: 0.25; $node-highlight-fill-opacity: 0.1; $node-highlight-stroke-opacity: 0.4; $node-highlight-stroke-width: 2;