diff --git a/client/.eslintrc b/client/.eslintrc index d5928ee0c..6ab748f15 100644 --- a/client/.eslintrc +++ b/client/.eslintrc @@ -1,216 +1,12 @@ { - "parser": "babel-eslint", - "plugins": [ - "react", - "jasmine" - ], - "env": { - "browser": true, - "node": true - }, - "ecmaFeatures": { - "arrowFunctions": true, - "blockBindings": true, - "classes": true, - "defaultParams": true, - "destructuring": true, - "forOf": true, - "generators": false, - "modules": true, - "objectLiteralComputedProperties": true, - "objectLiteralDuplicateProperties": false, - "objectLiteralShorthandMethods": true, - "objectLiteralShorthandProperties": true, - "spread": true, - "superInFunctions": true, - "templateStrings": true, - "jsx": true - }, + "extends": "airbnb", "globals": { __WS_URL__: false }, "rules": { -/** - * Strict mode - */ - // babel inserts "use strict"; for us - // http://eslint.org/docs/rules/strict - "strict": [2, "never"], - -/** - * ES6 - */ - "no-var": 2, // http://eslint.org/docs/rules/no-var - -/** - * Variables - */ - "no-shadow": 2, // http://eslint.org/docs/rules/no-shadow - "no-shadow-restricted-names": 2, // http://eslint.org/docs/rules/no-shadow-restricted-names - "no-unused-vars": [2, { // http://eslint.org/docs/rules/no-unused-vars - "vars": "local", - "args": "after-used" - }], - "no-use-before-define": 2, // http://eslint.org/docs/rules/no-use-before-define - -/** - * Possible errors - */ - "comma-dangle": [2, "never"], // http://eslint.org/docs/rules/comma-dangle - "no-cond-assign": [2, "always"], // http://eslint.org/docs/rules/no-cond-assign - "no-console": 1, // http://eslint.org/docs/rules/no-console - "no-debugger": 1, // http://eslint.org/docs/rules/no-debugger - "no-alert": 1, // http://eslint.org/docs/rules/no-alert - "no-constant-condition": 1, // http://eslint.org/docs/rules/no-constant-condition - "no-dupe-keys": 2, // http://eslint.org/docs/rules/no-dupe-keys - "no-duplicate-case": 2, // http://eslint.org/docs/rules/no-duplicate-case - "no-empty": 2, // http://eslint.org/docs/rules/no-empty - "no-ex-assign": 2, // http://eslint.org/docs/rules/no-ex-assign - "no-extra-boolean-cast": 0, // http://eslint.org/docs/rules/no-extra-boolean-cast - "no-extra-semi": 2, // http://eslint.org/docs/rules/no-extra-semi - "no-func-assign": 2, // http://eslint.org/docs/rules/no-func-assign - "no-inner-declarations": 2, // http://eslint.org/docs/rules/no-inner-declarations - "no-invalid-regexp": 2, // http://eslint.org/docs/rules/no-invalid-regexp - "no-irregular-whitespace": 2, // http://eslint.org/docs/rules/no-irregular-whitespace - "no-obj-calls": 2, // http://eslint.org/docs/rules/no-obj-calls - "no-reserved-keys": 2, // http://eslint.org/docs/rules/no-reserved-keys - "no-sparse-arrays": 2, // http://eslint.org/docs/rules/no-sparse-arrays - "no-unreachable": 2, // http://eslint.org/docs/rules/no-unreachable - "use-isnan": 2, // http://eslint.org/docs/rules/use-isnan - "block-scoped-var": 2, // http://eslint.org/docs/rules/block-scoped-var - -/** - * Best practices - */ - "consistent-return": 2, // http://eslint.org/docs/rules/consistent-return - "curly": [2, "multi-line"], // http://eslint.org/docs/rules/curly - "default-case": 2, // http://eslint.org/docs/rules/default-case - "dot-notation": [2, { // http://eslint.org/docs/rules/dot-notation - "allowKeywords": true - }], - "eqeqeq": 2, // http://eslint.org/docs/rules/eqeqeq - "guard-for-in": 2, // http://eslint.org/docs/rules/guard-for-in - "no-caller": 2, // http://eslint.org/docs/rules/no-caller - "no-else-return": 2, // http://eslint.org/docs/rules/no-else-return - "no-eq-null": 2, // http://eslint.org/docs/rules/no-eq-null - "no-eval": 2, // http://eslint.org/docs/rules/no-eval - "no-extend-native": 2, // http://eslint.org/docs/rules/no-extend-native - "no-extra-bind": 2, // http://eslint.org/docs/rules/no-extra-bind - "no-fallthrough": 2, // http://eslint.org/docs/rules/no-fallthrough - "no-floating-decimal": 2, // http://eslint.org/docs/rules/no-floating-decimal - "no-implied-eval": 2, // http://eslint.org/docs/rules/no-implied-eval - "no-lone-blocks": 2, // http://eslint.org/docs/rules/no-lone-blocks - "no-loop-func": 2, // http://eslint.org/docs/rules/no-loop-func - "no-multi-str": 2, // http://eslint.org/docs/rules/no-multi-str - "no-native-reassign": 2, // http://eslint.org/docs/rules/no-native-reassign - "no-new": 2, // http://eslint.org/docs/rules/no-new - "no-new-func": 2, // http://eslint.org/docs/rules/no-new-func - "no-new-wrappers": 2, // http://eslint.org/docs/rules/no-new-wrappers - "no-octal": 2, // http://eslint.org/docs/rules/no-octal - "no-octal-escape": 2, // http://eslint.org/docs/rules/no-octal-escape - "no-param-reassign": 2, // http://eslint.org/docs/rules/no-param-reassign - "no-proto": 2, // http://eslint.org/docs/rules/no-proto - "no-redeclare": 2, // http://eslint.org/docs/rules/no-redeclare - "no-return-assign": 2, // http://eslint.org/docs/rules/no-return-assign - "no-script-url": 2, // http://eslint.org/docs/rules/no-script-url - "no-self-compare": 2, // http://eslint.org/docs/rules/no-self-compare - "no-sequences": 2, // http://eslint.org/docs/rules/no-sequences - "no-throw-literal": 2, // http://eslint.org/docs/rules/no-throw-literal - "no-with": 2, // http://eslint.org/docs/rules/no-with - "radix": 2, // http://eslint.org/docs/rules/radix - "vars-on-top": 2, // http://eslint.org/docs/rules/vars-on-top - "wrap-iife": [2, "any"], // http://eslint.org/docs/rules/wrap-iife - "yoda": 2, // http://eslint.org/docs/rules/yoda - -/** - * Style - */ - "indent": [2, 2], // http://eslint.org/docs/rules/ - "brace-style": [2, // http://eslint.org/docs/rules/brace-style - "1tbs", { - "allowSingleLine": true - }], - "quotes": [ - 2, "single", "avoid-escape" // http://eslint.org/docs/rules/quotes - ], - "camelcase": [2, { // http://eslint.org/docs/rules/camelcase - "properties": "never" - }], - "comma-spacing": [2, { // http://eslint.org/docs/rules/comma-spacing - "before": false, - "after": true - }], - "comma-style": [2, "last"], // http://eslint.org/docs/rules/comma-style - "eol-last": 2, // http://eslint.org/docs/rules/eol-last - "func-names": 0, // http://eslint.org/docs/rules/func-names - "key-spacing": [2, { // http://eslint.org/docs/rules/key-spacing - "beforeColon": false, - "afterColon": true - }], - "new-cap": [2, { // http://eslint.org/docs/rules/new-cap - "newIsCap": true - }], - "no-multiple-empty-lines": [2, { // http://eslint.org/docs/rules/no-multiple-empty-lines - "max": 2 - }], - "no-nested-ternary": 2, // http://eslint.org/docs/rules/no-nested-ternary - "no-new-object": 2, // http://eslint.org/docs/rules/no-new-object - "no-spaced-func": 2, // http://eslint.org/docs/rules/no-spaced-func - "no-trailing-spaces": 2, // http://eslint.org/docs/rules/no-trailing-spaces - "no-wrap-func": 2, // http://eslint.org/docs/rules/no-wrap-func - "no-underscore-dangle": 0, // http://eslint.org/docs/rules/no-underscore-dangle - "one-var": [2, "never"], // http://eslint.org/docs/rules/one-var - "padded-blocks": [2, "never"], // http://eslint.org/docs/rules/padded-blocks - "semi": [2, "always"], // http://eslint.org/docs/rules/semi - "semi-spacing": [2, { // http://eslint.org/docs/rules/semi-spacing - "before": false, - "after": true - }], - "space-after-keywords": 2, // http://eslint.org/docs/rules/space-after-keywords - "space-before-blocks": 2, // http://eslint.org/docs/rules/space-before-blocks - "space-before-function-paren": [2, "never"], // http://eslint.org/docs/rules/space-before-function-paren - "space-infix-ops": 2, // http://eslint.org/docs/rules/space-infix-ops - "space-return-throw-case": 2, // http://eslint.org/docs/rules/space-return-throw-case - "spaced-line-comment": 2, // http://eslint.org/docs/rules/spaced-line-comment - -/** - * JSX style - */ - "react/display-name": 0, - "react/jsx-boolean-value": 2, - "react/jsx-quotes": [2, "double"], - "react/jsx-no-undef": 2, - "react/jsx-sort-props": 0, - "react/jsx-sort-prop-types": 0, - "react/jsx-uses-react": 2, - "react/jsx-uses-vars": 2, - "react/no-did-mount-set-state": [2, "allow-in-func"], - "react/no-did-update-set-state": 2, - "react/no-multi-comp": 2, - "react/no-unknown-property": 2, - "react/prop-types": 0, - "react/react-in-jsx-scope": 2, - "react/self-closing-comp": 2, - "react/wrap-multilines": 2, - "react/sort-comp": [2, { - "order": [ - "displayName", - "mixins", - "statics", - "propTypes", - "getDefaultProps", - "getInitialState", - "componentWillMount", - "componentDidMount", - "componentWillReceiveProps", - "shouldComponentUpdate", - "componentWillUpdate", - "componentWillUnmount", - "/^on.+$/", - "/^get.+$/", - "/^render.+$/", - "render" - ] - }] + "comma-dangle": 0, + "func-names": 0, + "react/sort-comp": 0, + "react/prop-types": 0 } } diff --git a/client/app/scripts/actions/app-actions.js b/client/app/scripts/actions/app-actions.js index 3950ec525..1e0223c17 100644 --- a/client/app/scripts/actions/app-actions.js +++ b/client/app/scripts/actions/app-actions.js @@ -85,7 +85,7 @@ module.exports = { WebapiUtils.doControl( probeId, nodeId, - control, + control ); }, diff --git a/client/app/scripts/charts/edge.js b/client/app/scripts/charts/edge.js index 5a40ea3cd..83ada988e 100644 --- a/client/app/scripts/charts/edge.js +++ b/client/app/scripts/charts/edge.js @@ -1,7 +1,8 @@ const _ = require('lodash'); const d3 = require('d3'); const React = require('react'); -const Spring = require('react-motion').Spring; +const Motion = require('react-motion').Motion; +const spring = require('react-motion').spring; const AppActions = require('../actions/app-actions'); @@ -15,8 +16,8 @@ const animConfig = [80, 20]; // stiffness, bounce const flattenPoints = function(points) { const flattened = {}; points.forEach(function(point, i) { - flattened['x' + i] = {val: point.x, config: animConfig}; - flattened['y' + i] = {val: point.y, config: animConfig}; + flattened['x' + i] = spring(point.x, animConfig); + flattened['y' + i] = spring(point.y, animConfig); }); return flattened; }; @@ -29,7 +30,7 @@ const extractPoints = function(points) { if (!extracted[index]) { extracted[index] = {}; } - extracted[index][axis] = value.val; + extracted[index][axis] = value; }); return extracted; }; @@ -66,7 +67,7 @@ const Edge = React.createClass({ const classes = classNames.join(' '); return ( - + {function(interpolated) { const path = line(extractPoints(interpolated)); return ( @@ -76,7 +77,7 @@ const Edge = React.createClass({ ); }} - + ); }, diff --git a/client/app/scripts/charts/node.js b/client/app/scripts/charts/node.js index a0dc57af9..b2c2d3ab7 100644 --- a/client/app/scripts/charts/node.js +++ b/client/app/scripts/charts/node.js @@ -1,5 +1,6 @@ const React = require('react'); -const Spring = require('react-motion').Spring; +const Motion = require('react-motion').Motion; +const spring = require('react-motion').spring; const AppActions = require('../actions/app-actions'); const NodeColorMixin = require('../mixins/node-color-mixin'); @@ -42,30 +43,30 @@ const Node = React.createClass({ const classes = classNames.join(' '); return ( - {function(interpolated) { - const transform = `translate(${interpolated.x.val},${interpolated.y.val})`; + const transform = `translate(${interpolated.x},${interpolated.y})`; return ( - {props.highlighted && } - - - - + {props.highlighted && } + + + + {label} - + {subLabel} ); }} - + ); }, diff --git a/client/app/scripts/charts/nodes-chart.js b/client/app/scripts/charts/nodes-chart.js index f2d3a2dd9..d8647cd77 100644 --- a/client/app/scripts/charts/nodes-chart.js +++ b/client/app/scripts/charts/nodes-chart.js @@ -4,7 +4,8 @@ const debug = require('debug')('scope:nodes-chart'); const React = require('react'); const makeMap = require('immutable').Map; const timely = require('timely'); -const Spring = require('react-motion').Spring; +const Motion = require('react-motion').Motion; +const spring = require('react-motion').spring; const AppActions = require('../actions/app-actions'); const AppStore = require('../stores/app-store'); @@ -199,7 +200,7 @@ const NodesChart = React.createClass({ render: function() { const nodeElements = this.renderGraphNodes(this.state.nodes, this.state.nodeScale); const edgeElements = this.renderGraphEdges(this.state.edges, this.state.nodeScale); - let scale = this.state.scale; + const scale = this.state.scale; // only animate shift behavior, not panning const panTranslate = this.state.panTranslate; @@ -213,15 +214,16 @@ const NodesChart = React.createClass({ const svgClassNames = this.state.maxNodesExceeded || nodeElements.size === 0 ? 'hide' : ''; const errorEmpty = this.renderEmptyTopologyError(AppStore.isTopologyEmpty()); const errorMaxNodesExceeded = this.renderMaxNodesError(this.state.maxNodesExceeded); + const motionConfig = [80, 20]; return (
{errorEmpty} {errorMaxNodesExceeded} - + {function(interpolated) { - let interpolatedTranslate = wasShifted ? interpolated.val : panTranslate; + const interpolatedTranslate = wasShifted ? [interpolated.x, interpolated.y] : panTranslate; const transform = 'translate(' + interpolatedTranslate + ')' + ' scale(' + scale + ')'; return ( @@ -235,7 +237,7 @@ const NodesChart = React.createClass({ ); }} - +
); @@ -291,14 +293,14 @@ const NodesChart = React.createClass({ centerSelectedNode: function(props, state) { let stateNodes = state.nodes; let stateEdges = state.edges; - let selectedLayoutNode = stateNodes.get(props.selectedNodeId); + const selectedLayoutNode = stateNodes.get(props.selectedNodeId); if (!selectedLayoutNode) { return {}; } const adjacency = AppStore.getAdjacentNodes(props.selectedNodeId); - let adjacentLayoutNodeIds = []; + const adjacentLayoutNodeIds = []; adjacency.forEach(function(adjacentId) { // filter loopback diff --git a/client/app/scripts/charts/nodes-error.js b/client/app/scripts/charts/nodes-error.js index 5c152678b..c2edda629 100644 --- a/client/app/scripts/charts/nodes-error.js +++ b/client/app/scripts/charts/nodes-error.js @@ -7,7 +7,7 @@ const NodesError = React.createClass({ if (this.props.hidden) { classNames += ' hide'; } - let iconClassName = 'fa ' + this.props.faIconClass; + const iconClassName = 'fa ' + this.props.faIconClass; return (
diff --git a/client/app/scripts/charts/nodes-layout.js b/client/app/scripts/charts/nodes-layout.js index 310192f02..21e74ebd8 100644 --- a/client/app/scripts/charts/nodes-layout.js +++ b/client/app/scripts/charts/nodes-layout.js @@ -1,3 +1,6 @@ +// polyfill +Object.assign = require('object-assign'); + const dagre = require('dagre'); const debug = require('debug')('scope:nodes-layout'); const makeMap = require('immutable').Map; @@ -181,7 +184,7 @@ function hasSameEndpoints(cachedEdge, nodes) { * @return {Object} layout clone */ function cloneLayout(layout, nodes, edges) { - const clone = {...layout, nodes, edges}; + const clone = Object.assign({}, layout, {nodes, edges}); return clone; } diff --git a/client/app/scripts/components/__tests__/node-details-test.js b/client/app/scripts/components/__tests__/node-details-test.js index d4b17f41d..0edc74f15 100644 --- a/client/app/scripts/components/__tests__/node-details-test.js +++ b/client/app/scripts/components/__tests__/node-details-test.js @@ -31,7 +31,7 @@ describe('NodeDetails', () => { const c = TestUtils.renderIntoDocument(); const title = TestUtils.findRenderedDOMComponentWithClass(c, 'node-details-header-label'); - expect(title.getDOMNode().textContent).toBe('Node 1'); + expect(title.textContent).toBe('Node 1'); }); }); diff --git a/client/app/scripts/components/app.js b/client/app/scripts/components/app.js index aaeabc08e..f31f70747 100644 --- a/client/app/scripts/components/app.js +++ b/client/app/scripts/components/app.js @@ -1,5 +1,4 @@ const React = require('react'); -const mui = require('material-ui'); const Logo = require('./logo'); const AppStore = require('../stores/app-store'); @@ -13,8 +12,6 @@ const Details = require('./details'); const Nodes = require('./nodes'); const RouterUtils = require('../utils/router-utils'); -const ThemeManager = new mui.Styles.ThemeManager(); - const ESC_KEY_CODE = 27; function getStateFromStores() { @@ -67,12 +64,6 @@ const App = React.createClass({ } }, - getChildContext: function() { - return { - muiTheme: ThemeManager.getCurrentTheme() - }; - }, - render: function() { const showingDetails = this.state.selectedNodeId; const versionString = this.state.version ? 'Version ' + this.state.version : ''; @@ -115,9 +106,6 @@ const App = React.createClass({ ); }, - childContextTypes: { - muiTheme: React.PropTypes.object - } }); module.exports = App; diff --git a/client/app/scripts/components/details.js b/client/app/scripts/components/details.js index 459e6a66f..9bd1b9c8c 100644 --- a/client/app/scripts/components/details.js +++ b/client/app/scripts/components/details.js @@ -1,6 +1,4 @@ const React = require('react'); -const mui = require('material-ui'); -const Paper = mui.Paper; const NodeDetails = require('./node-details'); @@ -9,9 +7,11 @@ const Details = React.createClass({ render: function() { return (
- +
- +
); } diff --git a/client/app/scripts/main.js b/client/app/scripts/main.js index 5be55cab5..d2ab52ec8 100644 --- a/client/app/scripts/main.js +++ b/client/app/scripts/main.js @@ -2,9 +2,10 @@ require('font-awesome-webpack'); require('../styles/main.less'); const React = require('react'); +const ReactDOM = require('react-dom'); const App = require('./components/app.js'); -React.render( +ReactDOM.render( , document.getElementById('app')); diff --git a/client/app/scripts/stores/app-store.js b/client/app/scripts/stores/app-store.js index 1c8606cd1..b13c6c6f7 100644 --- a/client/app/scripts/stores/app-store.js +++ b/client/app/scripts/stores/app-store.js @@ -242,186 +242,186 @@ const AppStore = assign({}, EventEmitter.prototype, { AppStore.registeredCallback = function(payload) { switch (payload.type) { - case ActionTypes.CHANGE_TOPOLOGY_OPTION: - if (topologyOptions.getIn([payload.topologyId, payload.option]) - !== payload.value) { - nodes = nodes.clear(); - } - topologyOptions = topologyOptions.setIn( - [payload.topologyId, payload.option], - payload.value - ); - AppStore.emit(AppStore.CHANGE_EVENT); - break; - - case ActionTypes.CLEAR_CONTROL_ERROR: - controlError = null; - AppStore.emit(AppStore.CHANGE_EVENT); - break; - - case ActionTypes.CLICK_CLOSE_DETAILS: - selectedNodeId = null; - AppStore.emit(AppStore.CHANGE_EVENT); - break; - - case ActionTypes.CLICK_NODE: - if (payload.nodeId === selectedNodeId) { - // clicking same node twice unsets the selection - selectedNodeId = null; - } else { - selectedNodeId = payload.nodeId; - } - AppStore.emit(AppStore.CHANGE_EVENT); - break; - - case ActionTypes.CLICK_TOPOLOGY: - selectedNodeId = null; - if (payload.topologyId !== currentTopologyId) { - setTopology(payload.topologyId); - nodes = nodes.clear(); - } - AppStore.emit(AppStore.CHANGE_EVENT); - break; - - case ActionTypes.CLOSE_WEBSOCKET: - websocketClosed = true; - AppStore.emit(AppStore.CHANGE_EVENT); - break; - - case ActionTypes.DO_CONTROL: - controlPending = true; - controlError = null; - AppStore.emit(AppStore.CHANGE_EVENT); - break; - - case ActionTypes.ENTER_EDGE: - mouseOverEdgeId = payload.edgeId; - AppStore.emit(AppStore.CHANGE_EVENT); - break; - - case ActionTypes.ENTER_NODE: - mouseOverNodeId = payload.nodeId; - AppStore.emit(AppStore.CHANGE_EVENT); - break; - - case ActionTypes.HIT_ESC_KEY: - nodeDetails = null; - selectedNodeId = null; - AppStore.emit(AppStore.CHANGE_EVENT); - break; - - case ActionTypes.LEAVE_EDGE: - mouseOverEdgeId = null; - AppStore.emit(AppStore.CHANGE_EVENT); - break; - - case ActionTypes.LEAVE_NODE: - mouseOverNodeId = null; - AppStore.emit(AppStore.CHANGE_EVENT); - break; - - case ActionTypes.OPEN_WEBSOCKET: - // flush nodes cache after re-connect + case ActionTypes.CHANGE_TOPOLOGY_OPTION: + if (topologyOptions.getIn([payload.topologyId, payload.option]) + !== payload.value) { nodes = nodes.clear(); - websocketClosed = false; + } + topologyOptions = topologyOptions.setIn( + [payload.topologyId, payload.option], + payload.value + ); + AppStore.emit(AppStore.CHANGE_EVENT); + break; - AppStore.emit(AppStore.CHANGE_EVENT); - break; + case ActionTypes.CLEAR_CONTROL_ERROR: + controlError = null; + AppStore.emit(AppStore.CHANGE_EVENT); + break; - case ActionTypes.DO_CONTROL_ERROR: - controlPending = false; - controlError = payload.error; - AppStore.emit(AppStore.CHANGE_EVENT); - break; + case ActionTypes.CLICK_CLOSE_DETAILS: + selectedNodeId = null; + AppStore.emit(AppStore.CHANGE_EVENT); + break; - case ActionTypes.DO_CONTROL_SUCCESS: - controlPending = false; - controlError = null; - AppStore.emit(AppStore.CHANGE_EVENT); - break; + case ActionTypes.CLICK_NODE: + if (payload.nodeId === selectedNodeId) { + // clicking same node twice unsets the selection + selectedNodeId = null; + } else { + selectedNodeId = payload.nodeId; + } + AppStore.emit(AppStore.CHANGE_EVENT); + break; - case ActionTypes.RECEIVE_ERROR: - errorUrl = payload.errorUrl; - AppStore.emit(AppStore.CHANGE_EVENT); - break; + case ActionTypes.CLICK_TOPOLOGY: + selectedNodeId = null; + if (payload.topologyId !== currentTopologyId) { + setTopology(payload.topologyId); + nodes = nodes.clear(); + } + AppStore.emit(AppStore.CHANGE_EVENT); + break; - case ActionTypes.RECEIVE_NODE_DETAILS: - errorUrl = null; - nodeDetails = payload.details; - AppStore.emit(AppStore.CHANGE_EVENT); - break; + case ActionTypes.CLOSE_WEBSOCKET: + websocketClosed = true; + AppStore.emit(AppStore.CHANGE_EVENT); + break; - case ActionTypes.RECEIVE_NODES_DELTA: - const emptyMessage = !payload.delta.add && !payload.delta.remove - && payload.delta.update; + case ActionTypes.DO_CONTROL: + controlPending = true; + controlError = null; + AppStore.emit(AppStore.CHANGE_EVENT); + break; - if (!emptyMessage) { - debug('RECEIVE_NODES_DELTA', - 'remove', _.size(payload.delta.remove), - 'update', _.size(payload.delta.update), - 'add', _.size(payload.delta.add)); + case ActionTypes.ENTER_EDGE: + mouseOverEdgeId = payload.edgeId; + AppStore.emit(AppStore.CHANGE_EVENT); + break; + + case ActionTypes.ENTER_NODE: + mouseOverNodeId = payload.nodeId; + AppStore.emit(AppStore.CHANGE_EVENT); + break; + + case ActionTypes.HIT_ESC_KEY: + nodeDetails = null; + selectedNodeId = null; + AppStore.emit(AppStore.CHANGE_EVENT); + break; + + case ActionTypes.LEAVE_EDGE: + mouseOverEdgeId = null; + AppStore.emit(AppStore.CHANGE_EVENT); + break; + + case ActionTypes.LEAVE_NODE: + mouseOverNodeId = null; + AppStore.emit(AppStore.CHANGE_EVENT); + break; + + case ActionTypes.OPEN_WEBSOCKET: + // flush nodes cache after re-connect + nodes = nodes.clear(); + websocketClosed = false; + + AppStore.emit(AppStore.CHANGE_EVENT); + break; + + case ActionTypes.DO_CONTROL_ERROR: + controlPending = false; + controlError = payload.error; + AppStore.emit(AppStore.CHANGE_EVENT); + break; + + case ActionTypes.DO_CONTROL_SUCCESS: + controlPending = false; + controlError = null; + AppStore.emit(AppStore.CHANGE_EVENT); + break; + + case ActionTypes.RECEIVE_ERROR: + errorUrl = payload.errorUrl; + AppStore.emit(AppStore.CHANGE_EVENT); + break; + + case ActionTypes.RECEIVE_NODE_DETAILS: + errorUrl = null; + nodeDetails = payload.details; + AppStore.emit(AppStore.CHANGE_EVENT); + break; + + case ActionTypes.RECEIVE_NODES_DELTA: + const emptyMessage = !payload.delta.add && !payload.delta.remove + && payload.delta.update; + + if (!emptyMessage) { + debug('RECEIVE_NODES_DELTA', + 'remove', _.size(payload.delta.remove), + 'update', _.size(payload.delta.update), + 'add', _.size(payload.delta.add)); + } + + errorUrl = null; + + // nodes that no longer exist + _.each(payload.delta.remove, function(nodeId) { + // in case node disappears before mouseleave event + if (mouseOverNodeId === nodeId) { + mouseOverNodeId = null; } - - errorUrl = null; - - // nodes that no longer exist - _.each(payload.delta.remove, function(nodeId) { - // in case node disappears before mouseleave event - if (mouseOverNodeId === nodeId) { - mouseOverNodeId = null; - } - if (nodes.has(nodeId) && _.contains(mouseOverEdgeId, nodeId)) { - mouseOverEdgeId = null; - } - nodes = nodes.delete(nodeId); - }); - - // update existing nodes - _.each(payload.delta.update, function(node) { - nodes = nodes.set(node.id, nodes.get(node.id).merge(makeNode(node))); - }); - - // add new nodes - _.each(payload.delta.add, function(node) { - nodes = nodes.set(node.id, Immutable.fromJS(makeNode(node))); - }); - - AppStore.emit(AppStore.CHANGE_EVENT); - break; - - case ActionTypes.RECEIVE_TOPOLOGIES: - errorUrl = null; - topologies = processTopologies(payload.topologies); - setTopology(currentTopologyId); - // only set on first load, if options are not already set via route - if (!topologiesLoaded && topologyOptions.size === 0) { - setDefaultTopologyOptions(topologies); + if (nodes.has(nodeId) && _.contains(mouseOverEdgeId, nodeId)) { + mouseOverEdgeId = null; } - topologiesLoaded = true; - AppStore.emit(AppStore.CHANGE_EVENT); - break; + nodes = nodes.delete(nodeId); + }); - case ActionTypes.RECEIVE_API_DETAILS: - errorUrl = null; - version = payload.version; - AppStore.emit(AppStore.CHANGE_EVENT); - break; + // update existing nodes + _.each(payload.delta.update, function(node) { + nodes = nodes.set(node.id, nodes.get(node.id).merge(makeNode(node))); + }); - case ActionTypes.ROUTE_TOPOLOGY: - routeSet = true; - if (currentTopologyId !== payload.state.topologyId) { - nodes = nodes.clear(); - } - setTopology(payload.state.topologyId); + // add new nodes + _.each(payload.delta.add, function(node) { + nodes = nodes.set(node.id, Immutable.fromJS(makeNode(node))); + }); + + AppStore.emit(AppStore.CHANGE_EVENT); + break; + + case ActionTypes.RECEIVE_TOPOLOGIES: + errorUrl = null; + topologies = processTopologies(payload.topologies); + setTopology(currentTopologyId); + // only set on first load, if options are not already set via route + if (!topologiesLoaded && topologyOptions.size === 0) { setDefaultTopologyOptions(topologies); - selectedNodeId = payload.state.selectedNodeId; - topologyOptions = Immutable.fromJS(payload.state.topologyOptions) - || topologyOptions; - AppStore.emit(AppStore.CHANGE_EVENT); - break; + } + topologiesLoaded = true; + AppStore.emit(AppStore.CHANGE_EVENT); + break; - default: - break; + case ActionTypes.RECEIVE_API_DETAILS: + errorUrl = null; + version = payload.version; + AppStore.emit(AppStore.CHANGE_EVENT); + break; + + case ActionTypes.ROUTE_TOPOLOGY: + routeSet = true; + if (currentTopologyId !== payload.state.topologyId) { + nodes = nodes.clear(); + } + setTopology(payload.state.topologyId); + setDefaultTopologyOptions(topologies); + selectedNodeId = payload.state.selectedNodeId; + topologyOptions = Immutable.fromJS(payload.state.topologyOptions) + || topologyOptions; + AppStore.emit(AppStore.CHANGE_EVENT); + break; + + default: + break; } }; diff --git a/client/package.json b/client/package.json index 6d4fcbdeb..52c9d4bd0 100644 --- a/client/package.json +++ b/client/package.json @@ -9,19 +9,22 @@ "d3": "~3.5.5", "dagre": "0.7.4", "debug": "~2.2.0", - "flux": "2.0.3", + "flux": "2.1.1", "font-awesome": "4.3.0", "font-awesome-webpack": "0.0.3", "immutable": "~3.7.4", "keymirror": "0.1.1", "lodash": "~3.9.3", - "material-ui": "0.11.0", "materialize-css": "0.96.1", "object-assign": "2.0.0", "page": "1.6.3", - "react": "~0.13.3", - "react-motion": "0.2.7", - "react-tap-event-plugin": "0.1.7", + "react": "0.14.2", + "react-addons-create-fragment": "0.14.2", + "react-addons-pure-render-mixin": "0.14.2", + "react-addons-transition-group": "0.14.2", + "react-addons-update": "0.14.2", + "react-dom": "0.14.2", + "react-motion": "0.3.1", "reqwest": "~1.1.5", "timely": "0.1.0" }, @@ -32,10 +35,11 @@ "babel-jest": "5.3.0", "babel-loader": "5.1.3", "css-loader": "0.14.4", - "eslint": "~0.21.2", - "eslint-loader": "0.11.2", + "eslint": "1.9.0", + "eslint-config-airbnb": "1.0.0", + "eslint-loader": "1.1.1", "eslint-plugin-jasmine": "1.0.0", - "eslint-plugin-react": "2.3.0", + "eslint-plugin-react": "3.8.0", "file-loader": "0.8.4", "jest-cli": "~0.4.19", "json-loader": "0.5.2",