BigW Consortium Gitlab

build.js 10.9 KB
Newer Older
1
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-use-before-define, no-param-reassign, quotes, yoda, no-else-return, consistent-return, comma-dangle, object-shorthand, prefer-template, one-var, one-var-declaration-per-line, no-unused-vars, max-len, vars-on-top */
2 3
/* global Breakpoints */

Fatih Acet committed
4
(function() {
5
  var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; };
6
  var AUTO_SCROLL_OFFSET = 75;
7
  var DOWN_BUILD_TRACE = '#down-build-trace';
Fatih Acet committed
8 9

  this.Build = (function() {
10
    Build.timeout = null;
Fatih Acet committed
11 12 13

    Build.state = null;

14
    function Build(options) {
15 16 17 18
      options = options || $('.js-build-options').data();
      this.pageUrl = options.pageUrl;
      this.buildUrl = options.buildUrl;
      this.buildStatus = options.buildStatus;
19
      this.state = options.logState;
20
      this.buildStage = options.buildStage;
21
      this.updateDropdown = bind(this.updateDropdown, this);
22
      this.$document = $(document);
23 24 25 26
      this.$body = $('body');
      this.$buildTrace = $('#build-trace');
      this.$autoScrollContainer = $('.autoscroll-container');
      this.$autoScrollStatus = $('#autoscroll-status');
27
      this.$autoScrollStatusText = this.$autoScrollStatus.find('.status-text');
28
      this.$upBuildTrace = $('#up-build-trace');
29
      this.$downBuildTrace = $(DOWN_BUILD_TRACE);
30 31
      this.$scrollTopBtn = $('#scroll-top');
      this.$scrollBottomBtn = $('#scroll-bottom');
32
      this.$buildRefreshAnimation = $('.js-build-refresh');
33

34
      clearTimeout(Build.timeout);
35
      // Init breakpoint checker
Fatih Acet committed
36
      this.bp = Breakpoints.get();
37

38
      this.initSidebar();
39
      this.$buildScroll = $('#js-build-scroll');
40

41 42 43
      this.populateJobs(this.buildStage);
      this.updateStageDropdownText(this.buildStage);
      this.sidebarOnResize();
44

45
      this.$document.off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.sidebarOnClick.bind(this));
46
      this.$document.off('click', '.stage-item').on('click', '.stage-item', this.updateDropdown);
47
      this.$document.on('scroll', this.initScrollMonitor.bind(this));
48 49
      $(window).off('resize.build').on('resize.build', this.sidebarOnResize.bind(this));
      $('a', this.$buildScroll).off('click.stepTrace').on('click.stepTrace', this.stepTrace);
Fatih Acet committed
50 51 52
      this.updateArtifactRemoveDate();
      if ($('#build-trace').length) {
        this.getInitialBuildTrace();
53
        this.initScrollButtonAffix();
Fatih Acet committed
54
      }
55
      this.invokeBuildTrace();
Fatih Acet committed
56 57
    }

58 59 60 61 62 63
    Build.prototype.initSidebar = function() {
      this.$sidebar = $('.js-build-sidebar');
      this.$sidebar.niceScroll();
      this.$document.off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.toggleSidebar);
    };

64 65 66 67
    Build.prototype.location = function() {
      return window.location.href.split("#")[0];
    };

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
    Build.prototype.invokeBuildTrace = function() {
      var continueRefreshStatuses = ['running', 'pending'];
      // Continue to update build trace when build is running or pending
      if (continueRefreshStatuses.indexOf(this.buildStatus) !== -1) {
        // Check for new build output if user still watching build page
        // Only valid for runnig build when output changes during time
        Build.timeout = setTimeout((function(_this) {
          return function() {
            if (_this.location() === _this.pageUrl) {
              return _this.getBuildTrace();
            }
          };
        })(this), 4000);
      }
    };

Fatih Acet committed
84
    Build.prototype.getInitialBuildTrace = function() {
85
      var removeRefreshStatuses = ['success', 'failed', 'canceled', 'skipped'];
86

Fatih Acet committed
87
      return $.ajax({
88
        url: this.buildUrl,
Fatih Acet committed
89
        dataType: 'json',
90 91
        success: function(buildData) {
          $('.js-build-output').html(buildData.trace_html);
92
          if (window.location.hash === DOWN_BUILD_TRACE) {
93 94
            $("html,body").scrollTop(this.$buildTrace.height());
          }
95
          if (removeRefreshStatuses.indexOf(buildData.status) !== -1) {
96 97
            this.$buildRefreshAnimation.remove();
            return this.initScrollMonitor();
98 99
          }
        }.bind(this)
Fatih Acet committed
100 101 102 103 104
      });
    };

    Build.prototype.getBuildTrace = function() {
      return $.ajax({
105
        url: this.pageUrl + "/trace.json?state=" + (encodeURIComponent(this.state)),
Fatih Acet committed
106 107 108
        dataType: "json",
        success: (function(_this) {
          return function(log) {
109 110
            var pageUrl;

Fatih Acet committed
111 112 113
            if (log.state) {
              _this.state = log.state;
            }
114
            _this.invokeBuildTrace();
Fatih Acet committed
115 116 117 118 119 120 121
            if (log.status === "running") {
              if (log.append) {
                $('.js-build-output').append(log.html);
              } else {
                $('.js-build-output').html(log.html);
              }
              return _this.checkAutoscroll();
122
            } else if (log.status !== _this.buildStatus) {
123 124
              pageUrl = _this.pageUrl;
              if (_this.$autoScrollStatus.data('state') === 'enabled') {
125
                pageUrl += DOWN_BUILD_TRACE;
126 127
              }

Bryce Johnson committed
128
              return gl.utils.visitUrl(pageUrl);
Fatih Acet committed
129 130 131 132 133 134 135
            }
          };
        })(this)
      });
    };

    Build.prototype.checkAutoscroll = function() {
136 137
      if (this.$autoScrollStatus.data("state") === "enabled") {
        return $("html,body").scrollTop(this.$buildTrace.height());
Fatih Acet committed
138
      }
139 140 141 142 143

      // Handle a situation where user started new build
      // but never scrolled a page
      if (!this.$scrollTopBtn.is(':visible') &&
          !this.$scrollBottomBtn.is(':visible') &&
144
          !gl.utils.isInViewport(this.$downBuildTrace.get(0))) {
145 146
        this.$scrollBottomBtn.show();
      }
Fatih Acet committed
147 148
    };

149
    Build.prototype.initScrollButtonAffix = function() {
150
      // Hide everything initially
151
      this.$scrollTopBtn.hide();
152
      this.$scrollBottomBtn.hide();
153
      this.$autoScrollContainer.hide();
154
    };
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170

    // Page scroll listener to detect if user has scrolling page
    // and handle following cases
    // 1) User is at Top of Build Log;
    //      - Hide Top Arrow button
    //      - Show Bottom Arrow button
    //      - Disable Autoscroll and hide indicator (when build is running)
    // 2) User is at Bottom of Build Log;
    //      - Show Top Arrow button
    //      - Hide Bottom Arrow button
    //      - Enable Autoscroll and show indicator (when build is running)
    // 3) User is somewhere in middle of Build Log;
    //      - Show Top Arrow button
    //      - Show Bottom Arrow button
    //      - Disable Autoscroll and hide indicator (when build is running)
    Build.prototype.initScrollMonitor = function() {
171 172 173
      if (!gl.utils.isInViewport(this.$upBuildTrace.get(0)) && !gl.utils.isInViewport(this.$downBuildTrace.get(0))) {
        // User is somewhere in middle of Build Log

174
        this.$scrollTopBtn.show();
175 176 177

        if (this.buildStatus === 'success' || this.buildStatus === 'failed') { // Check if Build is completed
          this.$scrollBottomBtn.show();
178
        } else if (this.$buildRefreshAnimation.is(':visible') && !gl.utils.isInViewport(this.$buildRefreshAnimation.get(0))) {
179 180 181 182
          this.$scrollBottomBtn.show();
        } else {
          this.$scrollBottomBtn.hide();
        }
183

184
        // Hide Autoscroll Status Indicator
185 186 187 188
        if (this.$scrollBottomBtn.is(':visible')) {
          this.$autoScrollContainer.hide();
          this.$autoScrollStatusText.removeClass('animate');
        } else {
189
          this.$autoScrollContainer.css({ top: this.$body.outerHeight() - AUTO_SCROLL_OFFSET }).show();
190 191
          this.$autoScrollStatusText.addClass('animate');
        }
192 193 194
      } else if (gl.utils.isInViewport(this.$upBuildTrace.get(0)) && !gl.utils.isInViewport(this.$downBuildTrace.get(0))) {
        // User is at Top of Build Log

195 196
        this.$scrollTopBtn.hide();
        this.$scrollBottomBtn.show();
197 198 199

        this.$autoScrollContainer.hide();
        this.$autoScrollStatusText.removeClass('animate');
200
      } else if ((!gl.utils.isInViewport(this.$upBuildTrace.get(0)) && gl.utils.isInViewport(this.$downBuildTrace.get(0))) ||
201 202 203
                 (this.$buildRefreshAnimation.is(':visible') && gl.utils.isInViewport(this.$buildRefreshAnimation.get(0)))) {
        // User is at Bottom of Build Log

204 205
        this.$scrollTopBtn.show();
        this.$scrollBottomBtn.hide();
206

207
        // Show and Reposition Autoscroll Status Indicator
208
        this.$autoScrollContainer.css({ top: this.$body.outerHeight() - AUTO_SCROLL_OFFSET }).show();
209
        this.$autoScrollStatusText.addClass('animate');
210 211 212
      } else if (gl.utils.isInViewport(this.$upBuildTrace.get(0)) && gl.utils.isInViewport(this.$downBuildTrace.get(0))) {
        // Build Log height is small

213 214
        this.$scrollTopBtn.hide();
        this.$scrollBottomBtn.hide();
215

216 217
        // Hide Autoscroll Status Indicator
        this.$autoScrollContainer.hide();
218
        this.$autoScrollStatusText.removeClass('animate');
219 220 221
      }

      if (this.buildStatus === "running" || this.buildStatus === "pending") {
222
        // Check if Refresh Animation is in Viewport and enable Autoscroll, disable otherwise.
223
        this.$autoScrollStatus.data("state", gl.utils.isInViewport(this.$buildRefreshAnimation.get(0)) ? 'enabled' : 'disabled');
224
      }
Fatih Acet committed
225 226
    };

227
    Build.prototype.shouldHideSidebarForViewport = function() {
Fatih Acet committed
228 229 230 231 232
      var bootstrapBreakpoint;
      bootstrapBreakpoint = this.bp.getBreakpointSize();
      return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm';
    };

233 234 235 236 237 238 239 240 241 242 243 244 245 246
    Build.prototype.toggleSidebar = function(shouldHide) {
      var shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined;
      this.$buildScroll.toggleClass('sidebar-expanded', shouldShow)
        .toggleClass('sidebar-collapsed', shouldHide);
      this.$sidebar.toggleClass('right-sidebar-expanded', shouldShow)
        .toggleClass('right-sidebar-collapsed', shouldHide);
    };

    Build.prototype.sidebarOnResize = function() {
      this.toggleSidebar(this.shouldHideSidebarForViewport());
    };

    Build.prototype.sidebarOnClick = function() {
      if (this.shouldHideSidebarForViewport()) this.toggleSidebar();
Fatih Acet committed
247 248 249 250 251 252 253
    };

    Build.prototype.updateArtifactRemoveDate = function() {
      var $date, date;
      $date = $('.js-artifacts-remove');
      if ($date.length) {
        date = $date.text();
254
        return $date.text(gl.utils.timeFor(new Date(date.replace(/([0-9]+)-([0-9]+)-([0-9]+)/g, '$1/$2/$3')), ' '));
Fatih Acet committed
255 256 257
      }
    };

258
    Build.prototype.populateJobs = function(stage) {
259 260 261 262
      $('.build-job').hide();
      $('.build-job[data-stage="' + stage + '"]').show();
    };

263 264 265 266
    Build.prototype.updateStageDropdownText = function(stage) {
      $('.stage-selection').text(stage);
    };

267 268
    Build.prototype.updateDropdown = function(e) {
      e.preventDefault();
269
      var stage = e.currentTarget.text;
270
      this.updateStageDropdownText(stage);
271
      this.populateJobs(stage);
272 273
    };

274
    Build.prototype.stepTrace = function(e) {
275
      var $currentTarget;
276 277 278
      e.preventDefault();
      $currentTarget = $(e.currentTarget);
      $.scrollTo($currentTarget.attr('href'), {
279
        offset: 0
280
      });
281 282
    };

Fatih Acet committed
283 284
    return Build;
  })();
285
}).call(window);