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 @@ ...@@ -15,7 +15,7 @@
15 */ 15 */
16 16
17 /* 17 /*
18 - ONOS GUI -- Our own Angular directives defined here. 18 + ONOS GUI -- General Purpose Angular directives defined here.
19 */ 19 */
20 20
21 (function () { 21 (function () {
...@@ -59,5 +59,14 @@ ...@@ -59,5 +59,14 @@
59 }); 59 });
60 } 60 }
61 }; 61 };
62 + }])
63 +
64 + .directive('ngRepeatComplete', [function () {
65 + return function (scope) {
66 + if (scope.$last) {
67 + scope.$emit('ngRepeatComplete');
68 + scope.$broadcast('ngRepeatComplete');
69 + }
70 + };
62 }]); 71 }]);
63 }()); 72 }());
......
...@@ -189,8 +189,9 @@ ...@@ -189,8 +189,9 @@
189 // does NOT use strict object reference equality, 189 // does NOT use strict object reference equality,
190 // instead checks each property individually for equality 190 // instead checks each property individually for equality
191 function containsObj(arr, obj) { 191 function containsObj(arr, obj) {
192 - var i; 192 + var i,
193 - for (i = 0; i < arr.length; i++) { 193 + len = arr.length;
194 + for (i = 0; i < len; i++) {
194 if (sameObjProps(arr[i], obj)) { 195 if (sameObjProps(arr[i], obj)) {
195 return true; 196 return true;
196 } 197 }
......
...@@ -217,37 +217,49 @@ ...@@ -217,37 +217,49 @@
217 function ($log, $parse, $timeout, fs) { 217 function ($log, $parse, $timeout, fs) {
218 218
219 return function (scope, element, attrs) { 219 return function (scope, element, attrs) {
220 - var rowData = $parse(attrs.row)(scope), 220 + var idProp = attrs.idProp,
221 - id = attrs.rowId, 221 + table = d3.select(element[0]),
222 - tr = d3.select(element[0]), 222 + trs, promise;
223 - multi = 'multiRow' in attrs,
224 - promise;
225 -
226 - scope.$watchCollection('changedData', function (newData) {
227 - var multiRows = null;
228 - if (multi) {
229 - // This is a way to identify which rows need to be
230 - // highlighted with the first one. It uses the unique
231 - // identifier as a class selection. If the unique ID
232 - // has invalid characters (like ':') then it won't work.
233 - multiRows = d3.selectAll('.multi-row-' + rowData[id]);
234 - }
235 223
224 + function highlightRows() {
225 + var changedRows = [];
236 function classRows(b) { 226 function classRows(b) {
237 - tr.classed('data-change', b); 227 + if (changedRows.length) {
238 - if (multiRows) { 228 + angular.forEach(changedRows, function (tr) {
239 - multiRows.classed('data-change', b); 229 + tr.classed('data-change', b);
230 + });
240 } 231 }
241 } 232 }
233 + // timeout because 'row-id' was the un-interpolated value
234 + // "{{link.one}}" for example, instead of link.one evaluated
235 + // timeout executes on the next digest -- after evaluation
236 + $timeout(function () {
237 + if (scope.tableData.length) {
238 + trs = table.selectAll('tr');
239 + }
242 240
243 - if (fs.find(rowData[id], newData, id) > -1) { 241 + if (trs && !trs.empty()) {
244 - classRows(true); 242 + trs.each(function () {
243 + var tr = d3.select(this);
244 + if (fs.find(tr.attr('row-id'),
245 + scope.changedData,
246 + idProp) > -1) {
247 + changedRows.push(tr);
248 + }
249 + });
250 + classRows(true);
251 + promise = $timeout(function () {
252 + classRows(false);
253 + }, flashTime);
254 + trs = undefined;
255 + }
256 + });
257 + }
245 258
246 - promise = $timeout(function () { 259 + // new items added:
247 - classRows(false); 260 + scope.$on('ngRepeatComplete', highlightRows);
248 - }, flashTime); 261 + // items changed in existing set:
249 - } 262 + scope.$watchCollection('changedData', highlightRows);
250 - });
251 263
252 scope.$on('$destroy', function () { 264 scope.$on('$destroy', function () {
253 if (promise) { 265 if (promise) {
......
...@@ -60,7 +60,6 @@ ...@@ -60,7 +60,6 @@
60 function respCb(data) { 60 function respCb(data) {
61 o.scope.tableData = data[root]; 61 o.scope.tableData = data[root];
62 onResp && onResp(); 62 onResp && onResp();
63 - o.scope.$apply();
64 63
65 // checks if data changed for row flashing 64 // checks if data changed for row flashing
66 if (!angular.equals(o.scope.tableData, oldTableData)) { 65 if (!angular.equals(o.scope.tableData, oldTableData)) {
...@@ -75,6 +74,7 @@ ...@@ -75,6 +74,7 @@
75 } 74 }
76 angular.copy(o.scope.tableData, oldTableData); 75 angular.copy(o.scope.tableData, oldTableData);
77 } 76 }
77 + o.scope.$apply();
78 } 78 }
79 handlers[resp] = respCb; 79 handlers[resp] = respCb;
80 wss.bindHandlers(handlers); 80 wss.bindHandlers(handlers);
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
51 </div> 51 </div>
52 52
53 <div class="table-body"> 53 <div class="table-body">
54 - <table> 54 + <table onos-flash-changes id-prop="id">
55 <tr ng-if="!tableData.length" class="no-data"> 55 <tr ng-if="!tableData.length" class="no-data">
56 <td colspan="5"> 56 <td colspan="5">
57 No Applications found 57 No Applications found
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
61 <tr ng-repeat="app in tableData track by $index" 61 <tr ng-repeat="app in tableData track by $index"
62 ng-click="selectCallback($event, app)" 62 ng-click="selectCallback($event, app)"
63 ng-class="{selected: app.id === selId}" 63 ng-class="{selected: app.id === selId}"
64 - onos-flash-changes row="{{app}}" row-id="id"> 64 + ng-repeat-complete row-id="{{app.id}}">
65 <td class="table-icon"> 65 <td class="table-icon">
66 <div icon icon-id="{{app._iconid_state}}"></div> 66 <div icon icon-id="{{app._iconid_state}}"></div>
67 </td> 67 </td>
......
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
41 </div> 41 </div>
42 42
43 <div class="table-body"> 43 <div class="table-body">
44 - <table> 44 + <table onos-flash-changes id-prop="id">
45 <tr ng-if="!tableData.length" class="no-data"> 45 <tr ng-if="!tableData.length" class="no-data">
46 <td colspan="5"> 46 <td colspan="5">
47 No Cluster Nodes found 47 No Cluster Nodes found
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
49 </tr> 49 </tr>
50 50
51 <tr ng-repeat="node in tableData track by $index" 51 <tr ng-repeat="node in tableData track by $index"
52 - onos-flash-changes row="{{node}}" row-id="id"> 52 + ng-repeat-complete row-id="{{node.id}}">
53 <td class="table-icon"> 53 <td class="table-icon">
54 <div icon icon-id="{{node._iconid_state}}"></div> 54 <div icon icon-id="{{node._iconid_state}}"></div>
55 </td> 55 </td>
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
45 </div> 45 </div>
46 46
47 <div class="table-body"> 47 <div class="table-body">
48 - <table> 48 + <table onos-flash-changes id-prop="id">
49 <tr ng-if="!tableData.length" class="no-data"> 49 <tr ng-if="!tableData.length" class="no-data">
50 <td colspan="9"> 50 <td colspan="9">
51 No Devices found 51 No Devices found
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
55 <tr ng-repeat="dev in tableData track by $index" 55 <tr ng-repeat="dev in tableData track by $index"
56 ng-click="selectCallback($event, dev)" 56 ng-click="selectCallback($event, dev)"
57 ng-class="{selected: dev.id === selId}" 57 ng-class="{selected: dev.id === selId}"
58 - onos-flash-changes row="{{dev}}" row-id="id"> 58 + ng-repeat-complete row-id="{{dev.id}}">
59 <td class="table-icon"> 59 <td class="table-icon">
60 <div icon icon-id="{{dev._iconid_available}}"></div> 60 <div icon icon-id="{{dev._iconid_available}}"></div>
61 </td> 61 </td>
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
48 </div> 48 </div>
49 49
50 <div class="table-body"> 50 <div class="table-body">
51 - <table> 51 + <table onos-flash-changes id-prop="id">
52 <tr ng-if="!tableData.length" class="no-data"> 52 <tr ng-if="!tableData.length" class="no-data">
53 <td colspan="10"> 53 <td colspan="10">
54 No Flows found 54 No Flows found
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
56 </tr> 56 </tr>
57 57
58 <tr ng-repeat-start="flow in tableData track by $index" 58 <tr ng-repeat-start="flow in tableData track by $index"
59 - onos-flash-changes row="{{flow}}" row-id="id" multi-row> 59 + ng-repeat-complete row-id="{{flow.id}}">
60 <td>{{flow.id}}</td> 60 <td>{{flow.id}}</td>
61 <td>{{flow.appId}}</td> 61 <td>{{flow.appId}}</td>
62 <td>{{flow.groupId}}</td> 62 <td>{{flow.groupId}}</td>
...@@ -68,10 +68,10 @@ ...@@ -68,10 +68,10 @@
68 <td>{{flow.packets}}</td> 68 <td>{{flow.packets}}</td>
69 <td>{{flow.bytes}}</td> 69 <td>{{flow.bytes}}</td>
70 </tr> 70 </tr>
71 - <tr class="multi-row-{{flow.id}}"> 71 + <tr row-id="{{flow.id}}">
72 <td class="selector" colspan="10">{{flow.selector}}</td> 72 <td class="selector" colspan="10">{{flow.selector}}</td>
73 </tr> 73 </tr>
74 - <tr class="multi-row-{{flow.id}}" ng-repeat-end> 74 + <tr row-id="{{flow.id}}" ng-repeat-end>
75 <td class="treatment" colspan="10">{{flow.treatment}}</td> 75 <td class="treatment" colspan="10">{{flow.treatment}}</td>
76 </tr> 76 </tr>
77 </table> 77 </table>
......
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
60 </div> 60 </div>
61 61
62 <div class="table-body"> 62 <div class="table-body">
63 - <table> 63 + <table onos-flash-changes id-prop="id">
64 <tr ng-if="!tableData.length" class="no-data"> 64 <tr ng-if="!tableData.length" class="no-data">
65 <td colspan="6"> 65 <td colspan="6">
66 No Groups found 66 No Groups found
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
68 </tr> 68 </tr>
69 69
70 <tr ng-repeat-start="group in tableData track by $index" 70 <tr ng-repeat-start="group in tableData track by $index"
71 - onos-flash-changes row="{{group}}" row-id="id" multi-row> 71 + ng-repeat-complete row-id="{{group.id}}">
72 <td>{{group.id}}</td> 72 <td>{{group.id}}</td>
73 <td>{{group.app_id}}</td> 73 <td>{{group.app_id}}</td>
74 <td>{{group.state}}</td> 74 <td>{{group.state}}</td>
...@@ -76,7 +76,7 @@ ...@@ -76,7 +76,7 @@
76 <td>{{group.packets}}</td> 76 <td>{{group.packets}}</td>
77 <td>{{group.bytes}}</td> 77 <td>{{group.bytes}}</td>
78 </tr> 78 </tr>
79 - <tr class="multi-row-{{group.id}}" ng-repeat-end> 79 + <tr row-id="{{group.id}}" ng-repeat-end>
80 <td class="buckets" colspan="6" 80 <td class="buckets" colspan="6"
81 ng-bind-html="group.buckets"></td> 81 ng-bind-html="group.buckets"></td>
82 </tr> 82 </tr>
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
26 </div> 26 </div>
27 27
28 <div class="table-body"> 28 <div class="table-body">
29 - <table> 29 + <table onos-flash-changes id-prop="id">
30 <tr ng-if="!tableData.length" class="no-data"> 30 <tr ng-if="!tableData.length" class="no-data">
31 <td colspan="6"> 31 <td colspan="6">
32 No Hosts found 32 No Hosts found
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
34 </tr> 34 </tr>
35 35
36 <tr ng-repeat="host in tableData track by $index" 36 <tr ng-repeat="host in tableData track by $index"
37 - onos-flash-changes row="{{host}}" row-id="id"> 37 + ng-repeat-complete row-id="{{host.id}}">
38 <td class="table-icon"> 38 <td class="table-icon">
39 <div icon icon-id="{{host._iconid_type}}"></div> 39 <div icon icon-id="{{host._iconid_type}}"></div>
40 </td> 40 </td>
......
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
41 </div> 41 </div>
42 42
43 <div class="table-body"> 43 <div class="table-body">
44 - <table> 44 + <table onos-flash-changes id-prop="key">
45 <tr ng-if="!tableData.length" class="no-data"> 45 <tr ng-if="!tableData.length" class="no-data">
46 <td colspan="5"> 46 <td colspan="5">
47 No Intents found 47 No Intents found
...@@ -49,17 +49,17 @@ ...@@ -49,17 +49,17 @@
49 </tr> 49 </tr>
50 50
51 <tr ng-repeat-start="intent in tableData track by $index" 51 <tr ng-repeat-start="intent in tableData track by $index"
52 - onos-flash-changes row="{{intent}}" row-id="key" multi-row> 52 + ng-repeat-complete row-id="{{intent.key}}">
53 <td>{{intent.appId}}</td> 53 <td>{{intent.appId}}</td>
54 <td>{{intent.key}}</td> 54 <td>{{intent.key}}</td>
55 <td>{{intent.type}}</td> 55 <td>{{intent.type}}</td>
56 <td>{{intent.priority}}</td> 56 <td>{{intent.priority}}</td>
57 <td>{{intent.state}}</td> 57 <td>{{intent.state}}</td>
58 </tr> 58 </tr>
59 - <tr class="multi-row-{{intent.key}}"> 59 + <tr row-id="{{intent.key}}">
60 <td class="resources" colspan="5">{{intent.resources}}</td> 60 <td class="resources" colspan="5">{{intent.resources}}</td>
61 </tr> 61 </tr>
62 - <tr class="multi-row-{{intent.key}}" ng-repeat-end> 62 + <tr row-id="{{intent.key}}" ng-repeat-end>
63 <td class="details" colspan="5">{{intent.details}}</td> 63 <td class="details" colspan="5">{{intent.details}}</td>
64 </tr> 64 </tr>
65 </table> 65 </table>
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
42 </div> 42 </div>
43 43
44 <div class="table-body"> 44 <div class="table-body">
45 - <table> 45 + <table onos-flash-changes id-prop="one">
46 <tr ng-if="!tableData.length" class="no-data"> 46 <tr ng-if="!tableData.length" class="no-data">
47 <td colspan="6"> 47 <td colspan="6">
48 No Links found 48 No Links found
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
50 </tr> 50 </tr>
51 51
52 <tr ng-repeat="link in tableData track by $index" 52 <tr ng-repeat="link in tableData track by $index"
53 - onos-flash-changes row="{{link}}" row-id="one"> 53 + ng-repeat-complete row-id="{{link.one}}">
54 <td class="table-icon"> 54 <td class="table-icon">
55 <div icon icon-id="{{link._iconid_state}}"></div> 55 <div icon icon-id="{{link._iconid_state}}"></div>
56 </td> 56 </td>
......
...@@ -42,4 +42,8 @@ ...@@ -42,4 +42,8 @@
42 42
43 #ov-port td { 43 #ov-port td {
44 text-align: right; 44 text-align: right;
45 -}
...\ No newline at end of file ...\ No newline at end of file
45 +}
46 +
47 +#ov-port tr.no-data td {
48 + text-align: center;
49 +}
......
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
62 </div> 62 </div>
63 63
64 <div class="table-body"> 64 <div class="table-body">
65 - <table> 65 + <table onos-flash-changes id-prop="id">
66 <tr ng-if="!tableData.length" class="no-data"> 66 <tr ng-if="!tableData.length" class="no-data">
67 <td colspan="8"> 67 <td colspan="8">
68 No Ports found 68 No Ports found
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
70 </tr> 70 </tr>
71 71
72 <tr ng-repeat="port in tableData track by $index" 72 <tr ng-repeat="port in tableData track by $index"
73 - onos-flash-changes row="{{port}}" row-id="id"> 73 + ng-repeat-complete row-id="{{port.id}}">
74 <td>{{port.id}}</td> 74 <td>{{port.id}}</td>
75 <td>{{port.pkt_rx}}</td> 75 <td>{{port.pkt_rx}}</td>
76 <td>{{port.pkt_tx}}</td> 76 <td>{{port.pkt_tx}}</td>
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
26 </div> 26 </div>
27 27
28 <div class="table-body"> 28 <div class="table-body">
29 - <table> 29 + <table onos-flash-changes id-prop="id">
30 <tr ng-if="!tableData.length" class="no-data"> 30 <tr ng-if="!tableData.length" class="no-data">
31 <td colspan="6"> 31 <td colspan="6">
32 No Settings found 32 No Settings found
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
34 </tr> 34 </tr>
35 35
36 <tr ng-repeat="prop in tableData track by $index" 36 <tr ng-repeat="prop in tableData track by $index"
37 - onos-flash-changes row="{{prop}}" row-id="id"> 37 + ng-repeat-complete row-id="{{prop.id}}">
38 <td>{{prop.component}}</td> 38 <td>{{prop.component}}</td>
39 <td>{{prop.id}}</td> 39 <td>{{prop.id}}</td>
40 <td>{{prop.type}}</td> 40 <td>{{prop.type}}</td>
......