mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-10-25 22:31:07 +02:00
Topo2: ONOS-5640, ONOS-5641 ONOS-5645 Show details for Hosts, Links, Sub-Regions
Added Links panel Details panel shared between Details, Link, Hosts and Regions Refactored List content for panel views Reference to the PanelService Element had a name change Added a Base UIView to extend future views from Extend method was being repeated Change-Id: I3fa070fc5140e98720e47f4b90e3571cb0347596
This commit is contained in:
parent
878c78cca3
commit
86af435285
@ -413,6 +413,29 @@
|
||||
return classes.join(' ');
|
||||
}
|
||||
|
||||
function extend(protoProps, staticProps) {
|
||||
|
||||
var parent = this,
|
||||
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('onosUtil')
|
||||
.factory('FnService',
|
||||
@ -452,7 +475,8 @@
|
||||
addToTrie: addToTrie,
|
||||
removeFromTrie: removeFromTrie,
|
||||
trieLookup: trieLookup,
|
||||
classNames: classNames
|
||||
classNames: classNames,
|
||||
extend: extend
|
||||
};
|
||||
}]);
|
||||
|
||||
|
||||
60
web/gui/src/main/webapp/app/fw/widget/listBuilder.js
Normal file
60
web/gui/src/main/webapp/app/fw/widget/listBuilder.js
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2015-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 -- Widget -- List Service
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function addProp(el, label, value) {
|
||||
var tr = el.append('tr'),
|
||||
lab;
|
||||
if (typeof label === 'string') {
|
||||
lab = label.replace(/_/g, ' ');
|
||||
} else {
|
||||
lab = label;
|
||||
}
|
||||
|
||||
function addCell(cls, txt) {
|
||||
tr.append('td').attr('class', cls).html(txt);
|
||||
}
|
||||
|
||||
addCell('label', lab + ' :');
|
||||
addCell('value', value);
|
||||
}
|
||||
|
||||
function addSep(el) {
|
||||
el.append('tr').append('td').attr('colspan', 2).append('hr');
|
||||
}
|
||||
|
||||
function listProps(el, data) {
|
||||
data.propOrder.forEach(function (p) {
|
||||
if (p === '-') {
|
||||
addSep(el);
|
||||
} else {
|
||||
addProp(el, p, data.props[p]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
angular.module('onosWidget')
|
||||
.factory('ListService', [
|
||||
function () {
|
||||
return listProps;
|
||||
}]);
|
||||
}());
|
||||
@ -181,7 +181,7 @@
|
||||
}
|
||||
|
||||
|
||||
#ov-topo2 svg .node.device.selected .node-container {
|
||||
#ov-topo2 svg .node.selected .node-container {
|
||||
stroke-width: 2.0;
|
||||
stroke: #009fdb;
|
||||
}
|
||||
|
||||
@ -22,7 +22,8 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var Model;
|
||||
var Model,
|
||||
extend;
|
||||
|
||||
function Collection(models, options) {
|
||||
|
||||
@ -91,34 +92,12 @@
|
||||
}
|
||||
};
|
||||
|
||||
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_) {
|
||||
['Topo2Model', 'FnService',
|
||||
function (_Model_, fn) {
|
||||
|
||||
Collection.extend = fn.extend;
|
||||
Model = _Model_;
|
||||
return Collection;
|
||||
}
|
||||
|
||||
63
web/gui/src/main/webapp/app/view/topo2/topo2DetailsPanel.js
Normal file
63
web/gui/src/main/webapp/app/view/topo2/topo2DetailsPanel.js
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.
|
||||
Module that displays the details panel for selected nodes
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// Injected Services
|
||||
var Panel;
|
||||
|
||||
// Internal State
|
||||
var detailsPanel;
|
||||
|
||||
// configuration
|
||||
var id = 'topo2-p-detail',
|
||||
className = 'topo-p',
|
||||
panelOpts = {
|
||||
width: 260 // summary and detail panel width
|
||||
};
|
||||
|
||||
function getInstance() {
|
||||
if (detailsPanel) {
|
||||
return detailsPanel;
|
||||
}
|
||||
|
||||
var options = angular.extend({}, panelOpts, {
|
||||
class: className
|
||||
});
|
||||
|
||||
detailsPanel = new Panel(id, options);
|
||||
detailsPanel.el.classed(className, true);
|
||||
|
||||
return detailsPanel;
|
||||
}
|
||||
|
||||
angular.module('ovTopo2')
|
||||
.factory('Topo2DetailsPanelService',
|
||||
['Topo2PanelService',
|
||||
function (_ps_) {
|
||||
|
||||
Panel = _ps_;
|
||||
|
||||
return getInstance;
|
||||
}
|
||||
]);
|
||||
})();
|
||||
@ -74,25 +74,7 @@
|
||||
},
|
||||
onClick: function () {
|
||||
|
||||
var ev = d3.event;
|
||||
|
||||
if (ev.shiftKey) {
|
||||
// TODO: Multi-Select Details Panel
|
||||
this.set('selected', true);
|
||||
} else {
|
||||
|
||||
var s = Boolean(this.get('selected'));
|
||||
// Clear all selected Items
|
||||
_.each(this.collection.models, function (m) {
|
||||
m.set('selected', false);
|
||||
});
|
||||
|
||||
this.set('selected', !s);
|
||||
}
|
||||
|
||||
var selected = this.collection.filter(function (m) {
|
||||
return m.get('selected');
|
||||
});
|
||||
var selected = this.select(d3.event);
|
||||
|
||||
if (_.isArray(selected) && selected.length > 0) {
|
||||
if (selected.length === 1) {
|
||||
|
||||
@ -23,17 +23,13 @@
|
||||
'use strict';
|
||||
|
||||
// Injected Services
|
||||
var Panel, gs, wss, flash, bs, fs, ns;
|
||||
var Panel, gs, wss, flash, bs, fs, ns, listProps;
|
||||
|
||||
// Internal State
|
||||
var detailsPanel;
|
||||
|
||||
// configuration
|
||||
var id = 'topo2-p-detail',
|
||||
className = 'topo-p',
|
||||
panelOpts = {
|
||||
width: 260 // summary and detail panel width
|
||||
},
|
||||
handlerMap = {
|
||||
'showDetails': showDetails
|
||||
};
|
||||
@ -69,43 +65,7 @@
|
||||
function init() {
|
||||
|
||||
bindHandlers();
|
||||
|
||||
var options = angular.extend({}, panelOpts, {
|
||||
class: className
|
||||
});
|
||||
|
||||
detailsPanel = new Panel(id, options);
|
||||
detailsPanel.p.classed(className, true);
|
||||
}
|
||||
|
||||
function addProp(tbody, label, value) {
|
||||
var tr = tbody.append('tr'),
|
||||
lab;
|
||||
if (typeof label === 'string') {
|
||||
lab = label.replace(/_/g, ' ');
|
||||
} else {
|
||||
lab = label;
|
||||
}
|
||||
|
||||
function addCell(cls, txt) {
|
||||
tr.append('td').attr('class', cls).html(txt);
|
||||
}
|
||||
addCell('label', lab + ' :');
|
||||
addCell('value', value);
|
||||
}
|
||||
|
||||
function addSep(tbody) {
|
||||
tbody.append('tr').append('td').attr('colspan', 2).append('hr');
|
||||
}
|
||||
|
||||
function listProps(tbody, data) {
|
||||
data.propOrder.forEach(function (p) {
|
||||
if (p === '-') {
|
||||
addSep(tbody);
|
||||
} else {
|
||||
addProp(tbody, p, data.props[p]);
|
||||
}
|
||||
});
|
||||
detailsPanel = Panel();
|
||||
}
|
||||
|
||||
function addBtnFooter() {
|
||||
@ -136,10 +96,6 @@
|
||||
cb: function () { ns.navTo(path, { devId: devId }); }
|
||||
});
|
||||
}
|
||||
// TODO: Implement Overlay service
|
||||
// else if (btn = _getButtonDef(id, data)) {
|
||||
// addAction(btn);
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
@ -196,17 +152,17 @@
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
var on = detailsPanel.p.toggle(),
|
||||
var on = detailsPanel.el.toggle(),
|
||||
verb = on ? 'Show' : 'Hide';
|
||||
flash.flash(verb + ' Details Panel');
|
||||
}
|
||||
|
||||
function show() {
|
||||
detailsPanel.p.show();
|
||||
detailsPanel.el.show();
|
||||
}
|
||||
|
||||
function hide() {
|
||||
detailsPanel.p.hide();
|
||||
detailsPanel.el.hide();
|
||||
}
|
||||
|
||||
function destroy() {
|
||||
@ -216,9 +172,9 @@
|
||||
|
||||
angular.module('ovTopo2')
|
||||
.factory('Topo2DeviceDetailsPanel',
|
||||
['Topo2PanelService', 'GlyphService', 'WebSocketService', 'FlashService',
|
||||
'ButtonService', 'FnService', 'NavService',
|
||||
function (_ps_, _gs_, _wss_, _flash_, _bs_, _fs_, _ns_) {
|
||||
['Topo2DetailsPanelService', 'GlyphService', 'WebSocketService', 'FlashService',
|
||||
'ButtonService', 'FnService', 'NavService', 'ListService',
|
||||
function (_ps_, _gs_, _wss_, _flash_, _bs_, _fs_, _ns_, _listService_) {
|
||||
|
||||
Panel = _ps_;
|
||||
gs = _gs_;
|
||||
@ -227,6 +183,7 @@
|
||||
bs = _bs_;
|
||||
fs = _fs_;
|
||||
ns = _ns_;
|
||||
listProps = _listService_;
|
||||
|
||||
return {
|
||||
init: init,
|
||||
|
||||
@ -48,12 +48,34 @@
|
||||
angular.module('ovTopo2')
|
||||
.factory('Topo2HostService', [
|
||||
'Topo2Collection', 'Topo2NodeModel', 'Topo2ViewService',
|
||||
'IconService', 'Topo2ZoomService',
|
||||
function (_Collection_, _NodeModel_, _t2vs_, is, zs) {
|
||||
'IconService', 'Topo2ZoomService', 'Topo2HostsPanelService',
|
||||
function (_Collection_, _NodeModel_, _t2vs_, is, zs, t2hds) {
|
||||
|
||||
Collection = _Collection_;
|
||||
|
||||
Model = _NodeModel_.extend({
|
||||
initialize: function () {
|
||||
this.super = this.constructor.__super__;
|
||||
this.super.initialize.apply(this, arguments);
|
||||
},
|
||||
events: {
|
||||
'click': 'onClick'
|
||||
},
|
||||
onChange: function () {
|
||||
// Update class names when the model changes
|
||||
if (this.el) {
|
||||
this.el.attr('class', this.svgClassName());
|
||||
}
|
||||
},
|
||||
onClick: function () {
|
||||
var selected = this.select(d3.select);
|
||||
|
||||
if (selected.length > 0) {
|
||||
t2hds.displayPanel(this);
|
||||
} else {
|
||||
t2hds.hide();
|
||||
}
|
||||
},
|
||||
nodeType: 'host',
|
||||
icon: function () {
|
||||
var type = this.get('type');
|
||||
@ -117,6 +139,7 @@
|
||||
.attr('text-anchor', 'middle');
|
||||
|
||||
this.setScale();
|
||||
this.setUpEvents();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
114
web/gui/src/main/webapp/app/view/topo2/topo2HostsPanel.js
Normal file
114
web/gui/src/main/webapp/app/view/topo2/topo2HostsPanel.js
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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 Layout Module.
|
||||
Module that contains the d3.force.layout logic
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// Injected Services
|
||||
var Panel, gs, wss, flash, listProps;
|
||||
|
||||
// Internal State
|
||||
var hostPanel, hostData;
|
||||
|
||||
function init() {
|
||||
hostPanel = Panel();
|
||||
}
|
||||
|
||||
function formatHostData(data) {
|
||||
return {
|
||||
title: data.get('id'),
|
||||
propOrder: ['MAC', 'IP', 'VLAN', '-', 'Latitude', 'Longitude'],
|
||||
props: {
|
||||
'-': '',
|
||||
'MAC': data.get('id'),
|
||||
'IP': data.get('ips')[0],
|
||||
'VLAN': 'None', // TODO
|
||||
'Latitude': data.get('location').lat,
|
||||
'Longitude': data.get('location').lng,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function displayPanel(data) {
|
||||
init();
|
||||
|
||||
hostData = formatHostData(data);
|
||||
render();
|
||||
}
|
||||
|
||||
function render() {
|
||||
hostPanel.el.show();
|
||||
hostPanel.emptyRegions();
|
||||
|
||||
var svg = hostPanel.appendToHeader('div')
|
||||
.classed('icon', true)
|
||||
.append('svg'),
|
||||
title = hostPanel.appendToHeader('h2'),
|
||||
table = hostPanel.appendToBody('table'),
|
||||
tbody = table.append('tbody');
|
||||
|
||||
title.text(hostData.title);
|
||||
gs.addGlyph(svg, 'bird', 24, 0, [1, 1]);
|
||||
listProps(tbody, hostData);
|
||||
}
|
||||
|
||||
function show() {
|
||||
hostPanel.el.show();
|
||||
}
|
||||
|
||||
function hide() {
|
||||
hostPanel.el.hide();
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
var on = hostPanel.el.toggle(),
|
||||
verb = on ? 'Show' : 'Hide';
|
||||
flash.flash(verb + ' host Panel');
|
||||
}
|
||||
|
||||
function destroy() {
|
||||
hostPanel.destroy();
|
||||
}
|
||||
|
||||
angular.module('ovTopo2')
|
||||
.factory('Topo2HostsPanelService',
|
||||
['Topo2DetailsPanelService', 'GlyphService', 'WebSocketService', 'FlashService', 'ListService',
|
||||
function (_ps_, _gs_, _wss_, _flash_, _listService_) {
|
||||
|
||||
Panel = _ps_;
|
||||
gs = _gs_;
|
||||
wss = _wss_;
|
||||
flash = _flash_;
|
||||
listProps = _listService_;
|
||||
|
||||
return {
|
||||
displayPanel: displayPanel,
|
||||
init: init,
|
||||
show: show,
|
||||
hide: hide,
|
||||
toggle: toggle,
|
||||
destroy: destroy,
|
||||
isVisible: function () { return hostPanel.isVisible(); }
|
||||
};
|
||||
}
|
||||
]);
|
||||
|
||||
})();
|
||||
@ -22,7 +22,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var $log, Collection, Model, ts, sus, t2zs, t2vs;
|
||||
var $log, Collection, Model, ts, sus, t2zs, t2vs, t2lps, fn;
|
||||
|
||||
var linkLabelOffset = '0.35em';
|
||||
|
||||
@ -124,6 +124,16 @@
|
||||
type: function () {
|
||||
return this.get('type');
|
||||
},
|
||||
svgClassName: function () {
|
||||
return fn.classNames('link',
|
||||
this.nodeType,
|
||||
this.get('type'),
|
||||
{
|
||||
enhanced: this.get('enhanced'),
|
||||
selected: this.get('selected')
|
||||
}
|
||||
);
|
||||
},
|
||||
expected: function () {
|
||||
// TODO: original code is: (s && s.expected) && (t && t.expected);
|
||||
return true;
|
||||
@ -137,6 +147,12 @@
|
||||
|
||||
return (sourceOnline) && (targetOnline);
|
||||
},
|
||||
onChange: function () {
|
||||
// Update class names when the model changes
|
||||
if (this.el) {
|
||||
this.el.attr('class', this.svgClassName());
|
||||
}
|
||||
},
|
||||
enhance: function () {
|
||||
var data = [],
|
||||
point;
|
||||
@ -145,7 +161,7 @@
|
||||
link.unenhance();
|
||||
});
|
||||
|
||||
this.el.classed('enhanced', true);
|
||||
this.set('enhanced', true);
|
||||
|
||||
if (showPort()) {
|
||||
point = this.locatePortLabel();
|
||||
@ -193,9 +209,36 @@
|
||||
}
|
||||
},
|
||||
unenhance: function () {
|
||||
this.el.classed('enhanced', false);
|
||||
this.set('enhanced', false);
|
||||
d3.select('#topo-portLabels').selectAll('.portLabel').remove();
|
||||
},
|
||||
select: function () {
|
||||
var ev = d3.event;
|
||||
|
||||
// TODO: if single selection clear selected devices, hosts, sub-regions
|
||||
var s = Boolean(this.get('selected'));
|
||||
// Clear all selected Items
|
||||
_.each(this.collection.models, function (m) {
|
||||
m.set('selected', false);
|
||||
});
|
||||
|
||||
this.set('selected', !s);
|
||||
|
||||
var selected = this.collection.filter(function (m) {
|
||||
return m.get('selected');
|
||||
});
|
||||
|
||||
return selected;
|
||||
},
|
||||
showDetails: function () {
|
||||
var selected = this.select(d3.event);
|
||||
|
||||
if (selected) {
|
||||
t2lps.displayLink(this);
|
||||
} else {
|
||||
t2lps.hide();
|
||||
}
|
||||
},
|
||||
locatePortLabel: function (src) {
|
||||
|
||||
var offset = 32 / (labelDim * t2zs.scale()),
|
||||
@ -259,6 +302,7 @@
|
||||
// from mouse position.
|
||||
this.el.on('mouseover', this.enhance.bind(this));
|
||||
this.el.on('mouseout', this.unenhance.bind(this));
|
||||
this.el.on('click', this.showDetails.bind(this));
|
||||
|
||||
if (this.get('type') === 'hostLink') {
|
||||
// sus.visible(link, api.showHosts());
|
||||
@ -277,7 +321,7 @@
|
||||
|
||||
},
|
||||
update: function () {
|
||||
if (this.el.classed('enhanced')) {
|
||||
if (this.get('enhanced')) {
|
||||
this.enhance();
|
||||
}
|
||||
}
|
||||
@ -298,9 +342,9 @@
|
||||
.factory('Topo2LinkService',
|
||||
['$log', 'Topo2Collection', 'Topo2Model',
|
||||
'ThemeService', 'SvgUtilService', 'Topo2ZoomService',
|
||||
'Topo2ViewService',
|
||||
'Topo2ViewService', 'Topo2LinkPanelService', 'FnService',
|
||||
function (_$log_, _Collection_, _Model_, _ts_, _sus_,
|
||||
_t2zs_, _t2vs_) {
|
||||
_t2zs_, _t2vs_, _t2lps_, _fn_) {
|
||||
|
||||
$log = _$log_;
|
||||
ts = _ts_;
|
||||
@ -309,6 +353,8 @@
|
||||
t2vs = _t2vs_;
|
||||
Collection = _Collection_;
|
||||
Model = _Model_;
|
||||
t2lps = _t2lps_;
|
||||
fn = _fn_;
|
||||
|
||||
return {
|
||||
createLinkCollection: createLinkCollection
|
||||
|
||||
127
web/gui/src/main/webapp/app/view/topo2/topo2LinkPanel.js
Normal file
127
web/gui/src/main/webapp/app/view/topo2/topo2LinkPanel.js
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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 Layout Module.
|
||||
Module that contains the d3.force.layout logic
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// Injected Services
|
||||
var Panel, gs, wss, flash, listProps;
|
||||
|
||||
// Internal State
|
||||
var linkPanel, linkData;
|
||||
|
||||
function init() {
|
||||
linkPanel = Panel();
|
||||
}
|
||||
|
||||
function formatLinkData(data) {
|
||||
|
||||
var source = data.get('source'),
|
||||
target = data.get('target');
|
||||
|
||||
return {
|
||||
title: 'Link',
|
||||
propOrder: [
|
||||
'Type', '-',
|
||||
'A Type', 'A Id', 'A Label', 'A Port', '-',
|
||||
'B Type', 'B Id', 'B Label', 'B Port'
|
||||
],
|
||||
props: {
|
||||
'-': '',
|
||||
'Type': data.get('type'),
|
||||
'A Type': source.get('nodeType'),
|
||||
'A Id': source.get('id'),
|
||||
'A Label': 'Label',
|
||||
'A Port': data.get('portA') || '',
|
||||
'B Type': target.get('nodeType'),
|
||||
'B Id': target.get('id'),
|
||||
'B Label': 'Label',
|
||||
'B Port': data.get('portB') || '',
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function displayLink(data) {
|
||||
init();
|
||||
|
||||
linkData = formatLinkData(data);
|
||||
render();
|
||||
}
|
||||
|
||||
function render() {
|
||||
linkPanel.el.show();
|
||||
linkPanel.emptyRegions();
|
||||
|
||||
var svg = linkPanel.appendToHeader('div')
|
||||
.classed('icon', true)
|
||||
.append('svg'),
|
||||
title = linkPanel.appendToHeader('h2'),
|
||||
table = linkPanel.appendToBody('table'),
|
||||
tbody = table.append('tbody');
|
||||
|
||||
title.text(linkData.title);
|
||||
gs.addGlyph(svg, 'bird', 24, 0, [1, 1]);
|
||||
listProps(tbody, linkData);
|
||||
}
|
||||
|
||||
function show() {
|
||||
linkPanel.el.show();
|
||||
}
|
||||
|
||||
function hide() {
|
||||
linkPanel.el.hide();
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
var on = linkPanel.el.toggle(),
|
||||
verb = on ? 'Show' : 'Hide';
|
||||
flash.flash(verb + ' Link Panel');
|
||||
}
|
||||
|
||||
function destroy() {
|
||||
wss.unbindHandlers(handlerMap);
|
||||
linkPanel.destroy();
|
||||
}
|
||||
|
||||
angular.module('ovTopo2')
|
||||
.factory('Topo2LinkPanelService',
|
||||
['Topo2DetailsPanelService', 'GlyphService', 'WebSocketService', 'FlashService', 'ListService',
|
||||
function (_ps_, _gs_, _wss_, _flash_, _listService_) {
|
||||
|
||||
Panel = _ps_;
|
||||
gs = _gs_;
|
||||
wss = _wss_;
|
||||
flash = _flash_;
|
||||
listProps = _listService_;
|
||||
|
||||
return {
|
||||
displayLink: displayLink,
|
||||
init: init,
|
||||
show: show,
|
||||
hide: hide,
|
||||
toggle: toggle,
|
||||
destroy: destroy,
|
||||
isVisible: function () { return linkPanel.isVisible(); }
|
||||
};
|
||||
}
|
||||
]);
|
||||
|
||||
})();
|
||||
@ -22,6 +22,8 @@ Visualization of the topology in an SVG layer, using a D3 Force Layout.
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var extend;
|
||||
|
||||
function Model(attributes) {
|
||||
|
||||
var attrs = attributes || {};
|
||||
@ -118,34 +120,13 @@ Visualization of the topology in an SVG layer, using a D3 Force Layout.
|
||||
}
|
||||
};
|
||||
|
||||
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 () {
|
||||
'FnService',
|
||||
function (fn) {
|
||||
Model.extend = fn.extend;
|
||||
|
||||
return Model;
|
||||
}
|
||||
]);
|
||||
|
||||
})();
|
||||
|
||||
@ -76,6 +76,31 @@
|
||||
'mouseout': 'mouseoutHandler'
|
||||
};
|
||||
},
|
||||
select: function () {
|
||||
var ev = d3.event;
|
||||
|
||||
// TODO: if single selection clear selected devices, hosts, sub-regions
|
||||
|
||||
if (ev.shiftKey) {
|
||||
// TODO: Multi-Select Details Panel
|
||||
this.set('selected', true);
|
||||
} else {
|
||||
|
||||
var s = Boolean(this.get('selected'));
|
||||
// Clear all selected Items
|
||||
_.each(this.collection.models, function (m) {
|
||||
m.set('selected', false);
|
||||
});
|
||||
|
||||
this.set('selected', !s);
|
||||
}
|
||||
|
||||
var selected = this.collection.filter(function (m) {
|
||||
return m.get('selected');
|
||||
});
|
||||
|
||||
return selected;
|
||||
},
|
||||
createNode: function () {
|
||||
this.set('svgClass', this.svgClassName());
|
||||
t2nps.positionNode(this);
|
||||
|
||||
@ -22,30 +22,24 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var ps;
|
||||
// Injected Services
|
||||
var flash, ps;
|
||||
|
||||
var Panel = function (id, options) {
|
||||
this.id = id;
|
||||
this.p = ps.createPanel(this.id, options);
|
||||
this.setup();
|
||||
var panel = {
|
||||
initialize: function (id, options) {
|
||||
this.id = id;
|
||||
this.el = ps.createPanel(id, options);
|
||||
this.setup();
|
||||
|
||||
if (options.show) {
|
||||
this.p.show();
|
||||
}
|
||||
};
|
||||
|
||||
Panel.prototype = {
|
||||
if (options.show) {
|
||||
this.el.show();
|
||||
}
|
||||
},
|
||||
setup: function () {
|
||||
var panel = this.p;
|
||||
panel.empty();
|
||||
|
||||
panel.append('div').classed('header', true);
|
||||
panel.append('div').classed('body', true);
|
||||
panel.append('div').classed('footer', true);
|
||||
|
||||
this.header = panel.el().select('.header');
|
||||
this.body = panel.el().select('.body');
|
||||
this.footer = panel.el().select('.body');
|
||||
this.el.empty();
|
||||
this.header = this.el.append('div').classed('header', true);
|
||||
this.body = this.el.append('div').classed('body', true);
|
||||
this.footer = this.el.append('div').classed('footer', true);
|
||||
},
|
||||
appendToHeader: function (x) {
|
||||
return this.header.append(x);
|
||||
@ -65,15 +59,19 @@
|
||||
ps.destroyPanel(this.id);
|
||||
},
|
||||
isVisible: function () {
|
||||
return this.p.isVisible();
|
||||
return this.el.isVisible();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
angular.module('ovTopo2')
|
||||
.factory('Topo2PanelService', ['PanelService',
|
||||
function (_ps_) {
|
||||
.factory('Topo2PanelService',
|
||||
['Topo2UIView', 'FlashService', 'PanelService',
|
||||
function (View, _flash_, _ps_) {
|
||||
|
||||
flash = _flash_;
|
||||
ps = _ps_;
|
||||
return Panel;
|
||||
|
||||
return View.extend(panel);
|
||||
}
|
||||
]);
|
||||
|
||||
|
||||
@ -54,8 +54,6 @@
|
||||
link.createLink();
|
||||
});
|
||||
|
||||
console.log(region.get('id'));
|
||||
|
||||
// TEMP Map Zoom
|
||||
var regionPanZooms = {
|
||||
"(root)": {
|
||||
|
||||
@ -41,9 +41,9 @@
|
||||
angular.module('ovTopo2')
|
||||
.factory('Topo2SubRegionService',
|
||||
['WebSocketService', 'Topo2Collection', 'Topo2NodeModel',
|
||||
'ThemeService', 'Topo2ViewService',
|
||||
'ThemeService', 'Topo2ViewService', 'Topo2SubRegionPanelService',
|
||||
|
||||
function (_wss_, _c_, _NodeModel_, _ts_, _t2vs_) {
|
||||
function (_wss_, _c_, _NodeModel_, _ts_, _t2vs_m, _t2srp_) {
|
||||
|
||||
wss = _wss_;
|
||||
Collection = _c_;
|
||||
@ -54,13 +54,29 @@
|
||||
this.super.initialize.apply(this, arguments);
|
||||
},
|
||||
events: {
|
||||
'dblclick': 'navigateToRegion'
|
||||
'dblclick': 'navigateToRegion',
|
||||
'click': 'onClick'
|
||||
},
|
||||
onChange: function () {
|
||||
// Update class names when the model changes
|
||||
if (this.el) {
|
||||
this.el.attr('class', this.svgClassName());
|
||||
}
|
||||
},
|
||||
nodeType: 'sub-region',
|
||||
icon: function () {
|
||||
var type = this.get('type');
|
||||
return remappedDeviceTypes[type] || type || 'm_cloud';
|
||||
},
|
||||
onClick: function () {
|
||||
var selected = this.select(d3.event);
|
||||
|
||||
if (selected.length > 0) {
|
||||
_t2srp_.displayPanel(this);
|
||||
} else {
|
||||
_t2srp_.hide();
|
||||
}
|
||||
},
|
||||
navigateToRegion: function () {
|
||||
|
||||
if (d3.event.defaultPrevented) return;
|
||||
|
||||
112
web/gui/src/main/webapp/app/view/topo2/topo2SubRegionPanel.js
Normal file
112
web/gui/src/main/webapp/app/view/topo2/topo2SubRegionPanel.js
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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 Layout Module.
|
||||
Module that contains the d3.force.layout logic
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// Injected Services
|
||||
var Panel, gs, wss, flash, listProps;
|
||||
|
||||
// Internal State
|
||||
var subRegionPanel, subRegionData;
|
||||
|
||||
function init() {
|
||||
subRegionPanel = Panel();
|
||||
}
|
||||
|
||||
function formatSubRegionData(data) {
|
||||
return {
|
||||
title: data.get('name'),
|
||||
propOrder: ['Id', 'Type', '-', 'Number of Devices', 'Number of Hosts'],
|
||||
props: {
|
||||
'-': '',
|
||||
'Id': data.get('id'),
|
||||
'Type': data.get('nodeType'),
|
||||
'Number of Devices': data.get('nDevs'),
|
||||
'Number of Hosts': data.get('nHosts')
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function displayPanel(data) {
|
||||
init();
|
||||
subRegionData = formatSubRegionData(data);
|
||||
render();
|
||||
}
|
||||
|
||||
function render() {
|
||||
subRegionPanel.el.show();
|
||||
subRegionPanel.emptyRegions();
|
||||
|
||||
var svg = subRegionPanel.appendToHeader('div')
|
||||
.classed('icon', true)
|
||||
.append('svg'),
|
||||
title = subRegionPanel.appendToHeader('h2'),
|
||||
table = subRegionPanel.appendToBody('table'),
|
||||
tbody = table.append('tbody');
|
||||
|
||||
title.text(subRegionData.title);
|
||||
gs.addGlyph(svg, 'bird', 24, 0, [1, 1]);
|
||||
listProps(tbody, subRegionData);
|
||||
}
|
||||
|
||||
function show() {
|
||||
subRegionPanel.el.show();
|
||||
}
|
||||
|
||||
function hide() {
|
||||
subRegionPanel.el.hide();
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
var on = subRegionPanel.el.toggle(),
|
||||
verb = on ? 'Show' : 'Hide';
|
||||
flash.flash(verb + ' subRegion Panel');
|
||||
}
|
||||
|
||||
function destroy() {
|
||||
subRegionPanel.destroy();
|
||||
}
|
||||
|
||||
angular.module('ovTopo2')
|
||||
.factory('Topo2SubRegionPanelService',
|
||||
['Topo2DetailsPanelService', 'GlyphService', 'WebSocketService', 'FlashService', 'ListService',
|
||||
function (_ps_, _gs_, _wss_, _flash_, _listService_) {
|
||||
|
||||
Panel = _ps_;
|
||||
gs = _gs_;
|
||||
wss = _wss_;
|
||||
flash = _flash_;
|
||||
listProps = _listService_;
|
||||
|
||||
return {
|
||||
displayPanel: displayPanel,
|
||||
init: init,
|
||||
show: show,
|
||||
hide: hide,
|
||||
toggle: toggle,
|
||||
destroy: destroy,
|
||||
isVisible: function () { return subRegionPanel.isVisible(); }
|
||||
};
|
||||
}
|
||||
]);
|
||||
|
||||
})();
|
||||
@ -23,7 +23,7 @@
|
||||
'use strict';
|
||||
|
||||
// Injected Services
|
||||
var Panel, gs, wss, flash;
|
||||
var Panel, gs, wss, flash, listProps;
|
||||
|
||||
// Internal State
|
||||
var summaryPanel, summaryData;
|
||||
@ -33,7 +33,7 @@
|
||||
className = 'topo-p',
|
||||
panelOpts = {
|
||||
show: true,
|
||||
width: 260 // summary and detail panel width
|
||||
width: 260 // summary and detail panel width
|
||||
},
|
||||
handlerMap = {
|
||||
showSummary: handleSummaryData
|
||||
@ -49,37 +49,7 @@
|
||||
});
|
||||
|
||||
summaryPanel = new Panel(id, options);
|
||||
summaryPanel.p.classed(className, true);
|
||||
}
|
||||
|
||||
function addProp(tbody, label, value) {
|
||||
var tr = tbody.append('tr'),
|
||||
lab;
|
||||
if (typeof label === 'string') {
|
||||
lab = label.replace(/_/g, ' ');
|
||||
} else {
|
||||
lab = label;
|
||||
}
|
||||
|
||||
function addCell(cls, txt) {
|
||||
tr.append('td').attr('class', cls).html(txt);
|
||||
}
|
||||
addCell('label', lab + ' :');
|
||||
addCell('value', value);
|
||||
}
|
||||
|
||||
function addSep(tbody) {
|
||||
tbody.append('tr').append('td').attr('colspan', 2).append('hr');
|
||||
}
|
||||
|
||||
function listProps(tbody, data) {
|
||||
summaryData.propOrder.forEach(function (p) {
|
||||
if (p === '-') {
|
||||
addSep(tbody);
|
||||
} else {
|
||||
addProp(tbody, p, summaryData.props[p]);
|
||||
}
|
||||
});
|
||||
summaryPanel.el.classed(className, true);
|
||||
}
|
||||
|
||||
function render() {
|
||||
@ -94,7 +64,7 @@
|
||||
|
||||
title.text(summaryData.title);
|
||||
gs.addGlyph(svg, 'bird', 24, 0, [1, 1]);
|
||||
listProps(tbody);
|
||||
listProps(tbody, summaryData);
|
||||
}
|
||||
|
||||
function handleSummaryData(data) {
|
||||
@ -107,7 +77,7 @@
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
var on = summaryPanel.p.toggle(),
|
||||
var on = summaryPanel.el.toggle(),
|
||||
verb = on ? 'Show' : 'Hide';
|
||||
flash.flash(verb + ' Summary Panel');
|
||||
}
|
||||
@ -119,17 +89,17 @@
|
||||
|
||||
angular.module('ovTopo2')
|
||||
.factory('Topo2SummaryPanelService',
|
||||
['Topo2PanelService', 'GlyphService', 'WebSocketService', 'FlashService',
|
||||
function (_ps_, _gs_, _wss_, _flash_) {
|
||||
['Topo2PanelService', 'GlyphService', 'WebSocketService', 'FlashService', 'ListService',
|
||||
function (_ps_, _gs_, _wss_, _flash_, _listService_) {
|
||||
|
||||
Panel = _ps_;
|
||||
gs = _gs_;
|
||||
wss = _wss_;
|
||||
flash = _flash_;
|
||||
listProps = _listService_;
|
||||
|
||||
return {
|
||||
init: init,
|
||||
|
||||
toggle: toggle,
|
||||
destroy: destroy,
|
||||
isVisible: function () { return summaryPanel.isVisible(); }
|
||||
|
||||
58
web/gui/src/main/webapp/app/view/topo2/uiView.js
Normal file
58
web/gui/src/main/webapp/app/view/topo2/uiView.js
Normal file
@ -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 -- Base UIView class.
|
||||
A base class for UIViews to extend from
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function View(options) {
|
||||
if (options && options.el) {
|
||||
this.el = options.el;
|
||||
this.$el = angular.element(this.el);
|
||||
}
|
||||
|
||||
this.initialize.apply(this, arguments);
|
||||
}
|
||||
|
||||
angular.module('ovTopo2')
|
||||
.factory('Topo2UIView',
|
||||
['FnService',
|
||||
function (fn) {
|
||||
|
||||
_.extend(View.prototype, {
|
||||
el: null,
|
||||
empty: function () {
|
||||
if (this.$el) {
|
||||
this.$el.empty();
|
||||
}
|
||||
},
|
||||
destroy: function () {
|
||||
// TODO: Unbind Events
|
||||
this.empty();
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
View.extend = fn.extend;
|
||||
return View;
|
||||
}
|
||||
]);
|
||||
|
||||
})();
|
||||
@ -83,6 +83,7 @@
|
||||
<script src="app/fw/widget/button.js"></script>
|
||||
<script src="app/fw/widget/tableBuilder.js"></script>
|
||||
<script src="app/fw/widget/chartBuilder.js"></script>
|
||||
<script src="app/fw/widget/listBuilder.js"></script>
|
||||
|
||||
<script src="app/fw/layer/layer.js"></script>
|
||||
<script src="app/fw/layer/panel.js"></script>
|
||||
@ -127,20 +128,23 @@
|
||||
<link rel="stylesheet" href="app/fw/widget/table-theme.css">
|
||||
|
||||
<!-- Under development for Region support. -->
|
||||
<!-- <script src="app/view/topo2/topo2.js"></script>
|
||||
<!--<script src="app/view/topo2/topo2.js"></script>
|
||||
<script src="app/view/topo2/topo2Breadcrumb.js"></script>
|
||||
<script src="app/view/topo2/topo2Collection.js"></script>
|
||||
<script src="app/view/topo2/topo2D3.js"></script>
|
||||
<script src="app/view/topo2/topo2Dialog.js"></script>
|
||||
<script src="app/view/topo2/topo2DetailsPanel.js"></script>
|
||||
<script src="app/view/topo2/topo2Device.js"></script>
|
||||
<script src="app/view/topo2/topo2DeviceDetailsPanel.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/topo2HostsPanel.js"></script>
|
||||
<script src="app/view/topo2/topo2Instance.js"></script>
|
||||
<script src="app/view/topo2/topo2KeyCommands.js"></script>
|
||||
<script src="app/view/topo2/topo2Layout.js"></script>
|
||||
<script src="app/view/topo2/topo2Link.js"></script>
|
||||
<script src="app/view/topo2/topo2LinkPanel.js"></script>
|
||||
<script src="app/view/topo2/topo2Map.js"></script>
|
||||
<script src="app/view/topo2/topo2MapCountryFilters.js"></script>
|
||||
<script src="app/view/topo2/topo2MapConfig.js"></script>
|
||||
@ -154,9 +158,11 @@
|
||||
<script src="app/view/topo2/topo2Select.js"></script>
|
||||
<script src="app/view/topo2/topo2SummaryPanel.js"></script>
|
||||
<script src="app/view/topo2/topo2SubRegion.js"></script>
|
||||
<script src="app/view/topo2/topo2SubRegionPanel.js"></script>
|
||||
<script src="app/view/topo2/topo2Theme.js"></script>
|
||||
<script src="app/view/topo2/topo2View.js"></script>
|
||||
<script src="app/view/topo2/topo2Zoom.js"></script>
|
||||
<script src="app/view/topo2/uiView.js"></script>
|
||||
<link rel="stylesheet" href="app/view/topo2/topo2.css">
|
||||
<link rel="stylesheet" href="app/view/topo2/topo2-theme.css">-->
|
||||
|
||||
|
||||
@ -212,12 +212,12 @@ describe('factory: fw/util/fn.js', function() {
|
||||
it('should define api functions', function () {
|
||||
expect(fs.areFunctions(fs, [
|
||||
'isF', 'isA', 'isS', 'isO', 'contains',
|
||||
'areFunctions', 'areFunctionsNonStrict', 'windowSize',
|
||||
'areFunctions', 'areFunctionsNonStrict', 'windowSize',
|
||||
'isMobile', 'isChrome', 'isSafari', 'isFirefox',
|
||||
'debugOn', 'debug',
|
||||
'find', 'inArray', 'removeFromArray', 'isEmptyObject', 'sameObjProps', 'containsObj', 'cap',
|
||||
'eecode', 'noPx', 'noPxStyle', 'endsWith', 'parseBitRate', 'addToTrie', 'removeFromTrie', 'trieLookup',
|
||||
'classNames'
|
||||
'classNames', 'extend'
|
||||
])).toBeTruthy();
|
||||
});
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user