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

     1  var mciModule = angular.module('MCI', [
     2    'filters.common',
     3    'directives.eventLogs',
     4    'directives.visualization',
     5    'directives.badges',
     6    'directives.admin',
     7    'directives.drawer',
     8    'directives.github',
     9    'directives.patch',
    10    'directives.spawn',
    11    'directives.events',
    12    'directives.tristateCheckbox',
    13    'directives.svg',
    14    'directives.confirm',
    15    'mciServices.rest',
    16    'mciServices.locationHash',
    17    'md5',
    18    'ngSanitize'
    19  ], function($interpolateProvider) {
    20    // Use [[ ]] to delimit AngularJS bindings, because using {{ }} confuses go
    21    $interpolateProvider.startSymbol('[[');
    22    $interpolateProvider.endSymbol(']]');
    23  }).factory('$now', [function() {
    24    return {
    25      now: function() {
    26        return new Date();
    27      }
    28    };
    29  }]).filter('taskStatusLabel', function() {
    30    return function(status, type) {
    31      switch (status) {
    32        case 'started':
    33          return type + '-info';
    34        case 'undispatched':
    35          return type + '-default';
    36        case 'dispatched':
    37          return type + '-info';
    38        case 'failed':
    39          return type + '-danger';
    40        case 'cancelled':
    41          return type + '-warning';
    42        case 'success':
    43          return type + '-success';
    44        default:
    45          return type + '-default';
    46      }
    47    }
    48  }).directive('bsPopover', function($parse, $compile, $templateCache, $q, $http) {
    49    // This is adapted from https://github.com/mgcrea/angular-strap/blob/master/src/directives/popover.js
    50    // but hacked to allow passing in the 'container' option
    51    // and fix weirdness by wrapping element with $()
    52  
    53    // Hide popovers when pressing esc
    54    $('body').on('keyup', function(ev) {
    55      if (ev.keyCode === 27) {
    56        $('.popover.in').popover('hide');
    57      }
    58    });
    59    var type = 'popover',
    60      dataPrefix = !!$.fn.emulateTransitionEnd ? 'bs.' : '',
    61      evSuffix = dataPrefix ? '.' + dataPrefix + type : '';
    62  
    63    return {
    64      restrict: 'A',
    65      scope: true,
    66      link: function postLink(scope, element, attr, ctrl) {
    67        var getter = $parse(attr.bsPopover),
    68          setter = getter.assign,
    69          value = getter(scope),
    70          options = {};
    71  
    72        if (angular.isObject(value)) {
    73          options = value;
    74        }
    75  
    76        $q.when(options.content || $templateCache.get(value) || $http.get(value, {
    77          cache: true
    78        })).then(function onSuccess(template) {
    79  
    80          // Handle response from $http promise
    81          if (angular.isObject(template)) {
    82            template = template.data;
    83          }
    84  
    85          // Handle data-placement and data-trigger attributes
    86          _.forEach(['placement', 'trigger', 'container'], function(name) {
    87            if (!!attr[name]) {
    88              options[name] = attr[name];
    89            }
    90          });
    91  
    92          // Handle data-unique attribute
    93          if (!!attr.unique) {
    94            $(element).on('show' + evSuffix, function(ev) { // requires bootstrap 2.3.0+
    95              // Hide any active popover except self
    96              $('.popover.in').not(element).popover('hide');
    97            });
    98          }
    99  
   100          // Handle data-hide attribute to toggle visibility
   101          if (!!attr.hide) {
   102            scope.$watch(attr.hide, function(newValue, oldValue) {
   103              if (!!newValue) {
   104                popover.hide();
   105              } else if (newValue !== oldValue) {
   106                $timeout(function() {
   107                  popover.show();
   108                });
   109              }
   110            });
   111          }
   112  
   113          if (!!attr.show) {
   114            scope.$watch(attr.show, function(newValue, oldValue) {
   115              if (!!newValue) {
   116                $timeout(function() {
   117                  popover.show();
   118                });
   119              } else if (newValue !== oldValue) {
   120                popover.hide();
   121              }
   122            });
   123          }
   124  
   125          // Initialize popover
   126          $(element).popover(angular.extend({}, options, {
   127            content: template,
   128            html: true
   129          }));
   130  
   131          // Bootstrap override to provide tip() reference & compilation
   132          var popover = $(element).data(dataPrefix + type);
   133          popover.hasContent = function() {
   134            return this.getTitle() || template; // fix multiple $compile()
   135          };
   136          popover.getPosition = function() {
   137            var r = $.fn.popover.Constructor.prototype.getPosition.apply(this, arguments);
   138  
   139            // Compile content
   140            $compile(this.$tip)(scope);
   141            scope.$digest();
   142  
   143            // Bind popover to the tip()
   144            this.$tip.data(dataPrefix + type, this);
   145  
   146            return r;
   147          };
   148  
   149          // Provide scope display functions
   150          scope.$popover = function(name) {
   151            popover(name);
   152          };
   153          _.forEach(['show', 'hide'], function(name) {
   154            scope[name] = function() {
   155              popover[name]();
   156            };
   157          });
   158          scope.dismiss = scope.hide;
   159  
   160          // Emit popover events
   161          _.forEach(['show', 'shown', 'hide', 'hidden'], function(name) {
   162            $(element).on(name + evSuffix, function(ev) {
   163              scope.$emit('popover-' + name, ev);
   164            });
   165          });
   166  
   167        });
   168      }
   169    }
   170  }).directive('elementTooltip', function() {
   171    return {
   172      scope: true,
   173      link: function(scope, element, attrs) {
   174        scope.$watch(attrs.elementTooltip, function(tip) {
   175          var obj = {
   176            title: tip
   177          };
   178          if (attrs.elementTooltipContainer) {
   179            obj.container = attrs.elementTooltipContainer;
   180          }
   181  
   182          $(element).elementTooltip = $(element).tooltip(obj);
   183          $(element).attr('title', tip).tooltip('fixTitle');
   184        });
   185      }
   186    }
   187  }).directive('buildTasksResultsBar', function() {
   188    return function(scope, element, attrs) {
   189      // Progress bar to display the state of tasks for a given uiBuild
   190      scope.$watch(attrs.buildTasksResultsBar, function(build) {
   191        if (build) {
   192          var numSuccess = 0;
   193          var numFailed = 0;
   194          var numStarted = 0;
   195          var numNeither = 0;
   196  
   197          for (var i = 0; i < build.Tasks.length; ++i) {
   198            switch (build.Tasks[i].Task.Status) {
   199              case 'success':
   200                ++numSuccess;
   201                break;
   202              case 'failed':
   203                ++numFailed;
   204                break;
   205              case 'started':
   206                ++numStarted;
   207                break;
   208              default:
   209                ++numNeither;
   210                break;
   211            }
   212          }
   213  
   214          var successTitle = numSuccess + " task" + (numSuccess == 1 ? "" : "s") + " succeeded";
   215          var failedTitle = numFailed + " task" + (numFailed == 1 ? "" : "s") + " failed";
   216          var startedTitle = numStarted + " task" + (numStarted == 1 ? "" : "s") + " in progress";
   217          var neitherTitle = numNeither + " task" + (numNeither == 1 ? "" : "s") + " not started or cancelled";
   218          element.html('<div class="progress-bar progress-bar-success" role="progressbar" style="width: ' + (numSuccess / build.Tasks.length * 100) + '%" data-toggle="tooltip" data-animation="" title="' + successTitle + '"></div>' +
   219            '<div class="progress-bar progress-bar-danger" role="progressbar" style="width: ' + (numFailed / build.Tasks.length * 100) + '%" data-toggle="tooltip" data-animation="" title="' + failedTitle + '"></div>' +
   220            '<div class="progress-bar progress-bar-warning" role="progressbar" style="width: ' + (numStarted / build.Tasks.length * 100) + '%" data-toggle="tooltip" data-animation="" title="' + startedTitle + '"></div>' +
   221            '<div class="progress-bar progress-bar-default" role="progressbar" style="width: ' + (numNeither / build.Tasks.length * 100) + '%" data-toggle="tooltip" data-animation="" title="' + neitherTitle + '"></div>');
   222  
   223          $(element.children('*[data-toggle="tooltip"]')).each(function(i, el) {
   224            $(el).tooltip();
   225          });
   226        }
   227      });
   228    };
   229  }).filter('statusFilter', function() {
   230    return function(task) {
   231      // for task test results, return the status passed in
   232      if (task !== Object(task)) {
   233        return task;
   234      }
   235      var cls = task.status;
   236      if (task.status == 'undispatched') {
   237        if (!task.activated) {
   238          cls = 'inactive';
   239        } else {
   240          cls = 'unstarted';
   241        }
   242      } else if (task.status == 'started') {
   243        cls = 'started';
   244      } else if (task.status == 'success') {
   245        cls = 'success';
   246      } else if (task.status == 'failed') {
   247        cls = 'failed';
   248        if ('task_end_details' in task) {
   249          if ('type' in task.task_end_details) {
   250            if (task.task_end_details.type == 'system') {
   251              cls = 'system-failed';
   252            }
   253          }
   254          if ('timed_out' in task.task_end_details) {
   255            if (task.task_end_details.timed_out && 'desc' in task.task_end_details && task.task_end_details.desc == 'heartbeat') {
   256              cls = 'system-failed';
   257            }
   258          }
   259        }
   260      }
   261      return cls;
   262    }
   263  }).filter('statusLabel', function() {
   264    return function(task) {
   265      if (task.status == 'started') {
   266        return 'started';
   267      } else if (task.status == 'undispatched' && task.activated) {
   268        if (task.task_waiting) {
   269          return task.task_waiting;
   270        }
   271        return 'scheduled';
   272      } else if (task.status == 'undispatched' && !task.activated){
   273        // dispatch_time could be a string or a number. to check when the dispatch_time
   274        // is a real value, this if-statement accounts for cases where 
   275        // dispatch_time is 0, "0" or even new Date(0) or older.
   276        if(+task.dispatch_time == 0 || (typeof task.dispatch_time == "string" && +new Date(task.dispatch_time) <= 0)){
   277          return "not scheduled"
   278        }
   279        return 'aborted';
   280      } else if (task.status == 'success') {
   281        return 'success';
   282      } else if (task.status == 'failed') {
   283        if ('task_end_details' in task) {
   284          if ('timed_out' in task.task_end_details) {
   285            if (task.task_end_details.timed_out && 'desc' in task.task_end_details && task.task_end_details.desc == 'heartbeat') {
   286              return 'system unresponsive';
   287            }
   288  
   289            if (task.task_end_details.type == 'system') {
   290              return 'system timed out';
   291            }
   292            return 'test timed out';
   293          }
   294          if (task.task_end_details.type == 'system') {
   295            return 'system failure';
   296          }
   297          return 'failed';
   298        }
   299      }
   300      return task.status;
   301    }
   302  }).filter('endOfPath', function() {
   303    return function(input) {
   304      var lastSlash = input.lastIndexOf('/');
   305      if (lastSlash === -1 || lastSlash === input.length - 1) {
   306        // try to find the index using windows-style filesystem separators
   307        lastSlash = input.lastIndexOf('\\');
   308        if (lastSlash === -1 || lastSlash === input.length - 1) {
   309          return input;
   310        }
   311      }
   312      return input.substring(lastSlash + 1);
   313    }
   314  }).filter('buildStatus', function() {
   315    // given a list of tasks, returns the status of the overall build.
   316    return function(tasks) {
   317      var countSuccess = 0;
   318      var countInProgress = 0;
   319      var countActive = 0;
   320      for(i=0;i<tasks.length;i++){
   321        // if any task is failed, the build status is "failed"
   322        if(tasks[i].status == "failed"){
   323          return "block-status-failed";
   324        }
   325        if(tasks[i].status == "success"){
   326          countSuccess++;
   327        } else if(tasks[i].status == "dispatched" || tasks[i].status=="started"){
   328          countInProgress++;
   329        } else if(tasks[i].status == "undispatched") {
   330          countActive += tasks[i].activated ? 1 : 0;
   331        }
   332      }
   333      if(countSuccess == tasks.length){ 
   334        // all tasks are passing
   335        return "block-status-success";
   336      }else if(countInProgress>0){
   337        // no failures yet, but at least 1 task in still progress
   338        return "block-status-started";
   339      }else if(countActive>0){
   340        // no failures yet, but at least 1 task still active
   341        return "block-status-created";
   342      }
   343      // no active tasks pending
   344      return "block-status-inactive";
   345    }
   346  }).factory('mciTime', [function() {
   347    var $time = {
   348      now: function() {
   349        return new Date();
   350      },
   351      // Some browsers, e.g. Safari, don't handle things like new Date(undefined)
   352      // particularly well, so this is to avoid that headache
   353      fromNanoseconds: function(nano) {
   354        if (nano) {
   355          return new Date(Math.ceil(nano / (1000 * 1000)));
   356        }
   357        return null;
   358      },
   359      fromMilliseconds: function(ms) {
   360        if (ms) {
   361          return new Date(ms);
   362        }
   363        return null;
   364      },
   365      finishConditional: function(start, finish, now) {
   366        // Pretty common calculation - if start is undefined, return 0.
   367        // If start is defined and finish isn't, return now - start in millis,
   368        // and if start and finish are both defined, return finish - start in millis
   369  
   370        if (!start || isNaN(start.getTime()) || start.getTime() <= 0) {
   371          return 0;
   372        } else if (!finish || isNaN(finish.getTime()) || finish.getTime() <= 0) {
   373          return (now || $time.now()).getTime() - start.getTime();
   374        } else {
   375          return finish.getTime() - start.getTime();
   376        }
   377      }
   378    };
   379  
   380    return $time;
   381  }]).config(['$compileProvider', function ($compileProvider) {
   382    //$compileProvider.debugInfoEnabled(false);
   383  }]);
   384