github.com/justinjmoses/evergreen@v0.0.0-20170530173719-1d50e381ff0d/public/static/js/grid.js (about) 1 mciModule.controller('VersionMatrixController', function($scope, $window, $location, $filter) { 2 $scope.baseVersion = $window.baseVersion; 3 $scope.gridCells = $window.gridCells; 4 $scope.revisionFailures = $window.revisionFailures; 5 $scope.allVersions = $window.allVersions; 6 $scope.userTz = $window.userTz; 7 $scope.baseRef = $window.baseRef; 8 9 $scope.consts = { recentFailuresView: "RF", 10 gridView: "GV", 11 taskFailuresView: "task", 12 testFailuresView: "test", 13 variantFailuresView: "variant", 14 revisionFailuresView: "revision", 15 numFailures: "NF", 16 nameSort: "NS", 17 revisionSort: "RS", 18 } 19 20 $scope.taskFailures = []; 21 $scope.testFailures = []; 22 $scope.variantFailures = []; 23 $scope.revisionFailures = []; 24 $scope.currentFailureView = $scope.consts.taskFailuresView; 25 $scope.sortBy = $scope.consts.numFailures; 26 27 $scope.testHeaders = [ 28 {name: "Task", by: "task", order: false}, 29 {name : "Variant", by: "variant", order: false} 30 ] 31 32 $scope.taskHeaders = [ 33 {name:"Test", by: "test", order: false}, 34 {name : "Variant", by: "variant", order: false} 35 ] 36 37 $scope.variantHeaders = [ 38 {name: "Task", by: "task", order: false}, 39 {name:"Test", by: "test", order: false} 40 ] 41 42 $scope.revisionHeaders = [ 43 {name: "Task", by: "task", order: false}, 44 {name:"Test", by: "test", order: false}, 45 {name: "Variant", by:"variant", order: false}, 46 ] 47 48 $scope.currentHeaders = $scope.taskHeaders; 49 50 $scope.widthPercentage = function(){ 51 return 96/($scope.currentHeaders.length) 52 } 53 54 $scope.selectedHeader = {}; 55 56 $scope.setSelectedHeader = function(headerField) { 57 if ($scope.selectedHeader.name == headerField.name) { 58 $scope.selectedHeader.order = !$scope.selectedHeader.order; 59 } else { 60 $scope.selectedHeader = headerField; 61 $scope.selectedHeader.order = false; 62 } 63 }; 64 65 $scope.selectedClass = function(headerField) { 66 var newIcon = 'fa-sort'; 67 if (headerField.name == $scope.selectedHeader.name) { 68 newIcon = 'fa-sort-up'; 69 if ($scope.selectedHeader.order) { 70 newIcon = 'fa-sort-down'; 71 } 72 } 73 return newIcon; 74 } 75 76 // If a tab name is specified in the URL, parse it out and set the tab 77 // name in the scope so that the correct tab is open when the page loads. 78 var hash = $location.hash(); 79 var path = $location.path(); 80 81 if (path && (path.substring(1) != "")) { 82 $scope.tab = path.substring(1); 83 } else if (hash) { 84 $scope.tab = hash; 85 } else { 86 $scope.tab = $scope.consts.recentFailuresView; 87 } 88 89 $scope.getTab = function() { 90 return $scope.tab; 91 } 92 93 $scope.getTab = function() { 94 return $scope.tab; 95 } 96 97 $scope.setTab = function(tabnum) { 98 $scope.tab = tabnum; 99 setTimeout(function() { 100 $location.hash('' + $scope.tab); 101 $scope.$apply(); 102 }, 0) 103 } 104 105 // to be able to toggle hiding and showing individual subtables 106 $scope.toggleView = function(index) { 107 $scope.currentFailures[index].hidden = !$scope.currentFailures[index].hidden; 108 } 109 110 $scope.getToggleClass = function(hidden) { 111 return hidden ? "fa-caret-right" : "fa-caret-down"; 112 } 113 114 // expand all of the current failures 115 $scope.expandAll = function() { 116 for (var i in $scope.currentFailures) { 117 $scope.currentFailures[i].hidden = false; 118 } 119 } 120 121 // collapse all of the current failures 122 $scope.collapseAll = function() { 123 for(var i in $scope.currentFailures) { 124 $scope.currentFailures[i].hidden = true; 125 } 126 } 127 128 //variable/function to handle expanding the header message 129 $scope.showFullMessage = false; 130 $scope.flipExpand = function() { 131 $scope.showFullMessage = !$scope.showFullMessage; 132 }; 133 134 $scope.setSort = function(sort) { 135 $scope.sortBy = sort; 136 if (sort == $scope.consts.numFailures){ 137 $scope.sortByFailures(); 138 } else if( sort == $scope.consts.nameSort) { 139 $scope.sortByName(); 140 } else { 141 $scope.sortByRevisionOrder(); 142 } 143 } 144 145 $scope.setSubSort = function(headerField, groupingField, ordering){ 146 var subGroup = $scope.currentFailures[groupingField]; 147 subGroup.sort(function(a,b){ 148 if (a[headerField] < b[headerField]) { 149 return 1; 150 } else if (a[headerField] > b[headerField]) { 151 return -1; 152 } else { 153 return 0; 154 } 155 }); 156 $scope.currentFailures[groupingField] = subGroup; 157 } 158 159 $scope.getHeaderVal = function(fields, index) { 160 return fields[$scope.currentHeaders[index].by]; 161 } 162 163 // sort by failures takes the current failures and sorts them on the number 164 $scope.sortByFailures = function(){ 165 $scope.currentFailures.sort(function(a,b){ 166 if (a.fields.length < b.fields.length) { 167 return 1; 168 } else if (a.fields.length > b.fields.length) { 169 return -1; 170 } else { 171 return 0; 172 } 173 }) 174 } 175 176 // sort by the name of the field 177 $scope.sortByName = function(){ 178 $scope.currentFailures.sort(function(a,b) { 179 if (a.groupingField < b.groupingField) { 180 return -1; 181 } else if (a.groupingField > b.groupingField) { 182 return 1 ; 183 } else { 184 return 0; 185 } 186 }); 187 } 188 189 190 $scope.grid = {}; 191 $scope.taskNames = []; 192 $scope.buildVariants = []; 193 194 $scope.groupByTask = function(){ 195 // group the failures by task and test 196 var failures = {}; 197 $scope.numTestFailures = 0; 198 for (var i = 0; i < $window.failures.length; i++) { 199 var failure = $window.failures[i]; 200 var identifier = failure.identifier; 201 identifier.test = $filter('endOfPath')(identifier.test); 202 if (!failures[identifier.task]) { 203 failures[identifier.task] = []; 204 $scope.numTestFailures += 1; 205 } 206 for (var j in failure.variants) { 207 failures[identifier.task].push({"test": identifier.test, 208 "variant": failure.variants[j].name, 209 "task_id": failure.variants[j].task_id, 210 }); 211 } 212 } 213 // sort failures by number of failing tests 214 $scope.taskFailures = []; 215 _.each(failures,function(value, key) { 216 $scope.taskFailures.push({ 217 "groupingField": key, 218 "fields": value, 219 "hidden" : false, 220 }); 221 }); 222 } 223 224 $scope.groupByTest = function(){ 225 // group the failures by task and test 226 var failures = {}; 227 $scope.numTestFailures = 0; 228 for (var i = 0; i < $window.failures.length; i++) { 229 var failure = $window.failures[i]; 230 var identifier = failure.identifier; 231 identifier.test = $filter('endOfPath')(identifier.test); 232 if (!failures[identifier.test]) { 233 failures[identifier.test] = []; 234 $scope.numTestFailures += 1; 235 } 236 for (var j in failure.variants) { 237 failures[identifier.test].push({"task": identifier.task, 238 "variant": failure.variants[j].name, 239 "task_id": failure.variants[j].task_id, 240 }); 241 } 242 } 243 _.each(failures,function(value, key) { 244 $scope.testFailures.push({ 245 "groupingField": key, 246 "fields": value, 247 "hidden" : false, 248 }); 249 }); 250 } 251 252 $scope.groupByVariant = function(){ 253 // group the failures by task and test 254 var failures = {}; 255 $scope.numTestFailures = 0; 256 for (var i = 0; i < $window.failures.length; i++) { 257 var failure = $window.failures[i]; 258 var identifier = failure.identifier; 259 identifier.test = $filter('endOfPath')(identifier.test); 260 for (var j in failure.variants) { 261 if (!failures[failure.variants[j].name]) { 262 failures[failure.variants[j].name] = []; 263 } 264 failures[failure.variants[j].name].push({"task": identifier.task, 265 "test": identifier.test, 266 "task_id": failure.variants[j].task_id, 267 }); 268 } 269 } 270 _.each(failures,function(value, key) { 271 $scope.variantFailures.push({ 272 "groupingField": key, 273 "fields": value, 274 "hidden" : false, 275 }); 276 }); 277 } 278 279 $scope.groupByRevision = function(){ 280 // group the revision failures by task, test and variant 281 var failures = {}; 282 $scope.numTestFailures = 0; 283 for (var i = 0; i < $window.revisionFailures.length; i++) { 284 var identifier = $window.revisionFailures[i].revision; 285 var revFailures = $window.revisionFailures[i].failures; 286 for (j in revFailures){ 287 var failure = revFailures[j]; 288 failure.test = $filter('endOfPath')(failure.test); 289 if (!failures[identifier]) { 290 failures[identifier] = []; 291 } 292 failures[identifier].push({ "task": failure.task, 293 "test": failure.test, 294 "task_id": failure.task_id, 295 "variant": failure.variant, 296 }); 297 298 } 299 } 300 _.each(failures,function(value, key) { 301 $scope.revisionFailures.push({ 302 "groupingField": key, 303 "order": $scope.allVersions[key].order, // add the order field from the dictionary of all versions. 304 "fields": value, 305 "hidden" : false, 306 }); 307 }); 308 309 // sort on revision order 310 $scope.revisionFailures.sort(function(a,b) { 311 if (a.order < b.order) { 312 return 1; 313 } else if (a.order > b.order) { 314 return -1; 315 } else { 316 return 0; 317 } 318 }); 319 320 } 321 322 323 // creates the grid view 324 $scope.createGrid = function () { 325 // create grid with map of buildvariant to its tasks 326 for (var i = 0; i < gridCells.length; i++) { 327 var task = gridCells[i].cellId.task; 328 var variant = gridCells[i].cellId.variant; 329 if (!$scope.grid[variant]) { 330 $scope.grid[variant] = {}; 331 $scope.buildVariants.push(variant); 332 } 333 if (!$scope.grid[variant][task]) { 334 $scope.grid[variant][task] = { 335 "current": gridCells[i].history[0], 336 }; 337 if ($scope.taskNames.indexOf(task) == -1) 338 $scope.taskNames.push(task); 339 $scope.grid[variant][task].prevTasks = gridCells[i].history.slice(1); 340 $scope.grid[variant][task].prevStatus = cellStatus(gridCells[i].history.slice(1)); 341 } 342 } 343 344 // sort tasks and buildvariants alphabetically 345 $scope.taskNames.sort(); 346 $scope.buildVariants.sort(); 347 348 $scope.currentTask = null; 349 $scope.currentCell = ''; 350 $scope.currentBuildVariant = ''; 351 $scope.currentTaskName = ''; 352 } 353 354 355 // pre-create all the groupings 356 $scope.groupByTask(); 357 $scope.groupByTest(); 358 $scope.groupByVariant(); 359 $scope.groupByRevision(); 360 361 $scope.createGrid(); 362 363 // set the default current failures to task failures 364 $scope.currentFailures = $scope.taskFailures; 365 $scope.setSort($scope.sortBy); 366 367 368 $scope.setFailureView = function(view) { 369 $scope.currentFailureView = view; 370 if (view == $scope.consts.taskFailuresView) { 371 $scope.currentFailures = $scope.taskFailures; 372 $scope.currentHeaders = $scope.taskHeaders; 373 } else if (view == $scope.consts.testFailuresView) { 374 $scope.currentFailures = $scope.testFailures; 375 $scope.currentHeaders = $scope.testHeaders; 376 } else if (view == $scope.consts.variantFailuresView) { 377 $scope.currentFailures = $scope.variantFailures; 378 $scope.currentHeaders = $scope.variantHeaders; 379 } else { 380 $scope.currentFailures = $scope.revisionFailures; 381 $scope.currentHeaders = $scope.revisionHeaders; 382 } 383 if (view != $scope.consts.revisionFailuresView){ 384 $scope.setSort($scope.sortBy); 385 } 386 } 387 388 $scope.getRevisionMessage = function(revision) { 389 return $scope.allVersions[revision].message; 390 }; 391 392 $scope.showTaskPopover = function(buildVariant, task, target) { 393 $scope.currentTask = target; 394 if ($scope.grid[buildVariant] && $scope.grid[buildVariant][task]) { 395 $scope.currentCell = $scope.grid[buildVariant][task]; 396 $scope.currentBuildVariant = buildVariant; 397 $scope.currentTaskName = task; 398 } else { 399 $scope.currentCell = null; 400 } 401 }; 402 403 function cellStatus(history) { 404 for (var i = 0; i < history.length; i++) { 405 if (history[i].status == 'success') { 406 return history[i].status; 407 } else if (history[i].status == 'failed') { 408 if ('task_end_details' in history[i]) { 409 if ('type' in history[i].task_end_details) { 410 if (history[i].task_end_details.type == 'system') { 411 return 'system-failed'; 412 } 413 } 414 } 415 return 'failure'; 416 } 417 } 418 return 'undispatched'; 419 } 420 421 $scope.highlightHeader = function(row, col) { 422 $('.header-cell.highlighted').removeClass('highlighted'); 423 $($('.header-cell').get(col)).addClass('highlighted'); 424 $('.tablerow .header').removeClass('highlighted'); 425 $($('.tablerow .header').get(row)).addClass('highlighted'); 426 }; 427 428 $scope.getGridClass = function(variant, task) { 429 var cellClass = ''; 430 if (!$scope.grid[variant]) 431 return 'skipped'; 432 var cell = $scope.grid[variant][task]; 433 if (!cell) return 'skipped'; 434 if (cell.current) { 435 if (cell.current.status == 'undispatched') { 436 cellClass = 'was-' + cell.prevStatus; 437 } else if (cell.current.status == 'failed') { 438 cellClass = 'failure'; 439 if ('task_end_details' in cell.current) { 440 if ('type' in cell.current.task_end_details) { 441 if (cell.current.task_end_details.type == 'system') { 442 cellClass = 'system-failed'; 443 } 444 } 445 } 446 } else if (cell.current.status == 'success') { 447 cellClass = 'success'; 448 } else if (cell.current.status == 'started' || cell.current.status == 'dispatched') { 449 cellClass = 'was-' + cell.prevStatus + ' started'; 450 } 451 return cellClass; 452 } else { 453 return "was-" + cell.prevStatus; 454 } 455 }; 456 });