diff --git a/client/.babelrc b/client/.babelrc index 9d92eb7b8..02eef7181 100644 --- a/client/.babelrc +++ b/client/.babelrc @@ -1,6 +1,7 @@ { "plugins": [ "lodash", + "transform-class-properties", ["transform-object-rest-spread", { "useBuiltIns": true }] ], "presets": ["env", "react"] diff --git a/client/app/scripts/components/node-details/node-details-table-row.js b/client/app/scripts/components/node-details/node-details-table-row.js index ed157ab3f..428681465 100644 --- a/client/app/scripts/components/node-details/node-details-table-row.js +++ b/client/app/scripts/components/node-details/node-details-table-row.js @@ -114,46 +114,44 @@ export default class NodeDetailsTableRow extends React.Component { // is most likely a details panel popping open. // this.state = { focused: false }; - this.mouseDragOrigin = [0, 0]; - - this.onMouseDown = this.onMouseDown.bind(this); - this.onMouseUp = this.onMouseUp.bind(this); - this.onMouseEnter = this.onMouseEnter.bind(this); - this.onMouseLeave = this.onMouseLeave.bind(this); + this.mouseDrag = {}; } - onMouseEnter() { + onMouseEnter = () => { this.setState({ focused: true }); if (this.props.onMouseEnter) { this.props.onMouseEnter(this.props.index, this.props.node); } } - onMouseLeave() { + onMouseLeave = () => { this.setState({ focused: false }); if (this.props.onMouseLeave) { this.props.onMouseLeave(); } } - onMouseDown(ev) { - const { pageX, pageY } = ev; - this.mouseDragOrigin = [pageX, pageY]; + onMouseDown = (ev) => { + this.mouseDrag = { + originX: ev.pageX, + originY: ev.pageY, + }; } - onMouseUp(ev) { - const [originX, originY] = this.mouseDragOrigin; - const { pageX, pageY } = ev; + onClick = (ev) => { const thresholdPx = 2; + const { pageX, pageY } = ev; + const { originX, originY } = this.mouseDrag; const movedTheMouseTooMuch = ( Math.abs(originX - pageX) > thresholdPx || Math.abs(originY - pageY) > thresholdPx ); - if (movedTheMouseTooMuch) { + if (movedTheMouseTooMuch && originX && originY) { return; } this.props.onClick(ev, this.props.node); + this.mouseDrag = {}; } render() { @@ -171,8 +169,8 @@ export default class NodeDetailsTableRow extends React.Component { return ( diff --git a/client/app/scripts/components/topologies.js b/client/app/scripts/components/topologies.js index d75439db8..7fa49eb13 100644 --- a/client/app/scripts/components/topologies.js +++ b/client/app/scripts/components/topologies.js @@ -39,7 +39,7 @@ class Topologies extends React.Component { const isActive = subTopology === this.props.currentTopology; const searchMatchCount = this.props.searchMatchCountByTopology.get(topologyId) || 0; const title = basicTopologyInfo(subTopology, searchMatchCount); - const className = classnames('topologies-sub-item', { + const className = classnames(`topologies-sub-item topologies-item-${topologyId}`, { // Don't show matches in the resource view as searching is not supported there yet. 'topologies-sub-item-matched': !this.props.isResourceViewMode && searchMatchCount, 'topologies-sub-item-active': isActive, @@ -60,14 +60,14 @@ class Topologies extends React.Component { } renderTopology(topology) { + const topologyId = topology.get('id'); const isActive = topology === this.props.currentTopology; const searchMatchCount = this.props.searchMatchCountByTopology.get(topology.get('id')) || 0; - const className = classnames('topologies-item-main', { + const className = classnames(`topologies-item-main topologies-item-${topologyId}`, { // Don't show matches in the resource view as searching is not supported there yet. 'topologies-item-main-matched': !this.props.isResourceViewMode && searchMatchCount, 'topologies-item-main-active': isActive, }); - const topologyId = topology.get('id'); const title = basicTopologyInfo(topology, searchMatchCount); return ( diff --git a/client/app/scripts/components/view-mode-button.js b/client/app/scripts/components/view-mode-button.js new file mode 100644 index 000000000..ce18bedfa --- /dev/null +++ b/client/app/scripts/components/view-mode-button.js @@ -0,0 +1,52 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import classNames from 'classnames'; + +import { trackAnalyticsEvent } from '../utils/tracking-utils'; + + +class ViewModeButton extends React.Component { + constructor(props) { + super(props); + + this.handleClick = this.handleClick.bind(this); + } + + handleClick() { + trackAnalyticsEvent('scope.layout.selector.click', { + layout: this.props.viewMode, + topologyId: this.props.currentTopology.get('id'), + parentTopologyId: this.props.currentTopology.get('parentId'), + }); + this.props.onClick(); + } + + render() { + const { label, viewMode, disabled } = this.props; + + const isSelected = (this.props.topologyViewMode === viewMode); + const className = classNames(`view-mode-selector-action view-${label}-action`, { + 'view-mode-selector-action-selected': isSelected, + }); + + return ( +
+ + {label} +
+ ); + } +} + +function mapStateToProps(state) { + return { + topologyViewMode: state.get('topologyViewMode'), + currentTopology: state.get('currentTopology'), + }; +} + +export default connect(mapStateToProps)(ViewModeButton); diff --git a/client/app/scripts/components/view-mode-selector.js b/client/app/scripts/components/view-mode-selector.js index b2a2b75ce..8c5cf9173 100644 --- a/client/app/scripts/components/view-mode-selector.js +++ b/client/app/scripts/components/view-mode-selector.js @@ -1,9 +1,8 @@ import React from 'react'; import { connect } from 'react-redux'; -import classNames from 'classnames'; +import ViewModeButton from './view-mode-button'; import MetricSelector from './metric-selector'; -import { trackAnalyticsEvent } from '../utils/tracking-utils'; import { setGraphView, setTableView, setResourceView } from '../actions/app-actions'; import { availableMetricsSelector } from '../selectors/node-metric'; import { @@ -24,44 +23,29 @@ class ViewModeSelector extends React.Component { } } - renderItem(icons, label, viewMode, setViewModeAction, isEnabled = true) { - const isSelected = (this.props.topologyViewMode === viewMode); - const className = classNames('view-mode-selector-action', { - 'view-mode-selector-action-selected': isSelected, - }); - const onClick = () => { - trackAnalyticsEvent('scope.layout.selector.click', { - layout: viewMode, - topologyId: this.props.currentTopology.get('id'), - parentTopologyId: this.props.currentTopology.get('parentId'), - }); - setViewModeAction(); - }; - - return ( -
- - {label} -
- ); - } - render() { - const { hasResourceView } = this.props; - return (
- {this.renderItem('fa fa-share-alt', 'Graph', GRAPH_VIEW_MODE, this.props.setGraphView)} - {this.renderItem('fa fa-table', 'Table', TABLE_VIEW_MODE, this.props.setTableView)} - {this.renderItem( -'fa fa-bar-chart', 'Resources', RESOURCE_VIEW_MODE, - this.props.setResourceView, hasResourceView -)} + + +
diff --git a/client/app/styles/_base.scss b/client/app/styles/_base.scss index 6352e295e..d00c82dab 100644 --- a/client/app/styles/_base.scss +++ b/client/app/styles/_base.scss @@ -371,10 +371,10 @@ a { .nodes-chart-overlay { pointer-events: none; - opacity: 0; + opacity: $node-elements-in-background-opacity; - &.active { - opacity: $node-elements-in-background-opacity; + &:not(.active) { + display: none; } } diff --git a/client/package.json b/client/package.json index e22620aae..126183f5f 100644 --- a/client/package.json +++ b/client/package.json @@ -54,6 +54,7 @@ "babel-eslint": "8.0.1", "babel-jest": "21.2.0", "babel-loader": "6.4.1", + "babel-plugin-transform-class-properties": "6.24.1", "babel-plugin-transform-object-rest-spread": "6.26.0", "babel-preset-env": "1.6.1", "babel-preset-react": "6.24.1", diff --git a/client/yarn.lock b/client/yarn.lock index 9aee46b7c..5d35f4f22 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -604,6 +604,10 @@ babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" +babel-plugin-syntax-class-properties@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" @@ -632,6 +636,15 @@ babel-plugin-transform-async-to-generator@^6.22.0: babel-plugin-syntax-async-functions "^6.8.0" babel-runtime "^6.22.0" +babel-plugin-transform-class-properties@6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" + dependencies: + babel-helper-function-name "^6.24.1" + babel-plugin-syntax-class-properties "^6.8.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-plugin-transform-es2015-arrow-functions@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221"