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}
);
@@ -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",