summaryrefslogtreecommitdiffstats
path: root/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoPanel.js
diff options
context:
space:
mode:
authorAshlee Young <ashlee@onosfw.com>2015-09-09 22:15:21 -0700
committerAshlee Young <ashlee@onosfw.com>2015-09-09 22:15:21 -0700
commit13d05bc8458758ee39cb829098241e89616717ee (patch)
tree22a4d1ce65f15952f07a3df5af4b462b4697cb3a /framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoPanel.js
parent6139282e1e93c2322076de4b91b1c85d0bc4a8b3 (diff)
ONOS checkin based on commit tag e796610b1f721d02f9b0e213cf6f7790c10ecd60
Change-Id: Ife8810491034fe7becdba75dda20de4267bd15cd
Diffstat (limited to 'framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoPanel.js')
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoPanel.js539
1 files changed, 539 insertions, 0 deletions
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoPanel.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoPanel.js
new file mode 100644
index 00000000..7db17f0d
--- /dev/null
+++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoPanel.js
@@ -0,0 +1,539 @@
+/*
+ * 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 Panel Module.
+ Defines functions for manipulating the summary, detail, and instance panels.
+ */
+
+(function () {
+ 'use strict';
+
+ // injected refs
+ var $log, $window, $rootScope, fs, ps, gs, flash, wss, bns, mast, ns;
+
+ // constants
+ var pCls = 'topo-p',
+ idSum = 'topo-p-summary',
+ idDet = 'topo-p-detail',
+ panelOpts = {
+ width: 260
+ },
+ sumMax = 240,
+ padTop = 20,
+ devPath = 'device';
+
+ // internal state
+ var useDetails = true, // should we show details if we have 'em?
+ haveDetails = false, // do we have details that we could show?
+ sumFromTop, // summary panel distance from top of screen
+ unbindWatch;
+
+ // panels
+ var summary, detail;
+
+ // === -----------------------------------------------------
+ // Panel API
+ function createTopoPanel(id, opts) {
+ var p = ps.createPanel(id, opts),
+ pid = id,
+ header, body, footer;
+ p.classed(pCls, true);
+
+ function panel() {
+ return p;
+ }
+
+ function hAppend(x) {
+ return header.append(x);
+ }
+
+ function bAppend(x) {
+ return body.append(x);
+ }
+
+ function fAppend(x) {
+ return footer.append(x);
+ }
+
+ function setup() {
+ 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 destroy() {
+ ps.destroyPanel(pid);
+ }
+
+ // fromTop is how many pixels from the top of the page the panel is
+ // max is the max height of the panel in pixels
+ // only adjusts if the body content would be 10px or larger
+ function adjustHeight(fromTop, max) {
+ var totalPHeight, avSpace,
+ overflow = 0,
+ pdg = 30;
+
+ if (!fromTop) {
+ $log.warn('adjustHeight: height from top of page not given');
+ return null;
+ } else if (!body || !p) {
+ $log.warn('adjustHeight: panel contents are not defined');
+ return null;
+ }
+
+ p.el().style('height', null);
+ body.style('height', null);
+
+ totalPHeight = fromTop + p.height();
+ avSpace = fs.windowSize(pdg).height;
+
+ if (totalPHeight >= avSpace) {
+ overflow = totalPHeight - avSpace;
+ }
+
+ function _adjustBody(height) {
+ if (height < 10) {
+ return false;
+ } else {
+ body.style('height', height + 'px');
+ }
+ return true;
+ }
+
+ if (!_adjustBody(fs.noPxStyle(body, 'height') - overflow)) {
+ return;
+ }
+
+ if (max && p.height() > max) {
+ _adjustBody(fs.noPxStyle(body, 'height') - (p.height() - max));
+ }
+ }
+
+ return {
+ panel: panel,
+ setup: setup,
+ destroy: destroy,
+ appendHeader: hAppend,
+ appendBody: bAppend,
+ appendFooter: fAppend,
+ adjustHeight: adjustHeight
+ };
+ }
+
+ // === -----------------------------------------------------
+ // Utility functions
+
+ function addSep(tbody) {
+ tbody.append('tr').append('td').attr('colspan', 2).append('hr');
+ }
+
+ function addBtnFooter() {
+ detail.appendFooter('hr');
+ detail.appendFooter('div').classed('actionBtns', 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 listProps(tbody, data) {
+ data.propOrder.forEach(function (p) {
+ if (p === '-') {
+ addSep(tbody);
+ } else {
+ addProp(tbody, p, data.props[p]);
+ }
+ });
+ }
+
+ function watchWindow() {
+ unbindWatch = $rootScope.$watchCollection(
+ function () {
+ return {
+ h: $window.innerHeight,
+ w: $window.innerWidth
+ };
+ }, function () {
+ summary.adjustHeight(sumFromTop, sumMax);
+ detail.adjustHeight(detail.ypos.current);
+ }
+ );
+ }
+
+ // === -----------------------------------------------------
+ // Functions for populating the summary panel
+
+ function populateSummary(data) {
+ summary.setup();
+
+ var svg = summary.appendHeader('div')
+ .classed('icon', true)
+ .append('svg'),
+ title = summary.appendHeader('h2'),
+ table = summary.appendBody('table'),
+ tbody = table.append('tbody'),
+ glyphId = data.type || 'node';
+
+ gs.addGlyph(svg, glyphId, 40);
+
+ if (glyphId === 'node') {
+ gs.addGlyph(svg, 'bird', 24, true, [8,12]);
+ }
+
+ title.text(data.title);
+ listProps(tbody, data);
+ }
+
+ // === -----------------------------------------------------
+ // Functions for populating the detail panel
+
+ var isDevice = {
+ switch: 1,
+ roadm: 1
+ };
+
+ function displaySingle(data) {
+ detail.setup();
+
+ var svg = detail.appendHeader('div')
+ .classed('icon clickable', true)
+ .append('svg'),
+ title = detail.appendHeader('h2')
+ .classed('clickable', true),
+ table = detail.appendBody('table'),
+ tbody = table.append('tbody'),
+ navFn;
+
+ gs.addGlyph(svg, (data.type || 'unknown'), 40);
+ title.text(data.title);
+
+ // only add navigation when displaying a device
+ if (isDevice[data.type]) {
+ navFn = function () {
+ ns.navTo(devPath, { devId: data.id });
+ };
+
+ svg.on('click', navFn);
+ title.on('click', navFn);
+ }
+
+ listProps(tbody, data);
+ addBtnFooter();
+ }
+
+ function displayMulti(ids) {
+ detail.setup();
+
+ var title = detail.appendHeader('h3'),
+ table = detail.appendBody('table'),
+ tbody = table.append('tbody');
+
+ title.text('Selected Nodes');
+ ids.forEach(function (d, i) {
+ addProp(tbody, i+1, d);
+ });
+ addBtnFooter();
+ }
+
+ function addAction(o) {
+ var btnDiv = d3.select('#' + idDet)
+ .select('.actionBtns')
+ .append('div')
+ .classed('actionBtn', true);
+ bns.button(btnDiv, idDet + '-' + o.id, o.gid, o.cb, o.tt);
+ }
+
+ var friendlyIndex = {
+ device: 1,
+ host: 0
+ };
+
+ function friendly(d) {
+ var i = friendlyIndex[d.class] || 0;
+ return (d.labels && d.labels[i]) || '';
+ }
+
+ function linkSummary(d) {
+ var o = d && d.online ? 'online' : 'offline';
+ return d ? d.type + ' / ' + o : '-';
+ }
+
+ // provided to change presentation of internal type name
+ var linkTypePres = {
+ hostLink: 'edge link'
+ };
+
+ function linkType(d) {
+ return linkTypePres[d.type()] || d.type();
+ }
+
+ var coreOrder = [
+ 'Type', '-',
+ 'A_type', 'A_id', 'A_label', 'A_port', '-',
+ 'B_type', 'B_id', 'B_label', 'B_port', '-'
+ ],
+ edgeOrder = [
+ 'Type', '-',
+ 'A_type', 'A_id', 'A_label', '-',
+ 'B_type', 'B_id', 'B_label', 'B_port'
+ ];
+
+ function displayLink(data) {
+ detail.setup();
+
+ var svg = detail.appendHeader('div')
+ .classed('icon', true)
+ .append('svg'),
+ title = detail.appendHeader('h2'),
+ table = detail.appendBody('table'),
+ tbody = table.append('tbody'),
+ edgeLink = data.type() === 'hostLink',
+ order = edgeLink ? edgeOrder : coreOrder;
+
+ gs.addGlyph(svg, 'ports', 40);
+ title.text('Link');
+
+
+ listProps(tbody, {
+ propOrder: order,
+ props: {
+ Type: linkType(data),
+
+ A_type: data.source.class,
+ A_id: data.source.id,
+ A_label: friendly(data.source),
+ A_port: data.srcPort,
+
+ B_type: data.target.class,
+ B_id: data.target.id,
+ B_label: friendly(data.target),
+ B_port: data.tgtPort
+ }
+ });
+
+ if (!edgeLink) {
+ addProp(tbody, 'A &rarr; B', linkSummary(data.fromSource));
+ addProp(tbody, 'B &rarr; A', linkSummary(data.fromTarget));
+ }
+ }
+
+ function displayNothing() {
+ haveDetails = false;
+ hideDetailPanel();
+ }
+
+ function displaySomething() {
+ haveDetails = true;
+ if (useDetails) {
+ showDetailPanel();
+ }
+ }
+
+ // === -----------------------------------------------------
+ // Event Handlers
+
+ function showSummary(data) {
+ populateSummary(data);
+ showSummaryPanel();
+ }
+
+ function toggleSummary(x) {
+ var kev = (x === 'keyev'),
+ on = kev ? !summary.panel().isVisible() : !!x,
+ verb = on ? 'Show' : 'Hide';
+
+ if (on) {
+ // ask server to start sending summary data.
+ wss.sendEvent('requestSummary');
+ // note: the summary panel will appear, once data arrives
+ } else {
+ hideSummaryPanel();
+ }
+ flash.flash(verb + ' summary panel');
+ return on;
+ }
+
+ // === -----------------------------------------------------
+ // === LOGIC For showing/hiding summary and detail panels...
+
+ function showSummaryPanel() {
+ function _show() {
+ summary.panel().show();
+ summary.adjustHeight(sumFromTop, sumMax);
+ }
+ if (detail.panel().isVisible()) {
+ detail.down(_show);
+ } else {
+ _show();
+ }
+ }
+
+ function hideSummaryPanel() {
+ // instruct server to stop sending summary data
+ wss.sendEvent("cancelSummary");
+ summary.panel().hide(detail.up);
+ }
+
+ function showDetailPanel() {
+ if (summary.panel().isVisible()) {
+ detail.down(detail.panel().show);
+ } else {
+ detail.up(detail.panel().show);
+ }
+ }
+
+ function hideDetailPanel() {
+ detail.panel().hide();
+ }
+
+ // ==========================
+
+ function augmentDetailPanel() {
+ var d = detail,
+ downPos = sumFromTop + sumMax + 20;
+ d.ypos = { up: sumFromTop, down: downPos, current: downPos};
+
+ d._move = function (y, cb) {
+ var yp = d.ypos,
+ endCb;
+
+ if (fs.isF(cb)) {
+ endCb = function () {
+ cb();
+ d.adjustHeight(d.ypos.current);
+ }
+ } else {
+ endCb = function () {
+ d.adjustHeight(d.ypos.current);
+ }
+ }
+ if (yp.current !== y) {
+ yp.current = y;
+ d.panel().el().transition().duration(300)
+ .each('end', endCb)
+ .style('top', yp.current + 'px');
+ } else {
+ endCb();
+ }
+ };
+
+ d.down = function (cb) { d._move(d.ypos.down, cb); };
+ d.up = function (cb) { d._move(d.ypos.up, cb); };
+ }
+
+ function toggleUseDetailsFlag(x) {
+ var kev = (x === 'keyev'),
+ verb;
+
+ useDetails = kev ? !useDetails : !!x;
+ verb = useDetails ? 'Enable' : 'Disable';
+
+ if (useDetails) {
+ if (haveDetails) {
+ showDetailPanel();
+ }
+ } else {
+ hideDetailPanel();
+ }
+ flash.flash(verb + ' details panel');
+ return useDetails;
+ }
+
+ // ==========================
+
+ function initPanels() {
+ sumFromTop = mast.mastHeight() + padTop;
+ summary = createTopoPanel(idSum, panelOpts);
+ detail = createTopoPanel(idDet, panelOpts);
+
+ augmentDetailPanel();
+ watchWindow();
+ }
+
+ function destroyPanels() {
+ summary.destroy();
+ summary = null;
+
+ detail.destroy();
+ detail = null;
+ haveDetails = false;
+ unbindWatch();
+ }
+
+ // ==========================
+
+ angular.module('ovTopo')
+ .factory('TopoPanelService',
+ ['$log', '$window', '$rootScope', 'FnService', 'PanelService', 'GlyphService',
+ 'FlashService', 'WebSocketService', 'ButtonService', 'MastService',
+ 'NavService',
+
+ function (_$log_, _$window_, _$rootScope_,
+ _fs_, _ps_, _gs_, _flash_, _wss_, _bns_, _mast_, _ns_) {
+ $log = _$log_;
+ $window = _$window_;
+ $rootScope = _$rootScope_;
+ fs = _fs_;
+ ps = _ps_;
+ gs = _gs_;
+ flash = _flash_;
+ wss = _wss_;
+ bns = _bns_;
+ mast = _mast_;
+ ns = _ns_;
+
+ return {
+ initPanels: initPanels,
+ destroyPanels: destroyPanels,
+ createTopoPanel: createTopoPanel,
+
+ showSummary: showSummary,
+ toggleSummary: toggleSummary,
+
+ toggleUseDetailsFlag: toggleUseDetailsFlag,
+ displaySingle: displaySingle,
+ displayMulti: displayMulti,
+ displayLink: displayLink,
+ displayNothing: displayNothing,
+ displaySomething: displaySomething,
+ addAction: addAction,
+
+ hideSummaryPanel: hideSummaryPanel,
+
+ detailVisible: function () { return detail.panel().isVisible(); },
+ summaryVisible: function () { return summary.panel().isVisible(); }
+ };
+ }]);
+}());