blob: 6bc66d8c28fc5733a9f95d4c8c3b53fc1faa2965 [file] [log] [blame]
/*
* Copyright 2015-present Open Networking Foundation
*
* 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 -- Device View Module
*/
(function () {
'use strict';
// injected refs
var $log, $scope, $loc, fs, mast, ps, wss, is, ns, ks, dps;
// internal state
var detailsPanel,
pStartY,
pHeight,
top,
wSize,
device;
// constants
var topPdg = 28,
ctnrPdg = 24,
scrollSize = 17,
portsTblPdg = 50,
pName = 'device-details-panel',
detailsReq = 'deviceDetailsRequest',
detailsResp = 'deviceDetailsResponse',
nameChangeReq = 'deviceNameChangeRequest',
nameChangeResp = 'deviceNameChangeResponse',
portCols = [
'enabled', 'id', 'speed', 'type', 'elinks_dest', 'name',
],
friendlyPortCols = [
'Enabled', 'ID', 'Speed', 'Type', 'Egress Links', 'Name',
];
var keyBindings = {
esc: [closePanel, 'Close the details panel'],
_helpFormat: ['esc'],
};
function closePanel() {
if (detailsPanel.isVisible()) {
$scope.selId = null;
detailsPanel.hide();
return true;
}
return false;
}
function setUpPanel() {
// var container, closeBtn, tblDiv;
dps.empty();
dps.addContainers();
dps.addCloseButton(closePanel);
var top = dps.top();
var bottom = dps.bottom();
dps.addHeading('dev-icon');
top.append('div').classed('top-content', true);
top.append('hr');
bottom.append('h2').classed('ports-title', true).text('Ports');
bottom.append('table');
}
function friendlyPropsList(details) {
return {
'URI': device.id,
'Type': device.type,
'Master ID': details['masterid'],
'Chassis ID': details['chassid'],
'Vendor': device.mfr,
'H/W Version': device.hw,
'S/W Version': device.sw,
'Protocol': details['protocol'],
'Serial #': device.serial,
'Pipeconf': details['pipeconf'],
};
}
function populateTop(tblDiv, details) {
is.loadEmbeddedIcon(dps.select('.iconDiv'), details._iconid_type, 40);
dps.top().select('h2').text(details.name);
dps.addPropsList(tblDiv, friendlyPropsList(details));
}
function addPortRow(tbody, port) {
var tr = tbody.append('tr');
portCols.forEach(function (col) {
tr.append('td').text(port[col]);
});
}
function populateBottom(table, ports) {
var theader = table.append('thead').append('tr'),
tbody = table.append('tbody'),
tbWidth, tbHeight;
friendlyPortCols.forEach(function (col) {
theader.append('th').text(col);
});
ports.forEach(function (port) {
addPortRow(tbody, port);
});
tbWidth = fs.noPxStyle(tbody, 'width') + scrollSize;
tbHeight = pHeight
- (fs.noPxStyle(detailsPanel.el().select('.top'), 'height')
+ fs.noPxStyle(detailsPanel.el().select('.ports-title'), 'height')
+ portsTblPdg);
table.style({
height: tbHeight + 'px',
width: tbWidth + 'px',
overflow: 'auto',
display: 'block',
});
detailsPanel.width(tbWidth + ctnrPdg);
}
function populateDetails(details) {
var btmTbl, ports;
setUpPanel();
btmTbl = dps.bottom().select('table');
ports = details.ports;
populateTop(dps.select('.top-content'), details);
populateBottom(btmTbl, ports);
detailsPanel.height(pHeight);
}
function respDetailsCb(data) {
$scope.panelData = data.details;
device = data.device;
$scope.$apply();
}
function respNameCb(data) {
if (data.warn) {
$log.warn(data.warn, data.id);
top.select('h2').text(data.id);
}
}
function createDetailsPanel() {
detailsPanel = dps.create(pName, {
width: wSize.width,
margin: 0,
hideMargin: 0,
scope: $scope,
keyBindings: keyBindings,
nameChangeRequest: nameChangeReq,
});
dps.setResponse(detailsResp, respDetailsCb);
$scope.hidePanel = function () { detailsPanel.hide(); };
}
// Sample functions for detail panel creation
function popTop(div) {
$log.debug('populateTop');
// TODO: real work
// div.append(.....);
// div.append(.....);
// div.append(.....);
}
function popMid(div) {
$log.debug('populateMiddle');
// TODO: real work
}
angular.module('ovDevice', [])
.controller('OvDeviceCtrl',
['$log', '$scope', '$location', 'TableBuilderService',
'TableDetailService', 'FnService',
'MastService', 'PanelService', 'WebSocketService', 'IconService',
'NavService', 'KeyService', 'DetailsPanelService',
function (_$log_, _$scope_, _$location_,
tbs, tds, _fs_, _mast_, _ps_, _wss_, _is_, _ns_, _ks_, _dps_) {
var params,
handlers = {};
$log = _$log_;
$scope = _$scope_;
$loc = _$location_;
fs = _fs_;
mast = _mast_;
ps = _ps_;
wss = _wss_;
is = _is_;
ns = _ns_;
ks = _ks_;
dps = _dps_;
params = $loc.search();
$scope.panelData = {};
$scope.flowTip = 'Show flow view for selected device';
$scope.portTip = 'Show port view for selected device';
$scope.groupTip = 'Show group view for selected device';
$scope.meterTip = 'Show meter view for selected device';
// details panel handlers
// handlers[detailsResp] = respDetailsCb;
handlers[nameChangeResp] = respNameCb;
wss.bindHandlers(handlers);
// query for if a certain device needs to be highlighted
if (params.hasOwnProperty('devId')) {
$scope.selId = params['devId'];
wss.sendEvent(detailsReq, { id: $scope.selId });
}
function selCb($event, row) {
if ($scope.selId) {
wss.sendEvent(detailsReq, { id: row.id });
} else {
$scope.hidePanel();
}
$log.debug('Got a click on:', row);
}
tbs.buildTable({
scope: $scope,
tag: 'device',
selCb: selCb,
});
// ==================== for testing for now ===============
// TODO: more than just an example
tds.buildBasePanel({
popTop: popTop,
popMid: popMid,
});
// ==================== for testing for now ===============
$scope.nav = function (path) {
if ($scope.selId) {
ns.navTo(path, { devId: $scope.selId });
}
};
$scope.$on('$destroy', function () {
dps.destroy();
wss.unbindHandlers(handlers);
});
$log.log('OvDeviceCtrl has been created');
}])
.directive('deviceDetailsPanel',
['$rootScope', '$window', '$timeout', 'KeyService',
function ($rootScope, $window, $timeout, ks) {
return function (scope) {
var unbindWatch;
function heightCalc() {
pStartY = fs.noPxStyle(d3.select('.tabular-header'), 'height')
+ mast.mastHeight() + topPdg;
wSize = fs.windowSize(pStartY);
pHeight = wSize.height;
}
function initPanel() {
heightCalc();
createDetailsPanel();
}
// Safari has a bug where it renders the fixed-layout table wrong
// if you ask for the window's size too early
if (scope.onos.browser === 'safari') {
$timeout(initPanel);
} else {
initPanel();
}
// create key bindings to handle panel
ks.keyBindings(keyBindings);
ks.gestureNotes([
['click', 'Select a row to show device details'],
['scroll down', 'See more devices'],
]);
// if the panelData changes
scope.$watch('panelData', function () {
if (!fs.isEmptyObject(scope.panelData)) {
populateDetails(scope.panelData);
detailsPanel.show();
}
});
// if the window size changes
unbindWatch = $rootScope.$watchCollection(
function () {
return {
h: $window.innerHeight,
w: $window.innerWidth,
};
}, function () {
if (!fs.isEmptyObject(scope.panelData)) {
heightCalc();
populateDetails(scope.panelData);
}
}
);
scope.$on('$destroy', function () {
unbindWatch();
ks.unbindKeys();
ps.destroyPanel(pName);
});
};
}]);
}());