Added Collections and Models for a Region.
Change-Id: Ic033b2890dad18e47b057e6b1d1c8535d812590d
diff --git a/.gitignore b/.gitignore
index 5817b7d..e109650 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,5 +22,7 @@
/bin/
web/gui/src/main/webapp/tests/node_modules
+web/gui/src/test/_karma/node_modules
web/gui/src/main/webapp/node_modules/
+
npm-debug.log
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2.js b/web/gui/src/main/webapp/app/view/topo2/topo2.js
index ce90af6..0631299 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2.js
@@ -1,18 +1,18 @@
/*
- * Copyright 2016-present Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+* Copyright 2016-present Open Networking Laboratory
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
/*
ONOS GUI -- Topology View Module
@@ -28,7 +28,7 @@
fs, mast, ks, zs,
gs, ms, sus, flash,
wss, ps, th,
- t2es, t2fs;
+ t2es, t2fs, t2is;
// DOM elements
var ovtopo2, svg, defs, zoomLayer, mapG, spriteG, forceG, noDevsLayer;
@@ -37,32 +37,66 @@
var zoomer, actionMap;
- // === Helper Functions
+ // --- Glyphs, Icons, and the like -----------------------------------
+
+ function setUpDefs() {
+ defs = svg.append('defs');
+ gs.loadDefs(defs);
+ sus.loadGlowDefs(defs);
+ }
// callback invoked when the SVG view has been resized..
function svgResized(s) {
- $log.debug("topo2 view resized", s);
+ $log.debug('topo2 view resized', s);
}
function setUpKeys(overlayKeys) {
$log.debug('topo2: set up keys....');
}
+ // --- Pan and Zoom --------------------------------------------------
+
+ // zoom enabled predicate. ev is a D3 source event.
+ function zoomEnabled(ev) {
+ return fs.isMobile() || (ev.metaKey || ev.altKey);
+ }
+
+ function zoomCallback() {
+ var sc = zoomer.scale(),
+ tr = zoomer.translate();
+
+ ps.setPrefs('topo_zoom', {tx:tr[0], ty:tr[1], sc:sc});
+
+ // keep the map lines constant width while zooming
+ mapG.style('stroke-width', (2.0 / sc) + 'px');
+ }
+
+ function setUpZoom() {
+ zoomLayer = svg.append('g').attr('id', 'topo-zoomlayer');
+ zoomer = zs.createZoomer({
+ svg: svg,
+ zoomLayer: zoomLayer,
+ zoomEnabled: zoomEnabled,
+ zoomCallback: zoomCallback
+ });
+ }
+
+
// === Controller Definition -----------------------------------------
angular.module('ovTopo2', ['onosUtil', 'onosSvg', 'onosRemote'])
- .controller('OvTopo2Ctrl',
+ .controller('OvTopo2Ctrl',
['$scope', '$log', '$location',
'FnService', 'MastService', 'KeyService', 'ZoomService',
'GlyphService', 'MapService', 'SvgUtilService', 'FlashService',
'WebSocketService', 'PrefsService', 'ThemeService',
- 'Topo2EventService', 'Topo2ForceService',
+ 'Topo2EventService', 'Topo2ForceService', 'Topo2InstanceService',
function (_$scope_, _$log_, _$loc_,
- _fs_, _mast_, _ks_, _zs_,
- _gs_, _ms_, _sus_, _flash_,
- _wss_, _ps_, _th_,
- _t2es_, _t2fs_) {
+ _fs_, _mast_, _ks_, _zs_,
+ _gs_, _ms_, _sus_, _flash_,
+ _wss_, _ps_, _th_,
+ _t2es_, _t2fs_, _t2is_) {
var params = _$loc_.search(),
projection,
@@ -95,9 +129,10 @@
wss = _wss_;
ps = _ps_;
th = _th_;
-
+
t2es = _t2es_;
t2fs = _t2fs_;
+ t2is = _t2is_;
// capture selected intent parameters (if they are set in the
// query string) so that the traffic overlay can highlight
@@ -134,24 +169,32 @@
// set up our keyboard shortcut bindings
setUpKeys();
+ setUpZoom();
+ setUpDefs();
// make sure we can respond to topology events from the server
t2es.bindHandlers();
// initialize the force layout, ready to render the topology
- t2fs.init();
+ forceG = zoomLayer.append('g').attr('id', 'topo-force');
+ t2fs.init(svg, forceG, uplink, dim);
// =-=-=-=-=-=-=-=-
// TODO: in future, we will load background map data
- // asynchronously (hence the promise) and then chain off
+ // asynchronously (hence the promise) and then chain off
// there to send the topo2start event to the server.
// For now, we'll send the event inline...
t2es.start();
-
+
+
+ t2is.initInst({ showMastership: t2fs.showMastership });
+
+
+
// === ORIGINAL CODE ===
-
+
// setUpKeys();
// setUpToolbar();
// setUpDefs();
@@ -192,7 +235,7 @@
// ttbs.setDefaultOverlay(prefsState.ovidx);
// $log.debug('registered overlays...', tov.list());
-
+
$log.log('OvTopo2Ctrl has been created');
}]);
}());
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Collection.js b/web/gui/src/main/webapp/app/view/topo2/topo2Collection.js
new file mode 100644
index 0000000..3116a6f
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Collection.js
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Topology Collection Module.
+ A Data Store that contains model data from the server
+ */
+
+(function () {
+ 'use strict';
+
+ var Model;
+
+ function Collection(models, options) {
+
+ options || (options = {});
+
+ this.models = [];
+ this._reset();
+
+ if (options.comparator !== void 0) this.comparator = options.comparator;
+
+ if (models) {
+ this.add(models);
+ }
+ }
+
+ Collection.prototype = {
+ model: Model,
+ add: function (data) {
+
+ var _this = this;
+
+ if (angular.isArray(data)) {
+
+ data.forEach(function (d) {
+
+ var model = new _this.model(d);
+ model.collection = _this;
+
+ _this.models.push(model);
+ _this._byId[d.id] = model;
+ });
+ }
+
+// this.sort();
+ },
+ get: function (id) {
+ if (!id) {
+ return void 0;
+ }
+ return this._byId[id] || null;
+ },
+ sort: function () {
+
+ var comparator = this.comparator;
+
+ // Check if function
+ comparator = comparator.bind(this);
+ this.models.sort(comparator);
+
+ return this;
+ },
+ _reset: function () {
+ this._byId = [];
+ this.models = [];
+ }
+ };
+
+ Collection.extend = function (protoProps, staticProps) {
+
+ var parent = this;
+ var child;
+
+ child = function () {
+ return parent.apply(this, arguments);
+ };
+
+ angular.extend(child, parent, staticProps);
+
+ // Set the prototype chain to inherit from `parent`, without calling
+ // `parent`'s constructor function and add the prototype properties.
+ child.prototype = angular.extend({}, parent.prototype, protoProps);
+ child.prototype.constructor = child;
+
+ // Set a convenience property in case the parent's prototype is needed
+ // later.
+ child.__super__ = parent.prototype;
+
+ return child;
+ };
+
+ angular.module('ovTopo2')
+ .factory('Topo2Collection',
+ ['Topo2Model',
+ function (_Model_) {
+
+ Model = _Model_;
+ return Collection;
+ }
+ ]);
+
+})();
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Device.js b/web/gui/src/main/webapp/app/view/topo2/topo2Device.js
new file mode 100644
index 0000000..ae04111
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Device.js
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Topology Devices Module.
+ Module that holds the devices for a region
+ */
+
+(function () {
+ 'use strict';
+
+ var Collection, Model;
+
+ function createDeviceCollection(data, region) {
+
+ var DeviceCollection = Collection.extend({
+ model: Model,
+ get: function () {},
+ comparator: function(a, b) {
+
+ var order = region.layerOrder;
+ return order.indexOf(a.get('layer')) - order.indexOf(b.get('layer'));
+ }
+ });
+
+ var devices = [];
+ data.forEach(function (deviceLayer) {
+ deviceLayer.forEach(function (device) {
+ devices.push(device);
+ });
+ });
+
+ var deviceCollection = new DeviceCollection(devices);
+ deviceCollection.sort();
+
+ return deviceCollection;
+ }
+
+ angular.module('ovTopo2')
+ .factory('Topo2DeviceService',
+ ['Topo2Collection', 'Topo2Model',
+
+ function (_Collection_, _Model_) {
+
+ Collection = _Collection_;
+ Model = _Model_.extend({});
+
+ return {
+ createDeviceCollection: createDeviceCollection
+ };
+ }
+ ]);
+
+})();
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Force.js b/web/gui/src/main/webapp/app/view/topo2/topo2Force.js
index 254f176..481b96b 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2Force.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Force.js
@@ -23,12 +23,99 @@
'use strict';
// injected refs
- var $log, wss;
+ var $log,
+ wss;
+
+ // SVG elements;
+ var linkG,
+ linkLabelG,
+ numLinkLblsG,
+ portLabelG,
+ nodeG;
+
+ // internal state
+ var settings, // merged default settings and options
+ force, // force layout object
+ drag, // drag behavior handler
+ network = {
+ nodes: [],
+ links: [],
+ linksByDevice: {},
+ lookup: {},
+ revLinkToKey: {}
+ },
+ lu, // shorthand for lookup
+ rlk, // shorthand for revLinktoKey
+ showHosts = false, // whether hosts are displayed
+ showOffline = true, // whether offline devices are displayed
+ nodeLock = false, // whether nodes can be dragged or not (locked)
+ fTimer, // timer for delayed force layout
+ fNodesTimer, // timer for delayed nodes update
+ fLinksTimer, // timer for delayed links update
+ dim, // the dimensions of the force layout [w,h]
+ linkNums = []; // array of link number labels
+
+ // D3 selections;
+ var link,
+ linkLabel,
+ node;
+
+ var $log, wss, t2is, t2rs;
// ========================== Helper Functions
- function init() {
+ function init(_svg_, forceG, _uplink_, _dim_, opts) {
+
$log.debug('Initialize topo force layout');
+
+ nodeG = forceG.append('g').attr('id', 'topo-nodes');
+ node = nodeG.selectAll('.node');
+
+ linkG = forceG.append('g').attr('id', 'topo-links');
+ linkLabelG = forceG.append('g').attr('id', 'topo-linkLabels');
+ numLinkLblsG = forceG.append('g').attr('id', 'topo-numLinkLabels');
+ nodeG = forceG.append('g').attr('id', 'topo-nodes');
+ portLabelG = forceG.append('g').attr('id', 'topo-portLabels');
+
+ link = linkG.selectAll('.link');
+ linkLabel = linkLabelG.selectAll('.linkLabel');
+ node = nodeG.selectAll('.node');
+
+ var width = 640,
+ height = 480;
+
+ var nodes = [
+ { x: width/3, y: height/2 },
+ { x: 2*width/3, y: height/2 }
+ ];
+
+ var links = [
+ { source: 0, target: 1 }
+ ];
+
+ var svg = d3.select('body').append('svg')
+ .attr('width', width)
+ .attr('height', height);
+
+ var force = d3.layout.force()
+ .size([width, height])
+ .nodes(nodes)
+ .links(links);
+
+ force.linkDistance(width/2);
+
+
+ var link = svg.selectAll('.link')
+ .data(links)
+ .enter().append('line')
+ .attr('class', 'link');
+
+ var node = svg.selectAll('.node')
+ .data(nodes)
+ .enter().append('circle')
+ .attr('class', 'node');
+
+ force.start();
}
function destroy() {
@@ -106,17 +193,19 @@
// ========================== Event Handlers
function allInstances(data) {
- $log.debug('>> topo2AllInstances event:', data)
+ $log.debug('>> topo2AllInstances event:', data);
doTmpCurrentLayout(data);
+ t2is.allInstances(data);
}
function currentLayout(data) {
- $log.debug('>> topo2CurrentLayout event:', data)
+ $log.debug('>> topo2CurrentLayout event:', data);
}
function currentRegion(data) {
- $log.debug('>> topo2CurrentRegion event:', data)
+ $log.debug('>> topo2CurrentRegion event:', data);
doTmpCurrentRegion(data);
+ t2rs.addRegion(data);
}
function topo2PeerRegions(data) {
@@ -129,27 +218,68 @@
}
function startDone(data) {
- $log.debug('>> topo2StartDone event:', data)
+ $log.debug('>> topo2StartDone event:', data);
}
-
+
+
+ function showMastership(masterId) {
+ if (!masterId) {
+ restoreLayerState();
+ } else {
+ showMastershipFor(masterId);
+ }
+ }
+
+ function restoreLayerState() {
+ // NOTE: this level of indirection required, for when we have
+ // the layer filter functionality re-implemented
+ suppressLayers(false);
+ }
+
+ // ========================== Main Service Definition
+
+ function showMastershipFor(id) {
+ suppressLayers(true);
+ node.each(function (n) {
+ if (n.master === id) {
+ n.el.classed('suppressedmax', false);
+ }
+ });
+ }
+
+ function supAmt(less) {
+ return less ? 'suppressed' : 'suppressedmax';
+ }
+
+ function suppressLayers(b, less) {
+ var cls = supAmt(less);
+ node.classed(cls, b);
+ // link.classed(cls, b);
+ }
+
// ========================== Main Service Definition
angular.module('ovTopo2')
.factory('Topo2ForceService',
- ['$log', 'WebSocketService',
-
- function (_$log_, _wss_) {
+ ['$log', 'WebSocketService', 'Topo2InstanceService', 'Topo2RegionService',
+ function (_$log_, _wss_, _t2is_, _t2rs_) {
$log = _$log_;
wss = _wss_;
-
+ t2is = _t2is_;
+ t2rs = _t2rs_;
+
return {
+
init: init,
+
destroy: destroy,
topo2AllInstances: allInstances,
topo2CurrentLayout: currentLayout,
topo2CurrentRegion: currentRegion,
- topo2PeerRegions: topo2PeerRegions,
- topo2StartDone: startDone
+ topo2StartDone: startDone,
+
+ showMastership: showMastership,
+ topo2PeerRegions: topo2PeerRegions
};
}]);
}());
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Host.js b/web/gui/src/main/webapp/app/view/topo2/topo2Host.js
new file mode 100644
index 0000000..19c2012
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Host.js
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Topology Hosts Module.
+ Module that holds the hosts for a region
+ */
+
+(function () {
+ 'use strict';
+
+ var Collection, Model;
+
+ function createHostCollection(data, region) {
+
+ var HostCollection = Collection.extend({
+ model: Model
+ });
+
+ var hosts = [];
+ data.forEach(function (hostsLayer) {
+ hostsLayer.forEach(function (host) {
+ hosts.push(host);
+ });
+ });
+
+ return new HostCollection(hosts);
+ }
+
+ angular.module('ovTopo2')
+ .factory('Topo2HostService',
+ ['Topo2Collection', 'Topo2Model',
+
+ function (_Collection_, _Model_) {
+
+ Collection = _Collection_;
+ Model = _Model_.extend();
+
+ return {
+ createHostCollection: createHostCollection
+ };
+ }
+ ]);
+
+})();
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Instance.js b/web/gui/src/main/webapp/app/view/topo2/topo2Instance.js
new file mode 100644
index 0000000..31c8886
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Instance.js
@@ -0,0 +1,301 @@
+(function () {
+ 'use strict';
+
+ // injected refs
+ var $log,
+ ps,
+ sus,
+ gs,
+ ts,
+ fs,
+ flash;
+
+ // api from topo
+ var api;
+
+ // configuration
+ var showLogicErrors = true,
+ idIns = 'topo-p-instance',
+ instOpts = {
+ edge: 'left',
+ width: 20
+ };
+
+ // internal state
+ var onosInstances,
+ onosOrder,
+ oiShowMaster,
+ oiBox;
+
+
+ function addInstance(data) {
+ var id = data.id;
+
+ if (onosInstances[id]) {
+ updateInstance(data);
+ return;
+ }
+ onosInstances[id] = data;
+ onosOrder.push(data);
+ updateInstances();
+ }
+
+ function updateInstance(data) {
+ var id = data.id,
+ d = onosInstances[id];
+ if (d) {
+ angular.extend(d, data);
+ updateInstances();
+ } else {
+ logicError('updateInstance: lookup fail: ID = "' + id + '"');
+ }
+ }
+
+ function removeInstance(data) {
+ var id = data.id,
+ d = onosInstances[id];
+ if (d) {
+ var idx = fs.find(id, onosOrder);
+ if (idx >= 0) {
+ onosOrder.splice(idx, 1);
+ }
+ delete onosInstances[id];
+ updateInstances();
+ } else {
+ logicError('removeInstance lookup fail. ID = "' + id + '"');
+ }
+ }
+
+ // ==========================
+
+ function clickInst(d) {
+ var el = d3.select(this),
+ aff = el.classed('affinity');
+ if (!aff) {
+ setAffinity(el, d);
+ } else {
+ cancelAffinity();
+ }
+ }
+
+ function setAffinity(el, d) {
+ d3.selectAll('.onosInst')
+ .classed('mastership', true)
+ .classed('affinity', false);
+ el.classed('affinity', true);
+
+ // suppress all elements except nodes whose master is this instance
+ api.showMastership(d.id);
+ oiShowMaster = true;
+ }
+
+ function cancelAffinity() {
+ d3.selectAll('.onosInst')
+ .classed('mastership affinity', false);
+
+ api.showMastership(null);
+ oiShowMaster = false;
+ }
+
+ function attachUiBadge(svg) {
+ gs.addGlyph(svg, 'uiAttached', 24, true, [14, 54])
+ .classed('badgeIcon uiBadge', true);
+ }
+
+ function attachReadyBadge(svg) {
+ gs.addGlyph(svg, 'checkMark', 16, true, [18, 40])
+ .classed('badgeIcon readyBadge', true);
+ }
+
+ function instColor(id, online) {
+ return sus.cat7().getColor(id, !online, ts.theme());
+ }
+
+ // ==============================
+
+ function updateInstances() {
+ var rox = 5,
+ roy = 5,
+ rw = 160,
+ rhh = 30,
+ rbh = 45,
+ tx = 48,
+ instSvg = {
+ width: 170,
+ height: 85,
+ viewBox: '0 0 170 85'
+ },
+ headRect = {
+ x: rox,
+ y: roy,
+ width: rw,
+ height: rhh
+ },
+ bodyRect = {
+ x: rox,
+ y: roy + rhh,
+ width: rw,
+ height: rbh
+ },
+ titleAttr = {
+ class: 'instTitle',
+ x: tx,
+ y: 27
+ };
+
+ var onoses = oiBox.el().selectAll('.onosInst')
+ .data(onosOrder, function (d) { return d.id; });
+
+ function nSw(n) {
+ return 'Devices: ' + n;
+ }
+
+ // operate on existing onos instances if necessary
+ onoses.each(function (d) {
+ var el = d3.select(this),
+ svg = el.select('svg');
+
+ // update online state
+ el.classed('online', d.online);
+ el.classed('ready', d.ready);
+
+ // update ui-attached state
+ svg.select('use.uiBadge').remove();
+ if (d.uiAttached) {
+ attachUiBadge(svg);
+ }
+
+ function updAttr(id, value) {
+ svg.select('text.instLabel.' + id).text(value);
+ }
+
+ updAttr('ip', d.ip);
+ updAttr('ns', nSw(d.switches));
+ });
+
+
+ // operate on new onos instances
+ var entering = onoses.enter()
+ .append('div')
+ .classed('onosInst', true)
+ .classed('online', function (d) { return d.online; })
+ .classed('ready', function (d) { return d.ready; })
+ .on('click', clickInst);
+
+ entering.each(function (d) {
+ var el = d3.select(this),
+ svg = el.append('svg').attr(instSvg);
+
+ svg.append('rect').attr(headRect);
+ svg.append('rect').attr(bodyRect);
+
+ gs.addGlyph(svg, 'bird', 20, false, [15, 10])
+ .classed('badgeIcon bird', true);
+
+ attachReadyBadge(svg);
+
+ if (d.uiAttached) {
+ attachUiBadge(svg);
+ }
+
+ svg.append('text')
+ .attr(titleAttr)
+ .text(d.id);
+
+ var ty = 55;
+ function addAttr(id, label) {
+ svg.append('text').attr({
+ class: 'instLabel ' + id,
+ x: tx,
+ y: ty
+ }).text(label);
+ ty += 18;
+ }
+
+ addAttr('ip', d.ip);
+ addAttr('ns', nSw(d.switches));
+ });
+
+ // operate on existing + new onoses here
+ // set the affinity colors...
+ onoses.each(function (d) {
+
+ var el = d3.select(this),
+ rect = el.select('svg').select('rect'),
+ col = instColor(d.id, d.online);
+
+ rect.style('fill', col);
+ });
+
+ // adjust the panel size appropriately...
+ oiBox.width(instSvg.width * onosOrder.length);
+ oiBox.height(instSvg.height);
+
+ // remove any outgoing instances
+ onoses.exit().remove();
+ }
+
+
+ // ==========================
+
+ function logicError(msg) {
+ if (showLogicErrors) {
+ $log.warn('TopoInstService: ' + msg);
+ }
+ }
+
+ function initInst(_api_) {
+ api = _api_;
+ oiBox = ps.createPanel(idIns, instOpts);
+ oiBox.show();
+
+ onosInstances = {};
+ onosOrder = [];
+ oiShowMaster = false;
+
+ // we want to update the instances, each time the theme changes
+ ts.addListener(updateInstances);
+ }
+
+ function destroyInst() {
+ ts.removeListener(updateInstances);
+
+ ps.destroyPanel(idIns);
+ oiBox = null;
+
+ onosInstances = {};
+ onosOrder = [];
+ oiShowMaster = false;
+ }
+
+ function allInstances(data) {
+ $log.debug('Update all instances', data);
+
+ var members = data.members;
+
+ members.forEach(function (member) {
+ addInstance(member);
+ });
+ }
+
+ angular.module('ovTopo2')
+ .factory('Topo2InstanceService',
+ ['$log', 'PanelService', 'SvgUtilService', 'GlyphService',
+ 'ThemeService', 'FnService', 'FlashService',
+
+ function (_$log_, _ps_, _sus_, _gs_, _ts_, _fs_, _flash_) {
+ $log = _$log_;
+ ps = _ps_;
+ sus = _sus_;
+ gs = _gs_;
+ ts = _ts_;
+ fs = _fs_;
+ flash = _flash_;
+
+ return {
+ initInst: initInst,
+ allInstances: allInstances
+ };
+ }]);
+
+}());
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Link.js b/web/gui/src/main/webapp/app/view/topo2/topo2Link.js
new file mode 100644
index 0000000..5f2b6b7
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Link.js
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Topology Links Module.
+ Module that holds the links for a region
+ */
+
+(function () {
+ 'use strict';
+
+ var Collection, Model;
+
+ function createLinkCollection(data, region) {
+
+ var LinkCollection = Collection.extend({
+ model: Model
+ });
+
+ return new LinkCollection(data);
+ }
+
+ angular.module('ovTopo2')
+ .factory('Topo2LinkService',
+ ['Topo2Collection', 'Topo2Model',
+
+ function (_Collection_, _Model_) {
+
+ Collection = _Collection_;
+ Model = _Model_.extend({});
+
+ return {
+ createLinkCollection: createLinkCollection
+ };
+ }
+ ]);
+
+})();
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Model.js b/web/gui/src/main/webapp/app/view/topo2/topo2Model.js
new file mode 100644
index 0000000..fa40d65
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Model.js
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Topology Force Module.
+ Visualization of the topology in an SVG layer, using a D3 Force Layout.
+ */
+
+(function () {
+ 'use strict';
+
+ function Model(attributes) {
+
+ var attrs = attributes || {};
+ this.attributes = {};
+
+ attrs = angular.extend({}, attrs);
+ this.set(attrs);
+ }
+
+ Model.prototype = {
+
+ get: function (attr) {
+ return this.attributes[attr];
+ },
+
+ set: function(data) {
+ angular.extend(this.attributes, data);
+ },
+ };
+
+
+ Model.extend = function (protoProps, staticProps) {
+
+ var parent = this;
+ var child;
+
+ child = function () {
+ return parent.apply(this, arguments);
+ };
+
+ angular.extend(child, parent, staticProps);
+
+ // Set the prototype chain to inherit from `parent`, without calling
+ // `parent`'s constructor function and add the prototype properties.
+ child.prototype = angular.extend({}, parent.prototype, protoProps);
+ child.prototype.constructor = child;
+
+ // Set a convenience property in case the parent's prototype is needed
+ // later.
+ child.__super__ = parent.prototype;
+
+ return child;
+ };
+
+ angular.module('ovTopo2')
+ .factory('Topo2Model',
+ [
+ function () {
+ return Model;
+ }
+ ]);
+
+})();
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Region.js b/web/gui/src/main/webapp/app/view/topo2/topo2Region.js
new file mode 100644
index 0000000..ff1d52f
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Region.js
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Topology Region Module.
+ Module that holds the current region in memory
+ */
+
+(function () {
+ 'use strict';
+
+ var $log,
+ wss,
+ t2sr,
+ t2ds,
+ t2hs,
+ t2ls;
+
+ var regions;
+
+ function init() {
+ regions = {};
+ }
+
+ function addRegion(data) {
+
+ var region = {
+ subregions: t2sr.createSubRegionCollection(data.subregions),
+ devices: t2ds.createDeviceCollection(data.devices, data),
+ hosts: t2hs.createHostCollection(data.hosts),
+ links: t2ls.createLinkCollection(data.links),
+ };
+
+ $log.debug('Region: ', region);
+ }
+
+ angular.module('ovTopo2')
+ .factory('Topo2RegionService',
+ ['$log', 'WebSocketService', 'Topo2SubRegionService', 'Topo2DeviceService',
+ 'Topo2HostService', 'Topo2LinkService',
+
+ function (_$log_, _wss_, _t2sr_, _t2ds_, _t2hs_, _t2ls_) {
+
+ $log = _$log_;
+ wss = _wss_;
+ t2sr = _t2sr_;
+ t2ds = _t2ds_;
+ t2hs = _t2hs_;
+ t2ls = _t2ls_;
+
+ return {
+ init: init,
+
+ addRegion: addRegion,
+ getSubRegions: t2sr.getSubRegions
+ };
+ }]);
+
+})();
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2SubRegion.js b/web/gui/src/main/webapp/app/view/topo2/topo2SubRegion.js
new file mode 100644
index 0000000..421f57d
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2SubRegion.js
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Topology SubRegion Module.
+ Module that holds the sub-regions for a region
+ */
+
+(function () {
+ 'use strict';
+
+ var Collection, Model;
+
+ function createSubRegionCollection(data, region) {
+
+ var SubRegionCollection = Collection.extend({
+ model: Model
+ });
+
+ return new SubRegionCollection(data);
+ }
+
+ angular.module('ovTopo2')
+ .factory('Topo2SubRegionService',
+ ['Topo2Collection', 'Topo2Model',
+
+ function (_Collection_, _Model_) {
+
+ Collection = _Collection_;
+ Model = _Model_.extend({});
+
+ return {
+ createSubRegionCollection: createSubRegionCollection
+ };
+ }
+ ]);
+
+})();
diff --git a/web/gui/src/main/webapp/index.html b/web/gui/src/main/webapp/index.html
index da438ba..5f3cfb5 100644
--- a/web/gui/src/main/webapp/index.html
+++ b/web/gui/src/main/webapp/index.html
@@ -127,8 +127,16 @@
<!-- Under development for Region support. -->
<script src="app/view/topo2/topo2.js"></script>
+ <script src="app/view/topo2/topo2Collection.js"></script>
+ <script src="app/view/topo2/topo2Device.js"></script>
+ <script src="app/view/topo2/topo2Model.js"></script>
<script src="app/view/topo2/topo2Event.js"></script>
<script src="app/view/topo2/topo2Force.js"></script>
+ <script src="app/view/topo2/topo2Host.js"></script>
+ <script src="app/view/topo2/topo2Instance.js"></script>
+ <script src="app/view/topo2/topo2Link.js"></script>
+ <script src="app/view/topo2/topo2Region.js"></script>
+ <script src="app/view/topo2/topo2SubRegion.js"></script>
<link rel="stylesheet" href="app/view/topo2/topo2.css">
<link rel="stylesheet" href="app/view/topo2/topo2-theme.css">