GUI -- WIP Device View details panel. Egress Links backend added, updated FnService, added CSS for panel, populates panel with properties and a close button.
Change-Id: Ia510b1e47fecc9140adcb1596c365a4114784b88
diff --git a/web/gui/src/main/webapp/app/view/device/device.js b/web/gui/src/main/webapp/app/view/device/device.js
index cd8d8b0..fbe5dbb 100644
--- a/web/gui/src/main/webapp/app/view/device/device.js
+++ b/web/gui/src/main/webapp/app/view/device/device.js
@@ -21,15 +21,209 @@
(function () {
'use strict';
+ // injected refs
+ var $log, $scope, fs, mast, ps, wss, is;
+
+ // internal state
+ var self,
+ detailsPane,
+ container, top, bottom, closeBtn;
+
+ // constants
+ // TODO: consider having a set y height that all tables start at
+ var h2Pdg = 40,
+ mastPdg = 8,
+ tbodyPdg = 5,
+ cntrPdg = 24,
+ pName = 'device-details-panel',
+ detailsReq = 'deviceDetailsRequest',
+ detailsResp = 'deviceDetailsResponse',
+ propOrder = [
+ 'type', 'masterid', 'chassisid',
+ 'mfr', 'hw', 'sw', 'protocol', 'serial'
+ ],
+ friendlyProps = [
+ 'Type', 'Master ID', 'Chassis ID',
+ 'Vendor', 'H/W Version', 'S/W Version', 'Protocol', 'Serial #'
+ ],
+ portCols = [
+ 'enabled', 'id', 'speed', 'type', 'elinks_dest'
+ ],
+ friendlyPortCols = [
+ 'Enabled', 'ID', 'Speed', 'Type', 'Egress Links'
+ ];
+
+ function setUpPanel() {
+ detailsPane.empty();
+
+ container = detailsPane.append('div').classed('container', true);
+
+ top = container.append('div').classed('top', true);
+ closeBtn = top.append('div').classed('close-btn', true);
+ addCloseBtn(closeBtn);
+ top.append('h2');
+ top.append('table');
+
+ container.append('hr');
+
+ bottom = container.append('div').classed('bottom', true);
+ bottom.append('h2').text('Ports');
+ bottom.append('table');
+ }
+
+ function createDetailsPane() {
+ var headerHeight = h2Pdg + fs.noPxStyle(d3.select('h2'), 'height'),
+ panelTop = headerHeight + tbodyPdg + mast.mastHeight() + mastPdg,
+ wSize = fs.windowSize(panelTop);
+
+ detailsPane = ps.createPanel(pName, {
+ height: wSize.height,
+ width: wSize.width / 2,
+ margin: 0,
+ hideMargin: 0
+ });
+
+ detailsPane.el().style({
+ position: 'absolute',
+ top: panelTop + 'px'
+ });
+
+ setUpPanel();
+
+ detailsPane.hide();
+ }
+
+ function addCloseBtn(div) {
+ is.loadEmbeddedIcon(div, 'appPlus', 30);
+ div.select('g').attr('transform', 'translate(25, 0) rotate(45)');
+ div.on('click', function () {
+ detailsPane.hide();
+ // TODO: deselect the table row when button is clicked
+ //$scope.sel = null;
+ });
+ }
+
+ function populateTopHalf(tbody, details) {
+ top.select('h2').text(details['id']);
+
+ propOrder.forEach(function (prop, i) {
+ addProp(tbody, i, details[prop]);
+ });
+ }
+
+ function populateBottomHalf(table, ports) {
+ var theader = table.append('thead').append('tr'),
+ tbody = table.append('tbody'),
+ tbWidth, tbHeight,
+ scrollSize = 20,
+ btmPdg = 50;
+
+ friendlyPortCols.forEach(function (header) {
+ theader.append('th').html(header);
+ });
+ ports.forEach(function (port) {
+ addPortRow(tbody, port);
+ });
+
+ tbWidth = fs.noPxStyle(tbody, 'width') + scrollSize;
+ tbHeight = detailsPane.height()
+ - (fs.noPxStyle(detailsPane.el().select('.top'), 'height')
+ + fs.noPxStyle(detailsPane.el().select('hr'), 'height')
+ + fs.noPxStyle(detailsPane.el().select('h2'), 'height')
+ + btmPdg);
+
+ table.style({
+ height: tbHeight + 'px',
+ width: tbWidth + 'px',
+ overflow: 'auto',
+ display: 'block'
+ });
+
+ detailsPane.width(tbWidth + cntrPdg);
+ }
+
+ function addProp(tbody, index, value) {
+ var tr = tbody.append('tr');
+
+ function addCell(cls, txt) {
+ tr.append('td').attr('class', cls).html(txt);
+ }
+ addCell('label', friendlyProps[index] + ' :');
+ addCell('value', value);
+ }
+
+ function addPortRow(tbody, port) {
+ var tr = tbody.append('tr');
+
+ portCols.forEach(function (col) {
+ if (col === 'type' || col === 'id') {
+ port[col] = fs.cap(port[col]);
+ }
+ tr.append('td').html(port[col]);
+ });
+ }
+
+ function populateDetails(details) {
+ setUpPanel();
+
+ var toptbody = top.select('table').append('tbody'),
+ btmTable = bottom.select('table'),
+ ports = details.ports;
+
+ populateTopHalf(toptbody, details);
+ populateBottomHalf(btmTable, ports);
+ }
+
+ function respDetailsCb(data) {
+ self.panelData = data['details'];
+ populateDetails(self.panelData);
+ detailsPane.show();
+ }
+
angular.module('ovDevice', [])
.controller('OvDeviceCtrl',
- ['$log', '$scope', 'TableBuilderService',
+ ['$log', '$scope', 'TableBuilderService', 'FnService',
+ 'MastService', 'PanelService', 'WebSocketService', 'IconService',
- function ($log, $scope, tbs) {
+ function (_$log_, _$scope_, tbs, _fs_, _mast_, _ps_, _wss_, _is_) {
+ $log = _$log_;
+ $scope = _$scope_;
+ fs = _fs_;
+ mast = _mast_;
+ ps = _ps_;
+ wss = _wss_;
+ is = _is_;
+ self = this;
+ var handlers = {};
+ self.panelData = [];
+
+ function selCb(row) {
+ // request the server for more information
+ // get the id from the row to request details with
+ if ($scope.sel) {
+ wss.sendEvent(detailsReq, { id: row.id });
+ } else {
+ detailsPane.hide();
+ }
+ $log.debug('Got a click on:', row);
+ }
+
tbs.buildTable({
- self: this,
+ self: self,
scope: $scope,
- tag: 'device'
+ tag: 'device',
+ selCb: selCb
+ });
+
+ createDetailsPane();
+
+ // bind websocket handlers
+ handlers[detailsResp] = respDetailsCb;
+ wss.bindHandlers(handlers);
+
+ $scope.$on('$destroy', function () {
+ ps.destroyPanel(pName);
+ wss.unbindHandlers(handlers);
});
$log.log('OvDeviceCtrl has been created');