From 99c76dc4c8d479177d73957c1aa1639327935d56 Mon Sep 17 00:00:00 2001 From: David Kaltschmidt Date: Wed, 27 May 2015 18:08:35 +0200 Subject: [PATCH 1/3] fix indentation to 2 spaces in js/less/html --- client/app/index.html | 50 +-- client/app/scripts/actions/app-actions.js | 152 +++---- client/app/scripts/charts/node.js | 96 ++--- client/app/scripts/charts/nodes-chart.js | 388 +++++++++--------- client/app/scripts/charts/nodes-layout.js | 114 ++--- client/app/scripts/components/app.js | 86 ++-- client/app/scripts/components/details.js | 32 +- client/app/scripts/components/explorer.js | 128 +++--- client/app/scripts/components/groupings.js | 86 ++-- client/app/scripts/components/logo.js | 114 ++--- .../scripts/components/node-details-table.js | 42 +- client/app/scripts/components/node-details.js | 54 +-- client/app/scripts/components/nodes.js | 74 ++-- client/app/scripts/components/status.js | 32 +- client/app/scripts/components/topologies.js | 66 +-- client/app/scripts/constants/action-types.js | 24 +- client/app/scripts/constants/topologies.js | 20 +- .../app/scripts/dispatcher/app-dispatcher.js | 6 +- client/app/scripts/main.js | 4 +- client/app/scripts/mixins/node-color-mixin.js | 24 +- .../stores/__tests__/app-store-test.js | 88 ++-- client/app/scripts/stores/app-store.js | 238 +++++------ client/app/scripts/utils/router-utils.js | 22 +- client/app/scripts/utils/web-api-utils.js | 74 ++-- client/app/styles/main.less | 378 +++++++++-------- 25 files changed, 1195 insertions(+), 1197 deletions(-) diff --git a/client/app/index.html b/client/app/index.html index 82ed22d65..3688c7914 100644 --- a/client/app/index.html +++ b/client/app/index.html @@ -1,33 +1,33 @@ - - - Weave Scope - - + + + Weave Scope + + - - + + - - - + + + - - - -
-
-
+ + + +
+
+
- - - + + + - - - - + + + + diff --git a/client/app/scripts/actions/app-actions.js b/client/app/scripts/actions/app-actions.js index 8f493e189..9ebef7b3e 100644 --- a/client/app/scripts/actions/app-actions.js +++ b/client/app/scripts/actions/app-actions.js @@ -2,92 +2,92 @@ var AppDispatcher = require('../dispatcher/app-dispatcher'); var ActionTypes = require('../constants/action-types'); module.exports = { - clickCloseDetails: function() { - AppDispatcher.dispatch({ - type: ActionTypes.CLICK_CLOSE_DETAILS - }); - RouterUtils.updateRoute(); - }, + clickCloseDetails: function() { + AppDispatcher.dispatch({ + type: ActionTypes.CLICK_CLOSE_DETAILS + }); + RouterUtils.updateRoute(); + }, - clickGrouping: function(grouping) { - AppDispatcher.dispatch({ - type: ActionTypes.CLICK_GROUPING, - grouping: grouping - }); - RouterUtils.updateRoute(); - WebapiUtils.getNodesDelta(AppStore.getCurrentTopologyUrl()); - }, + clickGrouping: function(grouping) { + AppDispatcher.dispatch({ + type: ActionTypes.CLICK_GROUPING, + grouping: grouping + }); + RouterUtils.updateRoute(); + WebapiUtils.getNodesDelta(AppStore.getCurrentTopologyUrl()); + }, - clickNode: function(nodeId) { - AppDispatcher.dispatch({ - type: ActionTypes.CLICK_NODE, - nodeId: nodeId - }); - RouterUtils.updateRoute(); - WebapiUtils.getNodeDetails(AppStore.getCurrentTopologyUrl(), AppStore.getSelectedNodeId()); - }, + clickNode: function(nodeId) { + AppDispatcher.dispatch({ + type: ActionTypes.CLICK_NODE, + nodeId: nodeId + }); + RouterUtils.updateRoute(); + WebapiUtils.getNodeDetails(AppStore.getCurrentTopologyUrl(), AppStore.getSelectedNodeId()); + }, - clickTopology: function(topologyId) { - AppDispatcher.dispatch({ - type: ActionTypes.CLICK_TOPOLOGY, - topologyId: topologyId - }); - RouterUtils.updateRoute(); - WebapiUtils.getNodesDelta(AppStore.getCurrentTopologyUrl()); - }, + clickTopology: function(topologyId) { + AppDispatcher.dispatch({ + type: ActionTypes.CLICK_TOPOLOGY, + topologyId: topologyId + }); + RouterUtils.updateRoute(); + WebapiUtils.getNodesDelta(AppStore.getCurrentTopologyUrl()); + }, - enterNode: function(nodeId) { - AppDispatcher.dispatch({ - type: ActionTypes.ENTER_NODE, - nodeId: nodeId - }); - }, + enterNode: function(nodeId) { + AppDispatcher.dispatch({ + type: ActionTypes.ENTER_NODE, + nodeId: nodeId + }); + }, - hitEsc: function() { - AppDispatcher.dispatch({ - type: ActionTypes.HIT_ESC_KEY - }); - RouterUtils.updateRoute(); - }, + hitEsc: function() { + AppDispatcher.dispatch({ + type: ActionTypes.HIT_ESC_KEY + }); + RouterUtils.updateRoute(); + }, - leaveNode: function(nodeId) { - AppDispatcher.dispatch({ - type: ActionTypes.LEAVE_NODE, - nodeId: nodeId - }); - }, + leaveNode: function(nodeId) { + AppDispatcher.dispatch({ + type: ActionTypes.LEAVE_NODE, + nodeId: nodeId + }); + }, - receiveNodeDetails: function(details) { - AppDispatcher.dispatch({ - type: ActionTypes.RECEIVE_NODE_DETAILS, - details: details - }); - }, + receiveNodeDetails: function(details) { + AppDispatcher.dispatch({ + type: ActionTypes.RECEIVE_NODE_DETAILS, + details: details + }); + }, - receiveNodesDelta: function(delta) { - AppDispatcher.dispatch({ - type: ActionTypes.RECEIVE_NODES_DELTA, - delta: delta - }); - }, + receiveNodesDelta: function(delta) { + AppDispatcher.dispatch({ + type: ActionTypes.RECEIVE_NODES_DELTA, + delta: delta + }); + }, - receiveTopologies: function(topologies) { - AppDispatcher.dispatch({ - type: ActionTypes.RECEIVE_TOPOLOGIES, - topologies: topologies - }); - WebapiUtils.getNodesDelta(AppStore.getCurrentTopologyUrl()); - WebapiUtils.getNodeDetails(AppStore.getCurrentTopologyUrl(), AppStore.getSelectedNodeId()); - }, + receiveTopologies: function(topologies) { + AppDispatcher.dispatch({ + type: ActionTypes.RECEIVE_TOPOLOGIES, + topologies: topologies + }); + WebapiUtils.getNodesDelta(AppStore.getCurrentTopologyUrl()); + WebapiUtils.getNodeDetails(AppStore.getCurrentTopologyUrl(), AppStore.getSelectedNodeId()); + }, - route: function(state) { - AppDispatcher.dispatch({ - state: state, - type: ActionTypes.ROUTE_TOPOLOGY - }); - WebapiUtils.getNodesDelta(AppStore.getCurrentTopologyUrl()); - WebapiUtils.getNodeDetails(AppStore.getCurrentTopologyUrl(), AppStore.getSelectedNodeId()); - } + route: function(state) { + AppDispatcher.dispatch({ + state: state, + type: ActionTypes.ROUTE_TOPOLOGY + }); + WebapiUtils.getNodesDelta(AppStore.getCurrentTopologyUrl()); + WebapiUtils.getNodeDetails(AppStore.getCurrentTopologyUrl(), AppStore.getSelectedNodeId()); + } }; // breaking circular deps diff --git a/client/app/scripts/charts/node.js b/client/app/scripts/charts/node.js index acfc42b69..738147d0d 100644 --- a/client/app/scripts/charts/node.js +++ b/client/app/scripts/charts/node.js @@ -5,59 +5,59 @@ var tweenState = require('react-tween-state'); var NodeColorMixin = require('../mixins/node-color-mixin'); var Node = React.createClass({ - mixins: [ - NodeColorMixin, - tweenState.Mixin - ], + mixins: [ + NodeColorMixin, + tweenState.Mixin + ], - getInitialState: function() { - return { - x: 0, - y: 0 - }; - }, + getInitialState: function() { + return { + x: 0, + y: 0 + }; + }, - componentWillMount: function() { - // initial node position when rendered the first time - this.setState({ - x: this.props.dx, - y: this.props.dy - }); - }, + componentWillMount: function() { + // initial node position when rendered the first time + this.setState({ + x: this.props.dx, + y: this.props.dy + }); + }, - componentWillReceiveProps: function(nextProps) { - // animate node transition to next position - this.tweenState('x', { - easing: tweenState.easingTypes.easeInOutQuad, - duration: 500, - endValue: nextProps.dx - }); - this.tweenState('y', { - easing: tweenState.easingTypes.easeInOutQuad, - duration: 500, - endValue: nextProps.dy - }); - }, + componentWillReceiveProps: function(nextProps) { + // animate node transition to next position + this.tweenState('x', { + easing: tweenState.easingTypes.easeInOutQuad, + duration: 500, + endValue: nextProps.dx + }); + this.tweenState('y', { + easing: tweenState.easingTypes.easeInOutQuad, + duration: 500, + endValue: nextProps.dy + }); + }, - render: function() { - var transform = "translate(" + this.getTweeningValue('x') + "," + this.getTweeningValue('y') + ")"; - var scale = this.props.scale; - var textOffsetX = 0; - var textOffsetY = scale(0.5) + 18; - var textAngle = _.isUndefined(this.props.angle) ? 0 : -1 * (this.props.angle * 180 / Math.PI - 90); - var color = this.getNodeColor(this.props.label); - var className = this.props.highlighted ? "node highlighted" : "node"; + render: function() { + var transform = "translate(" + this.getTweeningValue('x') + "," + this.getTweeningValue('y') + ")"; + var scale = this.props.scale; + var textOffsetX = 0; + var textOffsetY = scale(0.5) + 18; + var textAngle = _.isUndefined(this.props.angle) ? 0 : -1 * (this.props.angle * 180 / Math.PI - 90); + var color = this.getNodeColor(this.props.label); + var className = this.props.highlighted ? "node highlighted" : "node"; - return ( - - - - - {this.props.label} - {this.props.subLabel} - - ); - } + return ( + + + + + {this.props.label} + {this.props.subLabel} + + ); + } }); module.exports = Node; diff --git a/client/app/scripts/charts/nodes-chart.js b/client/app/scripts/charts/nodes-chart.js index 8b43528da..819cd158e 100644 --- a/client/app/scripts/charts/nodes-chart.js +++ b/client/app/scripts/charts/nodes-chart.js @@ -7,228 +7,228 @@ var Node = require('./node'); var MAX_NODES = 100; var MARGINS = { - top: 130, - left: 40, - right: 40, - bottom: 0 + top: 130, + left: 40, + right: 40, + bottom: 0 }; var line = d3.svg.line() - .interpolate("basis") - .x(function(d) { return d.x; }) - .y(function(d) { return d.y; }); + .interpolate("basis") + .x(function(d) { return d.x; }) + .y(function(d) { return d.y; }); var NodesChart = React.createClass({ - getInitialState: function() { - return { - nodes: {}, - edges: {}, - nodeScale: 1, - translate: "0,0", - scale: 1, - hasZoomed: false - }; - }, + getInitialState: function() { + return { + nodes: {}, + edges: {}, + nodeScale: 1, + translate: "0,0", + scale: 1, + hasZoomed: false + }; + }, - initNodes: function(topology, prevNodes) { - var centerX = this.props.width / 2; - var centerY = this.props.height / 2; - var nodes = {}; + initNodes: function(topology, prevNodes) { + var centerX = this.props.width / 2; + var centerY = this.props.height / 2; + var nodes = {}; - _.each(topology, function(node, id) { - nodes[id] = prevNodes[id] || {}; - _.defaults(nodes[id], { - x: centerX, - y: centerY, - textAnchor: 'start' - }); - _.assign(nodes[id], { - id: id, - label: node.label_major, - subLabel: node.label_minor, - degree: _.size(node.adjacency) - }); - }, this); + _.each(topology, function(node, id) { + nodes[id] = prevNodes[id] || {}; + _.defaults(nodes[id], { + x: centerX, + y: centerY, + textAnchor: 'start' + }); + _.assign(nodes[id], { + id: id, + label: node.label_major, + subLabel: node.label_minor, + degree: _.size(node.adjacency) + }); + }, this); - return nodes; - }, + return nodes; + }, - initEdges: function(topology, nodes) { - var edges = {}; + initEdges: function(topology, nodes) { + var edges = {}; - _.each(topology, function(node) { - _.each(node.adjacency, function(adjacent) { - var edge = [node.id, adjacent], - edgeId = edge.join('-'); + _.each(topology, function(node) { + _.each(node.adjacency, function(adjacent) { + var edge = [node.id, adjacent], + edgeId = edge.join('-'); - if (!edges[edgeId]) { - var source = nodes[edge[0]]; - var target = nodes[edge[1]]; + if (!edges[edgeId]) { + var source = nodes[edge[0]]; + var target = nodes[edge[1]]; - if(!source || !target) { - console.error("Missing edge node", edge[0], source, edge[1], target); - } + if(!source || !target) { + console.error("Missing edge node", edge[0], source, edge[1], target); + } - edges[edgeId] = { - id: edgeId, - value: 1, - source: source, - target: target - }; - } - }); - }, this); - - return edges; - }, - - getNodes: function(nodes, scale) { - return _.map(nodes, function (node) { - var highlighted = _.includes(this.props.highlightedNodes, node.id); - return ( - - ); - }, this); - }, - - getEdges: function(edges, scale) { - return _.map(edges, function(edge) { - return ( - - ); - }); - }, - - getTopologyFingerprint: function(topology) { - var nodes = _.keys(topology).sort(); - var fingerprint = []; - - _.each(topology, function(node) { - fingerprint.push(node.id); - if (node.adjacency) { - fingerprint.push(node.adjacency.join(',')); - } - }); - return fingerprint.join(';'); - }, - - updateGraphState: function(props) { - var nodes = this.initNodes(props.nodes, this.state.nodes); - var edges = this.initEdges(props.nodes, nodes); - - var expanse = Math.min(props.height, props.width); - var nodeSize = expanse / 2; - var n = _.size(props.nodes); - var nodeScale = d3.scale.linear().range([0, nodeSize/Math.pow(n, 0.7)]); - - var layoutId = 'layered node chart'; - console.time(layoutId); - var graph = NodesLayout.doLayout( - nodes, - edges, - props.width, - props.height, - nodeScale, - MARGINS - ); - console.timeEnd(layoutId); - - // adjust layout based on viewport - - var xFactor = (props.width - MARGINS.left - MARGINS.right) / graph.width; - var yFactor = props.height / graph.height; - var zoomFactor = Math.min(xFactor, yFactor); - var zoomScale = this.state.scale; - - if(this.zoom && !this.state.hasZoomed && zoomFactor > 0 && zoomFactor < 1) { - zoomScale = zoomFactor; - // saving in d3's behavior cache - this.zoom.scale(zoomFactor); + edges[edgeId] = { + id: edgeId, + value: 1, + source: source, + target: target + }; } + }); + }, this); - this.setState({ - nodes: nodes, - edges: edges, - nodeScale: nodeScale, - scale: zoomScale - }); - }, + return edges; + }, - componentWillMount: function() { - this.updateGraphState(this.props); - }, + getNodes: function(nodes, scale) { + return _.map(nodes, function (node) { + var highlighted = _.includes(this.props.highlightedNodes, node.id); + return ( + + ); + }, this); + }, - componentDidMount: function() { - this.zoom = d3.behavior.zoom() - .scaleExtent([0.1, 2]) - .on('zoom', this.zoomed); + getEdges: function(edges, scale) { + return _.map(edges, function(edge) { + return ( + + ); + }); + }, - d3.select('.nodes-chart') - .call(this.zoom); - }, + getTopologyFingerprint: function(topology) { + var nodes = _.keys(topology).sort(); + var fingerprint = []; - componentWillUnmount: function() { + _.each(topology, function(node) { + fingerprint.push(node.id); + if (node.adjacency) { + fingerprint.push(node.adjacency.join(',')); + } + }); + return fingerprint.join(';'); + }, - // undoing .call(zoom) + updateGraphState: function(props) { + var nodes = this.initNodes(props.nodes, this.state.nodes); + var edges = this.initEdges(props.nodes, nodes); - d3.select('.nodes-chart') - .on("mousedown.zoom", null) - .on("onwheel", null) - .on("onmousewheel", null) - .on("dblclick.zoom", null) - .on("touchstart.zoom", null); - }, + var expanse = Math.min(props.height, props.width); + var nodeSize = expanse / 2; + var n = _.size(props.nodes); + var nodeScale = d3.scale.linear().range([0, nodeSize/Math.pow(n, 0.7)]); - componentWillReceiveProps: function(nextProps) { - if (this.getTopologyFingerprint(nextProps.nodes) !== this.getTopologyFingerprint(this.props.nodes)) { - this.setState({ - nodes: {}, - edges: {} - }); - } + var layoutId = 'layered node chart'; + console.time(layoutId); + var graph = NodesLayout.doLayout( + nodes, + edges, + props.width, + props.height, + nodeScale, + MARGINS + ); + console.timeEnd(layoutId); - this.updateGraphState(nextProps); - }, + // adjust layout based on viewport - zoomed: function() { - this.setState({ - hasZoomed: true, - translate: d3.event.translate, - scale: d3.event.scale - }); - }, + var xFactor = (props.width - MARGINS.left - MARGINS.right) / graph.width; + var yFactor = props.height / graph.height; + var zoomFactor = Math.min(xFactor, yFactor); + var zoomScale = this.state.scale; - render: function() { - var nodeElements = this.getNodes(this.state.nodes, this.state.nodeScale); - var edgeElements = this.getEdges(this.state.edges, this.state.nodeScale); - var transform = 'translate(' + this.state.translate + ')' + - ' scale(' + this.state.scale + ')'; - - return ( - - - - {edgeElements} - - - {nodeElements} - - - - ); + if(this.zoom && !this.state.hasZoomed && zoomFactor > 0 && zoomFactor < 1) { + zoomScale = zoomFactor; + // saving in d3's behavior cache + this.zoom.scale(zoomFactor); } + this.setState({ + nodes: nodes, + edges: edges, + nodeScale: nodeScale, + scale: zoomScale + }); + }, + + componentWillMount: function() { + this.updateGraphState(this.props); + }, + + componentDidMount: function() { + this.zoom = d3.behavior.zoom() + .scaleExtent([0.1, 2]) + .on('zoom', this.zoomed); + + d3.select('.nodes-chart') + .call(this.zoom); + }, + + componentWillUnmount: function() { + + // undoing .call(zoom) + + d3.select('.nodes-chart') + .on("mousedown.zoom", null) + .on("onwheel", null) + .on("onmousewheel", null) + .on("dblclick.zoom", null) + .on("touchstart.zoom", null); + }, + + componentWillReceiveProps: function(nextProps) { + if (this.getTopologyFingerprint(nextProps.nodes) !== this.getTopologyFingerprint(this.props.nodes)) { + this.setState({ + nodes: {}, + edges: {} + }); + } + + this.updateGraphState(nextProps); + }, + + zoomed: function() { + this.setState({ + hasZoomed: true, + translate: d3.event.translate, + scale: d3.event.scale + }); + }, + + render: function() { + var nodeElements = this.getNodes(this.state.nodes, this.state.nodeScale); + var edgeElements = this.getEdges(this.state.edges, this.state.nodeScale); + var transform = 'translate(' + this.state.translate + ')' + + ' scale(' + this.state.scale + ')'; + + return ( + + + + {edgeElements} + + + {nodeElements} + + + + ); + } + }); module.exports = NodesChart; diff --git a/client/app/scripts/charts/nodes-layout.js b/client/app/scripts/charts/nodes-layout.js index 0f571532c..0556d7c41 100644 --- a/client/app/scripts/charts/nodes-layout.js +++ b/client/app/scripts/charts/nodes-layout.js @@ -4,70 +4,70 @@ var _ = require('lodash'); var MAX_NODES = 100; var doLayout = function(nodes, edges, width, height, scale, margins) { - var offsetX = 0 + margins.left; - var offsetY = 0 + margins.top; - var g = new dagre.graphlib.Graph({}); + var offsetX = 0 + margins.left; + var offsetY = 0 + margins.top; + var g = new dagre.graphlib.Graph({}); - if (_.size(nodes) > MAX_NODES) { - console.error('Too many nodes for graph layout engine. Limit: ' + MAX_NODES); - return; - } + if (_.size(nodes) > MAX_NODES) { + console.error('Too many nodes for graph layout engine. Limit: ' + MAX_NODES); + return; + } - // configure node margins + // configure node margins - g.setGraph({ - nodesep: scale(2.5), - ranksep: scale(2.5) + g.setGraph({ + nodesep: scale(2.5), + ranksep: scale(2.5) + }); + + // add nodes and edges to layout engine + + _.each(nodes, function(node) { + g.setNode(node.id, {id: node.id, width: scale(0.75), height: scale(0.75)}); + }); + + _.each(edges, function(edge) { + var virtualNodes = edge.source.id === edge.target.id ? 1 : 0; + g.setEdge(edge.source.id, edge.target.id, {id: edge.id, minlen: virtualNodes}); + }); + + dagre.layout(g); + + var graph = g.graph(); + + // shifting graph coordinates to center + + if (graph.width < width) { + offsetX = (width - graph.width) / 2 + margins.left; + } + if (graph.height < height) { + offsetY = (height - graph.height) / 2 + margins.top; + } + + // apply coordinates to nodes and edges + + g.nodes().forEach(function(id) { + var node = nodes[id]; + var graphNode = g.node(id); + node.x = graphNode.x + offsetX; + node.y = graphNode.y + offsetY; + }); + + g.edges().forEach(function(id) { + var graphEdge = g.edge(id); + var edge = edges[graphEdge.id]; + _.each(graphEdge.points, function(point) { + point.x += offsetX; + point.y += offsetY; }); + edge.points = graphEdge.points; + }); - // add nodes and edges to layout engine + // return object with width and height of layout - _.each(nodes, function(node) { - g.setNode(node.id, {id: node.id, width: scale(0.75), height: scale(0.75)}); - }); - - _.each(edges, function(edge) { - var virtualNodes = edge.source.id === edge.target.id ? 1 : 0; - g.setEdge(edge.source.id, edge.target.id, {id: edge.id, minlen: virtualNodes}); - }); - - dagre.layout(g); - - var graph = g.graph(); - - // shifting graph coordinates to center - - if (graph.width < width) { - offsetX = (width - graph.width) / 2 + margins.left; - } - if (graph.height < height) { - offsetY = (height - graph.height) / 2 + margins.top; - } - - // apply coordinates to nodes and edges - - g.nodes().forEach(function(id) { - var node = nodes[id]; - var graphNode = g.node(id); - node.x = graphNode.x + offsetX; - node.y = graphNode.y + offsetY; - }); - - g.edges().forEach(function(id) { - var graphEdge = g.edge(id); - var edge = edges[graphEdge.id]; - _.each(graphEdge.points, function(point) { - point.x += offsetX; - point.y += offsetY; - }); - edge.points = graphEdge.points; - }); - - // return object with width and height of layout - - return graph; + return graph; }; module.exports = { - doLayout: doLayout + doLayout: doLayout }; diff --git a/client/app/scripts/components/app.js b/client/app/scripts/components/app.js index 326fd891d..9f3d4e972 100644 --- a/client/app/scripts/components/app.js +++ b/client/app/scripts/components/app.js @@ -18,62 +18,62 @@ var RouterUtils = require('../utils/router-utils'); var ESC_KEY_CODE = 27; function getStateFromStores() { - return { - currentTopology: AppStore.getCurrentTopology(), - connectionState: AppStore.getConnectionState(), - currentGrouping: AppStore.getCurrentGrouping(), - selectedNodeId: AppStore.getSelectedNodeId(), - nodeDetails: AppStore.getNodeDetails(), - nodes: AppStore.getNodes(), - topologies: AppStore.getTopologies() - } + return { + currentTopology: AppStore.getCurrentTopology(), + connectionState: AppStore.getConnectionState(), + currentGrouping: AppStore.getCurrentGrouping(), + selectedNodeId: AppStore.getSelectedNodeId(), + nodeDetails: AppStore.getNodeDetails(), + nodes: AppStore.getNodes(), + topologies: AppStore.getTopologies() + } } var App = React.createClass({ - getInitialState: function() { - return getStateFromStores(); - }, + getInitialState: function() { + return getStateFromStores(); + }, - componentDidMount: function() { - AppStore.on(AppStore.CHANGE_EVENT, this.onChange); - window.addEventListener('keyup', this.onKeyPress); + componentDidMount: function() { + AppStore.on(AppStore.CHANGE_EVENT, this.onChange); + window.addEventListener('keyup', this.onKeyPress); - RouterUtils.getRouter().start({hashbang: true}); - WebapiUtils.getTopologies(); - }, + RouterUtils.getRouter().start({hashbang: true}); + WebapiUtils.getTopologies(); + }, - onChange: function() { - this.setState(getStateFromStores()); - }, + onChange: function() { + this.setState(getStateFromStores()); + }, - onKeyPress: function(ev) { - if (ev.keyCode === ESC_KEY_CODE) { - AppActions.hitEsc(); - } - }, + onKeyPress: function(ev) { + if (ev.keyCode === ESC_KEY_CODE) { + AppActions.hitEsc(); + } + }, - render: function() { - var showingDetails = this.state.selectedNodeId; + render: function() { + var showingDetails = this.state.selectedNodeId; - return ( -
- {showingDetails &&
} + return ( +
+ {showingDetails &&
} -
- - - - -
+
+ + + + +
- -
- ); - } + +
+ ); + } }); diff --git a/client/app/scripts/components/details.js b/client/app/scripts/components/details.js index c9092f5a3..161794578 100644 --- a/client/app/scripts/components/details.js +++ b/client/app/scripts/components/details.js @@ -11,23 +11,23 @@ var NodeDetails = require('./node-details'); var Details = React.createClass({ - handleClickClose: function(ev) { - ev.preventDefault(); - AppActions.clickCloseDetails(); - }, + handleClickClose: function(ev) { + ev.preventDefault(); + AppActions.clickCloseDetails(); + }, - render: function() { - return ( -
- -
- -
- -
-
- ); - } + render: function() { + return ( +
+ +
+ +
+ +
+
+ ); + } }); diff --git a/client/app/scripts/components/explorer.js b/client/app/scripts/components/explorer.js index f771b4b3a..84dd62f1e 100644 --- a/client/app/scripts/components/explorer.js +++ b/client/app/scripts/components/explorer.js @@ -13,82 +13,82 @@ var marginRight = 36; var Explorer = React.createClass({ - getInitialState: function() { - return { - layout: 'solar', - width: window.innerWidth - marginLeft - marginRight, - height: window.innerHeight - marginBottom - marginTop - }; - }, + getInitialState: function() { + return { + layout: 'solar', + width: window.innerWidth - marginLeft - marginRight, + height: window.innerHeight - marginBottom - marginTop + }; + }, - componentDidMount: function() { - window.addEventListener('resize', this.handleResize); - }, + componentDidMount: function() { + window.addEventListener('resize', this.handleResize); + }, - componentWillUnmount: function() { - window.removeEventListener('resize', this.handleResize); - }, + componentWillUnmount: function() { + window.removeEventListener('resize', this.handleResize); + }, - setDimensions: function() { - this.setState({ - height: window.innerHeight - marginBottom - marginTop, - width: window.innerWidth - marginLeft - marginRight - }); - }, + setDimensions: function() { + this.setState({ + height: window.innerHeight - marginBottom - marginTop, + width: window.innerWidth - marginLeft - marginRight + }); + }, - handleResize: function() { - this.setDimensions(); - }, + handleResize: function() { + this.setDimensions(); + }, - getSubTopology: function(topology) { - var subTopology = {}; - var nodeSet = []; + getSubTopology: function(topology) { + var subTopology = {}; + var nodeSet = []; - _.each(this.props.expandedNodes, function(nodeId) { - if (topology[nodeId]) { - subTopology[nodeId] = topology[nodeId]; - nodeSet = _.union(subTopology[nodeId].adjacency, nodeSet); - _.each(subTopology[nodeId].adjacency, function(adjacentId) { - var node = _.assign({}, topology[adjacentId]); + _.each(this.props.expandedNodes, function(nodeId) { + if (topology[nodeId]) { + subTopology[nodeId] = topology[nodeId]; + nodeSet = _.union(subTopology[nodeId].adjacency, nodeSet); + _.each(subTopology[nodeId].adjacency, function(adjacentId) { + var node = _.assign({}, topology[adjacentId]); - subTopology[adjacentId] = node; - }); - } - }); + subTopology[adjacentId] = node; + }); + } + }); - // weed out edges - _.each(subTopology, function(node) { - node.adjacency = _.intersection(node.adjacency, nodeSet); - }); + // weed out edges + _.each(subTopology, function(node) { + node.adjacency = _.intersection(node.adjacency, nodeSet); + }); - return subTopology; - }, + return subTopology; + }, - onNodeClick: function(ev) { - var nodeId = ev.currentTarget.id; - AppActions.clickNode(nodeId); - }, + onNodeClick: function(ev) { + var nodeId = ev.currentTarget.id; + AppActions.clickNode(nodeId); + }, - render: function() { - var subTopology = this.getSubTopology(this.props.nodes); + render: function() { + var subTopology = this.getSubTopology(this.props.nodes); - return ( -
- -
- -
-
- ); - } + return ( +
+ +
+ +
+
+ ); + } }); diff --git a/client/app/scripts/components/groupings.js b/client/app/scripts/components/groupings.js index d99457143..f6e8eeed7 100644 --- a/client/app/scripts/components/groupings.js +++ b/client/app/scripts/components/groupings.js @@ -7,61 +7,61 @@ var AppActions = require('../actions/app-actions'); var AppStore = require('../stores/app-store'); var GROUPINGS = [{ - id: 'none', - iconClass: 'fa fa-th', - needsTopology: false + id: 'none', + iconClass: 'fa fa-th', + needsTopology: false }, { - id: 'grouped', - iconClass: 'fa fa-th-large', - needsTopology: 'grouped_url' + id: 'grouped', + iconClass: 'fa fa-th-large', + needsTopology: 'grouped_url' }]; var Groupings = React.createClass({ - onGroupingClick: function(ev) { - ev.preventDefault(); - AppActions.clickGrouping(ev.currentTarget.getAttribute('rel')); - }, + onGroupingClick: function(ev) { + ev.preventDefault(); + AppActions.clickGrouping(ev.currentTarget.getAttribute('rel')); + }, - isGroupingSupportedByTopology: function(topology, grouping) { - return !grouping.needsTopology || topology && topology[grouping.needsTopology]; - }, + isGroupingSupportedByTopology: function(topology, grouping) { + return !grouping.needsTopology || topology && topology[grouping.needsTopology]; + }, - getGroupingsSupportedByTopology: function(topology) { - return _.filter(GROUPINGS, _.partial(this.isGroupingSupportedByTopology, topology)); - }, + getGroupingsSupportedByTopology: function(topology) { + return _.filter(GROUPINGS, _.partial(this.isGroupingSupportedByTopology, topology)); + }, - renderGrouping: function(grouping, activeGroupingId) { - var className = "groupings-item", - isSupportedByTopology = this.isGroupingSupportedByTopology(this.props.currentTopology, grouping); + renderGrouping: function(grouping, activeGroupingId) { + var className = "groupings-item", + isSupportedByTopology = this.isGroupingSupportedByTopology(this.props.currentTopology, grouping); - if (grouping.id === activeGroupingId) { - className += " groupings-item-active"; - } else if (!isSupportedByTopology) { - className += " groupings-item-disabled"; - } else { - className += " groupings-item-default"; - } + if (grouping.id === activeGroupingId) { + className += " groupings-item-active"; + } else if (!isSupportedByTopology) { + className += " groupings-item-disabled"; + } else { + className += " groupings-item-default"; + } - return ( -
- -
- ); - }, + return ( +
+ +
+ ); + }, - render: function() { - var activeGrouping = this.props.active, - isGroupingSupported = _.size(this.getGroupingsSupportedByTopology(this.props.currentTopology)) > 1; + render: function() { + var activeGrouping = this.props.active, + isGroupingSupported = _.size(this.getGroupingsSupportedByTopology(this.props.currentTopology)) > 1; - return ( -
- {isGroupingSupported && GROUPINGS.map(function(grouping) { - return this.renderGrouping(grouping, activeGrouping); - }, this)} -
- ); - } + return ( +
+ {isGroupingSupported && GROUPINGS.map(function(grouping) { + return this.renderGrouping(grouping, activeGrouping); + }, this)} +
+ ); + } }); diff --git a/client/app/scripts/components/logo.js b/client/app/scripts/components/logo.js index 45eb63200..bc3cf2b39 100644 --- a/client/app/scripts/components/logo.js +++ b/client/app/scripts/components/logo.js @@ -4,63 +4,63 @@ var React = require('react'); var Logo = React.createClass({ - render: function() { - return ( -
- - - - - - - - - - - - - - - - - - -
- ); - } + render: function() { + return ( +
+ + + + + + + + + + + + + + + + + + +
+ ); + } }); diff --git a/client/app/scripts/components/node-details-table.js b/client/app/scripts/components/node-details-table.js index aab2febe6..5ef29f6a3 100644 --- a/client/app/scripts/components/node-details-table.js +++ b/client/app/scripts/components/node-details-table.js @@ -5,29 +5,29 @@ var _ = require('lodash'); var NodeDetailsTable = React.createClass({ - render: function() { - var isNumeric = this.props.isNumeric; + render: function() { + var isNumeric = this.props.isNumeric; - return ( -
-

- {this.props.title} -

+ return ( +
+

+ {this.props.title} +

- {this.props.rows.map(function(row) { - return ( -
-
{row.key}
- {isNumeric &&
{row.value_major}
} - {isNumeric &&
{row.value_minor}
} - {!isNumeric &&
{row.value_major}
} - {!isNumeric && row.value_minor &&
{row.value_minor}
} -
- ); - })} -
- ); - } + {this.props.rows.map(function(row) { + return ( +
+
{row.key}
+ {isNumeric &&
{row.value_major}
} + {isNumeric &&
{row.value_minor}
} + {!isNumeric &&
{row.value_major}
} + {!isNumeric && row.value_minor &&
{row.value_minor}
} +
+ ); + })} +
+ ); + } }); diff --git a/client/app/scripts/components/node-details.js b/client/app/scripts/components/node-details.js index 45e22ec19..628755803 100644 --- a/client/app/scripts/components/node-details.js +++ b/client/app/scripts/components/node-details.js @@ -8,38 +8,38 @@ var NodeColorMixin = require('../mixins/node-color-mixin'); var NodeDetails = React.createClass({ - mixins: [ - NodeColorMixin - ], + mixins: [ + NodeColorMixin + ], - render: function() { - var node = this.props.details; + render: function() { + var node = this.props.details; - if (!node) { - return
; - } + if (!node) { + return
; + } - var style = { - "background-color": this.getNodeColorDark(node.label_major) - }; + var style = { + "background-color": this.getNodeColorDark(node.label_major) + }; - return ( -
-
-

- {node.label_major} -

-
{node.label_minor}
-
+ return ( +
+
+

+ {node.label_major} +

+
{node.label_minor}
+
-
- {this.props.details.tables.map(function(table) { - return ; - })} -
-
- ); - } +
+ {this.props.details.tables.map(function(table) { + return ; + })} +
+
+ ); + } }); diff --git a/client/app/scripts/components/nodes.js b/client/app/scripts/components/nodes.js index 34c6f7f6d..3b211f6c1 100644 --- a/client/app/scripts/components/nodes.js +++ b/client/app/scripts/components/nodes.js @@ -11,49 +11,49 @@ var marginLeft = 0; var Nodes = React.createClass({ - getInitialState: function() { - return { - width: window.innerWidth, - height: window.innerHeight - navbarHeight - marginTop - }; - }, + getInitialState: function() { + return { + width: window.innerWidth, + height: window.innerHeight - navbarHeight - marginTop + }; + }, - onNodeClick: function(ev) { - AppActions.clickNode(ev.currentTarget.id); - }, + onNodeClick: function(ev) { + AppActions.clickNode(ev.currentTarget.id); + }, - componentDidMount: function() { - window.addEventListener('resize', this.handleResize); - }, + componentDidMount: function() { + window.addEventListener('resize', this.handleResize); + }, - componentWillUnmount: function() { - window.removeEventListener('resize', this.handleResize); - }, + componentWillUnmount: function() { + window.removeEventListener('resize', this.handleResize); + }, - setDimensions: function() { - this.setState({ - height: window.innerHeight - navbarHeight - marginTop, - width: window.innerWidth - }); - }, + setDimensions: function() { + this.setState({ + height: window.innerHeight - navbarHeight - marginTop, + width: window.innerWidth + }); + }, - handleResize: function() { - this.setDimensions(); - }, + handleResize: function() { + this.setDimensions(); + }, - render: function() { - return ( -
- -
- ); - } + render: function() { + return ( +
+ +
+ ); + } }); diff --git a/client/app/scripts/components/status.js b/client/app/scripts/components/status.js index bd3b023cd..74005357d 100644 --- a/client/app/scripts/components/status.js +++ b/client/app/scripts/components/status.js @@ -4,24 +4,24 @@ var React = require('react'); var Status = React.createClass({ - renderConnectionState: function() { - return ( -
- - Scope is disconnected -
- ); - }, + renderConnectionState: function() { + return ( +
+ + Scope is disconnected +
+ ); + }, - render: function() { - var isDisconnected = this.props.connectionState === 'disconnected'; + render: function() { + var isDisconnected = this.props.connectionState === 'disconnected'; - return ( -
- {isDisconnected && this.renderConnectionState()} -
- ); - } + return ( +
+ {isDisconnected && this.renderConnectionState()} +
+ ); + } }); diff --git a/client/app/scripts/components/topologies.js b/client/app/scripts/components/topologies.js index b5347e406..4e4db8913 100644 --- a/client/app/scripts/components/topologies.js +++ b/client/app/scripts/components/topologies.js @@ -8,43 +8,43 @@ var AppStore = require('../stores/app-store'); var Topologies = React.createClass({ - onTopologyClick: function(ev) { - ev.preventDefault(); - AppActions.clickTopology(ev.currentTarget.getAttribute('rel')); - }, + onTopologyClick: function(ev) { + ev.preventDefault(); + AppActions.clickTopology(ev.currentTarget.getAttribute('rel')); + }, - renderTopology: function(topology, active) { - var isActive = topology.name === this.props.currentTopology.name, - className = isActive ? "topologies-item topologies-item-active" : "topologies-item", - topologyId = AppStore.getTopologyIdForUrl(topology.url), - title = ['Topology: ' + topology.name, - 'Nodes: ' + topology.stats.node_count, - 'Connections: ' + topology.stats.node_count].join('\n'); + renderTopology: function(topology, active) { + var isActive = topology.name === this.props.currentTopology.name, + className = isActive ? "topologies-item topologies-item-active" : "topologies-item", + topologyId = AppStore.getTopologyIdForUrl(topology.url), + title = ['Topology: ' + topology.name, + 'Nodes: ' + topology.stats.node_count, + 'Connections: ' + topology.stats.node_count].join('\n'); - return ( -
-
-
- {topology.name} -
-
-
- ); - }, + return ( +
+
+
+ {topology.name} +
+
+
+ ); + }, - render: function() { - var topologies = _.sortBy(this.props.topologies, function(topology) { - return topology.name; - }); + render: function() { + var topologies = _.sortBy(this.props.topologies, function(topology) { + return topology.name; + }); - return ( -
- {this.props.currentTopology && topologies.map(function(topology) { - return this.renderTopology(topology); - }, this)} -
- ); - } + return ( +
+ {this.props.currentTopology && topologies.map(function(topology) { + return this.renderTopology(topology); + }, this)} +
+ ); + } }); diff --git a/client/app/scripts/constants/action-types.js b/client/app/scripts/constants/action-types.js index e25f6e99c..1f1e7946f 100644 --- a/client/app/scripts/constants/action-types.js +++ b/client/app/scripts/constants/action-types.js @@ -1,16 +1,16 @@ var keymirror = require('keymirror'); module.exports = keymirror({ - CLICK_CLOSE_DETAILS: null, - CLICK_GROUPING: null, - CLICK_NODE: null, - CLICK_TOPOLOGY: null, - ENTER_NODE: null, - HIT_ESC_KEY: null, - LEAVE_NODE: null, - RECEIVE_NODE_DETAILS: null, - RECEIVE_NODES: null, - RECEIVE_NODES_DELTA: null, - RECEIVE_TOPOLOGIES: null, - ROUTE_TOPOLOGY: null + CLICK_CLOSE_DETAILS: null, + CLICK_GROUPING: null, + CLICK_NODE: null, + CLICK_TOPOLOGY: null, + ENTER_NODE: null, + HIT_ESC_KEY: null, + LEAVE_NODE: null, + RECEIVE_NODE_DETAILS: null, + RECEIVE_NODES: null, + RECEIVE_NODES_DELTA: null, + RECEIVE_TOPOLOGIES: null, + ROUTE_TOPOLOGY: null }); diff --git a/client/app/scripts/constants/topologies.js b/client/app/scripts/constants/topologies.js index 395da8edf..38c920fb5 100644 --- a/client/app/scripts/constants/topologies.js +++ b/client/app/scripts/constants/topologies.js @@ -1,13 +1,13 @@ module.exports = [ - { - url: '/api/topology/applications', - name: 'Applications', - stats: {} - }, - { - url: '/api/topology/hosts', - name: 'Hosts', - stats: {} - } + { + url: '/api/topology/applications', + name: 'Applications', + stats: {} + }, + { + url: '/api/topology/hosts', + name: 'Hosts', + stats: {} + } ]; diff --git a/client/app/scripts/dispatcher/app-dispatcher.js b/client/app/scripts/dispatcher/app-dispatcher.js index 4c5b1ebcb..e24c99866 100644 --- a/client/app/scripts/dispatcher/app-dispatcher.js +++ b/client/app/scripts/dispatcher/app-dispatcher.js @@ -4,9 +4,9 @@ var _ = require('lodash'); var AppDispatcher = new flux.Dispatcher(); AppDispatcher.dispatch = _.wrap(flux.Dispatcher.prototype.dispatch, function(func) { - var args = Array.prototype.slice.call(arguments, 1); - // console.log(args[0]); - func.apply(this, args); + var args = Array.prototype.slice.call(arguments, 1); + // console.log(args[0]); + func.apply(this, args); }); module.exports = AppDispatcher; diff --git a/client/app/scripts/main.js b/client/app/scripts/main.js index 91bf8528a..8085367af 100644 --- a/client/app/scripts/main.js +++ b/client/app/scripts/main.js @@ -7,5 +7,5 @@ var React = require('react'); var App = require('./components/app.js'); React.render( - , - document.getElementById('app')); + , + document.getElementById('app')); diff --git a/client/app/scripts/mixins/node-color-mixin.js b/client/app/scripts/mixins/node-color-mixin.js index b1c986f66..679e71e91 100644 --- a/client/app/scripts/mixins/node-color-mixin.js +++ b/client/app/scripts/mixins/node-color-mixin.js @@ -8,20 +8,20 @@ colors(internetLabel); var NodeColorMixin = { - getNodeColor: function(text) { - return colors(text); - }, - getNodeColorDark: function(text) { - var color = d3.rgb(colors(text)); - var hsl = color.hsl(); + getNodeColor: function(text) { + return colors(text); + }, + getNodeColorDark: function(text) { + var color = d3.rgb(colors(text)); + var hsl = color.hsl(); - // ensure darkness - // if (hsl.l > 0.5) { - hsl = hsl.darker(); - // } + // ensure darkness + // if (hsl.l > 0.5) { + hsl = hsl.darker(); + // } - return hsl.toString(); - } + return hsl.toString(); + } }; module.exports = NodeColorMixin; \ No newline at end of file diff --git a/client/app/scripts/stores/__tests__/app-store-test.js b/client/app/scripts/stores/__tests__/app-store-test.js index 4c7159d0a..9e30e5bd3 100644 --- a/client/app/scripts/stores/__tests__/app-store-test.js +++ b/client/app/scripts/stores/__tests__/app-store-test.js @@ -1,61 +1,61 @@ describe('AppStore', function() { - var ActionTypes = require('../../constants/action-types'); - var AppStore, registeredCallback; + var ActionTypes = require('../../constants/action-types'); + var AppStore, registeredCallback; - // actions + // actions - var ClickTopologyAction = { - type: ActionTypes.CLICK_TOPOLOGY, - topologyId: 'topo1' - }; + var ClickTopologyAction = { + type: ActionTypes.CLICK_TOPOLOGY, + topologyId: 'topo1' + }; - var ClickGroupingAction = { - type: ActionTypes.CLICK_GROUPING, - grouping: 'grouped' - }; + var ClickGroupingAction = { + type: ActionTypes.CLICK_GROUPING, + grouping: 'grouped' + }; - var ReceiveTopologiesAction = { - type: ActionTypes.RECEIVE_TOPOLOGIES, - topologies: [{ - url: '/topo1', - grouped_url: '/topo1grouped', - name: 'Topo1' - }] - }; + var ReceiveTopologiesAction = { + type: ActionTypes.RECEIVE_TOPOLOGIES, + topologies: [{ + url: '/topo1', + grouped_url: '/topo1grouped', + name: 'Topo1' + }] + }; - beforeEach(function() { - AppStore = require('../app-store'); - registeredCallback = AppStore.registeredCallback; - }); + beforeEach(function() { + AppStore = require('../app-store'); + registeredCallback = AppStore.registeredCallback; + }); - // topology tests + // topology tests - it('init with no topologies', function() { - var topos = AppStore.getTopologies(); - expect(topos.length).toBe(0); - expect(AppStore.getCurrentTopology()).toBeUndefined(); - }); + it('init with no topologies', function() { + var topos = AppStore.getTopologies(); + expect(topos.length).toBe(0); + expect(AppStore.getCurrentTopology()).toBeUndefined(); + }); - it('get current topology', function() { - registeredCallback(ClickTopologyAction); - registeredCallback(ReceiveTopologiesAction); + it('get current topology', function() { + registeredCallback(ClickTopologyAction); + registeredCallback(ReceiveTopologiesAction); - expect(AppStore.getTopologies().length).toBe(1); - expect(AppStore.getCurrentTopology().name).toBe('Topo1'); - expect(AppStore.getCurrentTopologyUrl()).toBe('/topo1'); - }); + expect(AppStore.getTopologies().length).toBe(1); + expect(AppStore.getCurrentTopology().name).toBe('Topo1'); + expect(AppStore.getCurrentTopologyUrl()).toBe('/topo1'); + }); - it('get grouped topology', function() { - registeredCallback(ClickTopologyAction); - registeredCallback(ReceiveTopologiesAction); - registeredCallback(ClickGroupingAction); + it('get grouped topology', function() { + registeredCallback(ClickTopologyAction); + registeredCallback(ReceiveTopologiesAction); + registeredCallback(ClickGroupingAction); - expect(AppStore.getTopologies().length).toBe(1); - expect(AppStore.getCurrentTopology().name).toBe('Topo1'); - expect(AppStore.getCurrentTopologyUrl()).toBe('/topo1grouped'); - }); + expect(AppStore.getTopologies().length).toBe(1); + expect(AppStore.getCurrentTopology().name).toBe('Topo1'); + expect(AppStore.getCurrentTopologyUrl()).toBe('/topo1grouped'); + }); }); \ No newline at end of file diff --git a/client/app/scripts/stores/app-store.js b/client/app/scripts/stores/app-store.js index e670b6170..b3d986236 100644 --- a/client/app/scripts/stores/app-store.js +++ b/client/app/scripts/stores/app-store.js @@ -22,166 +22,166 @@ var topologies = []; var AppStore = assign({}, EventEmitter.prototype, { - CHANGE_EVENT: 'change', + CHANGE_EVENT: 'change', - getAppState: function() { - return { - topologyId: currentTopologyId, - grouping: this.getCurrentGrouping(), - selectedNodeId: this.getSelectedNodeId() - }; - }, + getAppState: function() { + return { + topologyId: currentTopologyId, + grouping: this.getCurrentGrouping(), + selectedNodeId: this.getSelectedNodeId() + }; + }, - getConnectionState: function() { - return connectionState; - }, + getConnectionState: function() { + return connectionState; + }, - getCurrentTopology: function() { - return _.find(topologies, function(topology) { - return isUrlForTopologyId(topology.url, currentTopologyId); - }); - }, + getCurrentTopology: function() { + return _.find(topologies, function(topology) { + return isUrlForTopologyId(topology.url, currentTopologyId); + }); + }, - getCurrentTopologyUrl: function() { - var topology = this.getCurrentTopology(); + getCurrentTopologyUrl: function() { + var topology = this.getCurrentTopology(); - if (topology) { - return topology.grouped_url && currentGrouping == 'grouped' ? topology.grouped_url : topology.url; - } - }, + if (topology) { + return topology.grouped_url && currentGrouping == 'grouped' ? topology.grouped_url : topology.url; + } + }, - getCurrentGrouping: function() { - return currentGrouping; - }, + getCurrentGrouping: function() { + return currentGrouping; + }, - getNodeDetails: function() { - return nodeDetails; - }, + getNodeDetails: function() { + return nodeDetails; + }, - getNodes: function() { - return nodes; - }, + getNodes: function() { + return nodes; + }, - getSelectedNodeId: function() { - return selectedNodeId; - }, + getSelectedNodeId: function() { + return selectedNodeId; + }, - getTopologies: function() { - return topologies; - }, + getTopologies: function() { + return topologies; + }, - getTopologyIdForUrl: function(url) { - return url.split('/').pop(); - } + getTopologyIdForUrl: function(url) { + return url.split('/').pop(); + } }); // Helpers function isUrlForTopologyId(url, topologyId) { - return _.endsWith(url, topologyId); + return _.endsWith(url, topologyId); } // Store Dispatch Hooks AppStore.registeredCallback = function(payload) { - switch (payload.type) { + switch (payload.type) { - case ActionTypes.CLICK_CLOSE_DETAILS: - selectedNodeId = null; - AppStore.emit(AppStore.CHANGE_EVENT); - break; + case ActionTypes.CLICK_CLOSE_DETAILS: + selectedNodeId = null; + AppStore.emit(AppStore.CHANGE_EVENT); + break; - case ActionTypes.CLICK_GROUPING: - if (payload.grouping !== currentGrouping) { - currentGrouping = payload.grouping; - nodes = {}; - AppStore.emit(AppStore.CHANGE_EVENT); - } - break; + case ActionTypes.CLICK_GROUPING: + if (payload.grouping !== currentGrouping) { + currentGrouping = payload.grouping; + nodes = {}; + AppStore.emit(AppStore.CHANGE_EVENT); + } + break; - case ActionTypes.CLICK_NODE: - selectedNodeId = payload.nodeId; - AppStore.emit(AppStore.CHANGE_EVENT); - break; + case ActionTypes.CLICK_NODE: + selectedNodeId = payload.nodeId; + AppStore.emit(AppStore.CHANGE_EVENT); + break; - case ActionTypes.CLICK_TOPOLOGY: - if (payload.topologyId !== currentTopologyId) { - currentTopologyId = payload.topologyId; - nodes = {}; - } - AppStore.emit(AppStore.CHANGE_EVENT); - break; + case ActionTypes.CLICK_TOPOLOGY: + if (payload.topologyId !== currentTopologyId) { + currentTopologyId = payload.topologyId; + nodes = {}; + } + AppStore.emit(AppStore.CHANGE_EVENT); + break; - case ActionTypes.ENTER_NODE: - mouseOverNode = payload.nodeId; - AppStore.emit(AppStore.CHANGE_EVENT); - break; + case ActionTypes.ENTER_NODE: + mouseOverNode = 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.HIT_ESC_KEY: + nodeDetails = null; + selectedNodeId = null; + AppStore.emit(AppStore.CHANGE_EVENT); + break; - case ActionTypes.LEAVE_NODE: - mouseOverNode = null; - AppStore.emit(AppStore.CHANGE_EVENT); - break; + case ActionTypes.LEAVE_NODE: + mouseOverNode = null; + AppStore.emit(AppStore.CHANGE_EVENT); + break; - case ActionTypes.RECEIVE_NODE_DETAILS: - nodeDetails = payload.details; - AppStore.emit(AppStore.CHANGE_EVENT); - break; + case ActionTypes.RECEIVE_NODE_DETAILS: + nodeDetails = payload.details; + AppStore.emit(AppStore.CHANGE_EVENT); + break; - case ActionTypes.RECEIVE_NODES_DELTA: - console.log('RECEIVE_NODES_DELTA', - 'remove', _.size(payload.delta.remove), - 'update', _.size(payload.delta.update), - 'add', _.size(payload.delta.add)); + case ActionTypes.RECEIVE_NODES_DELTA: + console.log('RECEIVE_NODES_DELTA', + 'remove', _.size(payload.delta.remove), + 'update', _.size(payload.delta.update), + 'add', _.size(payload.delta.add)); - connectionState = "connected"; + connectionState = "connected"; - // nodes that no longer exist - _.each(payload.delta.remove, function(nodeId) { - // in case node disappears before mouseleave event - if (mouseOverNode === nodeId) { - mouseOverNode = null; - } - delete nodes[nodeId]; - }); + // nodes that no longer exist + _.each(payload.delta.remove, function(nodeId) { + // in case node disappears before mouseleave event + if (mouseOverNode === nodeId) { + mouseOverNode = null; + } + delete nodes[nodeId]; + }); - // update existing nodes - _.each(payload.delta.update, function(node) { - nodes[node.id] = node; - }); + // update existing nodes + _.each(payload.delta.update, function(node) { + nodes[node.id] = node; + }); - // add new nodes - _.each(payload.delta.add, function(node) { - nodes[node.id] = node; - }); + // add new nodes + _.each(payload.delta.add, function(node) { + nodes[node.id] = node; + }); - AppStore.emit(AppStore.CHANGE_EVENT); - break; + AppStore.emit(AppStore.CHANGE_EVENT); + break; - case ActionTypes.RECEIVE_TOPOLOGIES: - topologies = payload.topologies; - AppStore.emit(AppStore.CHANGE_EVENT); - break; + case ActionTypes.RECEIVE_TOPOLOGIES: + topologies = payload.topologies; + AppStore.emit(AppStore.CHANGE_EVENT); + break; - case ActionTypes.ROUTE_TOPOLOGY: - nodes = {}; - currentTopologyId = payload.state.topologyId; - currentGrouping = payload.state.grouping; - selectedNodeId = payload.state.selectedNodeId; - AppStore.emit(AppStore.CHANGE_EVENT); - break; + case ActionTypes.ROUTE_TOPOLOGY: + nodes = {}; + currentTopologyId = payload.state.topologyId; + currentGrouping = payload.state.grouping; + selectedNodeId = payload.state.selectedNodeId; + AppStore.emit(AppStore.CHANGE_EVENT); + break; - default: - break; + default: + break; - } + } }; AppStore.dispatchToken = AppDispatcher.register(AppStore.registeredCallback); diff --git a/client/app/scripts/utils/router-utils.js b/client/app/scripts/utils/router-utils.js index 4493cde30..12d56ef5c 100644 --- a/client/app/scripts/utils/router-utils.js +++ b/client/app/scripts/utils/router-utils.js @@ -5,27 +5,27 @@ var AppActions = require('../actions/app-actions'); var AppStore = require('../stores/app-store'); page('/', function(ctx) { - updateRoute(); + updateRoute(); }); page('/state/:state', function(ctx) { - var state = JSON.parse(ctx.params.state); - AppActions.route(state); + var state = JSON.parse(ctx.params.state); + AppActions.route(state); }); function updateRoute() { - var state = AppStore.getAppState(); - var stateUrl = JSON.stringify(state); - var dispatch = false; + var state = AppStore.getAppState(); + var stateUrl = JSON.stringify(state); + var dispatch = false; - page.show('/state/' + stateUrl, state, dispatch); + page.show('/state/' + stateUrl, state, dispatch); } module.exports = { - getRouter: function() { - return page; - }, + getRouter: function() { + return page; + }, - updateRoute: updateRoute + updateRoute: updateRoute }; \ No newline at end of file diff --git a/client/app/scripts/utils/web-api-utils.js b/client/app/scripts/utils/web-api-utils.js index cd391ffdb..f29722a5b 100644 --- a/client/app/scripts/utils/web-api-utils.js +++ b/client/app/scripts/utils/web-api-utils.js @@ -12,57 +12,57 @@ var updateFrequency = '5s'; var topologyTimer = 0; function createWebsocket(topologyUrl) { - if (socket) { - socket.onclose = null; - socket.close(); - } + if (socket) { + socket.onclose = null; + socket.close(); + } - socket = new WebSocket(WS_URL + topologyUrl + '/ws?t=' + updateFrequency); + socket = new WebSocket(WS_URL + topologyUrl + '/ws?t=' + updateFrequency); - socket.onclose = function() { - clearTimeout(reconnectTimer); - socket = null; + socket.onclose = function() { + clearTimeout(reconnectTimer); + socket = null; - reconnectTimer = setTimeout(function() { - createWebsocket(topologyUrl); - }, 5000); - } + reconnectTimer = setTimeout(function() { + createWebsocket(topologyUrl); + }, 5000); + } - socket.onmessage = function(event) { - var msg = JSON.parse(event.data); - if (msg.add || msg.remove || msg.update) { - AppActions.receiveNodesDelta(msg); - } - }; + socket.onmessage = function(event) { + var msg = JSON.parse(event.data); + if (msg.add || msg.remove || msg.update) { + AppActions.receiveNodesDelta(msg); + } + }; - currentUrl = topologyUrl; + currentUrl = topologyUrl; } function getTopologies() { - clearTimeout(topologyTimer); - reqwest('/api/topology', function(res) { - AppActions.receiveTopologies(res); - topologyTimer = setTimeout(getTopologies, 10000); - }); + clearTimeout(topologyTimer); + reqwest('/api/topology', function(res) { + AppActions.receiveTopologies(res); + topologyTimer = setTimeout(getTopologies, 10000); + }); } function getNodeDetails(topologyUrl, nodeId) { - if (topologyUrl && nodeId) { - var url = [topologyUrl, nodeId].join('/'); - reqwest(url, function(res) { - AppActions.receiveNodeDetails(res.node); - }); - } + if (topologyUrl && nodeId) { + var url = [topologyUrl, nodeId].join('/'); + reqwest(url, function(res) { + AppActions.receiveNodeDetails(res.node); + }); + } } module.exports = { - getNodeDetails: getNodeDetails, + getNodeDetails: getNodeDetails, - getTopologies: getTopologies, + getTopologies: getTopologies, - getNodesDelta: function(topologyUrl) { - if (topologyUrl && topologyUrl !== currentUrl) { - createWebsocket(topologyUrl); - } - } + getNodesDelta: function(topologyUrl) { + if (topologyUrl && topologyUrl !== currentUrl) { + createWebsocket(topologyUrl); + } + } } diff --git a/client/app/styles/main.less b/client/app/styles/main.less index 9881388bc..4a442f3e5 100644 --- a/client/app/styles/main.less +++ b/client/app/styles/main.less @@ -5,10 +5,10 @@ @import url(http://fonts.googleapis.com/css?family=Roboto:300,400); .browsehappy { - margin: 0.2em 0; - background: #ccc; - color: #000; - padding: 0.2em 0; + margin: 0.2em 0; + background: #ccc; + color: #000; + padding: 0.2em 0; } /* weave company colours */ @@ -35,250 +35,248 @@ html, body { /* Space out content a bit */ body { - background: linear-gradient(30deg, @background-color 0%, @background-secondary-color 100%); - color: @text-color; - line-height: 150%; + background: linear-gradient(30deg, @background-color 0%, @background-secondary-color 100%); + color: @text-color; + line-height: 150%; } #app { } .header { - position: absolute; - top: 32px; - width: 100%; - height: 80px; - z-index: 20; + position: absolute; + top: 32px; + width: 100%; + height: 80px; + z-index: 20; } .logo { - margin: -8px 0 0 64px; - height: 64px; - width: 250px; - float: left; + margin: -8px 0 0 64px; + height: 64px; + width: 250px; + float: left; } .topologies, .groupings { - float: left; - margin-top: 7px; - margin-left: 48px; + float: left; + margin-top: 7px; + margin-left: 48px; } .topologies { - &-icon { - font-size: 12px; - color: @text-secondary-color; - margin-right: 16px; - position: relative; - top: -1px; + &-icon { + font-size: 12px; + color: @text-secondary-color; + margin-right: 16px; + position: relative; + top: -1px; + } + + .topologies-item { + margin: 8px 16px 6px 0; + cursor: pointer; + display: inline-block; + + &-label { + color: @text-secondary-color; + font-size: 15px; + text-transform: uppercase; } - .topologies-item { - margin: 8px 16px 6px 0; - cursor: pointer; - display: inline-block; - - &-label { - color: @text-secondary-color; - font-size: 15px; - text-transform: uppercase; - } - - &-active, &:hover { - .topologies-item-label { - color: @text-color; - } - } + &-active, &:hover { + .topologies-item-label { + color: @text-color; + } } + } } .groupings { - &-item { - font-size: 15px; - margin: 8px 12px 6px 0; - cursor: pointer; - display: inline-block; - color: @text-tertiary-color; + &-item { + font-size: 15px; + margin: 8px 12px 6px 0; + cursor: pointer; + display: inline-block; + color: @text-tertiary-color; - &-disabled { - color: @text-tertiary-color; - cursor: default; - } - - &-default:hover, - &-active { - color: @text-color; - } + &-disabled { + color: @text-tertiary-color; + cursor: default; } + + &-default:hover, + &-active { + color: @text-color; + } + } } .status { - float: right; - margin-top: 14px; - margin-right: 64px; + float: right; + margin-top: 14px; + margin-right: 64px; - &-icon { - font-size: 16px; - position: relative; - top: 1px; - color: @text-secondary-color; - } + &-icon { + font-size: 16px; + position: relative; + top: 1px; + color: @text-secondary-color; + } - &-label { - margin-left: 0.5em; - } + &-label { + margin-left: 0.5em; + } } #nodes { - svg { - position: absolute; - top: 0px; - } + svg { + position: absolute; + top: 0px; + } - text { - font-size: 14px; - font-family: Roboto; - fill: @text-secondary-color; - text-shadow: 0 2px 0 @white, 2px 0 0 @white, 0 -2px 0 @white, -2px 0 0 @white; + text { + font-size: 14px; + font-family: Roboto; + fill: @text-secondary-color; + text-shadow: 0 2px 0 @white, 2px 0 0 @white, 0 -2px 0 @white, -2px 0 0 @white; - &.node-label { - fill: @text-color; - } - - &.node-sublabel { - font-size: 12px; - fill: @text-secondary-color; - } - } - - g.node { - cursor: pointer; - } - - .link { - stroke: @text-secondary-color; - stroke-width: 1.5px; - fill: none; - opacity: 0.5; - } - - circle.border { - stroke-width: 3px; - fill: none; - } - - circle.shadow { - stroke: none; - fill: @background-secondary-color; - } - - circle.node { + &.node-label { fill: @text-color; } + + &.node-sublabel { + font-size: 12px; + fill: @text-secondary-color; + } + } + + g.node { + cursor: pointer; + } + + .link { + stroke: @text-secondary-color; + stroke-width: 1.5px; + fill: none; + opacity: 0.5; + } + + circle.border { + stroke-width: 3px; + fill: none; + } + + circle.shadow { + stroke: none; + fill: @background-secondary-color; + } + + circle.node { + fill: @text-color; + } } #details { - position: absolute; - z-index: 1024; - display: block; - right: 36px; - top: 24px; - bottom: 48px; - width: 32em; + position: absolute; + z-index: 1024; + display: block; + right: 36px; + top: 24px; + bottom: 48px; + width: 32em; - .details-tools { - float: right; - padding: 16px 24px; - color: @white; + .details-tools { + float: right; + padding: 16px 24px; + color: @white; - span { - cursor: pointer; - &:hover { - color: white; - } - } + span { + cursor: pointer; + &:hover { + color: white; + } } + } } .mui-paper, .mui-paper-container { - height: 100%; + height: 100%; } .node-details { - height: 100%; + height: 100%; + width: 100%; + background-color: rgba(255, 255, 255, 0.86); + + &-header { + + padding: 24px 36px 24px 36px; + + &-label { + color: white; + margin-bottom: 0; + + &-minor { + font-size: 120%; + color: @white; + } + + } + } + + &-content { + position: absolute; + top: 115px; + bottom: 0; width: 100%; - background-color: rgba(255, 255, 255, 0.86); + padding: 0 36px 0 36px; + overflow-y: scroll; + } - &-header { + &-table { - padding: 24px 36px 24px 36px; + margin-bottom: 8px; - &-label { - color: white; - margin-bottom: 0; + &-title { + text-transform: uppercase; + margin-bottom: 0; + color: @text-secondary-color; + font-size: 100%; + } - &-minor { - font-size: 120%; - color: @white; - } + &-row { + white-space: nowrap; + clear: left; - } + &-key { + width: 9em; + float: left; + } + + &-value-major { + margin-right: 0.5em; + overflow: hidden; + text-overflow: ellipsis; + } + + &-value-scalar { + width: 2em; + text-align: right; + margin-right: 0.5em; + } + + &-value-minor, + &-value-unit { + font-size: 95%; + color: @text-secondary-color; + } } - &-content { - position: absolute; - top: 115px; - bottom: 0; - width: 100%; - padding: 0 36px 0 36px; - overflow-y: scroll; - } - - &-table { - - margin-bottom: 8px; - - &-title { - text-transform: uppercase; - margin-bottom: 0; - color: @text-secondary-color; - font-size: 100%; - } - - &-row { - white-space: nowrap; - clear: left; - - &-key { - float: left; - width: 9em; - } - - &-value-major { - margin-right: 0.5em; - - overflow: hidden; - text-overflow: ellipsis; - } - - &-value-scalar { - width: 2em; - text-align: right; - margin-right: 0.5em; - } - - &-value-minor, - &-value-unit { - font-size: 95%; - color: @text-secondary-color; - } - - } - - } + } } From 42a3f57e11fcc4f3db6135661a1340a347aa61b4 Mon Sep 17 00:00:00 2001 From: David Kaltschmidt Date: Wed, 27 May 2015 17:35:43 +0200 Subject: [PATCH 2/3] Added linter for js - use global stricts - use airbnb linter rules - gulp lint target - make target client-lint --- Makefile | 5 + client/.eslintrc | 212 ++++++++++++++++++ client/app/scripts/components/app.js | 2 - client/app/scripts/components/details.js | 2 - client/app/scripts/components/explorer.js | 2 - client/app/scripts/components/groupings.js | 2 - client/app/scripts/components/logo.js | 2 - .../scripts/components/node-details-table.js | 2 - client/app/scripts/components/node-details.js | 2 - client/app/scripts/components/nodes.js | 2 - client/app/scripts/components/status.js | 2 - client/app/scripts/components/topologies.js | 2 - client/app/scripts/constants/topologies.js | 1 - client/app/scripts/main.js | 4 - .../stores/__tests__/app-store-test.js | 1 - client/app/scripts/stores/app-store.js | 1 - client/app/scripts/utils/router-utils.js | 1 - client/gulpfile.js | 134 ++++++----- client/package.json | 6 +- 19 files changed, 296 insertions(+), 89 deletions(-) create mode 100644 client/.eslintrc diff --git a/Makefile b/Makefile index c5dcc48cb..a3d17c501 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,11 @@ client-test: client/test/* -v $(shell pwd)/client/test:/home/weave/test \ $(SCOPE_UI_BUILD_IMAGE) npm test +client-lint: + docker run -ti -v $(shell pwd)/client/app:/home/weave/app \ + -v $(shell pwd)/client/test:/home/weave/test \ + $(SCOPE_UI_BUILD_IMAGE) npm run lint + $(SCOPE_UI_BUILD_EXPORT): client/Dockerfile client/gulpfile.js client/package.json docker build -t $(SCOPE_UI_BUILD_IMAGE) client docker save $(SCOPE_UI_BUILD_IMAGE):latest > $@ diff --git a/client/.eslintrc b/client/.eslintrc new file mode 100644 index 000000000..3b842c853 --- /dev/null +++ b/client/.eslintrc @@ -0,0 +1,212 @@ +{ + "parser": "babel-eslint", + "plugins": [ + "react" + ], + "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 + }, + "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": 1, // 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": 2, + "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" + ] + }] + } +} diff --git a/client/app/scripts/components/app.js b/client/app/scripts/components/app.js index 9f3d4e972..7d9f293df 100644 --- a/client/app/scripts/components/app.js +++ b/client/app/scripts/components/app.js @@ -1,5 +1,3 @@ -/** @jsx React.DOM */ - var React = require('react'); var _ = require('lodash'); diff --git a/client/app/scripts/components/details.js b/client/app/scripts/components/details.js index 161794578..804bd36b5 100644 --- a/client/app/scripts/components/details.js +++ b/client/app/scripts/components/details.js @@ -1,5 +1,3 @@ -/** @jsx React.DOM */ - var React = require('react'); var _ = require('lodash'); var mui = require('material-ui'); diff --git a/client/app/scripts/components/explorer.js b/client/app/scripts/components/explorer.js index 84dd62f1e..522222190 100644 --- a/client/app/scripts/components/explorer.js +++ b/client/app/scripts/components/explorer.js @@ -1,5 +1,3 @@ -/** @jsx React.DOM */ - var React = require('react'); var _ = require('lodash'); diff --git a/client/app/scripts/components/groupings.js b/client/app/scripts/components/groupings.js index f6e8eeed7..2d8e61671 100644 --- a/client/app/scripts/components/groupings.js +++ b/client/app/scripts/components/groupings.js @@ -1,5 +1,3 @@ -/** @jsx React.DOM */ - var React = require('react'); var _ = require('lodash'); diff --git a/client/app/scripts/components/logo.js b/client/app/scripts/components/logo.js index bc3cf2b39..93b785ccc 100644 --- a/client/app/scripts/components/logo.js +++ b/client/app/scripts/components/logo.js @@ -1,5 +1,3 @@ -/** @jsx React.DOM */ - var React = require('react'); var Logo = React.createClass({ diff --git a/client/app/scripts/components/node-details-table.js b/client/app/scripts/components/node-details-table.js index 5ef29f6a3..6e280781b 100644 --- a/client/app/scripts/components/node-details-table.js +++ b/client/app/scripts/components/node-details-table.js @@ -1,5 +1,3 @@ -/** @jsx React.DOM */ - var React = require('react'); var _ = require('lodash'); diff --git a/client/app/scripts/components/node-details.js b/client/app/scripts/components/node-details.js index 628755803..cb58bb5d5 100644 --- a/client/app/scripts/components/node-details.js +++ b/client/app/scripts/components/node-details.js @@ -1,5 +1,3 @@ -/** @jsx React.DOM */ - var React = require('react'); var _ = require('lodash'); diff --git a/client/app/scripts/components/nodes.js b/client/app/scripts/components/nodes.js index 3b211f6c1..5b7923fba 100644 --- a/client/app/scripts/components/nodes.js +++ b/client/app/scripts/components/nodes.js @@ -1,5 +1,3 @@ -/** @jsx React.DOM */ - var React = require('react'); var NodesChart = require('../charts/nodes-chart'); diff --git a/client/app/scripts/components/status.js b/client/app/scripts/components/status.js index 74005357d..42a7e2657 100644 --- a/client/app/scripts/components/status.js +++ b/client/app/scripts/components/status.js @@ -1,5 +1,3 @@ -/** @jsx React.DOM */ - var React = require('react'); var Status = React.createClass({ diff --git a/client/app/scripts/components/topologies.js b/client/app/scripts/components/topologies.js index 4e4db8913..8c8f0255f 100644 --- a/client/app/scripts/components/topologies.js +++ b/client/app/scripts/components/topologies.js @@ -1,5 +1,3 @@ -/** @jsx React.DOM */ - var React = require('react'); var _ = require('lodash'); diff --git a/client/app/scripts/constants/topologies.js b/client/app/scripts/constants/topologies.js index 38c920fb5..b8180ef16 100644 --- a/client/app/scripts/constants/topologies.js +++ b/client/app/scripts/constants/topologies.js @@ -1,4 +1,3 @@ - module.exports = [ { url: '/api/topology/applications', diff --git a/client/app/scripts/main.js b/client/app/scripts/main.js index 8085367af..90c11851e 100644 --- a/client/app/scripts/main.js +++ b/client/app/scripts/main.js @@ -1,7 +1,3 @@ -/** - * @jsx React.DOM - */ - var React = require('react'); var App = require('./components/app.js'); diff --git a/client/app/scripts/stores/__tests__/app-store-test.js b/client/app/scripts/stores/__tests__/app-store-test.js index 9e30e5bd3..e9cae6ce9 100644 --- a/client/app/scripts/stores/__tests__/app-store-test.js +++ b/client/app/scripts/stores/__tests__/app-store-test.js @@ -1,4 +1,3 @@ - describe('AppStore', function() { var ActionTypes = require('../../constants/action-types'); diff --git a/client/app/scripts/stores/app-store.js b/client/app/scripts/stores/app-store.js index b3d986236..074382459 100644 --- a/client/app/scripts/stores/app-store.js +++ b/client/app/scripts/stores/app-store.js @@ -1,4 +1,3 @@ - var EventEmitter = require('events').EventEmitter; var _ = require('lodash'); var assign = require('object-assign'); diff --git a/client/app/scripts/utils/router-utils.js b/client/app/scripts/utils/router-utils.js index 12d56ef5c..3a3726e05 100644 --- a/client/app/scripts/utils/router-utils.js +++ b/client/app/scripts/utils/router-utils.js @@ -1,4 +1,3 @@ - var page = require('page'); var AppActions = require('../actions/app-actions'); diff --git a/client/gulpfile.js b/client/gulpfile.js index c443f086e..dfe0e806b 100644 --- a/client/gulpfile.js +++ b/client/gulpfile.js @@ -16,100 +16,114 @@ var isDev = true; var isProd = false; gulp.task('styles', function () { - return gulp.src('app/styles/main.less') - .pipe($.if(isDev, $.sourcemaps.init())) - .pipe($.less()) - .pipe($.autoprefixer('last 1 version')) - .pipe($.if(isDev, $.sourcemaps.write())) - .pipe($.if(isDev, gulp.dest('.tmp/styles'))) - .pipe($.if(isProd, $.csso())) - .pipe($.if(isProd, gulp.dest('dist/styles'))) - .pipe($.size()) - .pipe(livereload()); + return gulp.src('app/styles/main.less') + .pipe($.if(isDev, $.sourcemaps.init())) + .pipe($.less()) + .pipe($.autoprefixer('last 1 version')) + .pipe($.if(isDev, $.sourcemaps.write())) + .pipe($.if(isDev, gulp.dest('.tmp/styles'))) + .pipe($.if(isProd, $.csso())) + .pipe($.if(isProd, gulp.dest('dist/styles'))) + .pipe($.size()) + .pipe(livereload()); }); gulp.task('scripts', function() { - var bundler = browserify('./app/scripts/main.js', {debug: isDev}); - bundler.transform(reactify); + var bundler = browserify('./app/scripts/main.js', {debug: isDev}); + bundler.transform(reactify); - var stream = bundler.bundle(); + var stream = bundler.bundle(); - return stream - .pipe(source('bundle.js')) - .pipe($.if(isDev, gulp.dest('.tmp/scripts'))) - .pipe($.if(isProd, buffer())) - .pipe($.if(isProd, $.uglify())) - .pipe($.if(isProd, gulp.dest('dist/scripts'))) - .pipe(livereload()) - .on('error', $.util.log); + return stream + .pipe(source('bundle.js')) + .pipe($.if(isDev, gulp.dest('.tmp/scripts'))) + .pipe($.if(isProd, buffer())) + .pipe($.if(isProd, $.uglify())) + .pipe($.if(isProd, gulp.dest('dist/scripts'))) + .pipe(livereload()) + .on('error', $.util.log); }); gulp.task('html', ['styles', 'scripts'], function () { - return gulp.src('app/*.html') - .pipe($.preprocess()) - .pipe(gulp.dest('dist')) - .pipe($.size()) - .pipe(livereload()); + return gulp.src('app/*.html') + .pipe($.preprocess()) + .pipe(gulp.dest('dist')) + .pipe($.size()) + .pipe(livereload()); }); gulp.task('images', function () { - return gulp.src('app/images/**/*') - .pipe(gulp.dest('dist/images')) - .pipe($.size()); + return gulp.src('app/images/**/*') + .pipe(gulp.dest('dist/images')) + .pipe($.size()); }); gulp.task('fonts', function () { - return gulp.src('node_modules/font-awesome/fonts/*') - .pipe($.filter('**/*.{eot,svg,ttf,woff,woff2}')) - .pipe($.flatten()) - .pipe($.if(isDev, gulp.dest('.tmp/fonts'))) - .pipe($.if(isProd, gulp.dest('dist/fonts'))) - .pipe($.size()); + return gulp.src('node_modules/font-awesome/fonts/*') + .pipe($.filter('**/*.{eot,svg,ttf,woff,woff2}')) + .pipe($.flatten()) + .pipe($.if(isDev, gulp.dest('.tmp/fonts'))) + .pipe($.if(isProd, gulp.dest('dist/fonts'))) + .pipe($.size()); }); gulp.task('extras', function () { - return gulp.src(['app/*.*', '!app/*.html'], { dot: true }) - .pipe(gulp.dest('dist')); + return gulp.src(['app/*.*', '!app/*.html'], { dot: true }) + .pipe(gulp.dest('dist')); }); gulp.task('clean', function () { - return del(['.tmp', 'dist']); + return del(['.tmp', 'dist']); +}); + + +gulp.task('lint', function () { + return gulp.src(['app/**/*.js']) + // eslint() attaches the lint output to the eslint property + // of the file object so it can be used by other modules. + .pipe($.eslint()) + // eslint.format() outputs the lint results to the console. + // Alternatively use eslint.formatEach() (see Docs). + .pipe($.eslint.format()); + // To have the process exit with an error code (1) on + // lint error, return the stream and pipe to failOnError last. + //.pipe($.eslint.failOnError()); }); gulp.task('production', ['html', 'images', 'fonts', 'extras']); gulp.task('build', function () { - isDev = false; - isProd = true; - gulp.start('production'); + isDev = false; + isProd = true; + gulp.start('production'); }); gulp.task('default', ['clean'], function () { - gulp.start('build'); + gulp.start('build'); }); gulp.task('connect', function () { - connect.server({ - root: ['.tmp', 'app'], - port: 4041, - middleware: function(connect, o) { - return [(function() { - var url = require('url'); - var proxy = require('proxy-middleware'); - var options = url.parse('http://localhost:4040/api'); - options.route = '/api'; - return proxy(options); - })()]; - }, - livereload: false - }); + connect.server({ + root: ['.tmp', 'app'], + port: 4041, + middleware: function(connect, o) { + return [(function() { + var url = require('url'); + var proxy = require('proxy-middleware'); + var options = url.parse('http://localhost:4040/api'); + options.route = '/api'; + return proxy(options); + })()]; + }, + livereload: false + }); }); gulp.task('serve', ['connect', 'styles', 'scripts', 'fonts']); gulp.task('watch', ['serve'], function () { - livereload.listen(); - gulp.watch('app/styles/**/*.less', ['styles']); - gulp.watch('app/scripts/**/*.js', ['scripts']); - gulp.watch('app/images/**/*', ['images']); + livereload.listen(); + gulp.watch('app/styles/**/*.less', ['styles']); + gulp.watch('app/scripts/**/*.js', ['scripts']); + gulp.watch('app/images/**/*', ['images']); }); diff --git a/client/package.json b/client/package.json index 7b14a29f5..389854a93 100644 --- a/client/package.json +++ b/client/package.json @@ -21,16 +21,19 @@ "reqwest": "~1.1.5" }, "devDependencies": { + "babel-eslint": "^3.1.9", "browserify": "^10.2.0", "del": "^1.1.1", + "eslint": "^0.21.2", + "eslint-plugin-react": "^2.3.0", "gulp": "^3.8.11", "gulp-autoprefixer": "^2.3.0", "gulp-connect": "^2.2.0", "gulp-csso": "^1.0.0", + "gulp-eslint": "^0.12.0", "gulp-filter": "^2.0.2", "gulp-flatten": "^0.0.4", "gulp-if": "^1.2.5", - "gulp-jshint": "^1.10.0", "gulp-less": "^3.0.3", "gulp-livereload": "^3.8.0", "gulp-load-plugins": "^0.10.0", @@ -55,6 +58,7 @@ "vinyl-source-stream": "^1.1.0" }, "scripts": { + "lint": "gulp lint", "start": "gulp", "test": "karma start test/karma.conf.js --single-run" }, From 7d1ee40a2b9c2dd82b4f2e61ca71ee5a53c731dd Mon Sep 17 00:00:00 2001 From: David Kaltschmidt Date: Wed, 27 May 2015 19:46:16 +0200 Subject: [PATCH 3/3] Fixed lint errors in all js files - Also added linter configuration, and make linter fail on error - fixing ES6 errors and added ES6 transformer - gulp target to try local build - linted gulpfile - cant hook into gulp lint yet, because gulp does currently not support ES6 which some rules demand, since gulp cant transpile itself, we have a chicken and egg problem. - ES6 transpiler for test runner - removed old linter config - adapted editorconfig to reflect linter config --- client/.editorconfig | 9 +- client/.eslintignore | 1 + client/.eslintrc | 7 +- client/.jshintrc | 21 -- client/.yo-rc.json | 3 - client/app/scripts/actions/app-actions.js | 18 +- client/app/scripts/charts/node.js | 22 +- client/app/scripts/charts/nodes-chart.js | 257 +++++++++--------- client/app/scripts/charts/nodes-layout.js | 28 +- client/app/scripts/components/app.js | 31 +-- client/app/scripts/components/details.js | 27 +- client/app/scripts/components/explorer.js | 56 ++-- client/app/scripts/components/groupings.js | 33 ++- client/app/scripts/components/logo.js | 10 +- .../scripts/components/node-details-table.js | 9 +- client/app/scripts/components/node-details.js | 17 +- client/app/scripts/components/nodes.js | 41 ++- client/app/scripts/components/status.js | 6 +- client/app/scripts/components/topologies.js | 22 +- client/app/scripts/constants/action-types.js | 2 +- .../app/scripts/dispatcher/app-dispatcher.js | 8 +- client/app/scripts/main.js | 4 +- client/app/scripts/mixins/node-color-mixin.js | 16 +- .../stores/__tests__/app-store-test.js | 17 +- client/app/scripts/stores/app-store.js | 47 ++-- client/app/scripts/utils/router-utils.js | 31 +-- client/app/scripts/utils/web-api-utils.js | 25 +- client/gulpfile.js | 92 ++++--- client/package.json | 2 + client/test/karma.conf.js | 2 +- 30 files changed, 419 insertions(+), 445 deletions(-) create mode 100644 client/.eslintignore delete mode 100644 client/.jshintrc delete mode 100644 client/.yo-rc.json diff --git a/client/.editorconfig b/client/.editorconfig index 561df8158..62d19a839 100644 --- a/client/.editorconfig +++ b/client/.editorconfig @@ -9,7 +9,7 @@ root = true # Change these settings to your own preference indent_style = space -indent_size = 4 +indent_size = 2 # We recommend you to keep these unchanged end_of_line = lf @@ -20,10 +20,3 @@ insert_final_newline = true [*.md] trim_trailing_whitespace = false -[package.json] -indent_style = space -indent_size = 2 - -[bower.json] -indent_style = space -indent_size = 2 diff --git a/client/.eslintignore b/client/.eslintignore new file mode 100644 index 000000000..a2e2b2a31 --- /dev/null +++ b/client/.eslintignore @@ -0,0 +1 @@ +app/**/__tests__/*.js diff --git a/client/.eslintrc b/client/.eslintrc index 3b842c853..4dce480af 100644 --- a/client/.eslintrc +++ b/client/.eslintrc @@ -1,7 +1,8 @@ { "parser": "babel-eslint", "plugins": [ - "react" + "react", + "jasmine" ], "env": { "browser": true, @@ -138,7 +139,7 @@ }], "comma-style": [2, "last"], // http://eslint.org/docs/rules/comma-style "eol-last": 2, // http://eslint.org/docs/rules/eol-last - "func-names": 1, // http://eslint.org/docs/rules/func-names + "func-names": 0, // http://eslint.org/docs/rules/func-names "key-spacing": [2, { // http://eslint.org/docs/rules/key-spacing "beforeColon": false, "afterColon": true @@ -184,7 +185,7 @@ "react/no-did-update-set-state": 2, "react/no-multi-comp": 2, "react/no-unknown-property": 2, - "react/prop-types": 2, + "react/prop-types": 0, "react/react-in-jsx-scope": 2, "react/self-closing-comp": 2, "react/wrap-multilines": 2, diff --git a/client/.jshintrc b/client/.jshintrc deleted file mode 100644 index 287bc43d2..000000000 --- a/client/.jshintrc +++ /dev/null @@ -1,21 +0,0 @@ -{ - "node": true, - "browser": true, - "esnext": true, - "bitwise": true, - "camelcase": true, - "curly": true, - "eqeqeq": true, - "immed": true, - "indent": 4, - "latedef": true, - "newcap": true, - "noarg": true, - "quotmark": "single", - "undef": true, - "unused": true, - "strict": true, - "trailing": true, - "smarttabs": true, - "jquery": true -} diff --git a/client/.yo-rc.json b/client/.yo-rc.json deleted file mode 100644 index 7a2135249..000000000 --- a/client/.yo-rc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "generator-mocha": {} -} \ No newline at end of file diff --git a/client/app/scripts/actions/app-actions.js b/client/app/scripts/actions/app-actions.js index 9ebef7b3e..2aa991628 100644 --- a/client/app/scripts/actions/app-actions.js +++ b/client/app/scripts/actions/app-actions.js @@ -1,5 +1,8 @@ -var AppDispatcher = require('../dispatcher/app-dispatcher'); -var ActionTypes = require('../constants/action-types'); +let ActionTypes; +let AppDispatcher; +let AppStore; +let RouterUtils; +let WebapiUtils; module.exports = { clickCloseDetails: function() { @@ -90,8 +93,11 @@ module.exports = { } }; -// breaking circular deps +// require below export to break circular dep -var RouterUtils = require('../utils/router-utils'); -var WebapiUtils = require('../utils/web-api-utils'); -var AppStore = require('../stores/app-store'); \ No newline at end of file +AppDispatcher = require('../dispatcher/app-dispatcher'); +ActionTypes = require('../constants/action-types'); + +RouterUtils = require('../utils/router-utils'); +WebapiUtils = require('../utils/web-api-utils'); +AppStore = require('../stores/app-store'); diff --git a/client/app/scripts/charts/node.js b/client/app/scripts/charts/node.js index 738147d0d..fa8e46efa 100644 --- a/client/app/scripts/charts/node.js +++ b/client/app/scripts/charts/node.js @@ -1,10 +1,9 @@ -var _ = require('lodash'); -var React = require('react'); -var tweenState = require('react-tween-state'); +const React = require('react'); +const tweenState = require('react-tween-state'); -var NodeColorMixin = require('../mixins/node-color-mixin'); +const NodeColorMixin = require('../mixins/node-color-mixin'); -var Node = React.createClass({ +const Node = React.createClass({ mixins: [ NodeColorMixin, tweenState.Mixin @@ -40,13 +39,12 @@ var Node = React.createClass({ }, render: function() { - var transform = "translate(" + this.getTweeningValue('x') + "," + this.getTweeningValue('y') + ")"; - var scale = this.props.scale; - var textOffsetX = 0; - var textOffsetY = scale(0.5) + 18; - var textAngle = _.isUndefined(this.props.angle) ? 0 : -1 * (this.props.angle * 180 / Math.PI - 90); - var color = this.getNodeColor(this.props.label); - var className = this.props.highlighted ? "node highlighted" : "node"; + const transform = 'translate(' + this.getTweeningValue('x') + ',' + this.getTweeningValue('y') + ')'; + const scale = this.props.scale; + const textOffsetX = 0; + const textOffsetY = scale(0.5) + 18; + const color = this.getNodeColor(this.props.label); + const className = this.props.highlighted ? 'node highlighted' : 'node'; return ( diff --git a/client/app/scripts/charts/nodes-chart.js b/client/app/scripts/charts/nodes-chart.js index 819cd158e..91b1034dd 100644 --- a/client/app/scripts/charts/nodes-chart.js +++ b/client/app/scripts/charts/nodes-chart.js @@ -1,40 +1,133 @@ -var _ = require('lodash'); -var d3 = require('d3'); -var React = require('react'); +const _ = require('lodash'); +const d3 = require('d3'); +const React = require('react'); -var NodesLayout = require('./nodes-layout'); -var Node = require('./node'); +const NodesLayout = require('./nodes-layout'); +const Node = require('./node'); -var MAX_NODES = 100; -var MARGINS = { +const MARGINS = { top: 130, left: 40, right: 40, bottom: 0 }; -var line = d3.svg.line() - .interpolate("basis") +const line = d3.svg.line() + .interpolate('basis') .x(function(d) { return d.x; }) .y(function(d) { return d.y; }); -var NodesChart = React.createClass({ +const NodesChart = React.createClass({ getInitialState: function() { return { nodes: {}, edges: {}, nodeScale: 1, - translate: "0,0", + translate: '0,0', scale: 1, hasZoomed: false }; }, + componentWillMount: function() { + this.updateGraphState(this.props); + }, + + componentDidMount: function() { + this.zoom = d3.behavior.zoom() + .scaleExtent([0.1, 2]) + .on('zoom', this.zoomed); + + d3.select('.nodes-chart') + .call(this.zoom); + }, + + componentWillReceiveProps: function(nextProps) { + if (this.getTopologyFingerprint(nextProps.nodes) !== this.getTopologyFingerprint(this.props.nodes)) { + this.setState({ + nodes: {}, + edges: {} + }); + } + + this.updateGraphState(nextProps); + }, + + componentWillUnmount: function() { + // undoing .call(zoom) + + d3.select('.nodes-chart') + .on('mousedown.zoom', null) + .on('onwheel', null) + .on('onmousewheel', null) + .on('dblclick.zoom', null) + .on('touchstart.zoom', null); + }, + + getTopologyFingerprint: function(topology) { + const fingerprint = []; + + _.each(topology, function(node) { + fingerprint.push(node.id); + if (node.adjacency) { + fingerprint.push(node.adjacency.join(',')); + } + }); + return fingerprint.join(';'); + }, + + getGraphNodes: function(nodes, scale) { + return _.map(nodes, function(node) { + const highlighted = _.includes(this.props.highlightedNodes, node.id); + return ( + + ); + }, this); + }, + + getGraphEdges: function(edges) { + return _.map(edges, function(edge) { + return ( + + ); + }); + }, + + render: function() { + const nodeElements = this.getGraphNodes(this.state.nodes, this.state.nodeScale); + const edgeElements = this.getGraphEdges(this.state.edges, this.state.nodeScale); + const transform = 'translate(' + this.state.translate + ')' + + ' scale(' + this.state.scale + ')'; + + return ( + + + + {edgeElements} + + + {nodeElements} + + + + ); + }, + initNodes: function(topology, prevNodes) { - var centerX = this.props.width / 2; - var centerY = this.props.height / 2; - var nodes = {}; + const centerX = this.props.width / 2; + const centerY = this.props.height / 2; + const nodes = {}; _.each(topology, function(node, id) { nodes[id] = prevNodes[id] || {}; @@ -55,19 +148,19 @@ var NodesChart = React.createClass({ }, initEdges: function(topology, nodes) { - var edges = {}; + const edges = {}; _.each(topology, function(node) { _.each(node.adjacency, function(adjacent) { - var edge = [node.id, adjacent], - edgeId = edge.join('-'); + const edge = [node.id, adjacent]; + const edgeId = edge.join('-'); if (!edges[edgeId]) { - var source = nodes[edge[0]]; - var target = nodes[edge[1]]; + const source = nodes[edge[0]]; + const target = nodes[edge[1]]; - if(!source || !target) { - console.error("Missing edge node", edge[0], source, edge[1], target); + if (!source || !target) { + console.error('Missing edge node', edge[0], source, edge[1], target); } edges[edgeId] = { @@ -83,58 +176,18 @@ var NodesChart = React.createClass({ return edges; }, - getNodes: function(nodes, scale) { - return _.map(nodes, function (node) { - var highlighted = _.includes(this.props.highlightedNodes, node.id); - return ( - - ); - }, this); - }, - - getEdges: function(edges, scale) { - return _.map(edges, function(edge) { - return ( - - ); - }); - }, - - getTopologyFingerprint: function(topology) { - var nodes = _.keys(topology).sort(); - var fingerprint = []; - - _.each(topology, function(node) { - fingerprint.push(node.id); - if (node.adjacency) { - fingerprint.push(node.adjacency.join(',')); - } - }); - return fingerprint.join(';'); - }, - updateGraphState: function(props) { - var nodes = this.initNodes(props.nodes, this.state.nodes); - var edges = this.initEdges(props.nodes, nodes); + const nodes = this.initNodes(props.nodes, this.state.nodes); + const edges = this.initEdges(props.nodes, nodes); - var expanse = Math.min(props.height, props.width); - var nodeSize = expanse / 2; - var n = _.size(props.nodes); - var nodeScale = d3.scale.linear().range([0, nodeSize/Math.pow(n, 0.7)]); + const expanse = Math.min(props.height, props.width); + const nodeSize = expanse / 2; + const n = _.size(props.nodes); + const nodeScale = d3.scale.linear().range([0, nodeSize / Math.pow(n, 0.7)]); - var layoutId = 'layered node chart'; + const layoutId = 'layered node chart'; console.time(layoutId); - var graph = NodesLayout.doLayout( + const graph = NodesLayout.doLayout( nodes, edges, props.width, @@ -146,12 +199,12 @@ var NodesChart = React.createClass({ // adjust layout based on viewport - var xFactor = (props.width - MARGINS.left - MARGINS.right) / graph.width; - var yFactor = props.height / graph.height; - var zoomFactor = Math.min(xFactor, yFactor); - var zoomScale = this.state.scale; + const xFactor = (props.width - MARGINS.left - MARGINS.right) / graph.width; + const yFactor = props.height / graph.height; + const zoomFactor = Math.min(xFactor, yFactor); + let zoomScale = this.state.scale; - if(this.zoom && !this.state.hasZoomed && zoomFactor > 0 && zoomFactor < 1) { + if (this.zoom && !this.state.hasZoomed && zoomFactor > 0 && zoomFactor < 1) { zoomScale = zoomFactor; // saving in d3's behavior cache this.zoom.scale(zoomFactor); @@ -165,68 +218,12 @@ var NodesChart = React.createClass({ }); }, - componentWillMount: function() { - this.updateGraphState(this.props); - }, - - componentDidMount: function() { - this.zoom = d3.behavior.zoom() - .scaleExtent([0.1, 2]) - .on('zoom', this.zoomed); - - d3.select('.nodes-chart') - .call(this.zoom); - }, - - componentWillUnmount: function() { - - // undoing .call(zoom) - - d3.select('.nodes-chart') - .on("mousedown.zoom", null) - .on("onwheel", null) - .on("onmousewheel", null) - .on("dblclick.zoom", null) - .on("touchstart.zoom", null); - }, - - componentWillReceiveProps: function(nextProps) { - if (this.getTopologyFingerprint(nextProps.nodes) !== this.getTopologyFingerprint(this.props.nodes)) { - this.setState({ - nodes: {}, - edges: {} - }); - } - - this.updateGraphState(nextProps); - }, - zoomed: function() { this.setState({ hasZoomed: true, translate: d3.event.translate, scale: d3.event.scale }); - }, - - render: function() { - var nodeElements = this.getNodes(this.state.nodes, this.state.nodeScale); - var edgeElements = this.getEdges(this.state.edges, this.state.nodeScale); - var transform = 'translate(' + this.state.translate + ')' + - ' scale(' + this.state.scale + ')'; - - return ( - - - - {edgeElements} - - - {nodeElements} - - - - ); } }); diff --git a/client/app/scripts/charts/nodes-layout.js b/client/app/scripts/charts/nodes-layout.js index 0556d7c41..d21006894 100644 --- a/client/app/scripts/charts/nodes-layout.js +++ b/client/app/scripts/charts/nodes-layout.js @@ -1,16 +1,16 @@ -var dagre = require('dagre'); -var _ = require('lodash'); +const dagre = require('dagre'); +const _ = require('lodash'); -var MAX_NODES = 100; +const MAX_NODES = 100; -var doLayout = function(nodes, edges, width, height, scale, margins) { - var offsetX = 0 + margins.left; - var offsetY = 0 + margins.top; - var g = new dagre.graphlib.Graph({}); +const doLayout = function(nodes, edges, width, height, scale, margins) { + let offsetX = 0 + margins.left; + let offsetY = 0 + margins.top; + const g = new dagre.graphlib.Graph({}); if (_.size(nodes) > MAX_NODES) { console.error('Too many nodes for graph layout engine. Limit: ' + MAX_NODES); - return; + return null; } // configure node margins @@ -27,13 +27,13 @@ var doLayout = function(nodes, edges, width, height, scale, margins) { }); _.each(edges, function(edge) { - var virtualNodes = edge.source.id === edge.target.id ? 1 : 0; + const virtualNodes = edge.source.id === edge.target.id ? 1 : 0; g.setEdge(edge.source.id, edge.target.id, {id: edge.id, minlen: virtualNodes}); }); dagre.layout(g); - var graph = g.graph(); + const graph = g.graph(); // shifting graph coordinates to center @@ -47,15 +47,15 @@ var doLayout = function(nodes, edges, width, height, scale, margins) { // apply coordinates to nodes and edges g.nodes().forEach(function(id) { - var node = nodes[id]; - var graphNode = g.node(id); + const node = nodes[id]; + const graphNode = g.node(id); node.x = graphNode.x + offsetX; node.y = graphNode.y + offsetY; }); g.edges().forEach(function(id) { - var graphEdge = g.edge(id); - var edge = edges[graphEdge.id]; + const graphEdge = g.edge(id); + const edge = edges[graphEdge.id]; _.each(graphEdge.points, function(point) { point.x += offsetX; point.y += offsetY; diff --git a/client/app/scripts/components/app.js b/client/app/scripts/components/app.js index 7d9f293df..97cdc112e 100644 --- a/client/app/scripts/components/app.js +++ b/client/app/scripts/components/app.js @@ -1,19 +1,18 @@ -var React = require('react'); -var _ = require('lodash'); +const React = require('react'); -var Logo = require('./logo'); -var AppStore = require('../stores/app-store'); -var Groupings = require('./groupings.js'); -var Status = require('./status.js'); -var Topologies = require('./topologies.js'); -var WebapiUtils = require('../utils/web-api-utils'); -var AppActions = require('../actions/app-actions'); -var Details = require('./details'); -var Nodes = require('./nodes'); -var RouterUtils = require('../utils/router-utils'); +const Logo = require('./logo'); +const AppStore = require('../stores/app-store'); +const Groupings = require('./groupings.js'); +const Status = require('./status.js'); +const Topologies = require('./topologies.js'); +const WebapiUtils = require('../utils/web-api-utils'); +const AppActions = require('../actions/app-actions'); +const Details = require('./details'); +const Nodes = require('./nodes'); +const RouterUtils = require('../utils/router-utils'); -var ESC_KEY_CODE = 27; +const ESC_KEY_CODE = 27; function getStateFromStores() { return { @@ -24,11 +23,11 @@ function getStateFromStores() { nodeDetails: AppStore.getNodeDetails(), nodes: AppStore.getNodes(), topologies: AppStore.getTopologies() - } + }; } -var App = React.createClass({ +const App = React.createClass({ getInitialState: function() { return getStateFromStores(); @@ -53,7 +52,7 @@ var App = React.createClass({ }, render: function() { - var showingDetails = this.state.selectedNodeId; + const showingDetails = this.state.selectedNodeId; return (
diff --git a/client/app/scripts/components/details.js b/client/app/scripts/components/details.js index 804bd36b5..e22b815a2 100644 --- a/client/app/scripts/components/details.js +++ b/client/app/scripts/components/details.js @@ -1,18 +1,11 @@ -var React = require('react'); -var _ = require('lodash'); -var mui = require('material-ui'); -var Paper = mui.Paper; -var IconButton = mui.IconButton; +const React = require('react'); +const mui = require('material-ui'); +const Paper = mui.Paper; -var AppActions = require('../actions/app-actions'); -var NodeDetails = require('./node-details'); +const AppActions = require('../actions/app-actions'); +const NodeDetails = require('./node-details'); -var Details = React.createClass({ - - handleClickClose: function(ev) { - ev.preventDefault(); - AppActions.clickCloseDetails(); - }, +const Details = React.createClass({ render: function() { return ( @@ -25,8 +18,14 @@ var Details = React.createClass({
); + }, + + handleClickClose: function(ev) { + ev.preventDefault(); + AppActions.clickCloseDetails(); } + }); -module.exports = Details; \ No newline at end of file +module.exports = Details; diff --git a/client/app/scripts/components/explorer.js b/client/app/scripts/components/explorer.js index 522222190..606ea413e 100644 --- a/client/app/scripts/components/explorer.js +++ b/client/app/scripts/components/explorer.js @@ -1,15 +1,15 @@ -var React = require('react'); -var _ = require('lodash'); +const React = require('react'); +const _ = require('lodash'); -var NodesChart = require('../charts/nodes-chart'); -var NodeDetails = require('./node-details'); +const NodesChart = require('../charts/nodes-chart'); +const NodeDetails = require('./node-details'); -var marginBottom = 64; -var marginTop = 64; -var marginLeft = 36; -var marginRight = 36; +const marginBottom = 64; +const marginTop = 64; +const marginLeft = 36; +const marginRight = 36; -var Explorer = React.createClass({ +const Explorer = React.createClass({ getInitialState: function() { return { @@ -27,27 +27,16 @@ var Explorer = React.createClass({ window.removeEventListener('resize', this.handleResize); }, - setDimensions: function() { - this.setState({ - height: window.innerHeight - marginBottom - marginTop, - width: window.innerWidth - marginLeft - marginRight - }); - }, - - handleResize: function() { - this.setDimensions(); - }, - getSubTopology: function(topology) { - var subTopology = {}; - var nodeSet = []; + const subTopology = {}; + const nodeSet = []; _.each(this.props.expandedNodes, function(nodeId) { if (topology[nodeId]) { subTopology[nodeId] = topology[nodeId]; nodeSet = _.union(subTopology[nodeId].adjacency, nodeSet); _.each(subTopology[nodeId].adjacency, function(adjacentId) { - var node = _.assign({}, topology[adjacentId]); + const node = _.assign({}, topology[adjacentId]); subTopology[adjacentId] = node; }); @@ -62,20 +51,14 @@ var Explorer = React.createClass({ return subTopology; }, - onNodeClick: function(ev) { - var nodeId = ev.currentTarget.id; - AppActions.clickNode(nodeId); - }, - render: function() { - var subTopology = this.getSubTopology(this.props.nodes); + const subTopology = this.getSubTopology(this.props.nodes); return (
); + }, + + setDimensions: function() { + this.setState({ + height: window.innerHeight - marginBottom - marginTop, + width: window.innerWidth - marginLeft - marginRight + }); + }, + + handleResize: function() { + this.setDimensions(); } }); -module.exports = Explorer; \ No newline at end of file +module.exports = Explorer; diff --git a/client/app/scripts/components/groupings.js b/client/app/scripts/components/groupings.js index 2d8e61671..66809a28c 100644 --- a/client/app/scripts/components/groupings.js +++ b/client/app/scripts/components/groupings.js @@ -1,10 +1,9 @@ -var React = require('react'); -var _ = require('lodash'); +const React = require('react'); +const _ = require('lodash'); -var AppActions = require('../actions/app-actions'); -var AppStore = require('../stores/app-store'); +const AppActions = require('../actions/app-actions'); -var GROUPINGS = [{ +const GROUPINGS = [{ id: 'none', iconClass: 'fa fa-th', needsTopology: false @@ -14,31 +13,27 @@ var GROUPINGS = [{ needsTopology: 'grouped_url' }]; -var Groupings = React.createClass({ +const Groupings = React.createClass({ onGroupingClick: function(ev) { ev.preventDefault(); AppActions.clickGrouping(ev.currentTarget.getAttribute('rel')); }, - isGroupingSupportedByTopology: function(topology, grouping) { - return !grouping.needsTopology || topology && topology[grouping.needsTopology]; - }, - getGroupingsSupportedByTopology: function(topology) { return _.filter(GROUPINGS, _.partial(this.isGroupingSupportedByTopology, topology)); }, renderGrouping: function(grouping, activeGroupingId) { - var className = "groupings-item", - isSupportedByTopology = this.isGroupingSupportedByTopology(this.props.currentTopology, grouping); + let className = 'groupings-item'; + const isSupportedByTopology = this.isGroupingSupportedByTopology(this.props.currentTopology, grouping); if (grouping.id === activeGroupingId) { - className += " groupings-item-active"; + className += ' groupings-item-active'; } else if (!isSupportedByTopology) { - className += " groupings-item-disabled"; + className += ' groupings-item-disabled'; } else { - className += " groupings-item-default"; + className += ' groupings-item-default'; } return ( @@ -49,8 +44,8 @@ var Groupings = React.createClass({ }, render: function() { - var activeGrouping = this.props.active, - isGroupingSupported = _.size(this.getGroupingsSupportedByTopology(this.props.currentTopology)) > 1; + const activeGrouping = this.props.active; + const isGroupingSupported = _.size(this.getGroupingsSupportedByTopology(this.props.currentTopology)) > 1; return (
@@ -59,6 +54,10 @@ var Groupings = React.createClass({ }, this)}
); + }, + + isGroupingSupportedByTopology: function(topology, grouping) { + return !grouping.needsTopology || topology && topology[grouping.needsTopology]; } }); diff --git a/client/app/scripts/components/logo.js b/client/app/scripts/components/logo.js index 93b785ccc..003e40c79 100644 --- a/client/app/scripts/components/logo.js +++ b/client/app/scripts/components/logo.js @@ -1,6 +1,6 @@ -var React = require('react'); +const React = require('react'); -var Logo = React.createClass({ +const Logo = React.createClass({ render: function() { return ( @@ -16,7 +16,7 @@ var Logo = React.createClass({ - - @@ -29,4 +28,4 @@ var NodeDetailsTable = React.createClass({ }); -module.exports = NodeDetailsTable; \ No newline at end of file +module.exports = NodeDetailsTable; diff --git a/client/app/scripts/components/node-details.js b/client/app/scripts/components/node-details.js index cb58bb5d5..0f49fbe53 100644 --- a/client/app/scripts/components/node-details.js +++ b/client/app/scripts/components/node-details.js @@ -1,24 +1,23 @@ -var React = require('react'); -var _ = require('lodash'); +const React = require('react'); -var NodeDetailsTable = require('./node-details-table'); -var NodeColorMixin = require('../mixins/node-color-mixin'); +const NodeDetailsTable = require('./node-details-table'); +const NodeColorMixin = require('../mixins/node-color-mixin'); -var NodeDetails = React.createClass({ +const NodeDetails = React.createClass({ mixins: [ NodeColorMixin ], render: function() { - var node = this.props.details; + const node = this.props.details; if (!node) { return
; } - var style = { - "background-color": this.getNodeColorDark(node.label_major) + const style = { + 'background-color': this.getNodeColorDark(node.label_major) }; return ( @@ -41,4 +40,4 @@ var NodeDetails = React.createClass({ }); -module.exports = NodeDetails; \ No newline at end of file +module.exports = NodeDetails; diff --git a/client/app/scripts/components/nodes.js b/client/app/scripts/components/nodes.js index 5b7923fba..945428b6a 100644 --- a/client/app/scripts/components/nodes.js +++ b/client/app/scripts/components/nodes.js @@ -1,13 +1,12 @@ -var React = require('react'); +const React = require('react'); -var NodesChart = require('../charts/nodes-chart'); -var AppActions = require('../actions/app-actions'); +const NodesChart = require('../charts/nodes-chart'); +const AppActions = require('../actions/app-actions'); -var navbarHeight = 160; -var marginTop = 0; -var marginLeft = 0; +const navbarHeight = 160; +const marginTop = 0; -var Nodes = React.createClass({ +const Nodes = React.createClass({ getInitialState: function() { return { @@ -16,10 +15,6 @@ var Nodes = React.createClass({ }; }, - onNodeClick: function(ev) { - AppActions.clickNode(ev.currentTarget.id); - }, - componentDidMount: function() { window.addEventListener('resize', this.handleResize); }, @@ -28,15 +23,8 @@ var Nodes = React.createClass({ window.removeEventListener('resize', this.handleResize); }, - setDimensions: function() { - this.setState({ - height: window.innerHeight - navbarHeight - marginTop, - width: window.innerWidth - }); - }, - - handleResize: function() { - this.setDimensions(); + onNodeClick: function(ev) { + AppActions.clickNode(ev.currentTarget.id); }, render: function() { @@ -51,8 +39,19 @@ var Nodes = React.createClass({ />
); + }, + + handleResize: function() { + this.setDimensions(); + }, + + setDimensions: function() { + this.setState({ + height: window.innerHeight - navbarHeight - marginTop, + width: window.innerWidth + }); } }); -module.exports = Nodes; \ No newline at end of file +module.exports = Nodes; diff --git a/client/app/scripts/components/status.js b/client/app/scripts/components/status.js index 42a7e2657..d07d13f4f 100644 --- a/client/app/scripts/components/status.js +++ b/client/app/scripts/components/status.js @@ -1,6 +1,6 @@ -var React = require('react'); +const React = require('react'); -var Status = React.createClass({ +const Status = React.createClass({ renderConnectionState: function() { return ( @@ -12,7 +12,7 @@ var Status = React.createClass({ }, render: function() { - var isDisconnected = this.props.connectionState === 'disconnected'; + const isDisconnected = this.props.connectionState === 'disconnected'; return (
diff --git a/client/app/scripts/components/topologies.js b/client/app/scripts/components/topologies.js index 8c8f0255f..152e4245c 100644 --- a/client/app/scripts/components/topologies.js +++ b/client/app/scripts/components/topologies.js @@ -1,21 +1,21 @@ -var React = require('react'); -var _ = require('lodash'); +const React = require('react'); +const _ = require('lodash'); -var AppActions = require('../actions/app-actions'); -var AppStore = require('../stores/app-store'); +const AppActions = require('../actions/app-actions'); +const AppStore = require('../stores/app-store'); -var Topologies = React.createClass({ +const Topologies = React.createClass({ onTopologyClick: function(ev) { ev.preventDefault(); AppActions.clickTopology(ev.currentTarget.getAttribute('rel')); }, - renderTopology: function(topology, active) { - var isActive = topology.name === this.props.currentTopology.name, - className = isActive ? "topologies-item topologies-item-active" : "topologies-item", - topologyId = AppStore.getTopologyIdForUrl(topology.url), - title = ['Topology: ' + topology.name, + renderTopology: function(topology) { + const isActive = topology.name === this.props.currentTopology.name; + const className = isActive ? 'topologies-item topologies-item-active' : 'topologies-item'; + const topologyId = AppStore.getTopologyIdForUrl(topology.url); + const title = ['Topology: ' + topology.name, 'Nodes: ' + topology.stats.node_count, 'Connections: ' + topology.stats.node_count].join('\n'); @@ -31,7 +31,7 @@ var Topologies = React.createClass({ }, render: function() { - var topologies = _.sortBy(this.props.topologies, function(topology) { + const topologies = _.sortBy(this.props.topologies, function(topology) { return topology.name; }); diff --git a/client/app/scripts/constants/action-types.js b/client/app/scripts/constants/action-types.js index 1f1e7946f..91a3772c5 100644 --- a/client/app/scripts/constants/action-types.js +++ b/client/app/scripts/constants/action-types.js @@ -1,4 +1,4 @@ -var keymirror = require('keymirror'); +const keymirror = require('keymirror'); module.exports = keymirror({ CLICK_CLOSE_DETAILS: null, diff --git a/client/app/scripts/dispatcher/app-dispatcher.js b/client/app/scripts/dispatcher/app-dispatcher.js index e24c99866..1f24e13fc 100644 --- a/client/app/scripts/dispatcher/app-dispatcher.js +++ b/client/app/scripts/dispatcher/app-dispatcher.js @@ -1,10 +1,10 @@ -var flux = require('flux'); -var _ = require('lodash'); +const flux = require('flux'); +const _ = require('lodash'); -var AppDispatcher = new flux.Dispatcher(); +const AppDispatcher = new flux.Dispatcher(); AppDispatcher.dispatch = _.wrap(flux.Dispatcher.prototype.dispatch, function(func) { - var args = Array.prototype.slice.call(arguments, 1); + const args = Array.prototype.slice.call(arguments, 1); // console.log(args[0]); func.apply(this, args); }); diff --git a/client/app/scripts/main.js b/client/app/scripts/main.js index 90c11851e..330003e05 100644 --- a/client/app/scripts/main.js +++ b/client/app/scripts/main.js @@ -1,6 +1,6 @@ -var React = require('react'); +const React = require('react'); -var App = require('./components/app.js'); +const App = require('./components/app.js'); React.render( , diff --git a/client/app/scripts/mixins/node-color-mixin.js b/client/app/scripts/mixins/node-color-mixin.js index 679e71e91..c96b3468a 100644 --- a/client/app/scripts/mixins/node-color-mixin.js +++ b/client/app/scripts/mixins/node-color-mixin.js @@ -1,27 +1,27 @@ -var d3 = require('d3'); +const d3 = require('d3'); -var colors = d3.scale.category20(); +const colors = d3.scale.category20(); // make sure the internet always gets the same color -var internetLabel = "the Internet"; +const internetLabel = 'the Internet'; colors(internetLabel); -var NodeColorMixin = { +const NodeColorMixin = { getNodeColor: function(text) { return colors(text); }, getNodeColorDark: function(text) { - var color = d3.rgb(colors(text)); - var hsl = color.hsl(); + const color = d3.rgb(colors(text)); + let hsl = color.hsl(); // ensure darkness // if (hsl.l > 0.5) { - hsl = hsl.darker(); + hsl = hsl.darker(); // } return hsl.toString(); } }; -module.exports = NodeColorMixin; \ No newline at end of file +module.exports = NodeColorMixin; diff --git a/client/app/scripts/stores/__tests__/app-store-test.js b/client/app/scripts/stores/__tests__/app-store-test.js index e9cae6ce9..acc7065c0 100644 --- a/client/app/scripts/stores/__tests__/app-store-test.js +++ b/client/app/scripts/stores/__tests__/app-store-test.js @@ -1,21 +1,23 @@ -describe('AppStore', function() { - var ActionTypes = require('../../constants/action-types'); - var AppStore, registeredCallback; + +describe('AppStore', function() { + const ActionTypes = require('../../constants/action-types'); + let AppStore; + let registeredCallback; // actions - var ClickTopologyAction = { + const ClickTopologyAction = { type: ActionTypes.CLICK_TOPOLOGY, topologyId: 'topo1' }; - var ClickGroupingAction = { + const ClickGroupingAction = { type: ActionTypes.CLICK_GROUPING, grouping: 'grouped' }; - var ReceiveTopologiesAction = { + const ReceiveTopologiesAction = { type: ActionTypes.RECEIVE_TOPOLOGIES, topologies: [{ url: '/topo1', @@ -32,7 +34,7 @@ describe('AppStore', function() { // topology tests it('init with no topologies', function() { - var topos = AppStore.getTopologies(); + const topos = AppStore.getTopologies(); expect(topos.length).toBe(0); expect(AppStore.getCurrentTopology()).toBeUndefined(); }); @@ -56,5 +58,4 @@ describe('AppStore', function() { expect(AppStore.getCurrentTopologyUrl()).toBe('/topo1grouped'); }); - }); \ No newline at end of file diff --git a/client/app/scripts/stores/app-store.js b/client/app/scripts/stores/app-store.js index 074382459..1763c0321 100644 --- a/client/app/scripts/stores/app-store.js +++ b/client/app/scripts/stores/app-store.js @@ -1,25 +1,30 @@ -var EventEmitter = require('events').EventEmitter; -var _ = require('lodash'); -var assign = require('object-assign'); +const EventEmitter = require('events').EventEmitter; +const _ = require('lodash'); +const assign = require('object-assign'); -var AppDispatcher = require('../dispatcher/app-dispatcher'); -var ActionTypes = require('../constants/action-types'); +const AppDispatcher = require('../dispatcher/app-dispatcher'); +const ActionTypes = require('../constants/action-types'); +// Helpers + +function isUrlForTopologyId(url, topologyId) { + return _.endsWith(url, topologyId); +} // Initial values -var connectionState = 'disconnected'; -var currentGrouping = 'none'; -var currentTopologyId = 'applications'; -var mouseOverNode = null; -var nodes = {}; -var nodeDetails = null; -var selectedNodeId = null; -var topologies = []; +let connectionState = 'disconnected'; +let currentGrouping = 'none'; +let currentTopologyId = 'applications'; +let mouseOverNode = null; +let nodes = {}; +let nodeDetails = null; +let selectedNodeId = null; +let topologies = []; // Store API -var AppStore = assign({}, EventEmitter.prototype, { +const AppStore = assign({}, EventEmitter.prototype, { CHANGE_EVENT: 'change', @@ -42,10 +47,10 @@ var AppStore = assign({}, EventEmitter.prototype, { }, getCurrentTopologyUrl: function() { - var topology = this.getCurrentTopology(); + const topology = this.getCurrentTopology(); if (topology) { - return topology.grouped_url && currentGrouping == 'grouped' ? topology.grouped_url : topology.url; + return topology.grouped_url && currentGrouping === 'grouped' ? topology.grouped_url : topology.url; } }, @@ -74,14 +79,6 @@ var AppStore = assign({}, EventEmitter.prototype, { } }); - -// Helpers - -function isUrlForTopologyId(url, topologyId) { - return _.endsWith(url, topologyId); -} - - // Store Dispatch Hooks AppStore.registeredCallback = function(payload) { @@ -140,7 +137,7 @@ AppStore.registeredCallback = function(payload) { 'update', _.size(payload.delta.update), 'add', _.size(payload.delta.add)); - connectionState = "connected"; + connectionState = 'connected'; // nodes that no longer exist _.each(payload.delta.remove, function(nodeId) { diff --git a/client/app/scripts/utils/router-utils.js b/client/app/scripts/utils/router-utils.js index 3a3726e05..bd484a260 100644 --- a/client/app/scripts/utils/router-utils.js +++ b/client/app/scripts/utils/router-utils.js @@ -1,25 +1,24 @@ -var page = require('page'); +const page = require('page'); -var AppActions = require('../actions/app-actions'); -var AppStore = require('../stores/app-store'); - -page('/', function(ctx) { - updateRoute(); -}); - -page('/state/:state', function(ctx) { - var state = JSON.parse(ctx.params.state); - AppActions.route(state); -}); +const AppActions = require('../actions/app-actions'); +const AppStore = require('../stores/app-store'); function updateRoute() { - var state = AppStore.getAppState(); - var stateUrl = JSON.stringify(state); - var dispatch = false; + const state = AppStore.getAppState(); + const stateUrl = JSON.stringify(state); + const dispatch = false; page.show('/state/' + stateUrl, state, dispatch); } +page('/', function() { + updateRoute(); +}); + +page('/state/:state', function(ctx) { + const state = JSON.parse(ctx.params.state); + AppActions.route(state); +}); module.exports = { getRouter: function() { @@ -27,4 +26,4 @@ module.exports = { }, updateRoute: updateRoute -}; \ No newline at end of file +}; diff --git a/client/app/scripts/utils/web-api-utils.js b/client/app/scripts/utils/web-api-utils.js index f29722a5b..e1ae0b234 100644 --- a/client/app/scripts/utils/web-api-utils.js +++ b/client/app/scripts/utils/web-api-utils.js @@ -1,15 +1,15 @@ -var reqwest = require('reqwest'); +const reqwest = require('reqwest'); -var AppActions = require('../actions/app-actions'); +const AppActions = require('../actions/app-actions'); -var WS_URL = window.WS_URL || 'ws://' + location.host; +const WS_URL = window.WS_URL || 'ws://' + location.host; -var socket; -var reconnectTimer = 0; -var currentUrl = null; -var updateFrequency = '5s'; -var topologyTimer = 0; +let socket; +let reconnectTimer = 0; +let currentUrl = null; +let updateFrequency = '5s'; +let topologyTimer = 0; function createWebsocket(topologyUrl) { if (socket) { @@ -26,10 +26,10 @@ function createWebsocket(topologyUrl) { reconnectTimer = setTimeout(function() { createWebsocket(topologyUrl); }, 5000); - } + }; socket.onmessage = function(event) { - var msg = JSON.parse(event.data); + const msg = JSON.parse(event.data); if (msg.add || msg.remove || msg.update) { AppActions.receiveNodesDelta(msg); } @@ -48,7 +48,7 @@ function getTopologies() { function getNodeDetails(topologyUrl, nodeId) { if (topologyUrl && nodeId) { - var url = [topologyUrl, nodeId].join('/'); + const url = [topologyUrl, nodeId].join('/'); reqwest(url, function(res) { AppActions.receiveNodeDetails(res.node); }); @@ -65,4 +65,5 @@ module.exports = { createWebsocket(topologyUrl); } } -} +}; + diff --git a/client/gulpfile.js b/client/gulpfile.js index dfe0e806b..c8a192958 100644 --- a/client/gulpfile.js +++ b/client/gulpfile.js @@ -1,21 +1,21 @@ -'use strict'; -var gulp = require('gulp'); -var connect = require('gulp-connect'); -var livereload = require('gulp-livereload'); -var browserify = require('browserify'); -var del = require('del'); -var source = require('vinyl-source-stream'); -var buffer = require('vinyl-buffer'); -var reactify = require('reactify'); +const gulp = require('gulp'); +const connect = require('gulp-connect'); +const livereload = require('gulp-livereload'); +const babelify = require('babelify'); +const browserify = require('browserify'); +const del = require('del'); +const source = require('vinyl-source-stream'); +const vbuffer = require('vinyl-buffer'); +const reactify = require('reactify'); // load plugins -var $ = require('gulp-load-plugins')(); +const $ = require('gulp-load-plugins')(); var isDev = true; var isProd = false; -gulp.task('styles', function () { +gulp.task('styles', function() { return gulp.src('app/styles/main.less') .pipe($.if(isDev, $.sourcemaps.init())) .pipe($.less()) @@ -29,22 +29,23 @@ gulp.task('styles', function () { }); gulp.task('scripts', function() { - var bundler = browserify('./app/scripts/main.js', {debug: isDev}); + const bundler = browserify('./app/scripts/main.js', {debug: isDev}); bundler.transform(reactify); + bundler.transform(babelify); - var stream = bundler.bundle(); + const stream = bundler.bundle(); return stream .pipe(source('bundle.js')) .pipe($.if(isDev, gulp.dest('.tmp/scripts'))) - .pipe($.if(isProd, buffer())) + .pipe($.if(isProd, vbuffer())) .pipe($.if(isProd, $.uglify())) + .on('error', $.util.log) .pipe($.if(isProd, gulp.dest('dist/scripts'))) - .pipe(livereload()) - .on('error', $.util.log); + .pipe(livereload()); }); -gulp.task('html', ['styles', 'scripts'], function () { +gulp.task('html', ['styles', 'scripts'], function() { return gulp.src('app/*.html') .pipe($.preprocess()) .pipe(gulp.dest('dist')) @@ -52,13 +53,13 @@ gulp.task('html', ['styles', 'scripts'], function () { .pipe(livereload()); }); -gulp.task('images', function () { +gulp.task('images', function() { return gulp.src('app/images/**/*') .pipe(gulp.dest('dist/images')) .pipe($.size()); }); -gulp.task('fonts', function () { +gulp.task('fonts', function() { return gulp.src('node_modules/font-awesome/fonts/*') .pipe($.filter('**/*.{eot,svg,ttf,woff,woff2}')) .pipe($.flatten()) @@ -67,50 +68,51 @@ gulp.task('fonts', function () { .pipe($.size()); }); -gulp.task('extras', function () { +gulp.task('extras', function() { return gulp.src(['app/*.*', '!app/*.html'], { dot: true }) .pipe(gulp.dest('dist')); }); -gulp.task('clean', function () { +gulp.task('clean', function() { return del(['.tmp', 'dist']); }); -gulp.task('lint', function () { +gulp.task('lint', function() { return gulp.src(['app/**/*.js']) - // eslint() attaches the lint output to the eslint property - // of the file object so it can be used by other modules. + // eslint() attaches the lint output to the eslint property + // of the file object so it can be used by other modules. .pipe($.eslint()) - // eslint.format() outputs the lint results to the console. - // Alternatively use eslint.formatEach() (see Docs). - .pipe($.eslint.format()); - // To have the process exit with an error code (1) on - // lint error, return the stream and pipe to failOnError last. - //.pipe($.eslint.failOnError()); + // eslint.format() outputs the lint results to the console. + // Alternatively use eslint.formatEach() (see Docs). + .pipe($.eslint.format()) + // To have the process exit with an error code (1) on + // lint error, return the stream and pipe to failOnError last. + .pipe($.eslint.failOnError()); }); gulp.task('production', ['html', 'images', 'fonts', 'extras']); -gulp.task('build', function () { +gulp.task('build', function() { isDev = false; isProd = true; gulp.start('production'); }); -gulp.task('default', ['clean'], function () { +gulp.task('default', ['clean'], function() { gulp.start('build'); }); -gulp.task('connect', function () { +gulp.task('connect', function() { + const root = isProd ? ['dist'] : ['.tmp', 'app']; connect.server({ - root: ['.tmp', 'app'], + root: root, port: 4041, - middleware: function(connect, o) { + middleware: function() { return [(function() { - var url = require('url'); - var proxy = require('proxy-middleware'); - var options = url.parse('http://localhost:4040/api'); + const url = require('url'); + const proxy = require('proxy-middleware'); + const options = url.parse('http://localhost:4040/api'); options.route = '/api'; return proxy(options); })()]; @@ -121,7 +123,19 @@ gulp.task('connect', function () { gulp.task('serve', ['connect', 'styles', 'scripts', 'fonts']); -gulp.task('watch', ['serve'], function () { +gulp.task('serve-build', function() { + isDev = false; + isProd = true; + + // use local WS api + gulp.src('app/*.html') + .pipe($.preprocess({context: {DEBUG: true} })) + .pipe(gulp.dest('dist')); + + gulp.start('connect'); +}); + +gulp.task('watch', ['serve'], function() { livereload.listen(); gulp.watch('app/styles/**/*.less', ['styles']); gulp.watch('app/scripts/**/*.js', ['scripts']); diff --git a/client/package.json b/client/package.json index 389854a93..e45f17f09 100644 --- a/client/package.json +++ b/client/package.json @@ -22,9 +22,11 @@ }, "devDependencies": { "babel-eslint": "^3.1.9", + "babelify": "^6.1.2", "browserify": "^10.2.0", "del": "^1.1.1", "eslint": "^0.21.2", + "eslint-plugin-jasmine": "^1.0.0", "eslint-plugin-react": "^2.3.0", "gulp": "^3.8.11", "gulp-autoprefixer": "^2.3.0", diff --git a/client/test/karma.conf.js b/client/test/karma.conf.js index 1d50e1f7b..068b09e99 100644 --- a/client/test/karma.conf.js +++ b/client/test/karma.conf.js @@ -14,7 +14,7 @@ module.exports = function(config) { }, browserify: { debug: true, - transform: ['reactify'] + transform: ['reactify', 'babelify'] }, reporters: [ 'dots'