From 643ee33289bd2cb9e6afbfb09b4ed72d467ba1c2 Mon Sep 17 00:00:00 2001 From: Ashlee Young Date: Tue, 3 Nov 2015 14:08:10 -0800 Subject: This updates ONOS src tree to commit id 03fa5e571cabbd001ddb1598847e1150b11c7333 Change-Id: I13b554026d6f902933e35887d29bd5fdb669c0bd Signed-off-by: Ashlee Young --- .../web/gui/src/main/webapp/app/view/topo/topo.css | 51 ++++++ .../web/gui/src/main/webapp/app/view/topo/topo.js | 20 ++- .../gui/src/main/webapp/app/view/topo/topoD3.js | 60 +++++-- .../src/main/webapp/app/view/topo/topoDialog.js | 183 +++++++++++++++++++++ .../gui/src/main/webapp/app/view/topo/topoEvent.js | 2 + .../gui/src/main/webapp/app/view/topo/topoForce.js | 8 +- .../src/main/webapp/app/view/topo/topoOverlay.js | 7 +- .../src/main/webapp/app/view/topo/topoSelect.js | 30 +++- .../src/main/webapp/app/view/topo/topoToolbar.js | 1 + .../src/main/webapp/app/view/topo/topoTraffic.js | 9 + 10 files changed, 349 insertions(+), 22 deletions(-) create mode 100644 framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoDialog.js (limited to 'framework/src/onos/web/gui/src/main/webapp/app/view/topo') diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.css b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.css index f4b089a0..dda6d5c6 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.css +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.css @@ -96,6 +96,24 @@ html[data-platform='iPad'] #topo-p-detail { height: 30px; } +/* --- Topo Dialog Panel --- */ + +#topo-p-dialog .dialog-button { + display: inline-block; + cursor: pointer; + height: 20px; + padding: 2px 6px; + margin: 4px; + float: right; +} + +.light #topo-p-dialog .dialog-button { + background-color: #fec; +} +.dark #topo-p-dialog .dialog-button { + background-color: #369; +} + /* --- general topo-panel styling --- */ .topo-p div.header div.icon { @@ -427,6 +445,39 @@ html[data-platform='iPad'] #topo-p-detail { fill: #f90; } +/* Badges */ +/* (... works for both light and dark themes...) */ +#ov-topo svg .node .badge circle { + stroke: #aaa; +} + +#ov-topo svg .node .badge.badgeInfo circle { + fill: #ccf; +} + +#ov-topo svg .node .badge.badgeWarn circle { + fill: #da2; +} + +#ov-topo svg .node .badge.badgeError circle { + fill: #e44; +} + +#ov-topo svg .node .badge use { + fill: white; +} + +#ov-topo svg .node .badge.badgeInfo use { + fill: #448; +} + +#ov-topo svg .node .badge text { + fill: white; +} + +#ov-topo svg .node .badge.badgeInfo text { + fill: #448; +} /* Host Nodes */ diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.js index 0dfd6281..7ddfd136 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topo.js @@ -412,6 +412,12 @@ flash.enable(true); } + function topoStartDone() { + var d = $scope.intentData; + if (d) { + tts.selectIntent(d); + } + } // --- Controller Definition ----------------------------------------- @@ -430,7 +436,8 @@ _zs_, _gs_, _ms_, _sus_, _flash_, _wss_, _ps_, _tes_, _tfs_, _tps_, _tis_, _tss_, _tls_, _tts_, _tos_, _fltr_, _ttbs_, tspr, _ttip_, _tov_) { - var projection, + var params = $loc.search(), + projection, dim, uplink = { // provides function calls back into this space @@ -438,7 +445,8 @@ projection: function () { return projection; }, zoomLayer: function () { return zoomLayer; }, zoomer: function () { return zoomer; }, - opacifyMap: opacifyMap + opacifyMap: opacifyMap, + topoStartDone: topoStartDone }; $scope = _$scope_; @@ -469,6 +477,14 @@ ttip = _ttip_; tov = _tov_; + if (params.intentKey && params.intentAppId && params.intentAppName) { + $scope.intentData = { + key: params.intentKey, + appId: params.intentAppId, + appName: params.intentAppName + }; + } + $scope.notifyResize = function () { svgResized(fs.windowSize(mast.mastHeight())); }; diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoD3.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoD3.js index 1f061dd6..1d2c5b10 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoD3.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoD3.js @@ -55,8 +55,23 @@ height: 14 } }, + badgeConfig = { + radius: 12, + yoff: 5, + gdelta: 10 + }, icfg; + var status = { + i: 'badgeInfo', + w: 'badgeWarn', + e: 'badgeError' + }; + + function badgeStatus(badge) { + return status[badge.status] || status.i; + } + // internal state var deviceLabelIndex = 0, hostLabelIndex = 0; @@ -186,12 +201,15 @@ } - function updateDeviceLabel(d) { + function updateDeviceRendering(d) { var label = trimLabel(deviceLabel(d)), noLabel = !label, node = d.el, dim = icfg.device.dim, - box, dx, dy; + box, dx, dy, bsel, + bdg = d.badge, + bcr = badgeConfig.radius, + bcgd = badgeConfig.gdelta; node.select('text') .text(label) @@ -216,23 +234,34 @@ node.select('g.deviceIcon') .transition() .attr('transform', sus.translate(dx, dy)); - } - function updateDeviceBadge(d) { - // TODO: Fix this WIP - var node = d.el, - bsel; + // handle badge, if defined + if (bdg) { + node.select('g.badge').remove(); - if (d.badge) { bsel = node.append('g') .classed('badge', true) - .attr('transform', sus.translate(-14, -14)); + .classed(badgeStatus(bdg), true) + .attr('transform', sus.translate(dx + dim, dy)); bsel.append('circle') - .attr('r', 14); - bsel.append('text') - .attr('transform', sus.translate(-5, 3)) - .text('42'); + .attr('r', bcr); + + if (bdg.txt) { + bsel.append('text') + .attr('dy', badgeConfig.yoff) + .attr('text-anchor', 'middle') + .text(bdg.txt); + } else if (bdg.gid) { + bsel.append('use') + .attr({ + width: bcgd * 2, + height: bcgd * 2, + transform: sus.translate(-bcgd, -bcgd), + 'xlink:href': '#' + bdg.gid + }); + + } } } @@ -258,8 +287,7 @@ function deviceExisting(d) { var node = d.el; node.classed('online', d.online); - updateDeviceLabel(d); - updateDeviceBadge(d); + updateDeviceRendering(d); api.posNode(d, true); } @@ -574,7 +602,7 @@ deviceLabel: deviceLabel, trimLabel: trimLabel, - updateDeviceLabel: updateDeviceLabel, + updateDeviceLabel: updateDeviceRendering, updateHostLabel: updateHostLabel, updateDeviceColors: updateDeviceColors, diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoDialog.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoDialog.js new file mode 100644 index 00000000..93079183 --- /dev/null +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoDialog.js @@ -0,0 +1,183 @@ +/* + * Copyright 2015 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 Dialog Module. + Defines functions for manipulating a dialog box. + */ + +(function () { + 'use strict'; + + // injected refs + var $log, $window, $rootScope, fs, ps, bns; + + // constants + var pCls = 'topo-p dialog', + idDialog = 'topo-p-dialog', + panelOpts = { + width: 300, + edge: 'left' + }; + + // internal state + var pApi, panel, dApi; + + // TODO: ESC key invokes Cancel callback + // TODO: Enter invokes OK callback + + // create the dialog; return its API + function createDialog() { + var header, body, footer, + p = ps.createPanel(idDialog, panelOpts); + p.classed(pCls, true); + panel = p; + + function reset() { + p.empty(); + p.append('div').classed('header', true); + p.append('div').classed('body', true); + p.append('div').classed('footer', true); + + header = p.el().select('.header'); + body = p.el().select('.body'); + footer = p.el().select('.footer'); + } + + function hAppend(x) { + if (typeof x === 'string') { + return header.append(x); + } + header.node().appendChild(x.node()); + return header; + } + + function bAppend(x) { + if (typeof x === 'string') { + return body.append(x); + } + body.node().appendChild(x.node()); + return body; + } + + function fAppend(x) { + if (typeof x === 'string') { + return footer.append(x); + } + footer.node().appendChild(x.node()); + return footer; + } + + function destroy() { + ps.destroyPanel(idDialog); + } + + return { + reset: reset, + appendHeader: hAppend, + appendBody: bAppend, + appendFooter: fAppend, + destroy: destroy + }; + } + + function makeButton(text, callback) { + var cb = fs.isF(callback); + + function invoke() { + cb && cb(); + panel.hide(); + } + return createDiv('dialog-button') + .text(text) + .on('click', invoke); + } + + function addContent(content) { + if (pApi) { + pApi.appendBody(content); + } + return dApi; + } + + function addButton(text, cb) { + if (pApi) { + pApi.appendFooter(makeButton(text, cb)); + } + return dApi; + } + + // opens the dialog (creates if necessary) + function openDialog() { + $log.debug('Open DIALOG'); + if (!pApi) { + pApi = createDialog(); + } + pApi.reset(); + pApi.appendHeader('h2').text('=dialog='); + panel.show(); + + // return the dialog object API + dApi = { + addContent: addContent, + addButton: addButton + }; + return dApi; + } + + // closes the dialog (destroying panel) + function closeDialog() { + $log.debug('Close DIALOG'); + if (pApi) { + panel.hide(); + pApi.destroy(); + pApi = null; + dApi = null; + } + } + + // creates a detached div, returning D3 selection + // optional CSS class may be provided + function createDiv(cls) { + var div = d3.select(document.createElement('div')); + if (cls) { + div.classed(cls, true); + } + return div; + } + + // ========================== + + angular.module('ovTopo') + .factory('TopoDialogService', + ['$log', '$window', '$rootScope', 'FnService', 'PanelService', 'ButtonService', + + function (_$log_, _$window_, _$rootScope_, + _fs_, _ps_, _bns_) { + $log = _$log_; + $window = _$window_; + $rootScope = _$rootScope_; + fs = _fs_; + ps = _ps_; + bns = _bns_; + + return { + openDialog: openDialog, + closeDialog: closeDialog, + createDiv: createDiv + }; + }]); +}()); diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js index 5fd38bf6..2957629a 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js @@ -60,6 +60,8 @@ updateLink: tfs, removeLink: tfs, + topoStartDone: tfs, + spriteListResponse: tspr, spriteDataResponse: tspr }; diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js index f00b87fa..844d7dc9 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js @@ -240,6 +240,11 @@ } } + function topoStartDone(data) { + // called when the initial barrage of data has been sent from server + uplink.topoStartDone(); + } + // ======================== function nodeById(id) { @@ -1140,7 +1145,8 @@ removeHost: removeHost, addLink: addLink, updateLink: updateLink, - removeLink: removeLink + removeLink: removeLink, + topoStartDone: topoStartDone }; }]); }()); diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoOverlay.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoOverlay.js index 9a3b4358..2dee4c40 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoOverlay.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoOverlay.js @@ -34,7 +34,8 @@ // internal state var overlays = {}, - current = null; + current = null, + reset = true; function error(fn, msg) { $log.error(tos + fn + '(): ' + msg); @@ -144,7 +145,8 @@ payload[op] = oid; } - if (!same) { + if (reset || !same) { + reset = false; current && doop('deactivate'); current = overlays[id]; current && doop('activate'); @@ -390,6 +392,7 @@ tbSelection: tbSelection, installButtons: installButtons, addDetailButton: addDetailButton, + resetOnToolbarDestroy: function () { reset = true; }, hooks: { escape: escapeHook, emptySelect: emptySelectHook, diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoSelect.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoSelect.js index 483c4baa..4ad76903 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoSelect.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoSelect.js @@ -240,6 +240,33 @@ return cc; } + // returns a selection context, providing info about what is selected + function selectionContext() { + var devices = [], + hosts = [], + types = {}; + + angular.forEach(selections, function (d) { + var o = d.obj, + c = o.class; + + if (c === 'device') { + devices.push(o.id); + types[o.id] = o.type; + } + if (c === 'host') { + hosts.push(o.id); + types[o.id] = o.type; + } + }); + + return { + devices: devices, + hosts: hosts, + types: types + }; + } + // === ----------------------------------------------------- // === MODULE DEFINITION === @@ -280,7 +307,8 @@ selectOrder: function () { return selectOrder; }, somethingSelected: somethingSelected, - clickConsumed: clickConsumed + clickConsumed: clickConsumed, + selectionContext: selectionContext }; }]); }()); diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoToolbar.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoToolbar.js index 3928cd21..06285442 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoToolbar.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoToolbar.js @@ -243,6 +243,7 @@ function destroyToolbar() { tbs.destroyToolbar(name); + tov.resetOnToolbarDestroy(); } // allows us to ensure the button states track key strokes diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoTraffic.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoTraffic.js index ca379360..ff690c49 100644 --- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoTraffic.js +++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoTraffic.js @@ -152,6 +152,14 @@ } } + // force the system to create a single intent selection + function selectIntent(data) { + trafficMode = 'intents'; + hoverMode = null; + wss.sendEvent('selectIntent', data); + flash.flash('Selecting Intent ' + data.key); + } + // === ------------------------------------------------------ // action buttons on detail panel (multiple selection) @@ -207,6 +215,7 @@ showPrevIntent: showPrevIntent, showNextIntent: showNextIntent, showSelectedIntentTraffic: showSelectedIntentTraffic, + selectIntent: selectIntent, // invoked from mouseover/mouseout and selection change requestTrafficForMode: requestTrafficForMode, -- cgit 1.2.3-korg