Revert change to design. Go back to scrollable page
This commit is contained in:
parent
9e4aef263a
commit
2c1f000e3e
|
@ -13,25 +13,21 @@ window.Build = (function () {
|
|||
this.options = options || $('.js-build-options').data();
|
||||
|
||||
this.pageUrl = this.options.pageUrl;
|
||||
this.buildUrl = this.options.buildUrl;
|
||||
this.buildStatus = this.options.buildStatus;
|
||||
this.state = this.options.logState;
|
||||
this.buildStage = this.options.buildStage;
|
||||
this.$document = $(document);
|
||||
this.logBytes = 0;
|
||||
this.scrollOffsetPadding = 30;
|
||||
this.hasBeenScrolled = false;
|
||||
|
||||
this.updateDropdown = this.updateDropdown.bind(this);
|
||||
this.getBuildTrace = this.getBuildTrace.bind(this);
|
||||
this.scrollToBottom = this.scrollToBottom.bind(this);
|
||||
|
||||
this.$body = $('body');
|
||||
this.$buildTrace = $('#build-trace');
|
||||
this.$buildRefreshAnimation = $('.js-build-refresh');
|
||||
this.$truncatedInfo = $('.js-truncated-info');
|
||||
this.$buildTraceOutput = $('.js-build-output');
|
||||
this.$scrollContainer = $('.js-scroll-container');
|
||||
this.$topBar = $('.js-top-bar');
|
||||
|
||||
// Scroll controllers
|
||||
this.$scrollTopBtn = $('.js-scroll-up');
|
||||
|
@ -63,13 +59,22 @@ window.Build = (function () {
|
|||
.off('click')
|
||||
.on('click', this.scrollToBottom.bind(this));
|
||||
|
||||
const scrollThrottled = _.throttle(this.toggleScroll.bind(this), 100);
|
||||
this.scrollThrottled = _.throttle(this.toggleScroll.bind(this), 100);
|
||||
|
||||
this.$scrollContainer
|
||||
$(window)
|
||||
.off('scroll')
|
||||
.on('scroll', () => {
|
||||
this.hasBeenScrolled = true;
|
||||
scrollThrottled();
|
||||
const contentHeight = this.$buildTraceOutput.prop('scrollHeight');
|
||||
if (contentHeight > this.windowSize) {
|
||||
// means the user did not scroll, the content was updated.
|
||||
this.windowSize = contentHeight;
|
||||
} else {
|
||||
// User scrolled
|
||||
this.hasBeenScrolled = true;
|
||||
this.toggleScrollAnimation(false);
|
||||
}
|
||||
|
||||
this.scrollThrottled();
|
||||
});
|
||||
|
||||
$(window)
|
||||
|
@ -77,59 +82,73 @@ window.Build = (function () {
|
|||
.on('resize.build', _.throttle(this.sidebarOnResize.bind(this), 100));
|
||||
|
||||
this.updateArtifactRemoveDate();
|
||||
this.initAffixTopArea();
|
||||
|
||||
// eslint-disable-next-line
|
||||
this.getBuildTrace()
|
||||
.then(() => this.toggleScroll())
|
||||
.then(() => {
|
||||
if (!this.hasBeenScrolled) {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
})
|
||||
.then(() => this.verifyTopPosition());
|
||||
this.getBuildTrace();
|
||||
}
|
||||
|
||||
Build.prototype.canScroll = function () {
|
||||
return (this.$scrollContainer.prop('scrollHeight') - this.scrollOffsetPadding) > this.$scrollContainer.height();
|
||||
Build.prototype.initAffixTopArea = function () {
|
||||
/**
|
||||
If the browser does not support position sticky, it returns the position as static.
|
||||
If the browser does support sticky, then we allow the browser to handle it, if not
|
||||
then we default back to Bootstraps affix
|
||||
**/
|
||||
if (this.$topBar.css('position') !== 'static') return;
|
||||
|
||||
const offsetTop = this.$buildTrace.offset().top;
|
||||
|
||||
this.$topBar.affix({
|
||||
offset: {
|
||||
top: offsetTop,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
Build.prototype.canScroll = function () {
|
||||
return document.body.scrollHeight > window.innerHeight;
|
||||
};
|
||||
|
||||
/**
|
||||
* | | Up | Down |
|
||||
* |--------------------------|----------|----------|
|
||||
* | on scroll bottom | active | disabled |
|
||||
* | on scroll top | disabled | active |
|
||||
* | no scroll | disabled | disabled |
|
||||
* | on.('scroll') is on top | disabled | active |
|
||||
* | on('scroll) is on bottom | active | disabled |
|
||||
*
|
||||
*/
|
||||
Build.prototype.toggleScroll = function () {
|
||||
const currentPosition = this.$scrollContainer.scrollTop();
|
||||
const bottomScroll = currentPosition + this.$scrollContainer.innerHeight();
|
||||
const currentPosition = document.body.scrollTop;
|
||||
const windowHeight = window.innerHeight;
|
||||
|
||||
if (this.canScroll()) {
|
||||
if (currentPosition === 0) {
|
||||
if (currentPosition > 0 &&
|
||||
(document.body.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 Build Log
|
||||
|
||||
this.toggleDisableButton(this.$scrollTopBtn, true);
|
||||
this.toggleDisableButton(this.$scrollBottomBtn, false);
|
||||
} else if (bottomScroll === this.$scrollContainer.prop('scrollHeight')) {
|
||||
} else if (document.body.scrollHeight - currentPosition === windowHeight) {
|
||||
// User is at the bottom of the build log.
|
||||
|
||||
this.toggleDisableButton(this.$scrollTopBtn, false);
|
||||
this.toggleDisableButton(this.$scrollBottomBtn, true);
|
||||
} else {
|
||||
this.toggleDisableButton(this.$scrollTopBtn, false);
|
||||
this.toggleDisableButton(this.$scrollBottomBtn, false);
|
||||
}
|
||||
} else {
|
||||
this.toggleDisableButton(this.$scrollTopBtn, true);
|
||||
this.toggleDisableButton(this.$scrollBottomBtn, true);
|
||||
}
|
||||
};
|
||||
|
||||
Build.prototype.scrollToTop = function () {
|
||||
this.hasBeenScrolled = true;
|
||||
this.$scrollContainer.scrollTop(0);
|
||||
this.toggleScroll();
|
||||
Build.prototype.scrollDown = function () {
|
||||
document.body.scrollTop = document.body.scrollHeight;
|
||||
};
|
||||
|
||||
Build.prototype.scrollToBottom = function () {
|
||||
this.scrollDown();
|
||||
this.hasBeenScrolled = true;
|
||||
this.toggleScroll();
|
||||
};
|
||||
|
||||
Build.prototype.scrollToTop = function () {
|
||||
document.body.scrollTop = 0;
|
||||
this.hasBeenScrolled = true;
|
||||
this.$scrollContainer.scrollTop(this.$scrollContainer.prop('scrollHeight'));
|
||||
this.toggleScroll();
|
||||
};
|
||||
|
||||
|
@ -142,47 +161,6 @@ window.Build = (function () {
|
|||
this.$scrollBottomBtn.toggleClass('animate', toggle);
|
||||
};
|
||||
|
||||
/**
|
||||
* Build trace top position depends on the space ocupied by the elments rendered before
|
||||
*/
|
||||
Build.prototype.verifyTopPosition = function () {
|
||||
const $buildPage = $('.build-page');
|
||||
|
||||
const $flashError = $('.alert-wrapper');
|
||||
const $header = $('.build-header', $buildPage);
|
||||
const $runnersStuck = $('.js-build-stuck', $buildPage);
|
||||
const $startsEnvironment = $('.js-environment-container', $buildPage);
|
||||
const $erased = $('.js-build-erased', $buildPage);
|
||||
const prependTopDefault = 20;
|
||||
|
||||
// header + navigation + margin
|
||||
let topPostion = 168;
|
||||
|
||||
if ($header.length) {
|
||||
topPostion += $header.outerHeight();
|
||||
}
|
||||
|
||||
if ($runnersStuck.length) {
|
||||
topPostion += $runnersStuck.outerHeight();
|
||||
}
|
||||
|
||||
if ($startsEnvironment.length) {
|
||||
topPostion += $startsEnvironment.outerHeight() + prependTopDefault;
|
||||
}
|
||||
|
||||
if ($erased.length) {
|
||||
topPostion += $erased.outerHeight() + prependTopDefault;
|
||||
}
|
||||
|
||||
if ($flashError.length) {
|
||||
topPostion += $flashError.outerHeight() + prependTopDefault;
|
||||
}
|
||||
|
||||
this.$buildTrace.css({
|
||||
top: topPostion,
|
||||
});
|
||||
};
|
||||
|
||||
Build.prototype.initSidebar = function () {
|
||||
this.$sidebar = $('.js-build-sidebar');
|
||||
this.$sidebar.niceScroll();
|
||||
|
@ -200,6 +178,8 @@ window.Build = (function () {
|
|||
this.state = log.state;
|
||||
}
|
||||
|
||||
this.windowSize = this.$buildTraceOutput.prop('scrollHeight');
|
||||
|
||||
if (log.append) {
|
||||
this.$buildTraceOutput.append(log.html);
|
||||
this.logBytes += log.size;
|
||||
|
@ -227,14 +207,7 @@ window.Build = (function () {
|
|||
}
|
||||
|
||||
Build.timeout = setTimeout(() => {
|
||||
//eslint-disable-next-line
|
||||
this.getBuildTrace()
|
||||
.then(() => {
|
||||
if (!this.hasBeenScrolled) {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
})
|
||||
.then(() => this.verifyTopPosition());
|
||||
this.getBuildTrace();
|
||||
}, 4000);
|
||||
} else {
|
||||
this.$buildRefreshAnimation.remove();
|
||||
|
@ -247,7 +220,13 @@ window.Build = (function () {
|
|||
})
|
||||
.fail(() => {
|
||||
this.$buildRefreshAnimation.remove();
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
if (!this.hasBeenScrolled) {
|
||||
this.scrollDown();
|
||||
}
|
||||
})
|
||||
.then(() => this.toggleScroll());
|
||||
};
|
||||
|
||||
Build.prototype.shouldHideSidebarForViewport = function () {
|
||||
|
@ -259,14 +238,11 @@ window.Build = (function () {
|
|||
const shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined;
|
||||
const $toggleButton = $('.js-sidebar-build-toggle-header');
|
||||
|
||||
this.$buildTrace
|
||||
.toggleClass('sidebar-expanded', shouldShow)
|
||||
.toggleClass('sidebar-collapsed', shouldHide);
|
||||
this.$sidebar
|
||||
.toggleClass('right-sidebar-expanded', shouldShow)
|
||||
.toggleClass('right-sidebar-collapsed', shouldHide);
|
||||
|
||||
$('.js-build-page')
|
||||
this.$topBar
|
||||
.toggleClass('sidebar-expanded', shouldShow)
|
||||
.toggleClass('sidebar-collapsed', shouldHide);
|
||||
|
||||
|
@ -279,17 +255,10 @@ window.Build = (function () {
|
|||
|
||||
Build.prototype.sidebarOnResize = function () {
|
||||
this.toggleSidebar(this.shouldHideSidebarForViewport());
|
||||
|
||||
this.verifyTopPosition();
|
||||
|
||||
if (this.canScroll()) {
|
||||
this.toggleScroll();
|
||||
}
|
||||
};
|
||||
|
||||
Build.prototype.sidebarOnClick = function () {
|
||||
if (this.shouldHideSidebarForViewport()) this.toggleSidebar();
|
||||
this.verifyTopPosition();
|
||||
};
|
||||
|
||||
Build.prototype.updateArtifactRemoveDate = function () {
|
||||
|
|
|
@ -26,14 +26,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
mounted() {
|
||||
this.mediator.initBuildClass();
|
||||
},
|
||||
updated() {
|
||||
// Wait for flash message to be appended
|
||||
Vue.nextTick(() => {
|
||||
if (this.mediator.build) {
|
||||
this.mediator.build.verifyTopPosition();
|
||||
}
|
||||
});
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement('job-header', {
|
||||
props: {
|
||||
|
|
|
@ -37,65 +37,77 @@
|
|||
}
|
||||
|
||||
.build-page {
|
||||
.sticky {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
.build-trace-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.build-trace-container {
|
||||
position: absolute;
|
||||
top: 225px;
|
||||
left: 15px;
|
||||
bottom: 10px;
|
||||
.build-trace {
|
||||
background: $black;
|
||||
color: $gray-darkest;
|
||||
font-family: $monospace_font;
|
||||
white-space: pre;
|
||||
overflow-x: auto;
|
||||
font-size: 12px;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
|
||||
&.sidebar-expanded {
|
||||
right: 305px;
|
||||
.bash {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.top-bar {
|
||||
height: 35px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
background: $gray-light;
|
||||
border: 1px solid $border-color;
|
||||
color: $gl-text-color;
|
||||
position: sticky;
|
||||
position: -webkit-sticky;
|
||||
top: 50px;
|
||||
|
||||
&.affix {
|
||||
top: 50px;
|
||||
}
|
||||
|
||||
&.sidebar-collapsed {
|
||||
// with sidebar
|
||||
&.affix.sidebar-expanded {
|
||||
right: 306px;
|
||||
left: 16px;
|
||||
}
|
||||
|
||||
// without sidebar
|
||||
&.affix.sidebar-collapsed {
|
||||
right: 16px;
|
||||
left: 16px;
|
||||
}
|
||||
|
||||
code {
|
||||
background: $black;
|
||||
color: $gray-darkest;
|
||||
&.affix-top {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.top-bar {
|
||||
top: 0;
|
||||
height: 35px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
background: $gray-light;
|
||||
border: 1px solid $border-color;
|
||||
color: $gl-text-color;
|
||||
.truncated-info {
|
||||
margin: 0 auto;
|
||||
align-self: center;
|
||||
|
||||
.truncated-info {
|
||||
margin: 0 auto;
|
||||
align-self: center;
|
||||
.truncated-info-size {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.truncated-info-size {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.raw-link {
|
||||
color: $gl-text-color;
|
||||
margin-left: 5px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.raw-link {
|
||||
color: $gl-text-color;
|
||||
margin-left: 5px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.controllers {
|
||||
display: flex;
|
||||
align-self: center;
|
||||
font-size: 15px;
|
||||
margin-bottom: 4px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
svg {
|
||||
height: 15px;
|
||||
|
@ -103,17 +115,9 @@
|
|||
fill: $gl-text-color;
|
||||
}
|
||||
|
||||
.controllers-buttons,
|
||||
.btn-scroll {
|
||||
color: $gl-text-color;
|
||||
height: 15px;
|
||||
vertical-align: middle;
|
||||
padding: 0;
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
.controllers-buttons {
|
||||
margin: 1px 10px;
|
||||
color: $gl-text-color;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.btn-scroll.animate {
|
||||
|
@ -143,15 +147,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.bash {
|
||||
top: 35px;
|
||||
left: 10px;
|
||||
bottom: 0;
|
||||
padding: 10px 20px 20px 5px;
|
||||
white-space: pre-wrap;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.environment-information {
|
||||
border: 1px solid $border-color;
|
||||
padding: 8px $gl-padding 12px;
|
||||
|
|
|
@ -54,13 +54,14 @@
|
|||
- else
|
||||
Job has been erased #{time_ago_with_tooltip(@build.erased_at)}
|
||||
|
||||
.build-trace-container#build-trace
|
||||
.top-bar.sticky
|
||||
.build-trace-container.prepend-top-default
|
||||
.top-bar.js-top-bar
|
||||
.js-truncated-info.truncated-info.hidden<
|
||||
Showing last
|
||||
%span.js-truncated-info-size.truncated-info-size><
|
||||
KiB of log -
|
||||
%a.js-raw-link.raw-link{ href: raw_namespace_project_job_path(@project.namespace, @project, @build) }>< Complete Raw
|
||||
|
||||
.controllers
|
||||
- if @build.has_trace?
|
||||
= link_to raw_namespace_project_job_path(@project.namespace, @project, @build),
|
||||
|
@ -82,10 +83,12 @@
|
|||
.has-tooltip.controllers-buttons{ title: 'Scroll to bottom', data: { placement: 'top', container: 'body'} }
|
||||
%button.js-scroll-down.btn-scroll.btn-transparent.btn-blank{ type: 'button', disabled: true }
|
||||
= custom_icon('scroll_down')
|
||||
.bash.sticky.js-scroll-container
|
||||
%code.js-build-output
|
||||
|
||||
%pre.build-trace#build-trace
|
||||
%code.bash.js-build-output
|
||||
.build-loader-animation.js-build-refresh
|
||||
|
||||
|
||||
= render "sidebar"
|
||||
|
||||
.js-build-options{ data: javascript_build_options }
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Update jobs page output to have a scrollable page
|
||||
merge_request: 12587
|
||||
author:
|
Loading…
Reference in New Issue