提交 2c1f000e 编写于 作者: F Filipa Lacerda 提交者: Phil Hughes

Revert change to design. Go back to scrollable page

上级 9e4aef26
...@@ -13,25 +13,21 @@ window.Build = (function () { ...@@ -13,25 +13,21 @@ window.Build = (function () {
this.options = options || $('.js-build-options').data(); this.options = options || $('.js-build-options').data();
this.pageUrl = this.options.pageUrl; this.pageUrl = this.options.pageUrl;
this.buildUrl = this.options.buildUrl;
this.buildStatus = this.options.buildStatus; this.buildStatus = this.options.buildStatus;
this.state = this.options.logState; this.state = this.options.logState;
this.buildStage = this.options.buildStage; this.buildStage = this.options.buildStage;
this.$document = $(document); this.$document = $(document);
this.logBytes = 0; this.logBytes = 0;
this.scrollOffsetPadding = 30;
this.hasBeenScrolled = false; this.hasBeenScrolled = false;
this.updateDropdown = this.updateDropdown.bind(this); this.updateDropdown = this.updateDropdown.bind(this);
this.getBuildTrace = this.getBuildTrace.bind(this); this.getBuildTrace = this.getBuildTrace.bind(this);
this.scrollToBottom = this.scrollToBottom.bind(this);
this.$body = $('body');
this.$buildTrace = $('#build-trace'); this.$buildTrace = $('#build-trace');
this.$buildRefreshAnimation = $('.js-build-refresh'); this.$buildRefreshAnimation = $('.js-build-refresh');
this.$truncatedInfo = $('.js-truncated-info'); this.$truncatedInfo = $('.js-truncated-info');
this.$buildTraceOutput = $('.js-build-output'); this.$buildTraceOutput = $('.js-build-output');
this.$scrollContainer = $('.js-scroll-container'); this.$topBar = $('.js-top-bar');
// Scroll controllers // Scroll controllers
this.$scrollTopBtn = $('.js-scroll-up'); this.$scrollTopBtn = $('.js-scroll-up');
...@@ -63,13 +59,22 @@ window.Build = (function () { ...@@ -63,13 +59,22 @@ window.Build = (function () {
.off('click') .off('click')
.on('click', this.scrollToBottom.bind(this)); .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') .off('scroll')
.on('scroll', () => { .on('scroll', () => {
this.hasBeenScrolled = true; const contentHeight = this.$buildTraceOutput.prop('scrollHeight');
scrollThrottled(); 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) $(window)
...@@ -77,59 +82,73 @@ window.Build = (function () { ...@@ -77,59 +82,73 @@ window.Build = (function () {
.on('resize.build', _.throttle(this.sidebarOnResize.bind(this), 100)); .on('resize.build', _.throttle(this.sidebarOnResize.bind(this), 100));
this.updateArtifactRemoveDate(); this.updateArtifactRemoveDate();
this.initAffixTopArea();
// eslint-disable-next-line this.getBuildTrace();
this.getBuildTrace()
.then(() => this.toggleScroll())
.then(() => {
if (!this.hasBeenScrolled) {
this.scrollToBottom();
}
})
.then(() => this.verifyTopPosition());
} }
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 () { Build.prototype.canScroll = function () {
return (this.$scrollContainer.prop('scrollHeight') - this.scrollOffsetPadding) > this.$scrollContainer.height(); 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 () { Build.prototype.toggleScroll = function () {
const currentPosition = this.$scrollContainer.scrollTop(); const currentPosition = document.body.scrollTop;
const bottomScroll = currentPosition + this.$scrollContainer.innerHeight(); const windowHeight = window.innerHeight;
if (this.canScroll()) { 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.$scrollTopBtn, true);
this.toggleDisableButton(this.$scrollBottomBtn, false); 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.$scrollTopBtn, false);
this.toggleDisableButton(this.$scrollBottomBtn, true); 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 () { Build.prototype.scrollDown = function () {
document.body.scrollTop = document.body.scrollHeight;
};
Build.prototype.scrollToBottom = function () {
this.scrollDown();
this.hasBeenScrolled = true; this.hasBeenScrolled = true;
this.$scrollContainer.scrollTop(0);
this.toggleScroll(); this.toggleScroll();
}; };
Build.prototype.scrollToBottom = function () { Build.prototype.scrollToTop = function () {
document.body.scrollTop = 0;
this.hasBeenScrolled = true; this.hasBeenScrolled = true;
this.$scrollContainer.scrollTop(this.$scrollContainer.prop('scrollHeight'));
this.toggleScroll(); this.toggleScroll();
}; };
...@@ -142,47 +161,6 @@ window.Build = (function () { ...@@ -142,47 +161,6 @@ window.Build = (function () {
this.$scrollBottomBtn.toggleClass('animate', toggle); 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 () { Build.prototype.initSidebar = function () {
this.$sidebar = $('.js-build-sidebar'); this.$sidebar = $('.js-build-sidebar');
this.$sidebar.niceScroll(); this.$sidebar.niceScroll();
...@@ -200,6 +178,8 @@ window.Build = (function () { ...@@ -200,6 +178,8 @@ window.Build = (function () {
this.state = log.state; this.state = log.state;
} }
this.windowSize = this.$buildTraceOutput.prop('scrollHeight');
if (log.append) { if (log.append) {
this.$buildTraceOutput.append(log.html); this.$buildTraceOutput.append(log.html);
this.logBytes += log.size; this.logBytes += log.size;
...@@ -227,14 +207,7 @@ window.Build = (function () { ...@@ -227,14 +207,7 @@ window.Build = (function () {
} }
Build.timeout = setTimeout(() => { Build.timeout = setTimeout(() => {
//eslint-disable-next-line this.getBuildTrace();
this.getBuildTrace()
.then(() => {
if (!this.hasBeenScrolled) {
this.scrollToBottom();
}
})
.then(() => this.verifyTopPosition());
}, 4000); }, 4000);
} else { } else {
this.$buildRefreshAnimation.remove(); this.$buildRefreshAnimation.remove();
...@@ -247,7 +220,13 @@ window.Build = (function () { ...@@ -247,7 +220,13 @@ window.Build = (function () {
}) })
.fail(() => { .fail(() => {
this.$buildRefreshAnimation.remove(); this.$buildRefreshAnimation.remove();
}); })
.then(() => {
if (!this.hasBeenScrolled) {
this.scrollDown();
}
})
.then(() => this.toggleScroll());
}; };
Build.prototype.shouldHideSidebarForViewport = function () { Build.prototype.shouldHideSidebarForViewport = function () {
...@@ -259,14 +238,11 @@ window.Build = (function () { ...@@ -259,14 +238,11 @@ window.Build = (function () {
const shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined; const shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined;
const $toggleButton = $('.js-sidebar-build-toggle-header'); const $toggleButton = $('.js-sidebar-build-toggle-header');
this.$buildTrace
.toggleClass('sidebar-expanded', shouldShow)
.toggleClass('sidebar-collapsed', shouldHide);
this.$sidebar this.$sidebar
.toggleClass('right-sidebar-expanded', shouldShow) .toggleClass('right-sidebar-expanded', shouldShow)
.toggleClass('right-sidebar-collapsed', shouldHide); .toggleClass('right-sidebar-collapsed', shouldHide);
$('.js-build-page') this.$topBar
.toggleClass('sidebar-expanded', shouldShow) .toggleClass('sidebar-expanded', shouldShow)
.toggleClass('sidebar-collapsed', shouldHide); .toggleClass('sidebar-collapsed', shouldHide);
...@@ -279,17 +255,10 @@ window.Build = (function () { ...@@ -279,17 +255,10 @@ window.Build = (function () {
Build.prototype.sidebarOnResize = function () { Build.prototype.sidebarOnResize = function () {
this.toggleSidebar(this.shouldHideSidebarForViewport()); this.toggleSidebar(this.shouldHideSidebarForViewport());
this.verifyTopPosition();
if (this.canScroll()) {
this.toggleScroll();
}
}; };
Build.prototype.sidebarOnClick = function () { Build.prototype.sidebarOnClick = function () {
if (this.shouldHideSidebarForViewport()) this.toggleSidebar(); if (this.shouldHideSidebarForViewport()) this.toggleSidebar();
this.verifyTopPosition();
}; };
Build.prototype.updateArtifactRemoveDate = function () { Build.prototype.updateArtifactRemoveDate = function () {
......
...@@ -26,14 +26,6 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -26,14 +26,6 @@ document.addEventListener('DOMContentLoaded', () => {
mounted() { mounted() {
this.mediator.initBuildClass(); this.mediator.initBuildClass();
}, },
updated() {
// Wait for flash message to be appended
Vue.nextTick(() => {
if (this.mediator.build) {
this.mediator.build.verifyTopPosition();
}
});
},
render(createElement) { render(createElement) {
return createElement('job-header', { return createElement('job-header', {
props: { props: {
......
...@@ -37,65 +37,77 @@ ...@@ -37,65 +37,77 @@
} }
.build-page { .build-page {
.sticky { .build-trace-container {
position: absolute; position: relative;
left: 0;
right: 0;
} }
.build-trace-container { .build-trace {
position: absolute;
top: 225px;
left: 15px;
bottom: 10px;
background: $black; background: $black;
color: $gray-darkest; color: $gray-darkest;
font-family: $monospace_font; white-space: pre;
overflow-x: auto;
font-size: 12px; font-size: 12px;
border-radius: 0;
border: none;
&.sidebar-expanded { .bash {
right: 305px; display: block;
} }
}
&.sidebar-collapsed { .top-bar {
right: 16px; 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;
} }
code { // with sidebar
background: $black; &.affix.sidebar-expanded {
color: $gray-darkest; right: 306px;
left: 16px;
} }
.top-bar { // without sidebar
top: 0; &.affix.sidebar-collapsed {
height: 35px; right: 16px;
display: flex; left: 16px;
justify-content: flex-end; }
background: $gray-light;
border: 1px solid $border-color;
color: $gl-text-color;
.truncated-info { &.affix-top {
margin: 0 auto; position: absolute;
align-self: center; right: 0;
left: 0;
}
.truncated-info-size { .truncated-info {
margin: 0 5px; margin: 0 auto;
} align-self: center;
.raw-link { .truncated-info-size {
color: $gl-text-color; margin: 0 5px;
margin-left: 5px; }
text-decoration: underline;
} .raw-link {
color: $gl-text-color;
margin-left: 5px;
text-decoration: underline;
} }
} }
.controllers { .controllers {
display: flex; display: flex;
align-self: center;
font-size: 15px; font-size: 15px;
margin-bottom: 4px; justify-content: center;
align-items: center;
svg { svg {
height: 15px; height: 15px;
...@@ -103,17 +115,9 @@ ...@@ -103,17 +115,9 @@
fill: $gl-text-color; fill: $gl-text-color;
} }
.controllers-buttons,
.btn-scroll {
color: $gl-text-color;
height: 15px;
vertical-align: middle;
padding: 0;
width: 12px;
}
.controllers-buttons { .controllers-buttons {
margin: 1px 10px; color: $gl-text-color;
margin: 0 10px;
} }
.btn-scroll.animate { .btn-scroll.animate {
...@@ -143,15 +147,6 @@ ...@@ -143,15 +147,6 @@
} }
} }
.bash {
top: 35px;
left: 10px;
bottom: 0;
padding: 10px 20px 20px 5px;
white-space: pre-wrap;
overflow: auto;
}
.environment-information { .environment-information {
border: 1px solid $border-color; border: 1px solid $border-color;
padding: 8px $gl-padding 12px; padding: 8px $gl-padding 12px;
......
...@@ -54,13 +54,14 @@ ...@@ -54,13 +54,14 @@
- else - else
Job has been erased #{time_ago_with_tooltip(@build.erased_at)} Job has been erased #{time_ago_with_tooltip(@build.erased_at)}
.build-trace-container#build-trace .build-trace-container.prepend-top-default
.top-bar.sticky .top-bar.js-top-bar
.js-truncated-info.truncated-info.hidden< .js-truncated-info.truncated-info.hidden<
Showing last Showing last
%span.js-truncated-info-size.truncated-info-size>< %span.js-truncated-info-size.truncated-info-size><
KiB of log - KiB of log -
%a.js-raw-link.raw-link{ href: raw_namespace_project_job_path(@project.namespace, @project, @build) }>< Complete Raw %a.js-raw-link.raw-link{ href: raw_namespace_project_job_path(@project.namespace, @project, @build) }>< Complete Raw
.controllers .controllers
- if @build.has_trace? - if @build.has_trace?
= link_to raw_namespace_project_job_path(@project.namespace, @project, @build), = link_to raw_namespace_project_job_path(@project.namespace, @project, @build),
...@@ -82,10 +83,12 @@ ...@@ -82,10 +83,12 @@
.has-tooltip.controllers-buttons{ title: 'Scroll to bottom', data: { placement: 'top', container: 'body'} } .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 } %button.js-scroll-down.btn-scroll.btn-transparent.btn-blank{ type: 'button', disabled: true }
= custom_icon('scroll_down') = 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 .build-loader-animation.js-build-refresh
= render "sidebar" = render "sidebar"
.js-build-options{ data: javascript_build_options } .js-build-options{ data: javascript_build_options }
......
---
title: Update jobs page output to have a scrollable page
merge_request: 12587
author:
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册