| /* |
| * 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, fs, ps, gs, flash, wss, bns; |
| |
| // constants |
| var pCls = 'topo-p', |
| idSum = 'topo-p-summary', |
| idDet = 'topo-p-detail', |
| panelOpts = { |
| width: 260 |
| }; |
| |
| // panels |
| var summaryPanel, |
| detailPanel; |
| |
| // internal state |
| var useDetails = true, // should we show details if we have 'em? |
| haveDetails = false; // do we have details that we could show? |
| |
| // === ----------------------------------------------------- |
| // Utility functions |
| |
| function addSep(tbody) { |
| tbody.append('tr').append('td').attr('colspan', 2).append('hr'); |
| } |
| |
| 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 dpa(x) { |
| return detailPanel.append(x); |
| } |
| |
| function spa(x) { |
| return summaryPanel.append(x); |
| } |
| |
| // === ----------------------------------------------------- |
| // Functions for populating the summary panel |
| |
| function populateSummary(data) { |
| summaryPanel.empty(); |
| |
| var svg = spa('svg'), |
| title = spa('h2'), |
| table = spa('table'), |
| tbody = table.append('tbody'); |
| |
| gs.addGlyph(svg, 'node', 40); |
| gs.addGlyph(svg, 'bird', 24, true, [8,12]); |
| |
| title.text(data.id); |
| listProps(tbody, data); |
| } |
| |
| // === ----------------------------------------------------- |
| // Functions for populating the detail panel |
| |
| function displaySingle(data) { |
| detailPanel.empty(); |
| |
| var svg = dpa('svg'), |
| title = dpa('h2'), |
| table = dpa('table'), |
| tbody = table.append('tbody'); |
| |
| gs.addGlyph(svg, (data.type || 'unknown'), 40); |
| title.text(data.id); |
| listProps(tbody, data); |
| dpa('hr'); |
| dpa('div').classed('actionBtns', true); |
| } |
| |
| function displayMulti(ids) { |
| detailPanel.empty(); |
| |
| var title = dpa('h3'), |
| table = dpa('table'), |
| tbody = table.append('tbody'); |
| |
| title.text('Selected Nodes'); |
| ids.forEach(function (d, i) { |
| addProp(tbody, i+1, d); |
| }); |
| dpa('hr'); |
| dpa('div').classed('actionBtns', true); |
| } |
| |
| 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) { |
| detailPanel.empty(); |
| |
| var svg = dpa('svg'), |
| title = dpa('h2'), |
| table = dpa('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 → B', linkSummary(data.fromSource)); |
| addProp(tbody, 'B → 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 ? !summaryPanel.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() { |
| if (detailPanel.isVisible()) { |
| detailPanel.down(summaryPanel.show); |
| } else { |
| summaryPanel.show(); |
| } |
| } |
| |
| function hideSummaryPanel() { |
| // instruct server to stop sending summary data |
| wss.sendEvent("cancelSummary"); |
| summaryPanel.hide(detailPanel.up); |
| } |
| |
| function showDetailPanel() { |
| if (summaryPanel.isVisible()) { |
| detailPanel.down(detailPanel.show); |
| } else { |
| detailPanel.up(detailPanel.show); |
| } |
| } |
| |
| function hideDetailPanel() { |
| detailPanel.hide(); |
| } |
| |
| // ========================== |
| |
| function noop () {} |
| |
| function augmentDetailPanel() { |
| var dp = detailPanel; |
| dp.ypos = { up: 64, down: 320, current: 320}; |
| |
| dp._move = function (y, cb) { |
| var endCb = fs.isF(cb) || noop, |
| yp = dp.ypos; |
| if (yp.current !== y) { |
| yp.current = y; |
| dp.el().transition().duration(300) |
| .each('end', endCb) |
| .style('top', yp.current + 'px'); |
| } else { |
| endCb(); |
| } |
| }; |
| |
| dp.down = function (cb) { dp._move(dp.ypos.down, cb); }; |
| dp.up = function (cb) { dp._move(dp.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() { |
| summaryPanel = ps.createPanel(idSum, panelOpts); |
| detailPanel = ps.createPanel(idDet, panelOpts); |
| |
| summaryPanel.classed(pCls, true); |
| detailPanel.classed(pCls, true); |
| |
| augmentDetailPanel(); |
| } |
| |
| function destroyPanels() { |
| ps.destroyPanel(idSum); |
| ps.destroyPanel(idDet); |
| summaryPanel = detailPanel = null; |
| haveDetails = false; |
| } |
| |
| // ========================== |
| |
| angular.module('ovTopo') |
| .factory('TopoPanelService', |
| ['$log', 'FnService', 'PanelService', 'GlyphService', |
| 'FlashService', 'WebSocketService', 'ButtonService', |
| |
| function (_$log_, _fs_, _ps_, _gs_, _flash_, _wss_, _bns_) { |
| $log = _$log_; |
| fs = _fs_; |
| ps = _ps_; |
| gs = _gs_; |
| flash = _flash_; |
| wss = _wss_; |
| bns = _bns_; |
| |
| return { |
| initPanels: initPanels, |
| destroyPanels: destroyPanels, |
| |
| showSummary: showSummary, |
| toggleSummary: toggleSummary, |
| |
| toggleUseDetailsFlag: toggleUseDetailsFlag, |
| displaySingle: displaySingle, |
| displayMulti: displayMulti, |
| addAction: addAction, |
| displayLink: displayLink, |
| displayNothing: displayNothing, |
| displaySomething: displaySomething, |
| |
| hideSummaryPanel: hideSummaryPanel, |
| |
| detailVisible: function () { return detailPanel.isVisible(); }, |
| summaryVisible: function () { return summaryPanel.isVisible(); } |
| }; |
| }]); |
| }()); |