gitlab-org--gitlab-foss/app/assets/javascripts/job.js

282 lines
8.0 KiB
JavaScript
Raw Normal View History

import $ from 'jquery';
2017-05-30 08:43:13 +00:00
import _ from 'underscore';
2018-05-21 21:27:34 +00:00
import StickyFill from 'stickyfilljs';
2018-01-30 16:33:23 +00:00
import axios from './lib/utils/axios_utils';
2017-12-11 12:28:11 +00:00
import { visitUrl } from './lib/utils/url_utility';
import bp from './breakpoints';
import { numberToHumanSize } from './lib/utils/number_utils';
import { setCiStatusFavicon } from './lib/utils/common_utils';
export default class Job {
constructor(options) {
this.timeout = null;
this.state = null;
this.fetchingStatusFavicon = false;
this.options = options || $('.js-build-options').data();
this.pagePath = this.options.pagePath;
this.buildStatus = this.options.buildStatus;
this.state = this.options.logState;
this.buildStage = this.options.buildStage;
this.$document = $(document);
this.$window = $(window);
this.logBytes = 0;
2017-05-30 08:43:13 +00:00
this.updateDropdown = this.updateDropdown.bind(this);
this.$buildTrace = $('#build-trace');
this.$buildRefreshAnimation = $('.js-build-refresh');
this.$truncatedInfo = $('.js-truncated-info');
2017-05-30 08:43:13 +00:00
this.$buildTraceOutput = $('.js-build-output');
this.$topBar = $('.js-top-bar');
2017-05-30 08:43:13 +00:00
// Scroll controllers
this.$scrollTopBtn = $('.js-scroll-up');
this.$scrollBottomBtn = $('.js-scroll-down');
clearTimeout(this.timeout);
this.initSidebar();
this.populateJobs(this.buildStage);
this.updateStageDropdownText(this.buildStage);
this.sidebarOnResize();
this.$document
.off('click', '.js-sidebar-build-toggle')
.on('click', '.js-sidebar-build-toggle', this.sidebarOnClick.bind(this));
this.$document
.off('click', '.stage-item')
.on('click', '.stage-item', this.updateDropdown);
2017-05-30 08:43:13 +00:00
// add event listeners to the scroll buttons
this.$scrollTopBtn
.off('click')
.on('click', this.scrollToTop.bind(this));
this.$scrollBottomBtn
.off('click')
.on('click', this.scrollToBottom.bind(this));
this.scrollThrottled = _.throttle(this.toggleScroll.bind(this), 100);
2017-06-09 11:58:52 +00:00
this.$window
2017-06-09 11:58:52 +00:00
.off('scroll')
.on('scroll', () => {
if (!this.isScrolledToBottom()) {
this.toggleScrollAnimation(false);
} else if (this.isScrolledToBottom() && !this.isLogComplete) {
this.toggleScrollAnimation(true);
}
this.scrollThrottled();
2017-06-09 11:58:52 +00:00
});
this.$window
.off('resize.build')
2017-06-02 16:16:54 +00:00
.on('resize.build', _.throttle(this.sidebarOnResize.bind(this), 100));
this.initAffixTopArea();
2017-05-30 08:43:13 +00:00
this.getBuildTrace();
}
initAffixTopArea() {
2018-05-21 21:27:34 +00:00
StickyFill.add(this.$topBar);
}
// eslint-disable-next-line class-methods-use-this
canScroll() {
return $(document).height() > $(window).height();
}
2017-05-30 08:43:13 +00:00
toggleScroll() {
2018-01-02 21:06:56 +00:00
const $document = $(document);
const currentPosition = $document.scrollTop();
const scrollHeight = $document.height();
2017-05-30 08:43:13 +00:00
const windowHeight = $(window).height();
2017-05-30 08:43:13 +00:00
if (this.canScroll()) {
if (currentPosition > 0 &&
(scrollHeight - currentPosition !== windowHeight)) {
// User is in the middle of the log
this.toggleDisableButton(this.$scrollTopBtn, false);
this.toggleDisableButton(this.$scrollBottomBtn, false);
} else if (currentPosition === 0) {
// User is at Top of Log
2017-05-30 08:43:13 +00:00
this.toggleDisableButton(this.$scrollTopBtn, true);
this.toggleDisableButton(this.$scrollBottomBtn, false);
} else if (this.isScrolledToBottom()) {
// User is at the bottom of the build log.
2017-05-30 08:43:13 +00:00
this.toggleDisableButton(this.$scrollTopBtn, false);
this.toggleDisableButton(this.$scrollBottomBtn, true);
}
} else {
this.toggleDisableButton(this.$scrollTopBtn, true);
this.toggleDisableButton(this.$scrollBottomBtn, true);
2017-05-30 08:43:13 +00:00
}
}
// eslint-disable-next-line class-methods-use-this
isScrolledToBottom() {
const $document = $(document);
const currentPosition = $document.scrollTop();
const scrollHeight = $document.height();
const windowHeight = $(window).height();
return scrollHeight - currentPosition === windowHeight;
}
// eslint-disable-next-line class-methods-use-this
scrollDown() {
const $document = $(document);
$document.scrollTop($document.height());
}
scrollToBottom() {
this.scrollDown();
2017-06-09 11:58:52 +00:00
this.hasBeenScrolled = true;
2017-05-30 08:43:13 +00:00
this.toggleScroll();
}
2017-05-30 08:43:13 +00:00
scrollToTop() {
$(document).scrollTop(0);
2017-06-09 11:58:52 +00:00
this.hasBeenScrolled = true;
2017-05-30 08:43:13 +00:00
this.toggleScroll();
}
2017-05-30 08:43:13 +00:00
// eslint-disable-next-line class-methods-use-this
toggleDisableButton($button, disable) {
2017-05-30 08:43:13 +00:00
if (disable && $button.prop('disabled')) return;
$button.prop('disabled', disable);
}
2017-05-30 08:43:13 +00:00
toggleScrollAnimation(toggle) {
2017-05-30 08:43:13 +00:00
this.$scrollBottomBtn.toggleClass('animate', toggle);
}
2017-05-30 08:43:13 +00:00
initSidebar() {
this.$sidebar = $('.js-build-sidebar');
}
getBuildTrace() {
2018-01-30 16:33:23 +00:00
return axios.get(`${this.pagePath}/trace.json`, {
params: { state: this.state },
2017-05-30 08:43:13 +00:00
})
2018-01-30 16:33:23 +00:00
.then((res) => {
const log = res.data;
if (!this.fetchingStatusFavicon) {
this.fetchingStatusFavicon = true;
setCiStatusFavicon(`${this.pagePath}/status.json`)
.then(() => {
this.fetchingStatusFavicon = false;
})
.catch(() => {
this.fetchingStatusFavicon = false;
});
}
if (log.state) {
this.state = log.state;
}
this.isScrollInBottom = this.isScrolledToBottom();
if (log.append) {
2017-05-30 08:43:13 +00:00
this.$buildTraceOutput.append(log.html);
this.logBytes += log.size;
} else {
2017-05-30 08:43:13 +00:00
this.$buildTraceOutput.html(log.html);
this.logBytes = log.size;
}
// if the incremental sum of logBytes we received is less than the total
// we need to show a message warning the user about that.
if (this.logBytes < log.total) {
// size is in bytes, we need to calculate KiB
const size = numberToHumanSize(this.logBytes);
$('.js-truncated-info-size').html(`${size}`);
this.$truncatedInfo.removeClass('hidden');
} else {
this.$truncatedInfo.addClass('hidden');
}
this.isLogComplete = log.complete;
if (log.complete === false) {
this.timeout = setTimeout(() => {
this.getBuildTrace();
}, 4000);
} else {
this.$buildRefreshAnimation.remove();
2017-05-30 08:43:13 +00:00
this.toggleScrollAnimation(false);
}
if (log.status !== this.buildStatus) {
2017-12-11 12:28:11 +00:00
visitUrl(this.pagePath);
}
2017-05-30 08:43:13 +00:00
})
2018-01-30 16:33:23 +00:00
.catch(() => {
this.$buildRefreshAnimation.remove();
})
.then(() => {
if (this.isScrollInBottom) {
this.scrollDown();
}
})
.then(() => this.toggleScroll());
}
// eslint-disable-next-line class-methods-use-this
shouldHideSidebarForViewport() {
const bootstrapBreakpoint = bp.getBreakpointSize();
return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm';
}
toggleSidebar(shouldHide) {
const shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined;
const $toggleButton = $('.js-sidebar-build-toggle-header');
2017-05-30 08:43:13 +00:00
this.$sidebar
.toggleClass('right-sidebar-expanded', shouldShow)
.toggleClass('right-sidebar-collapsed', shouldHide);
this.$topBar
.toggleClass('sidebar-expanded', shouldShow)
.toggleClass('sidebar-collapsed', shouldHide);
if (this.$sidebar.hasClass('right-sidebar-expanded')) {
$toggleButton.addClass('hidden');
} else {
$toggleButton.removeClass('hidden');
}
}
sidebarOnResize() {
this.toggleSidebar(this.shouldHideSidebarForViewport());
}
sidebarOnClick() {
if (this.shouldHideSidebarForViewport()) this.toggleSidebar();
}
// eslint-disable-next-line class-methods-use-this
populateJobs(stage) {
$('.build-job').hide();
$(`.build-job[data-stage="${stage}"]`).show();
}
// eslint-disable-next-line class-methods-use-this
updateStageDropdownText(stage) {
$('.stage-selection').text(stage);
}
updateDropdown(e) {
e.preventDefault();
const stage = e.currentTarget.text;
this.updateStageDropdownText(stage);
this.populateJobs(stage);
}
}