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
diff --git a/web/gui/src/main/webapp/app/directives.js b/web/gui/src/main/webapp/app/directives.js
index b3c34ab..0b4f495 100644
--- a/web/gui/src/main/webapp/app/directives.js
+++ b/web/gui/src/main/webapp/app/directives.js
@@ -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');
+ }
+ };
}]);
}());
diff --git a/web/gui/src/main/webapp/app/fw/util/fn.js b/web/gui/src/main/webapp/app/fw/util/fn.js
index ad441cd..6fee2bf 100644
--- a/web/gui/src/main/webapp/app/fw/util/fn.js
+++ b/web/gui/src/main/webapp/app/fw/util/fn.js
@@ -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;
}
diff --git a/web/gui/src/main/webapp/app/fw/widget/table.js b/web/gui/src/main/webapp/app/fw/widget/table.js
index ad06205..327aedb 100644
--- a/web/gui/src/main/webapp/app/fw/widget/table.js
+++ b/web/gui/src/main/webapp/app/fw/widget/table.js
@@ -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;
+ var idProp = attrs.idProp,
+ table = d3.select(element[0]),
+ trs, 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]);
- }
-
+ 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) {
diff --git a/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js b/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js
index 7a38feb..c731600 100644
--- a/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js
+++ b/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js
@@ -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);
diff --git a/web/gui/src/main/webapp/app/view/app/app.html b/web/gui/src/main/webapp/app/view/app/app.html
index 8f80a07..0db8d9b 100644
--- a/web/gui/src/main/webapp/app/view/app/app.html
+++ b/web/gui/src/main/webapp/app/view/app/app.html
@@ -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>
diff --git a/web/gui/src/main/webapp/app/view/cluster/cluster.html b/web/gui/src/main/webapp/app/view/cluster/cluster.html
index 27bad4e..68b1b09 100644
--- a/web/gui/src/main/webapp/app/view/cluster/cluster.html
+++ b/web/gui/src/main/webapp/app/view/cluster/cluster.html
@@ -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>
diff --git a/web/gui/src/main/webapp/app/view/device/device.html b/web/gui/src/main/webapp/app/view/device/device.html
index c6f12b2..609423d 100644
--- a/web/gui/src/main/webapp/app/view/device/device.html
+++ b/web/gui/src/main/webapp/app/view/device/device.html
@@ -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>
diff --git a/web/gui/src/main/webapp/app/view/flow/flow.html b/web/gui/src/main/webapp/app/view/flow/flow.html
index d9d3618..1338a89 100644
--- a/web/gui/src/main/webapp/app/view/flow/flow.html
+++ b/web/gui/src/main/webapp/app/view/flow/flow.html
@@ -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>
diff --git a/web/gui/src/main/webapp/app/view/group/group.html b/web/gui/src/main/webapp/app/view/group/group.html
index 5387f34..6f2362e 100644
--- a/web/gui/src/main/webapp/app/view/group/group.html
+++ b/web/gui/src/main/webapp/app/view/group/group.html
@@ -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>
diff --git a/web/gui/src/main/webapp/app/view/host/host.html b/web/gui/src/main/webapp/app/view/host/host.html
index 6298ebd..5103b45 100644
--- a/web/gui/src/main/webapp/app/view/host/host.html
+++ b/web/gui/src/main/webapp/app/view/host/host.html
@@ -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>
diff --git a/web/gui/src/main/webapp/app/view/intent/intent.html b/web/gui/src/main/webapp/app/view/intent/intent.html
index eeaf21e..581d12a 100644
--- a/web/gui/src/main/webapp/app/view/intent/intent.html
+++ b/web/gui/src/main/webapp/app/view/intent/intent.html
@@ -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>
diff --git a/web/gui/src/main/webapp/app/view/link/link.html b/web/gui/src/main/webapp/app/view/link/link.html
index 69a4737..3ed80a5 100644
--- a/web/gui/src/main/webapp/app/view/link/link.html
+++ b/web/gui/src/main/webapp/app/view/link/link.html
@@ -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>
diff --git a/web/gui/src/main/webapp/app/view/port/port.css b/web/gui/src/main/webapp/app/view/port/port.css
index 6639539..7fcfee3 100644
--- a/web/gui/src/main/webapp/app/view/port/port.css
+++ b/web/gui/src/main/webapp/app/view/port/port.css
@@ -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;
+}
diff --git a/web/gui/src/main/webapp/app/view/port/port.html b/web/gui/src/main/webapp/app/view/port/port.html
index d18d883..2a6d59e 100644
--- a/web/gui/src/main/webapp/app/view/port/port.html
+++ b/web/gui/src/main/webapp/app/view/port/port.html
@@ -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>
diff --git a/web/gui/src/main/webapp/app/view/settings/settings.html b/web/gui/src/main/webapp/app/view/settings/settings.html
index b4226f4..0faa1c2 100644
--- a/web/gui/src/main/webapp/app/view/settings/settings.html
+++ b/web/gui/src/main/webapp/app/view/settings/settings.html
@@ -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>