From 816e1e9e995748916e8fed0d8ae2e8de45dbbc75 Mon Sep 17 00:00:00 2001 From: David Kaltschmidt Date: Fri, 12 Jun 2015 11:37:49 +0200 Subject: [PATCH] layout of sub-topologies * uses injected static topology, see web-api-utils.js --- client/app/scripts/components/app.js | 2 - client/app/scripts/components/topologies.js | 27 ++++++-- .../stores/__tests__/app-store-test.js | 27 +++++--- client/app/scripts/stores/app-store.js | 24 +++++-- client/app/scripts/utils/web-api-utils.js | 44 ++++++++++++- client/app/styles/main.less | 62 ++++++++----------- 6 files changed, 124 insertions(+), 62 deletions(-) diff --git a/client/app/scripts/components/app.js b/client/app/scripts/components/app.js index c8a78a080..febbebb16 100644 --- a/client/app/scripts/components/app.js +++ b/client/app/scripts/components/app.js @@ -2,7 +2,6 @@ const React = require('react'); 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'); @@ -67,7 +66,6 @@ const App = React.createClass({
-
diff --git a/client/app/scripts/components/topologies.js b/client/app/scripts/components/topologies.js index 152e4245c..d13a9e955 100644 --- a/client/app/scripts/components/topologies.js +++ b/client/app/scripts/components/topologies.js @@ -11,29 +11,46 @@ const Topologies = React.createClass({ AppActions.clickTopology(ev.currentTarget.getAttribute('rel')); }, + renderSubTopology: function(subTopology) { + const isActive = subTopology.name === this.props.currentTopology.name; + const topologyId = AppStore.getTopologyIdForUrl(subTopology.url); + const className = isActive ? 'topologies-sub-item topologies-sub-item-active' : 'topologies-sub-item'; + + return ( +
+
+ {subTopology.name} +
+
+ ); + }, + renderTopology: function(topology) { const isActive = topology.name === this.props.currentTopology.name; - const className = isActive ? 'topologies-item topologies-item-active' : 'topologies-item'; + const className = isActive ? 'topologies-item-main topologies-item-main-active' : 'topologies-item-main'; const topologyId = AppStore.getTopologyIdForUrl(topology.url); const title = ['Topology: ' + topology.name, 'Nodes: ' + topology.stats.node_count, 'Connections: ' + topology.stats.node_count].join('\n'); return ( -
-
+
+
{topology.name}
+
+ {topology.sub_topologies && topology.sub_topologies.map(this.renderSubTopology)} +
); }, render: function() { const topologies = _.sortBy(this.props.topologies, function(topology) { - return topology.name; - }); + return topology.name; + }); return (
diff --git a/client/app/scripts/stores/__tests__/app-store-test.js b/client/app/scripts/stores/__tests__/app-store-test.js index bcca13750..7ca3c6668 100644 --- a/client/app/scripts/stores/__tests__/app-store-test.js +++ b/client/app/scripts/stores/__tests__/app-store-test.js @@ -16,6 +16,11 @@ describe('AppStore', function() { nodeId: 'n1' }; + const ClickSubTopologyAction = { + type: ActionTypes.CLICK_TOPOLOGY, + topologyId: 'topo1-grouped' + }; + const ClickTopologyAction = { type: ActionTypes.CLICK_TOPOLOGY, topologyId: 'topo1' @@ -45,8 +50,11 @@ describe('AppStore', function() { type: ActionTypes.RECEIVE_TOPOLOGIES, topologies: [{ url: '/topo1', - grouped_url: '/topo1grouped', - name: 'Topo1' + name: 'Topo1', + sub_topologies: [{ + url: '/topo1-grouped', + name: 'topo 1 grouped' + }] }] }; @@ -77,14 +85,13 @@ describe('AppStore', function() { expect(AppStore.getCurrentTopologyUrl()).toBe('/topo1'); }); - it('get grouped topology', function() { - registeredCallback(ClickTopologyAction); + it('get sub-topology', function() { registeredCallback(ReceiveTopologiesAction); - registeredCallback(ClickGroupingAction); + registeredCallback(ClickSubTopologyAction); expect(AppStore.getTopologies().length).toBe(1); - expect(AppStore.getCurrentTopology().name).toBe('Topo1'); - expect(AppStore.getCurrentTopologyUrl()).toBe('/topo1grouped'); + expect(AppStore.getCurrentTopology().name).toBe('topo 1 grouped'); + expect(AppStore.getCurrentTopologyUrl()).toBe('/topo1-grouped'); }); // browsing @@ -110,14 +117,14 @@ describe('AppStore', function() { registeredCallback(ReceiveNodesDeltaAction); // TODO clear AppStore cache expect(AppStore.getAppState()) - .toEqual({"topologyId":"topo1","grouping":"grouped","selectedNodeId": null}); + .toEqual({"topologyId":"topo1-grouped","grouping":"none","selectedNodeId": null}); registeredCallback(ClickNodeAction); expect(AppStore.getAppState()) - .toEqual({"topologyId":"topo1","grouping":"grouped","selectedNodeId": 'n1'}); + .toEqual({"topologyId":"topo1-grouped","grouping":"none","selectedNodeId": 'n1'}); // go back in browsing - RouteAction.state = {"topologyId":"topo1","grouping":"grouped","selectedNodeId": null}; + RouteAction.state = {"topologyId":"topo1-grouped","grouping":"none","selectedNodeId": null}; registeredCallback(RouteAction); expect(AppStore.getSelectedNodeId()).toBe(null); expect(AppStore.getNodes()).toEqual(NODE_SET); diff --git a/client/app/scripts/stores/app-store.js b/client/app/scripts/stores/app-store.js index 4670b823d..8db061b74 100644 --- a/client/app/scripts/stores/app-store.js +++ b/client/app/scripts/stores/app-store.js @@ -9,8 +9,22 @@ const Naming = require('../constants/naming'); // Helpers -function isUrlForTopologyId(url, topologyId) { - return _.endsWith(url, topologyId); +function findCurrentTopology(subTree, topologyId) { + let foundTopology; + + _.each(subTree, function(topology) { + if (_.endsWith(topology.url, topologyId)) { + foundTopology = topology; + } + if (!foundTopology) { + foundTopology = findCurrentTopology(topology.sub_topologies, topologyId); + } + if (foundTopology) { + return false; + } + }); + + return foundTopology; } // Initial values @@ -45,16 +59,14 @@ const AppStore = assign({}, EventEmitter.prototype, { }, getCurrentTopology: function() { - return _.find(topologies, function(topology) { - return isUrlForTopologyId(topology.url, currentTopologyId); - }); + return findCurrentTopology(topologies, currentTopologyId); }, getCurrentTopologyUrl: function() { const topology = this.getCurrentTopology(); if (topology) { - return topology.grouped_url && currentGrouping === 'grouped' ? topology.grouped_url : topology.url; + return topology.url; } }, diff --git a/client/app/scripts/utils/web-api-utils.js b/client/app/scripts/utils/web-api-utils.js index dce7160c3..b5d37e851 100644 --- a/client/app/scripts/utils/web-api-utils.js +++ b/client/app/scripts/utils/web-api-utils.js @@ -39,10 +39,50 @@ function createWebsocket(topologyUrl) { currentUrl = topologyUrl; } + +const TOPOLOGIES = [ + { + 'name': 'Applications', + 'url': '/api/topology/applications', + 'stats': { + 'node_count': 12, + 'nonpseudo_node_count': 10, + 'edge_count': 13 + }, + 'sub_topologies': [ + { + 'name': 'by name', + 'url': '/api/topology/applications-grouped' + } + ] + }, + { + 'name': 'Containers', + 'url': '/api/topology/containers', + 'grouped_url': '/api/topology/containers-grouped', + 'stats': { + 'node_count': 2, + 'nonpseudo_node_count': 1, + 'edge_count': 2 + } + }, + { + 'name': 'Hosts', + 'url': '/api/topology/hosts', + 'stats': { + 'node_count': 2, + 'nonpseudo_node_count': 1, + 'edge_count': 2 + } + } +]; + + function getTopologies() { clearTimeout(topologyTimer); - reqwest('/api/topology', function(res) { - AppActions.receiveTopologies(res); + reqwest('/api/topology', function() { + // injecting static topos + AppActions.receiveTopologies(TOPOLOGIES); topologyTimer = setTimeout(getTopologies, 10000); }); } diff --git a/client/app/styles/main.less b/client/app/styles/main.less index b4df69bf9..fb3f342cd 100644 --- a/client/app/styles/main.less +++ b/client/app/styles/main.less @@ -81,59 +81,47 @@ body { float: left; } -.topologies, -.groupings { - float: left; - margin-top: 7px; - margin-left: 48px; -} - .topologies { - &-icon { - font-size: 12px; - color: @text-secondary-color; - margin-right: 16px; - position: relative; - top: -1px; - } + float: left; + margin: 4px 64px; .topologies-item { - margin: 8px 16px 6px 0; - cursor: pointer; - display: inline-block; + margin: 0px 16px; + float: left; &-label { color: @text-secondary-color; - font-size: 15px; + font-size: 16px; text-transform: uppercase; } + } + + .topologies-sub { + margin-top: 4px; + + &-item { + &-label { + color: @text-secondary-color; + font-size: 12px; + text-transform: uppercase; + } + } + } + + .topologies-item-main, + .topologies-sub-item { + cursor: pointer; + &-active, &:hover { + .topologies-sub-item-label, .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; - - &-disabled { - color: @text-tertiary-color; - cursor: default; - } - - &-default:hover, - &-active { - color: @text-color; - } - } } .status {