Bri Prebilic Cole

ONOS-1842 - GUI -- Tables have better resizing behavior -- column headers stay a…

…bove their columns and table cell text is constrained to one size.

Change-Id: I89ca7d25d46d895c78c41b8250ce40408fbaba85
......@@ -16,68 +16,80 @@
/* ------ for summary-list tables ------ */
table.summary-list {
margin: 0 20px 16px 12px;
div.summary-list {
margin: 0 20px 16px 10px;
font-size: 10pt;
border-spacing: 0;
}
table.summary-list td.nodata {
div.summary-list table {
border-collapse: collapse;
table-layout: fixed;
empty-cells: show;
margin: 0;
}
div.summary-list div.table-body {
overflow-y: scroll;
}
div.summary-list tr.no-data td {
text-align: center;
font-style: italic;
}
.light table.summary-list tr:nth-child(even) {
.light div.summary-list tr:nth-child(even) {
background-color: #ddd;
}
.light table.summary-list tr:nth-child(odd) {
.light div.summary-list tr:nth-child(odd) {
background-color: #eee;
}
.dark table.summary-list tr:nth-child(even) {
.dark div.summary-list tr:nth-child(even) {
background-color: #333;
}
.dark table.summary-list tr:nth-child(odd) {
.dark div.summary-list tr:nth-child(odd) {
background-color: #444;
}
.light table.summary-list tr.selected {
.light div.summary-list tr.selected {
background-color: deepskyblue;
}
.dark table.summary-list tr.selected {
.dark div.summary-list tr.selected {
background-color: #304860;
}
table.summary-list td,
table.summary-list th {
div.summary-list td {
padding: 6px;
text-align: left;
word-wrap: break-word;
}
table.summary-list th {
div.summary-list .table-header td {
letter-spacing: 0.02em;
cursor: pointer;
font-weight: bold;
}
table.summary-list th:first-child {
div.summary-list .table-header td:first-child {
border-radius: 8px 0 0 0;
}
table.summary-list th:last-child {
div.summary-list .table-header td:last-child {
border-radius: 0 8px 0 0;
}
.light table.summary-list th {
.light div.summary-list .table-header td {
background-color: #bbb;
}
.dark table.summary-list th {
.dark div.summary-list .table-header td {
background-color: #222;
color: #ccc;
}
/* rows are selectable */
table.summary-list td {
div.summary-list .table-body td {
cursor: pointer;
}
.dark table.summary-list td {
.dark div.summary-list td {
color: #ccc;
}
......
......@@ -37,86 +37,68 @@
prevCol = {},
sortIconAPI;
// Functions for creating a fixed header on a table (Angular Directive)
// Functions for creating a scrolling table body with fixed table header
function setElemWidth(elem, size) {
elem.style('width', size + 'px')
function _width(elem, width) {
elem.style('width', width);
}
function setColWidth(th, td, size) {
setElemWidth(th, size);
setElemWidth(td, size);
function defaultSize(table, width) {
var thead = table.select('.table-header').select('table'),
tbody = table.select('.table-body').select('table'),
wpx = width + 'px';
_width(thead, wpx);
_width(tbody, wpx);
}
// count number of headers of
// - assigned width,
// - icon width,
// - and default width
// assumes assigned width is not given to icons
// returns the width of all columns that are not icons
// or have an assigned width
function getDefaultWidth(headers) {
var winWidth = fs.windowSize().width,
iconCols = 0,
regCols = 0,
cstmColWidth = 0;
headers.each(function (d, i) {
var thElement = d3.select(this),
cstmWidth = thElement.attr(colWidth);
if (cstmWidth) {
cstmColWidth += fs.noPx(cstmWidth);
} else if (thElement.classed(tableIcon)) {
iconCols += 1;
} else {
regCols += 1;
}
});
return Math.floor((winWidth - cstmColWidth -
(iconCols * tableIconTdSize)) / regCols);
}
function adjustTable(table, width, height) {
var thead = table.select('.table-header').select('table'),
tbodyDiv = table.select('.table-body'),
tbody = tbodyDiv.select('table'),
cstmWidths = {};
function setTableWidth(t) {
var tHeaders = t.selectAll('th'),
defaultColWidth = getDefaultWidth(tHeaders);
tHeaders.each(function (d, i) {
var thElement = d3.select(this),
tr = t.select('tr:nth-of-type(2)'),
tdElement = tr.select('td:nth-of-type(' + (i + 1) + ')'),
custWidth = thElement.attr(colWidth);
if (custWidth) {
setColWidth(thElement, tdElement, fs.noPx(custWidth));
} else if (thElement.classed(tableIcon)) {
setColWidth(thElement, tdElement, tableIconTdSize);
} else {
setColWidth(thElement, tdElement, defaultColWidth);
}
});
}
function findCstmWidths() {
var headers = thead.selectAll('td');
// get the size of the window and then subtract the extra space at the top
// to get the height of the table
function setTableHeight(thead, tbody) {
var ttlHgt = fs.noPxStyle(d3.select('.tabular-header'), 'height'),
thHgt = fs.noPxStyle(thead, 'height'),
totalHgt = ttlHgt + thHgt + pdg,
tbleHgt = fs.windowSize(mast.mastHeight() + totalHgt).height;
thead.style('display', 'block');
tbody.style({
display: 'block',
height: tbleHgt + 'px',
overflow: 'auto'
});
}
headers.each(function (d, i) {
var h = d3.select(this),
index = i.toString();
if (h.classed(tableIcon)) {
cstmWidths[index] = tableIconTdSize + 'px';
}
if (h.attr(colWidth)) {
cstmWidths[index] = h.attr(colWidth);
}
});
$log.debug('Headers with custom widths: ', cstmWidths);
}
function fixTable(t, th, tb) {
setTableWidth(t);
setTableHeight(th, tb);
function setTdWidths(elem) {
var tds = elem.selectAll('tr:not(.ignore-width)').selectAll('td');
_width(elem, width + 'px');
tds.each(function (d, i) {
var td = d3.select(this),
index = i.toString();
if (cstmWidths.hasOwnProperty(index)) {
_width(td, cstmWidths[index]);
}
});
}
function setHeight(body) {
var h = height - (mast.mastHeight() +
fs.noPxStyle(d3.select('.tabular-header'), 'height') +
fs.noPxStyle(thead, 'height') + pdg);
body.style('height', h + 'px');
}
findCstmWidths();
setTdWidths(thead);
setTdWidths(tbody);
setHeight(tbodyDiv);
cstmWidths = {};
}
// Functions for sorting table rows by header
......@@ -163,40 +145,42 @@
}
angular.module('onosWidget')
.directive('onosFixedHeader', ['$window', 'FnService', 'MastService',
function (_$window_, _fs_, _mast_) {
.directive('onosFixedHeader', ['$log','$window',
'FnService', 'MastService',
function (_$log_, _$window_, _fs_, _mast_) {
return function (scope, element) {
$log = _$log_;
$window = _$window_;
fs = _fs_;
mast = _mast_;
var w = angular.element($window),
table = d3.select(element[0]),
thead = table.select('thead'),
tbody = table.select('tbody'),
canAdjust = false;
scope.$watch(function () {
return {
h: window.innerHeight,
w: window.innerWidth
h: $window.innerHeight,
w: $window.innerWidth
};
}, function (newVal) {
var wsz = fs.windowSize(0, 30);
scope.windowHeight = newVal.h;
scope.windowWidth = newVal.w;
}, function () {
var wsz = fs.windowSize(0, 30),
wWidth = wsz.width,
wHeight = wsz.height;
// default table size in case no data elements
table.style('width', wsz.width + 'px');
if (!scope.tableData.length) {
defaultSize(table, wWidth);
}
scope.$on('LastElement', function () {
// only adjust the table once it's completely loaded
fixTable(table, thead, tbody);
adjustTable(table, wWidth, wHeight);
canAdjust = true;
});
if (canAdjust) {
fixTable(table, thead, tbody);
adjustTable(table, wWidth, wHeight);
}
}, true);
......@@ -215,16 +199,16 @@
link: function (scope, element) {
$log = _$log_;
is = _is_;
var table = d3.select(element[0]);
var header = d3.select(element[0]);
sortIconAPI = is.sortIcons();
// when a header is clicked, change its icon tag
// when a header is clicked, change its sort direction
// and get sorting order to send to the server.
table.selectAll('th').on('click', function () {
var thElem = d3.select(this);
header.selectAll('td').on('click', function () {
var col = d3.select(this);
if (thElem.attr('sortable') === '') {
updateSortDirection(thElem);
if (col.attr('sortable') === '') {
updateSortDirection(col);
scope.ctrlCallback({
requestParams: sortRequestParams()
});
......@@ -234,9 +218,9 @@
};
}])
.factory('TableService', ['$log', 'IconService',
.factory('TableService', ['IconService',
function ($log, is) {
function (is) {
sortIconAPI = is.sortIcons();
return {
......
......@@ -25,7 +25,6 @@
// example params to buildTable:
// {
// self: this, <- controller object
// scope: $scope, <- controller scope
// tag: 'device', <- table identifier
// selCb: selCb <- row selection callback (optional)
......@@ -43,10 +42,10 @@
resp = o.tag + 'DataResponse',
onSel = fs.isF(o.selCb);
o.self.tableData = [];
o.scope.tableData = [];
function respCb(data) {
o.self.tableData = data[root];
o.scope.tableData = data[root];
o.scope.$apply();
}
......
<!-- app partial HTML -->
<div id="ov-app">
<div class="tabular-header">
<h2>Applications ({{ctrl.tableData.length}} total)</h2>
<h2>Applications ({{tableData.length}} total)</h2>
<div class="ctrl-btns">
<div class="refresh active"
icon icon-size="36" icon-id="refresh"
......@@ -19,39 +19,44 @@
</form>
</div>
<table class="summary-list"
onos-fixed-header
onos-sortable-header
sort-callback="sortCallback(requestParams)">
<thead>
<tr>
<th colId="state" class="table-icon" sortable></th>
<th colId="id" sortable>App ID </th>
<th colId="version" sortable>Version </th>
<th colId="origin" sortable>Origin </th>
<th colId="desc" col-width="640px">Description </th>
</tr>
</thead>
<div class="summary-list" onos-fixed-header>
<tbody>
<tr ng-hide="ctrl.tableData.length">
<td class="nodata" colspan="5">
No Applications found
</td>
</tr>
<div class="table-header"
onos-sortable-header sort-callback="sortCallback(requestParams)">
<table>
<tr>
<td colId="state" class="table-icon" sortable></td>
<td colId="id" sortable>App ID </td>
<td colId="version" sortable>Version </td>
<td colId="origin" sortable>Origin </td>
<td colId="desc" col-width="475px">Description </td>
</tr>
</table>
</div>
<div class="table-body">
<table>
<tr ng-hide="tableData.length" class="no-data ignore-width">
<td colspan="5">
No Applications found
</td>
</tr>
<tr ng-repeat="app in tableData"
ng-click="selectCallback($event, app)"
ng-class="{selected: app === sel}"
ng-repeat-done>
<td class="table-icon">
<div icon icon-id="{{app._iconid_state}}"></div>
</td>
<td>{{app.id}}</td>
<td>{{app.version}}</td>
<td>{{app.origin}}</td>
<td>{{app.desc}}</td>
</tr>
</table>
</div>
</div>
<tr ng-repeat="app in ctrl.tableData"
ng-click="selectCallback($event, app)"
ng-class="{selected: app === sel}"
ng-repeat-done>
<td class="table-icon">
<div icon icon-id="{{app._iconid_state}}"></div>
</td>
<td>{{app.id}}</td>
<td>{{app.version}}</td>
<td>{{app.origin}}</td>
<td>{{app.desc}}</td>
</tr>
</tbody>
</table>
</div>
......
......@@ -71,7 +71,6 @@
d3.select('#app-deactivate').on('click', function () { appAction('deactivate'); });
tbs.buildTable({
self: this,
scope: $scope,
tag: 'app',
selCb: selCb
......
......@@ -17,7 +17,7 @@
<!-- Cluster partial HTML -->
<div id="ov-cluster">
<div class="tabular-header">
<h2>Cluster Nodes ({{ctrl.tableData.length}} total)</h2>
<h2>Cluster Nodes ({{tableData.length}} total)</h2>
<div class="ctrl-btns">
<div class="refresh active"
icon icon-size="36" icon-id="refresh"
......@@ -25,37 +25,42 @@
</div>
</div>
<table class="summary-list"
onos-fixed-header
onos-sortable-header
sort-callback="sortCallback(requestParams)">
<thead>
<tr>
<th colId="_iconid_state" class="table-icon" sortable></th>
<th colId="id" sortable>ID </th>
<th colId="ip" sortable>IP Address </th>
<th colId="tcp" sortable>TCP Port </th>
<th colId="updated" sortable>Last Updated </th>
</tr>
</thead>
<div class="summary-list" onos-fixed-header>
<tbody>
<tr ng-hide="ctrl.tableData.length">
<td class="nodata" colspan="5">
No Cluster Nodes found
</td>
</tr>
<div class="table-header"
onos-sortable-header sort-callback="sortCallback(requestParams)">
<table>
<tr>
<td colId="_iconid_state" class="table-icon" sortable></td>
<td colId="id" sortable>ID </td>
<td colId="ip" sortable>IP Address </td>
<td colId="tcp" sortable>TCP Port </td>
<td colId="updated" sortable>Last Updated </td>
</tr>
</table>
</div>
<div class="table-body">
<table>
<tr ng-hide="tableData.length" class="no-data ignore-width">
<td colspan="5">
No Cluster Nodes found
</td>
</tr>
<tr ng-repeat="node in tableData"
ng-repeat-done>
<td class="table-icon">
<div icon icon-id="{{node._iconid_state}}"></div>
</td>
<td>{{node.id}}</td>
<td>{{node.ip}}</td>
<td>{{node.tcp}}</td>
<td>{{node.updated}}</td>
</tr>
</table>
</div>
</div>
<tr ng-repeat="node in ctrl.tableData"
ng-repeat-done>
<td class="table-icon">
<div icon icon-id="{{node._iconid_state}}"></div>
</td>
<td>{{node.id}}</td>
<td>{{node.ip}}</td>
<td>{{node.tcp}}</td>
<td>{{node.updated}}</td>
</tr>
</tbody>
</table>
</div>
......
......@@ -27,7 +27,6 @@
function ($log, $scope, ts, tbs) {
tbs.buildTable({
self: this,
scope: $scope,
tag: 'cluster'
});
......
<!-- Device partial HTML -->
<div id="ov-device">
<div class="tabular-header">
<h2>Devices ({{ctrl.tableData.length}} total)</h2>
<h2>Devices ({{tableData.length}} total)</h2>
<div class="ctrl-btns">
<div class="refresh active"
icon icon-size="36" icon-id="refresh"
......@@ -9,49 +9,54 @@
</div>
</div>
<table class="summary-list"
onos-fixed-header
onos-sortable-header
sort-callback="sortCallback(requestParams)">
<thead>
<tr>
<th colId="available" class="table-icon" sortable></th>
<th colId="type" class="table-icon" sortable></th>
<th colId="id" sortable>Device ID </th>
<th colId="masterid" sortable>Master Instance </th>
<th colId="num_ports" sortable>Ports </th>
<th colId="mfr" sortable>Vendor </th>
<th colId="hw" sortable>H/W Version </th>
<th colId="sw" sortable>S/W Version </th>
<th colId="protocol" sortable>Protocol </th>
</tr>
</thead>
<div class="summary-list" onos-fixed-header>
<tbody>
<tr ng-hide="ctrl.tableData.length">
<td class="nodata" colspan="9">
No Devices found
</td>
</tr>
<div class="table-header"
onos-sortable-header sort-callback="sortCallback(requestParams)">
<table>
<tr>
<td colId="available" class="table-icon" sortable></td>
<td colId="type" class="table-icon" sortable></td>
<td colId="id" sortable>Device ID </td>
<td colId="masterid" sortable>Master Instance </td>
<td colId="num_ports" sortable>Ports </td>
<td colId="mfr" sortable>Vendor </td>
<td colId="hw" sortable>H/W Version </td>
<td colId="sw" sortable>S/W Version </td>
<td colId="protocol" sortable>Protocol </td>
</tr>
</table>
</div>
<div class="table-body">
<table>
<tr ng-hide="tableData.length" class="no-data ignore-width">
<td colspan="9">
No Devices found
</td>
</tr>
<tr ng-repeat="dev in tableData"
ng-click="selectCallback($event, dev)"
ng-class="{selected: dev === sel}"
ng-repeat-done>
<td class="table-icon">
<div icon icon-id="{{dev._iconid_available}}"></div>
</td>
<td class="table-icon">
<div icon icon-id="{{dev._iconid_type}}"></div>
</td>
<td>{{dev.id}}</td>
<td>{{dev.masterid}}</td>
<td>{{dev.num_ports}}</td>
<td>{{dev.mfr}}</td>
<td>{{dev.hw}}</td>
<td>{{dev.sw}}</td>
<td>{{dev.protocol}}</td>
</tr>
</table>
</div>
</div>
<tr ng-repeat="dev in ctrl.tableData"
ng-click="selectCallback($event, dev)"
ng-class="{selected: dev === sel}"
ng-repeat-done>
<td class="table-icon">
<div icon icon-id="{{dev._iconid_available}}"></div>
</td>
<td class="table-icon">
<div icon icon-id="{{dev._iconid_type}}"></div>
</td>
<td>{{dev.id}}</td>
<td>{{dev.masterid}}</td>
<td>{{dev.num_ports}}</td>
<td>{{dev.mfr}}</td>
<td>{{dev.hw}}</td>
<td>{{dev.sw}}</td>
<td>{{dev.protocol}}</td>
</tr>
</tbody>
</table>
</div>
......
......@@ -25,8 +25,7 @@
var $log, $scope, fs, mast, ps, wss, is, bns, ns, ttip;
// internal state
var self,
detailsPanel,
var detailsPanel,
pStartY, pHeight,
top, bottom, iconDiv,
wSize, selRow;
......@@ -183,8 +182,8 @@
}
function respDetailsCb(data) {
self.panelData = data.details;
populateDetails(self.panelData);
$scope.panelData = data.details;
populateDetails($scope.panelData);
detailsPanel.show();
}
......@@ -219,9 +218,8 @@
bns = _bns_;
ns = _ns_;
ttip = _ttip_;
self = this;
var handlers = {};
self.panelData = [];
$scope.panelData = [];
pStartY = fs.noPxStyle(d3.select('.tabular-header'), 'height')
+ mast.mastHeight() + topPdg;
wSize = fs.windowSize(pStartY);
......@@ -238,7 +236,6 @@
}
tbs.buildTable({
self: self,
scope: $scope,
tag: 'device',
selCb: selCb
......
......@@ -50,4 +50,5 @@
#ov-flow td.selector,
#ov-flow td.treatment {
padding-left: 36px;
opacity: 0.65;
}
\ No newline at end of file
......
......@@ -2,8 +2,8 @@
<div id="ov-flow">
<div class="tabular-header">
<h2>
Flows for Device {{ctrl.devId || "(No device selected)"}}
({{ctrl.tableData.length}} total)
Flows for Device {{devId || "(No device selected)"}}
({{tableData.length}} total)
</h2>
<div class="ctrl-btns">
<div class="refresh active"
......@@ -12,46 +12,52 @@
</div>
</div>
<table class="summary-list"
onos-fixed-header
onos-sortable-header
sort-callback="sortCallback(requestParams)">
<thead>
<tr>
<th colId="id" sortable>Flow ID </th>
<th colId="appId" sortable>App ID </th>
<th colId="groupId" sortable>Group ID </th>
<th colId="tableId" sortable>Table ID </th>
<th colId="priority" sortable>Priority </th>
<th colId="timeout" sortable>Timeout </th>
<th colId="permanent" sortable>Permanent </th>
<th colId="state" sortable>State </th>
</tr>
</thead>
<div class="summary-list" onos-fixed-header>
<tbody>
<tr ng-hide="ctrl.tableData.length">
<td class="nodata" colspan="8">
No Flows found
</td>
</tr>
<div class="table-header"
onos-sortable-header sort-callback="sortCallback(requestParams)">
<table>
<tr>
<td colId="id" col-width="180px" sortable>Flow ID </td>
<td colId="appId" sortable>App ID </td>
<td colId="groupId" sortable>Group ID </td>
<td colId="tableId" sortable>Table ID </td>
<td colId="priority" sortable>Priority </td>
<td colId="timeout" sortable>Timeout </td>
<td colId="permanent" sortable>Permanent </td>
<td colId="state" sortable>State </td>
</tr>
</table>
</div>
<div class="table-body">
<table>
<tr ng-hide="tableData.length" class="no-data ignore-width">
<td colspan="8">
No Flows found
</td>
</tr>
<tr ng-repeat-start="flow in tableData">
<td>{{flow.id}}</td>
<td>{{flow.appId}}</td>
<td>{{flow.groupId}}</td>
<td>{{flow.tableId}}</td>
<td>{{flow.priority}}</td>
<td>{{flow.timeout}}</td>
<td>{{flow.permanent}}</td>
<td>{{flow.state}}</td>
</tr>
<tr class="ignore-width">
<td class="selector" colspan="8">{{flow.selector}}</td>
</tr>
<tr class="ignore-width"
ng-repeat-end ng-repeat-done>
<td class="treatment" colspan="8">{{flow.treatment}}</td>
</tr>
</table>
</div>
</div>
<tr ng-repeat-start="flow in ctrl.tableData">
<td>{{flow.id}}</td>
<td>{{flow.appId}}</td>
<td>{{flow.groupId}}</td>
<td>{{flow.tableId}}</td>
<td>{{flow.priority}}</td>
<td>{{flow.timeout}}</td>
<td>{{flow.permanent}}</td>
<td>{{flow.state}}</td>
</tr>
<tr>
<td class="selector" colspan="8">{{flow.selector}}</td>
</tr>
<tr ng-repeat-end ng-repeat-done>
<td class="treatment" colspan="8">{{flow.treatment}}</td>
</tr>
</tbody>
</table>
</div>
......
......@@ -30,8 +30,7 @@
'FnService', 'TableService', 'TableBuilderService',
function (_$log_, _$scope_, _$location_, _fs_, _ts_, _tbs_) {
var self = this,
params;
var params;
$log = _$log_;
$scope = _$scope_;
$location = _$location_;
......@@ -41,11 +40,10 @@
params = $location.search();
if (params.hasOwnProperty('devId')) {
self.devId = params['devId'];
$scope.devId = params['devId'];
}
tbs.buildTable({
self: self,
scope: $scope,
tag: 'flow',
query: params
......
<!-- Host partial HTML -->
<div id="ov-host">
<div class="tabular-header">
<h2>Hosts ({{ctrl.tableData.length}} total)</h2>
<h2>Hosts ({{tableData.length}} total)</h2>
<div class="ctrl-btns">
<div class="refresh active"
icon icon-size="36" icon-id="refresh"
......@@ -9,39 +9,44 @@
</div>
</div>
<table class="summary-list"
onos-fixed-header
onos-sortable-header
sort-callback="sortCallback(requestParams)">
<thead>
<tr>
<th colId="type" class="table-icon" sortable></th>
<th colId="id" sortable>Host ID </th>
<th colId="mac" sortable>MAC Address </th>
<th colId="vlan" sortable>VLAN ID </th>
<th colId="ips" sortable>IP Addresses </th>
<th colId="location" sortable>Location </th>
</tr>
</thead>
<div class="summary-list" onos-fixed-header>
<tbody>
<tr ng-hide="ctrl.tableData.length">
<td class="nodata" colspan="6">
No Hosts found
</td>
</tr>
<div class="table-header"
onos-sortable-header sort-callback="sortCallback(requestParams)">
<table>
<tr>
<td colId="type" class="table-icon" sortable></td>
<td colId="id" sortable>Host ID </td>
<td colId="mac" sortable>MAC Address </td>
<td colId="vlan" sortable>VLAN ID </td>
<td colId="ips" sortable>IP Addresses </td>
<td colId="location" sortable>Location </td>
</tr>
</table>
</div>
<div class="table-body">
<table>
<tr ng-hide="tableData.length" class="no-data ignore-width">
<td colspan="6">
No Hosts found
</td>
</tr>
<tr ng-repeat="host in tableData"
ng-repeat-done>
<td class="table-icon">
<div icon icon-id="{{host._iconid_type}}"></div>
</td>
<td>{{host.id}}</td>
<td>{{host.mac}}</td>
<td>{{host.vlan}}</td>
<td>{{host.ips}}</td>
<td>{{host.location}}</td>
</tr>
</table>
</div>
</div>
<tr ng-repeat="host in ctrl.tableData"
ng-repeat-done>
<td class="table-icon">
<div icon icon-id="{{host._iconid_type}}"></div>
</td>
<td>{{host.id}}</td>
<td>{{host.mac}}</td>
<td>{{host.vlan}}</td>
<td>{{host.ips}}</td>
<td>{{host.location}}</td>
</tr>
</tbody>
</table>
</div>
......
......@@ -27,7 +27,6 @@
function ($log, $scope, ts, tbs) {
tbs.buildTable({
self: this,
scope: $scope,
tag: 'host'
});
......@@ -37,7 +36,7 @@
ts.resetSortIcons();
$scope.sortCallback();
};
$log.log('OvHostCtrl has been created');
}]);
}());
......
......@@ -50,4 +50,5 @@
#ov-intent td.resources,
#ov-intent td.details {
padding-left: 36px;
opacity: 0.65;
}
......
......@@ -17,45 +17,51 @@
<!-- Intent partial HTML -->
<div id="ov-intent">
<div class="tabular-header">
<h2>Intents ({{ctrl.tableData.length}} total)</h2>
<h2>Intents ({{tableData.length}} total)</h2>
<div class="ctrl-btns">
<div class="refresh active"
icon icon-size="36" icon-id="refresh"
ng-click="refresh()"></div>
</div>
</div>
<table class="summary-list"
onos-fixed-header
onos-sortable-header
sort-callback="sortCallback(requestParams)">
<thead>
<tr>
<th colId="appId" sortable>Application ID </th>
<th colId="key" sortable>Key </th>
<th colId="type" sortable>Type </th>
<th colId="priority" sortable>Priority </th>
</tr>
</thead>
<tbody>
<tr ng-hide="ctrl.tableData.length">
<td class="nodata" colspan="4">
No Intents found
</td>
</tr>
<div class="summary-list" onos-fixed-header>
<div class="table-header"
onos-sortable-header sort-callback="sortCallback(requestParams)">
<table>
<tr>
<td colId="appId" sortable>Application ID </td>
<td colId="key" sortable>Key </td>
<td colId="type" sortable>Type </td>
<td colId="priority" sortable>Priority </td>
</tr>
</table>
</div>
<div class="table-body">
<table>
<tr ng-hide="tableData.length" class="no-data ignore-width">
<td colspan="4">
No Intents found
</td>
</tr>
<tr ng-repeat-start="intent in tableData">
<td>{{intent.appId}}</td>
<td>{{intent.key}}</td>
<td>{{intent.type}}</td>
<td>{{intent.priority}}</td>
</tr>
<tr>
<td class="resources" colspan="4">{{intent.resources}}</td>
</tr>
<tr ng-repeat-end ng-repeat-done>
<td class="details" colspan="4">{{intent.details}}</td>
</tr>
</table>
</div>
</div>
<tr ng-repeat-start="intent in ctrl.tableData">
<td>{{intent.appId}}</td>
<td>{{intent.key}}</td>
<td>{{intent.type}}</td>
<td>{{intent.priority}}</td>
</tr>
<tr>
<td class="resources" colspan="4">{{intent.resources}}</td>
</tr>
<tr ng-repeat-end ng-repeat-done>
<td class="details" colspan="4">{{intent.details}}</td>
</tr>
</tbody>
</table>
</div>
......
......@@ -27,7 +27,6 @@
function ($log, $scope, ts, tbs) {
tbs.buildTable({
self: this,
scope: $scope,
tag: 'intent'
});
......
......@@ -17,7 +17,7 @@
<!-- Link partial HTML -->
<div id="ov-link">
<div class="tabular-header">
<h2>Links ({{ctrl.tableData.length}} total)</h2>
<h2>Links ({{tableData.length}} total)</h2>
<div class="ctrl-btns">
<div class="refresh active"
icon icon-size="36" icon-id="refresh"
......@@ -25,39 +25,44 @@
</div>
</div>
<table class="summary-list"
onos-fixed-header
onos-sortable-header
sort-callback="sortCallback(requestParams)">
<thead>
<tr>
<th colId="_iconid_state" class="table-icon" sortable></th>
<th colId="one" sortable>Port 1 </th>
<th colId="two" sortable>Port 2 </th>
<th colId="type" sortable>Type </th>
<th colId="direction" sortable>Direction </th>
<th colId="durable" sortable>Durable </th>
</tr>
</thead>
<div class="summary-list" onos-fixed-header>
<tbody>
<tr ng-hide="ctrl.tableData.length">
<td class="nodata" colspan="6">
No Links found
</td>
</tr>
<div class="table-header"
onos-sortable-header sort-callback="sortCallback(requestParams)">
<table>
<tr>
<td colId="_iconid_state" class="table-icon" sortable></td>
<td colId="one" sortable>Port 1 </td>
<td colId="two" sortable>Port 2 </td>
<td colId="type" sortable>Type </td>
<td colId="direction" sortable>Direction </td>
<td colId="durable" sortable>Durable </td>
</tr>
</table>
</div>
<div class="table-body">
<table>
<tr ng-hide="tableData.length" class="no-data ignore-width">
<td colspan="6">
No Links found
</td>
</tr>
<tr ng-repeat="link in tableData"
ng-repeat-done>
<td class="table-icon">
<div icon icon-id="{{link._iconid_state}}"></div>
</td>
<td>{{link.one}}</td>
<td>{{link.two}}</td>
<td>{{link.type}}</td>
<td>{{link.direction}}</td>
<td>{{link.durable}}</td>
</tr>
</table>
</div>
</div>
<tr ng-repeat="link in ctrl.tableData"
ng-repeat-done>
<td class="table-icon">
<div icon icon-id="{{link._iconid_state}}"></div>
</td>
<td>{{link.one}}</td>
<td>{{link.two}}</td>
<td>{{link.type}}</td>
<td>{{link.direction}}</td>
<td>{{link.durable}}</td>
</tr>
</tbody>
</table>
</div>
......
......@@ -27,7 +27,6 @@
function ($log, $scope, ts, tbs) {
tbs.buildTable({
self: this,
scope: $scope,
tag: 'link'
});
......@@ -37,7 +36,7 @@
ts.resetSortIcons();
$scope.sortCallback();
};
$log.log('OvLinkCtrl has been created');
}]);
}());
......
......@@ -48,7 +48,6 @@ describe('factory: fw/widget/tableBuilder.js', function () {
beforeEach(function () {
mockObj = {
self: {},
scope: $rootScope.$new(),
tag: 'foo',
selCb: mockSelCb
......@@ -78,10 +77,10 @@ describe('factory: fw/widget/tableBuilder.js', function () {
});
it('should set tableData', function () {
expect(mockObj.self.tableData).not.toBeDefined();
expect(mockObj.scope.tableData).not.toBeDefined();
tbs.buildTable(mockObj);
expect(fs.isA(mockObj.self.tableData)).toBeTruthy();
expect(mockObj.self.tableData.length).toBe(0);
expect(fs.isA(mockObj.scope.tableData)).toBeTruthy();
expect(mockObj.scope.tableData.length).toBe(0);
});
it('should unbind handlers on destroyed scope', function () {
......