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  });