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.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 () {
|
||||||
.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 () {
|
||||||
.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.canScroll = function () {
|
Build.prototype.initAffixTopArea = function () {
|
||||||
return (this.$scrollContainer.prop('scrollHeight') - this.scrollOffsetPadding) > this.$scrollContainer.height();
|
/**
|
||||||
|
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 () {
|
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 () {
|
||||||
this.hasBeenScrolled = true;
|
document.body.scrollTop = document.body.scrollHeight;
|
||||||
this.$scrollContainer.scrollTop(0);
|
|
||||||
this.toggleScroll();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Build.prototype.scrollToBottom = function () {
|
Build.prototype.scrollToBottom = function () {
|
||||||
|
this.scrollDown();
|
||||||
|
this.hasBeenScrolled = true;
|
||||||
|
this.toggleScroll();
|
||||||
|
};
|
||||||
|
|
||||||
|
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 () {
|
||||||
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 () {
|
||||||
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 () {
|
||||||
}
|
}
|
||||||
|
|
||||||
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 () {
|
||||||
})
|
})
|
||||||
.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 () {
|
||||||
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 () {
|
||||||
|
|
||||||
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', () => {
|
||||||
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 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
right: 16px;
|
||||||
|
left: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
&.affix-top {
|
||||||
background: $black;
|
position: absolute;
|
||||||
color: $gray-darkest;
|
right: 0;
|
||||||
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-bar {
|
.truncated-info {
|
||||||
top: 0;
|
margin: 0 auto;
|
||||||
height: 35px;
|
align-self: center;
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
background: $gray-light;
|
|
||||||
border: 1px solid $border-color;
|
|
||||||
color: $gl-text-color;
|
|
||||||
|
|
||||||
.truncated-info {
|
.truncated-info-size {
|
||||||
margin: 0 auto;
|
margin: 0 5px;
|
||||||
align-self: center;
|
}
|
||||||
|
|
||||||
.truncated-info-size {
|
.raw-link {
|
||||||
margin: 0 5px;
|
color: $gl-text-color;
|
||||||
}
|
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 @@
|
||||||
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 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.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 @@
|
||||||
- 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 @@
|
||||||
.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 }
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
title: Update jobs page output to have a scrollable page
|
||||||
|
merge_request: 12587
|
||||||
|
author:
|
Loading…
Reference in New Issue