Bri Prebilic Cole

ONOS-2325 - GUI -- Rewrite / bug fix for table row flashing. Multi-rows act like…

… a unit and row flashes when a single new element is added.

Change-Id: I7be876281c0c86b927366223fc87372ea21034ec
......@@ -15,7 +15,7 @@
*/
/*
ONOS GUI -- Our own Angular directives defined here.
ONOS GUI -- General Purpose Angular directives defined here.
*/
(function () {
......@@ -59,5 +59,14 @@
});
}
};
}])
.directive('ngRepeatComplete', [function () {
return function (scope) {
if (scope.$last) {
scope.$emit('ngRepeatComplete');
scope.$broadcast('ngRepeatComplete');
}
};
}]);
}());
......
......@@ -189,8 +189,9 @@
// does NOT use strict object reference equality,
// instead checks each property individually for equality
function containsObj(arr, obj) {
var i;
for (i = 0; i < arr.length; i++) {
var i,
len = arr.length;
for (i = 0; i < len; i++) {
if (sameObjProps(arr[i], obj)) {
return true;
}
......
......@@ -217,37 +217,49 @@
function ($log, $parse, $timeout, fs) {
return function (scope, element, attrs) {
var rowData = $parse(attrs.row)(scope),
id = attrs.rowId,
tr = d3.select(element[0]),
multi = 'multiRow' in attrs,
promise;
scope.$watchCollection('changedData', function (newData) {
var multiRows = null;
if (multi) {
// This is a way to identify which rows need to be
// highlighted with the first one. It uses the unique
// identifier as a class selection. If the unique ID
// has invalid characters (like ':') then it won't work.
multiRows = d3.selectAll('.multi-row-' + rowData[id]);
}
var idProp = attrs.idProp,
table = d3.select(element[0]),
trs, promise;
function highlightRows() {
var changedRows = [];
function classRows(b) {
tr.classed('data-change', b);
if (multiRows) {
multiRows.classed('data-change', b);
if (changedRows.length) {
angular.forEach(changedRows, function (tr) {
tr.classed('data-change', b);
});
}
}
// timeout because 'row-id' was the un-interpolated value
// "{{link.one}}" for example, instead of link.one evaluated
// timeout executes on the next digest -- after evaluation
$timeout(function () {
if (scope.tableData.length) {
trs = table.selectAll('tr');
}
if (fs.find(rowData[id], newData, id) > -1) {
classRows(true);
if (trs && !trs.empty()) {
trs.each(function () {
var tr = d3.select(this);
if (fs.find(tr.attr('row-id'),
scope.changedData,
idProp) > -1) {
changedRows.push(tr);
}
});
classRows(true);
promise = $timeout(function () {
classRows(false);
}, flashTime);
trs = undefined;
}
});
}
promise = $timeout(function () {
classRows(false);
}, flashTime);
}
});
// new items added:
scope.$on('ngRepeatComplete', highlightRows);
// items changed in existing set:
scope.$watchCollection('changedData', highlightRows);
scope.$on('$destroy', function () {
if (promise) {
......
......@@ -60,7 +60,6 @@
function respCb(data) {
o.scope.tableData = data[root];
onResp && onResp();
o.scope.$apply();
// checks if data changed for row flashing
if (!angular.equals(o.scope.tableData, oldTableData)) {
......@@ -75,6 +74,7 @@
}
angular.copy(o.scope.tableData, oldTableData);
}
o.scope.$apply();
}
handlers[resp] = respCb;
wss.bindHandlers(handlers);
......
......@@ -51,7 +51,7 @@
</div>
<div class="table-body">
<table>
<table onos-flash-changes id-prop="id">
<tr ng-if="!tableData.length" class="no-data">
<td colspan="5">
No Applications found
......@@ -61,7 +61,7 @@
<tr ng-repeat="app in tableData track by $index"
ng-click="selectCallback($event, app)"
ng-class="{selected: app.id === selId}"
onos-flash-changes row="{{app}}" row-id="id">
ng-repeat-complete row-id="{{app.id}}">
<td class="table-icon">
<div icon icon-id="{{app._iconid_state}}"></div>
</td>
......
......@@ -41,7 +41,7 @@
</div>
<div class="table-body">
<table>
<table onos-flash-changes id-prop="id">
<tr ng-if="!tableData.length" class="no-data">
<td colspan="5">
No Cluster Nodes found
......@@ -49,7 +49,7 @@
</tr>
<tr ng-repeat="node in tableData track by $index"
onos-flash-changes row="{{node}}" row-id="id">
ng-repeat-complete row-id="{{node.id}}">
<td class="table-icon">
<div icon icon-id="{{node._iconid_state}}"></div>
</td>
......
......@@ -45,7 +45,7 @@
</div>
<div class="table-body">
<table>
<table onos-flash-changes id-prop="id">
<tr ng-if="!tableData.length" class="no-data">
<td colspan="9">
No Devices found
......@@ -55,7 +55,7 @@
<tr ng-repeat="dev in tableData track by $index"
ng-click="selectCallback($event, dev)"
ng-class="{selected: dev.id === selId}"
onos-flash-changes row="{{dev}}" row-id="id">
ng-repeat-complete row-id="{{dev.id}}">
<td class="table-icon">
<div icon icon-id="{{dev._iconid_available}}"></div>
</td>
......
......@@ -48,7 +48,7 @@
</div>
<div class="table-body">
<table>
<table onos-flash-changes id-prop="id">
<tr ng-if="!tableData.length" class="no-data">
<td colspan="10">
No Flows found
......@@ -56,7 +56,7 @@
</tr>
<tr ng-repeat-start="flow in tableData track by $index"
onos-flash-changes row="{{flow}}" row-id="id" multi-row>
ng-repeat-complete row-id="{{flow.id}}">
<td>{{flow.id}}</td>
<td>{{flow.appId}}</td>
<td>{{flow.groupId}}</td>
......@@ -68,10 +68,10 @@
<td>{{flow.packets}}</td>
<td>{{flow.bytes}}</td>
</tr>
<tr class="multi-row-{{flow.id}}">
<tr row-id="{{flow.id}}">
<td class="selector" colspan="10">{{flow.selector}}</td>
</tr>
<tr class="multi-row-{{flow.id}}" ng-repeat-end>
<tr row-id="{{flow.id}}" ng-repeat-end>
<td class="treatment" colspan="10">{{flow.treatment}}</td>
</tr>
</table>
......
......@@ -60,7 +60,7 @@
</div>
<div class="table-body">
<table>
<table onos-flash-changes id-prop="id">
<tr ng-if="!tableData.length" class="no-data">
<td colspan="6">
No Groups found
......@@ -68,7 +68,7 @@
</tr>
<tr ng-repeat-start="group in tableData track by $index"
onos-flash-changes row="{{group}}" row-id="id" multi-row>
ng-repeat-complete row-id="{{group.id}}">
<td>{{group.id}}</td>
<td>{{group.app_id}}</td>
<td>{{group.state}}</td>
......@@ -76,7 +76,7 @@
<td>{{group.packets}}</td>
<td>{{group.bytes}}</td>
</tr>
<tr class="multi-row-{{group.id}}" ng-repeat-end>
<tr row-id="{{group.id}}" ng-repeat-end>
<td class="buckets" colspan="6"
ng-bind-html="group.buckets"></td>
</tr>
......
......@@ -26,7 +26,7 @@
</div>
<div class="table-body">
<table>
<table onos-flash-changes id-prop="id">
<tr ng-if="!tableData.length" class="no-data">
<td colspan="6">
No Hosts found
......@@ -34,7 +34,7 @@
</tr>
<tr ng-repeat="host in tableData track by $index"
onos-flash-changes row="{{host}}" row-id="id">
ng-repeat-complete row-id="{{host.id}}">
<td class="table-icon">
<div icon icon-id="{{host._iconid_type}}"></div>
</td>
......
......@@ -41,7 +41,7 @@
</div>
<div class="table-body">
<table>
<table onos-flash-changes id-prop="key">
<tr ng-if="!tableData.length" class="no-data">
<td colspan="5">
No Intents found
......@@ -49,17 +49,17 @@
</tr>
<tr ng-repeat-start="intent in tableData track by $index"
onos-flash-changes row="{{intent}}" row-id="key" multi-row>
ng-repeat-complete row-id="{{intent.key}}">
<td>{{intent.appId}}</td>
<td>{{intent.key}}</td>
<td>{{intent.type}}</td>
<td>{{intent.priority}}</td>
<td>{{intent.state}}</td>
</tr>
<tr class="multi-row-{{intent.key}}">
<tr row-id="{{intent.key}}">
<td class="resources" colspan="5">{{intent.resources}}</td>
</tr>
<tr class="multi-row-{{intent.key}}" ng-repeat-end>
<tr row-id="{{intent.key}}" ng-repeat-end>
<td class="details" colspan="5">{{intent.details}}</td>
</tr>
</table>
......
......@@ -42,7 +42,7 @@
</div>
<div class="table-body">
<table>
<table onos-flash-changes id-prop="one">
<tr ng-if="!tableData.length" class="no-data">
<td colspan="6">
No Links found
......@@ -50,7 +50,7 @@
</tr>
<tr ng-repeat="link in tableData track by $index"
onos-flash-changes row="{{link}}" row-id="one">
ng-repeat-complete row-id="{{link.one}}">
<td class="table-icon">
<div icon icon-id="{{link._iconid_state}}"></div>
</td>
......
......@@ -42,4 +42,8 @@
#ov-port td {
text-align: right;
}
\ No newline at end of file
}
#ov-port tr.no-data td {
text-align: center;
}
......
......@@ -62,7 +62,7 @@
</div>
<div class="table-body">
<table>
<table onos-flash-changes id-prop="id">
<tr ng-if="!tableData.length" class="no-data">
<td colspan="8">
No Ports found
......@@ -70,7 +70,7 @@
</tr>
<tr ng-repeat="port in tableData track by $index"
onos-flash-changes row="{{port}}" row-id="id">
ng-repeat-complete row-id="{{port.id}}">
<td>{{port.id}}</td>
<td>{{port.pkt_rx}}</td>
<td>{{port.pkt_tx}}</td>
......
......@@ -26,7 +26,7 @@
</div>
<div class="table-body">
<table>
<table onos-flash-changes id-prop="id">
<tr ng-if="!tableData.length" class="no-data">
<td colspan="6">
No Settings found
......@@ -34,7 +34,7 @@
</tr>
<tr ng-repeat="prop in tableData track by $index"
onos-flash-changes row="{{prop}}" row-id="id">
ng-repeat-complete row-id="{{prop.id}}">
<td>{{prop.component}}</td>
<td>{{prop.id}}</td>
<td>{{prop.type}}</td>
......