diff --git a/web/gui/src/main/webapp/app/fw/svg/glyph.js b/web/gui/src/main/webapp/app/fw/svg/glyph.js index 1ce4b562ac..ba5c08a056 100644 --- a/web/gui/src/main/webapp/app/fw/svg/glyph.js +++ b/web/gui/src/main/webapp/app/fw/svg/glyph.js @@ -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," + diff --git a/web/gui/src/main/webapp/app/fw/widget/table.js b/web/gui/src/main/webapp/app/fw/widget/table.js index 699aad13f7..eb05bdfe23 100644 --- a/web/gui/src/main/webapp/app/fw/widget/table.js +++ b/web/gui/src/main/webapp/app/fw/widget/table.js @@ -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'); diff --git a/web/gui/src/main/webapp/app/view/topo/topo.css b/web/gui/src/main/webapp/app/view/topo/topo.css index c45bbedf30..b629559a39 100644 --- a/web/gui/src/main/webapp/app/view/topo/topo.css +++ b/web/gui/src/main/webapp/app/view/topo/topo.css @@ -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; -} diff --git a/web/gui/src/main/webapp/app/view/topo/topo.js b/web/gui/src/main/webapp/app/view/topo/topo.js index 0579a989c9..a6624ca696 100644 --- a/web/gui/src/main/webapp/app/view/topo/topo.js +++ b/web/gui/src/main/webapp/app/view/topo/topo.js @@ -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 () { diff --git a/web/gui/src/main/webapp/app/view/topo/topoFilter.js b/web/gui/src/main/webapp/app/view/topo/topoFilter.js index 53a6302094..1226664af1 100644 --- a/web/gui/src/main/webapp/app/view/topo/topoFilter.js +++ b/web/gui/src/main/webapp/app/view/topo/topoFilter.js @@ -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, diff --git a/web/gui/src/main/webapp/app/view/topo/topoForce.js b/web/gui/src/main/webapp/app/view/topo/topoForce.js index bbc697daae..425a87f11e 100644 --- a/web/gui/src/main/webapp/app/view/topo/topoForce.js +++ b/web/gui/src/main/webapp/app/view/topo/topoForce.js @@ -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(); diff --git a/web/gui/src/main/webapp/app/view/topo/topoToolbar.js b/web/gui/src/main/webapp/app/view/topo/topoToolbar.js index f9ff18bc53..eb7c0069fd 100644 --- a/web/gui/src/main/webapp/app/view/topo/topoToolbar.js +++ b/web/gui/src/main/webapp/app/view/topo/topoToolbar.js @@ -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'); } diff --git a/web/gui/src/main/webapp/tests/app/fw/svg/glyph-spec.js b/web/gui/src/main/webapp/tests/app/fw/svg/glyph-spec.js index c5b47d40ad..9b24e471aa 100644 --- a/web/gui/src/main/webapp/tests/app/fw/svg/glyph-spec.js +++ b/web/gui/src/main/webapp/tests/app/fw/svg/glyph-spec.js @@ -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', diff --git a/web/gui/src/main/webapp/tests/app/fw/widget/table-spec.js b/web/gui/src/main/webapp/tests/app/fw/widget/table-spec.js index 908ea16652..29927cd31b 100644 --- a/web/gui/src/main/webapp/tests/app/fw/widget/table-spec.js +++ b/web/gui/src/main/webapp/tests/app/fw/widget/table-spec.js @@ -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 = '' + '
'; - 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'); } diff --git a/web/gui/src/main/webapp/tests/app/view/topo/topoFilter-spec.js b/web/gui/src/main/webapp/tests/app/view/topo/topoFilter-spec.js index 8466dbe3c3..fc5b512518 100644 --- a/web/gui/src/main/webapp/tests/app/view/topo/topoFilter-spec.js +++ b/web/gui/src/main/webapp/tests/app/view/topo/topoFilter-spec.js @@ -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 });