github.com/justinjmoses/evergreen@v0.0.0-20170530173719-1d50e381ff0d/public/static/js/patch_new.js (about)

     1  mciModule.controller('PatchController', function($scope, $filter, $window, notificationService, $http) {
     2    $scope.userTz = $window.userTz;
     3    $scope.canEdit = $window.canEdit;
     4    $scope.enabledTasks = _.pluck($window.tasks, "Name");
     5  
     6    var checkedProp = _.property("checked");
     7  
     8    // Event handler for when the user clicks on one of the variants 
     9    // in the left panel. Also accounts for special toggle behavior when the user
    10    // is holding shift/meta/ctrl when clicking.
    11    $scope.selectVariant = function($event, index){
    12      $event.preventDefault();
    13      if ($event.ctrlKey || $event.metaKey) {
    14        // Ctrl/Meta+Click: Toggle just the variant being clicked.
    15        $scope.variants[index].checked = !$scope.variants[index].checked;
    16      } else if ($event.shiftKey) {
    17        // Shift+Click: Select everything between the first element 
    18        // that's already selected element and the element being clicked on.
    19        var firstCheckedIndex = _.findIndex($scope.variants, checkedProp);
    20        firstCheckedIndex = Math.max(firstCheckedIndex, 0); // if nothing selected yet, start at 0.
    21        var indexBounds = Array(firstCheckedIndex, index).sort(function(a, b){
    22          return a-b;
    23        })
    24        for(var i=indexBounds[0]; i<=indexBounds[1]; i++){
    25          $scope.variants[i].checked = true;
    26        }
    27      } else {
    28        // Regular click: Select *only* the one being clicked, and unselect all others.
    29        for(var i=0; i<$scope.variants.length;i++){
    30          $scope.variants[i].checked = (i == index);
    31        }
    32      }
    33    }
    34  
    35    // Returns an object containing the total number of tasks to be scheduled,
    36    // and the number of variants with at least 1 task to be scheduled.
    37    // Return value is in the format format {numVariants: 3, numTasks: 25}
    38    $scope.selectionCount = function(){
    39      var numVariants = _.filter($scope.variants, function(x){return _.filter(x.tasks, checkedProp).length > 0}).length;
    40      var numTasks = _.reduce(_.map($scope.variants, function(x){return _.filter(x.tasks, checkedProp).length}), function(x, y){return x+y}, 0);
    41      return {numVariants: numVariants, numTasks: numTasks};
    42    }
    43  
    44    // Returns the number of tasks checked only within the specified variant.
    45    // Used to populate the count badge next to each variant in the left panel
    46    $scope.numSetForVariant = function(variantId){
    47      var v = _.find($scope.variants, function(x){return x.id == variantId});
    48      return _.filter(_.pluck(v.tasks, "checked"), _.identity).length;
    49    }
    50  
    51    // Gets the subset of variants that are active by the user
    52    $scope.selectedVariants = function(){
    53      return _.filter($scope.variants, checkedProp);
    54    }
    55  
    56    $scope.isMac = function(){
    57      return navigator.platform.toUpperCase().indexOf('MAC')>=0;
    58    }
    59  
    60      
    61  
    62    // Gets the list of tasks that are active across all the list of currently
    63    // selected variants, sorted by name. Used to populate the field of
    64    // checkboxes in the main panel.
    65    $scope.getActiveTasks = function(){
    66      var selectedVariants = $scope.selectedVariants();
    67  
    68      // return the union of the set of tasks shared by all of them, sorted by name
    69      var tasksInSelectedVariants = _.uniq(_.flatten(_.map(_.pluck(selectedVariants, "tasks"), _.keys)));
    70      return tasksInSelectedVariants.sort();
    71    }
    72  
    73    // Click handler for "all" and "none" links. Applies the given state to all
    74    // tasks within the current set of active variants
    75    $scope.changeStateAll = function(state){
    76      var selectedVariantNames = _.object(_.map(_.pluck($scope.selectedVariants(), "id"), function(id){return [id, true]}));
    77      var activeTasks = $scope.getActiveTasks();
    78      for(var i=0;i<$scope.variants.length;i++){
    79        var v = $scope.variants[i];
    80        if(!(v.id in selectedVariantNames)){
    81          continue;
    82        }
    83        _.each(activeTasks, function(taskName){
    84          if(_.has(v.tasks, taskName)){
    85            v.tasks[taskName].checked = state;
    86          }
    87        })
    88      }
    89    }
    90  
    91    // Sends the current patch config to the server to save.
    92    $scope.save = function(){
    93      var data = {
    94        "description": $scope.patch.Description,
    95        "variants_tasks": _.filter(_.map($scope.variants, function(v){
    96          return {
    97            variant: v.id, 
    98            tasks: _.keys(_.omit(v.tasks, function(v){return !v.checked})),
    99          };
   100        }), function(v){return v.tasks.length > 0})
   101      }
   102      $http.post('/patch/' + $scope.patch.Id, data).
   103        success(function(data, status) {
   104          window.location.replace("/version/" + data.version);
   105        }).
   106        error(function(data, status, errorThrown) {
   107        	notificationService.pushNotification('Error retrieving logs: ' + JSON.stringify(data), 'errorHeader');
   108        });
   109    };
   110  
   111    $scope.setPatchInfo = function() {
   112      $scope.patch = $window.patch;
   113      $scope.patchContainer = {'Patch':$scope.patch};
   114      var patch = $scope.patch;
   115      var variantsFilteredTasks = _.mapObject($window.variants, function(v, k){
   116        v.Tasks = _.filter(v.Tasks, function(x){return _.contains($scope.enabledTasks, x.Name)});
   117        return v;
   118      })
   119      $scope.variants = _.sortBy(_.map(variantsFilteredTasks, function(v, variantId){
   120        return {
   121          id: variantId, 
   122          checked:false,
   123          name: v.DisplayName,
   124          tasks : _.object(_.map(_.pluck(v.Tasks, "Name"), function(t){
   125            return [t, {checked:false}];
   126          }))
   127        };
   128      }), "name");
   129  
   130      // If there's only one variant, just pre-select it.
   131      if($scope.variants.length == 1 ){
   132        $scope.variants[0].checked = true;
   133      }
   134  
   135      var allUniqueTaskNames = _.uniq(_.flatten(_.map(_.pluck($scope.variants, "tasks"), _.keys)));
   136  
   137      $scope.tasks = _.object(_.map(allUniqueTaskNames, function(taskName){
   138        // create a getter/setter for the state of the task
   139        return [taskName, function(newValue){
   140          var selectedVariants = $scope.selectedVariants();
   141          if(!arguments.length){ // called with no args, act as a getter
   142            var statusAcrossVariants = _.flatten(_.map(_.pluck($scope.selectedVariants(), "tasks"), function(o){return _.filter(o, function(v, k){return k==taskName})}));
   143            var groupCountedStatus = _.countBy(statusAcrossVariants, function(x){return x.checked == true});
   144            if(groupCountedStatus[true] == statusAcrossVariants.length ){
   145              return true;
   146            }else if(groupCountedStatus[false] == statusAcrossVariants.length ){
   147              return false;
   148            }
   149            return null;
   150          }
   151  
   152          var selectedVariantNames = _.object(_.map(_.pluck(selectedVariants, "id"), function(id){return [id, true]}));
   153          
   154          // act as a setter
   155          for(var i=0;i<$scope.variants.length;i++){
   156            var v = $scope.variants[i];
   157            if(!(v.id in selectedVariantNames)){
   158              continue;
   159            }
   160            if(_.has(v.tasks, taskName)){
   161              v.tasks[taskName].checked = newValue;
   162            }
   163          }
   164          return newValue;
   165        }];
   166      }))
   167    }
   168  
   169    // Older patches may only have the fields "Variants" and "Tasks" but newer patches
   170    // have a VariantsTasks field that has all pairs grouped together by variant.
   171    // This function backfills the VariantsTasks field for older patches that were created
   172    // before the schema change. 
   173    if(!patch.VariantsTasks && (patch.Tasks || []).length > 0 && (patch.BuildVariants || []).length > 0){
   174      patch.VariantsTasks = _.map(patch.BuildVariants, function(v){
   175        // The _intersection limits the set of tasks to be included
   176        // to just the ones that actually exist in the config for that variant.
   177        return {Variant:v, Tasks: _.intersection(_.pluck(($window.variants[v] || {}).Tasks , "Name"), patch.Tasks)};
   178      });
   179    }
   180  
   181    $scope.setPatchInfo();
   182  
   183    // Populate the checkboxes in the UI according to the variants and tasks that
   184    // were specified on the command line, or that may have already been created
   185    // if the patch was finalized already.
   186    if((patch.VariantsTasks || []).length>0){
   187      for(var i=0;i<patch.VariantsTasks.length;i++){
   188        var vt = patch.VariantsTasks[i];
   189        var variantIndex = _.findIndex($scope.variants, function(x){return x.id == patch.VariantsTasks[i].Variant});
   190        if(variantIndex >= 0 ){
   191          _.each(vt.Tasks, function(x){
   192            $scope.variants[variantIndex].tasks[x] = {checked:true};
   193            if(!!patch.Version){
   194              // if the task was already created, we can't uncheck the box
   195              $scope.variants[variantIndex].tasks[x].disabled = true;
   196            }
   197          })
   198        }
   199      }
   200    }
   201  })