GUI -- Topology View all, packet, and optical layer radio buttons are now part of the topology view toolbar, instead of being in the masthead. Keystroke 'N' for cycle node layers added. Button glyph added. Fixed previously unseen broken unit tests for table.js.

Change-Id: I6e53bdc6cacbf41b990abd07d30fc99ef4c3b8c0
This commit is contained in:
Bri Prebilic Cole 2015-04-07 14:58:09 -07:00
parent 1bf1e8c499
commit b5f2b1523f
10 changed files with 89 additions and 176 deletions

View File

@ -207,6 +207,15 @@
"91.4,54.9,91.4z M84,87.1c0,2.4-1.9,4.3-4.3,4.3c-2.4,0-4.3-1.9" +
"-4.3-4.3c0-2.4,1.9-4.3,4.3-4.3C82.1,82.8,84,84.7,84,87.1z",
filters: "M24.8,13.3L9.8,40.5h75.3l15.0-27.2H24.8z M72.8,32.1l-" +
"9.7-8.9l-19.3,8.9l-6.0-7.4L24.1,30.9l-1.2-2.7l15.7-7.1l6.0,7.4" +
"l19.0-8.8l9.7,8.8l11.5-5.6l1.3,2.7L72.8,32.1zM24.3,68.3L9.3," +
"95.5h75.3l15.0-27.2H24.3z M84.3,85.9L70.7,79.8l-6.0,7.4l-19.3" +
"-8.9l-9.7,8.9l-13.3-6.5l1.3-2.7l11.5,5.6l9.7-8.8l19.0,8.8l6.0" +
"-7.4l15.7,7.1L84.3,85.9z M15.3,57h-6v-4h6V57zM88.1,57H76.0v-4h" +
"12.1V57z M69.9,57H57.8v-4h12.1V57z M51.7,57H39.6v-4H51.7V57z " +
"M33.5,57H21.4v-4h12.1V57zM100.2,57h-6v-4h6V57z",
resetZoom: "M86,79.8L61.7,54.3c1.8-2.9,2.8-6.3,2.9-10c0.3-11.2" +
"-8.6-20.5-19.8-20.8C33.7,23.2,24.3,32,24.1,43.2c-0.3,11.2,8.6," +
"20.5,19.8,20.8c4,0.1,8.9-0.8,11.9-3.6l23.7,25c1.5,1.6,4,2.3," +

View File

@ -100,8 +100,8 @@
// to get the height of the table
function setTableHeight(thead, tbody) {
var titleHeight = h2Pdg + fs.noPxStyle(d3.select('h2'), 'height'),
thHeight = thPdg + fs.noPxStyle(d3.select('th'), 'height'),
totalHeight = titleHeight + thHeight + tbodyPdg + mastPdg,
thHeight = thPdg + fs.noPxStyle(thead, 'height'),
totalHeight = titleHeight + thHeight + mastPdg - tbodyPdg,
tableHeight = fs.windowSize(mast.mastHeight() + totalHeight).height;
thead.style('display', 'block');

View File

@ -542,41 +542,3 @@
fill: #eee;
}
/* radio buttons injected into masthead */
#topo-radio-group span.radio {
font-size: 10pt;
margin: 4px 2px;
padding: 1px 6px;
-moz-border-radius: 3px;
border-radius: 3px;
cursor: pointer;
}
.light #topo-radio-group span.radio {
border: 1px dotted #222;
color: #eee;
}
.dark #topo-radio-group span.radio {
border: 1px dotted #bbb;
color: #888;
}
#topo-radio-group span.radio.active {
padding: 1px 6px;
}
.light #topo-radio-group span.radio.active {
background-color: #bbb;
border: 1px solid #eee;
color: #666;
}
.dark #topo-radio-group span.radio.active {
background-color: #222;
border: 1px solid #eee;
color: #78a;
}

View File

@ -29,7 +29,7 @@
// references to injected services etc.
var $log, fs, ks, zs, gs, ms, sus, flash, wss,
tes, tfs, tps, tis, tss, tls, tts, tos, ttbs;
tes, tfs, tps, tis, tss, tls, tts, tos, fltr, ttbs;
// DOM elements
var ovtopo, svg, defs, zoomLayer, mapG, forceG, noDevsLayer;
@ -55,6 +55,7 @@
//X: [toggleNodeLock, 'Lock / unlock node positions'],
Z: [tos.toggleOblique, 'Toggle oblique view (Experimental)'],
N: [fltr.clickAction, 'Cycle node layers'],
L: [tfs.cycleDeviceLabels, 'Cycle device labels'],
U: [tfs.unpin, 'Unpin node (hover mouse over)'],
R: [resetZoom, 'Reset pan / zoom'],
@ -75,7 +76,7 @@
_helpFormat: [
['I', 'O', 'D', '-', 'H', 'M', 'P', 'dash', 'B' ],
['X', 'Z', 'L', 'U', 'R', '-', 'dot'],
['X', 'Z', 'N', 'L', 'U', 'R', '-', 'dot'],
['V', 'rightArrow', 'leftArrow', 'W', 'A', 'F', '-', 'E' ]
]
};
@ -244,11 +245,12 @@
'WebSocketService',
'TopoEventService', 'TopoForceService', 'TopoPanelService',
'TopoInstService', 'TopoSelectService', 'TopoLinkService',
'TopoTrafficService', 'TopoObliqueService', 'TopoToolbarService',
'TopoTrafficService', 'TopoObliqueService', 'TopoFilterService',
'TopoToolbarService',
function ($scope, _$log_, $loc, $timeout, _fs_, mast, _ks_, _zs_,
_gs_, _ms_, _sus_, _flash_, _wss_, _tes_, _tfs_, _tps_,
_tis_, _tss_, _tls_, _tts_, _tos_, _ttbs_) {
_tis_, _tss_, _tls_, _tts_, _tos_, _fltr_, _ttbs_) {
var self = this,
projection,
dim,
@ -281,6 +283,7 @@
tls = _tls_;
tts = _tts_;
tos = _tos_;
fltr = _fltr_;
ttbs = _ttbs_;
self.notifyResize = function () {

View File

@ -35,86 +35,51 @@
// which "layer" a particular item "belongs to"
var layerLookup = {
host: {
endstation: 'pkt', // default, if host event does not define type
router: 'pkt',
bgpSpeaker: 'pkt'
},
device: {
switch: 'pkt',
roadm: 'opt'
},
link: {
hostLink: 'pkt',
direct: 'pkt',
indirect: '',
tunnel: '',
optical: 'opt'
}
};
var idPrefix = 'topo-rb-';
var dispatch = {
all: function () { suppressLayers(false); },
pkt: function () { showLayer('pkt'); },
opt: function () { showLayer('opt'); }
},
filterButtons = [
{ text: 'All Layers', id: 'all' },
{ text: 'Packet Only', id: 'pkt' },
{ text: 'Optical Only', id: 'opt' }
],
btnG,
btnDef = {},
targetDiv;
function injectButtons(div) {
targetDiv = div;
btnG = div.append('div').attr('id', 'topo-radio-group');
filterButtons.forEach(function (btn, i) {
var bid = btn.id,
txt = btn.text,
uid = idPrefix + bid,
button = btnG.append('span')
.attr({
id: uid,
'class': 'radio'
})
.text(txt);
btnDef[uid] = btn;
if (i === 0) {
button.classed('active', true);
btnG.selected = bid;
host: {
endstation: 'pkt', // default, if host event does not define type
router: 'pkt',
bgpSpeaker: 'pkt'
},
device: {
switch: 'pkt',
roadm: 'opt'
},
link: {
hostLink: 'pkt',
direct: 'pkt',
indirect: '',
tunnel: '',
optical: 'opt'
}
});
},
// order of layer cycling in button
dispatch = [
{
type: 'all',
action: function () { suppressLayers(false); },
msg: 'All Layers Shown'
},
{
type: 'pkt',
action: function () { showLayer('pkt'); },
msg: 'Packet Layer Shown'
},
{
type: 'opt',
action: function () { showLayer('opt'); },
msg: 'Optical Layer Shown'
}
],
layer = 0;
btnG.selectAll('span')
.on('click', function () {
var button = d3.select(this),
uid = button.attr('id'),
btn = btnDef[uid],
act = button.classed('active');
if (!act) {
btnG.selectAll('span').classed('active', false);
button.classed('active', true);
btnG.selected = btn.id;
clickAction(btn.id);
}
});
}
function clickAction(which) {
dispatch[which]();
function clickAction() {
layer = (layer + 1) % dispatch.length;
dispatch[layer].action();
flash.flash(dispatch[layer].msg);
}
function selected() {
return btnG ? btnG.selected : '';
return dispatch[layer].type;
}
function inLayer(d, layer) {
@ -169,20 +134,12 @@
tps = _tps_;
tts = _tts_;
function initFilter(_api_, div) {
function initFilter(_api_) {
api = _api_;
injectButtons(div);
}
function destroyFilter() {
targetDiv.select('#topo-radio-group').remove();
btnG = null;
btnDef = {};
}
return {
initFilter: initFilter,
destroyFilter: destroyFilter,
clickAction: clickAction,
selected: selected,

View File

@ -816,7 +816,7 @@
tss.initSelect(mkSelectApi(uplink));
tts.initTraffic(mkTrafficApi(uplink));
tos.initOblique(mkObliqueApi(uplink, fltr));
fltr.initFilter(mkFilterApi(uplink), d3.select('#mast-right'));
fltr.initFilter(mkFilterApi(uplink));
tls.initLink(mkLinkApi(svg, uplink), td3);
settings = angular.extend({}, defaultSettings, opts);
@ -855,7 +855,6 @@
force.stop();
tls.destroyLink();
fltr.destroyFilter();
tos.destroyOblique();
tts.destroyTraffic();
tss.destroySelect();

View File

@ -44,6 +44,7 @@
//X: { id: 'nodelock-tog', gid: 'lock', isel: false },
Z: { id: 'oblique-tog', gid: 'oblique', isel: false },
N: { id: 'filters-btn', gid: 'filters' },
L: { id: 'cycleLabels-btn', gid: 'cycleLabels' },
R: { id: 'resetZoom-btn', gid: 'resetZoom' },
@ -93,6 +94,7 @@
function addSecondRow() {
//addToggle('X');
addToggle('Z');
addButton('N');
addButton('L');
addButton('R');
}

View File

@ -20,7 +20,7 @@
describe('factory: fw/svg/glyph.js', function() {
var $log, fs, gs, d3Elem, svg;
var numBaseGlyphs = 34,
var numBaseGlyphs = 35,
vbBird = '352 224 113 112',
vbGlyph = '0 0 110 110',
vbBadge = '0 0 10 10',
@ -46,6 +46,7 @@ describe('factory: fw/svg/glyph.js', function() {
map: 'M95.8,9.2H14.2c-2.8,0-5,2.2-5,5v66',
cycleLabels: 'M72.5,33.9c',
oblique: 'M80.9,30.2h',
filters: 'M24.8,13.3L',
resetZoom: 'M86,79.8L',
relatedIntents: 'M99.9,43.7',
nextIntent: 'M88.1,55.7',
@ -74,8 +75,8 @@ describe('factory: fw/svg/glyph.js', function() {
'unknown', 'node', 'switch', 'roadm', 'endstation', 'router',
'bgpSpeaker', 'chain', 'crown', 'lock',
'summary', 'details', 'ports', 'map', 'cycleLabels', 'oblique',
'resetZoom', 'relatedIntents', 'nextIntent', 'prevIntent',
'intentTraffic', 'allTraffic', 'flows', 'eqMaster'
'filters', 'resetZoom', 'relatedIntents', 'nextIntent',
'prevIntent', 'intentTraffic', 'allTraffic', 'flows', 'eqMaster'
],
badgeIds = [
'uiAttached', 'checkMark', 'xMark', 'triangleUp', 'triangleDown',

View File

@ -19,11 +19,12 @@
*/
describe('factory: fw/widget/table.js', function () {
var $log, $compile, $rootScope,
fs, is,
fs, mast, is,
scope, compiled,
table, thead, tbody,
table, thead, tbody, mockHeader,
mockh2Height = '10px',
tableIconTdSize = 100,
bottomMargin = 200,
pdgTop = 101,
numTestElems = 4;
var onosFixedHeaderTags = '<table ' +
@ -73,7 +74,7 @@ describe('factory: fw/widget/table.js', function () {
'</tbody>' +
'</table>';
beforeEach(module('onosWidget', 'onosUtil', 'onosSvg'));
beforeEach(module('onosWidget', 'onosUtil', 'onosMast', 'onosSvg'));
var mockWindow = {
innerWidth: 400,
@ -92,11 +93,12 @@ describe('factory: fw/widget/table.js', function () {
});
beforeEach(inject(function (_$log_, _$compile_, _$rootScope_,
FnService, IconService) {
FnService, MastService, IconService) {
$log = _$log_;
$compile = _$compile_;
$rootScope = _$rootScope_;
fs = FnService;
mast = MastService;
is = IconService;
}));
@ -104,10 +106,18 @@ describe('factory: fw/widget/table.js', function () {
scope = $rootScope.$new();
});
beforeEach(function () {
mockHeader = d3.select('body')
.append('h2')
.style('height', mockh2Height)
.html('Some Header');
});
afterEach(function () {
table = null;
thead = null;
tbody = null;
mockHeader.remove();
});
function compileTable() {
@ -127,11 +137,11 @@ describe('factory: fw/widget/table.js', function () {
}
function verifyCssDisplay() {
var winHeight = fs.windowSize().height;
var tableHeight = fs.windowSize(pdgTop).height;
expect(thead.css('display')).toBe('block');
expect(tbody.css('display')).toBe('block');
expect(tbody.css('height')).toBe((winHeight - bottomMargin) + 'px');
expect(tbody.css('height')).toBe(tableHeight + 'px');
expect(tbody.css('overflow')).toBe('auto');
}

View File

@ -18,7 +18,7 @@
ONOS GUI -- Topo View -- Topo Filter Service - Unit Tests
*/
describe('factory: view/topo/topoFilter.js', function() {
var $log, fs, fltr, d3Elem, api;
var $log, fs, fltr, api;
var mockNodes = {
each: function () {},
@ -35,7 +35,6 @@ describe('factory: view/topo/topoFilter.js', function() {
$log = _$log_;
fs = FnService;
fltr = TopoFilterService;
d3Elem = d3.select('body').append('div').attr('id', 'myMastDiv');
api = {
node: function () { return mockNodes; },
@ -44,7 +43,7 @@ describe('factory: view/topo/topoFilter.js', function() {
}));
afterEach(function () {
d3.select('#myMastDiv').remove();
});
it('should define TopoFilterService', function () {
@ -53,45 +52,16 @@ describe('factory: view/topo/topoFilter.js', function() {
it('should define api functions', function () {
expect(fs.areFunctions(fltr, [
'initFilter', 'destroyFilter',
'clickAction', 'selected', 'inLayer',
'initFilter',
'clickAction', 'selected', 'inLayer'
])).toBeTruthy();
});
it('should inject the buttons into the given div', function () {
fltr.initFilter(api, d3Elem);
var grpdiv = d3Elem.select('#topo-radio-group');
expect(grpdiv.size()).toBe(1);
var btns = grpdiv.selectAll('span');
expect(btns.size()).toBe(3);
var prefix = 'topo-rb-',
expIds = [ 'all', 'pkt', 'opt' ];
btns.each(function (d, i) {
var b = d3.select(this);
expect(b.attr('id')).toEqual(prefix + expIds[i]);
// 0th button is active - others are not
expect(b.classed('active')).toEqual(i === 0);
});
});
it('should remove the buttons from the given div', function () {
fltr.initFilter(api, d3Elem);
var grpdiv = d3Elem.select('#topo-radio-group');
expect(grpdiv.size()).toBe(1);
fltr.destroyFilter();
grpdiv = d3Elem.select('#topo-radio-group');
expect(grpdiv.size()).toBe(0);
});
it('should report the selected button', function () {
fltr.initFilter(api, d3Elem);
fltr.initFilter(api);
expect(fltr.selected()).toEqual('all');
});
// TODO: figure out how to trigger the click function on the spans..
// TODO: test the on click functions
});