parent
af07c490b2
commit
90216b2066
11 changed files with 175 additions and 30 deletions
125
app/assets/javascripts/ide/components/jobs/detail.vue
Normal file
125
app/assets/javascripts/ide/components/jobs/detail.vue
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
<script>
|
||||||
|
import { mapState } from 'vuex';
|
||||||
|
import tooltip from '../../../vue_shared/directives/tooltip';
|
||||||
|
import Icon from '../../../vue_shared/components/icon.vue';
|
||||||
|
import Job from '../../../job';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
directives: {
|
||||||
|
tooltip,
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Icon,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState('pipelines', ['detailJob']),
|
||||||
|
rawUrl() {
|
||||||
|
return `${this.detailJob.path}/raw`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.job = new Job({
|
||||||
|
buildStage: 'a',
|
||||||
|
buildState: this.detailJob.status.text,
|
||||||
|
pagePath: this.detailJob.path,
|
||||||
|
redirectToJob: false,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.job.destroy();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="ide-pipeline build-page">
|
||||||
|
<header
|
||||||
|
class="ide-tree-header ide-pipeline-header"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="btn btn-default btn-sm"
|
||||||
|
@click="() => { $store.state.pipelines.detailJob = null; $store.dispatch('setRightPane', 'pipelines-list') }"
|
||||||
|
>
|
||||||
|
<icon
|
||||||
|
name="chevron-left"
|
||||||
|
/>
|
||||||
|
{{ __('View jobs') }}
|
||||||
|
</button>
|
||||||
|
</header>
|
||||||
|
<div class="build-trace-container prepend-top-default">
|
||||||
|
<div
|
||||||
|
v-once
|
||||||
|
class="top-bar js-top-bar"
|
||||||
|
>
|
||||||
|
<div class="controllers float-right">
|
||||||
|
<a
|
||||||
|
v-tooltip
|
||||||
|
:title="__('Show complete raw')"
|
||||||
|
data-placement="top"
|
||||||
|
data-container="body"
|
||||||
|
class="js-raw-link-controller controllers-buttons"
|
||||||
|
:href="rawUrl"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
aria-hidden="true"
|
||||||
|
class="fa fa-file-text-o"
|
||||||
|
></i>
|
||||||
|
</a>
|
||||||
|
<div
|
||||||
|
v-tooltip
|
||||||
|
class="controllers-buttons"
|
||||||
|
data-container="body"
|
||||||
|
data-placement="top"
|
||||||
|
:title="__('Scroll to top')"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="js-scroll-up btn-scroll btn-transparent btn-blank"
|
||||||
|
disabled
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<icon
|
||||||
|
name="scroll_up"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-tooltip
|
||||||
|
class="controllers-buttons"
|
||||||
|
data-container="body"
|
||||||
|
data-placement="top"
|
||||||
|
:title="__('Scroll to top')"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="js-scroll-up btn-scroll btn-transparent btn-blank"
|
||||||
|
disabled
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<icon
|
||||||
|
name="scroll_down"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<pre
|
||||||
|
class="build-trace"
|
||||||
|
id="build-trace"
|
||||||
|
>
|
||||||
|
<code class="bash js-build-output">
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.build-trace-container {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ide-tree-header .btn {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -42,5 +42,17 @@ export default {
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
|
<button
|
||||||
|
class="btn btn-default btn-sm"
|
||||||
|
@click="() => { $store.state.pipelines.detailJob = job; $store.dispatch('setRightPane', 'jobs-detail') }"
|
||||||
|
>
|
||||||
|
{{ __('View log') }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.btn {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -4,6 +4,7 @@ import tooltip from '../../../vue_shared/directives/tooltip';
|
||||||
import Icon from '../../../vue_shared/components/icon.vue';
|
import Icon from '../../../vue_shared/components/icon.vue';
|
||||||
import { rightSidebarViews } from '../../constants';
|
import { rightSidebarViews } from '../../constants';
|
||||||
import PipelinesList from '../pipelines/list.vue';
|
import PipelinesList from '../pipelines/list.vue';
|
||||||
|
import JobsDetail from '../jobs/detail.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
directives: {
|
directives: {
|
||||||
|
@ -12,6 +13,7 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
Icon,
|
Icon,
|
||||||
PipelinesList,
|
PipelinesList,
|
||||||
|
JobsDetail,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['rightPane']),
|
...mapState(['rightPane']),
|
||||||
|
|
|
@ -23,4 +23,5 @@ export const viewerTypes = {
|
||||||
|
|
||||||
export const rightSidebarViews = {
|
export const rightSidebarViews = {
|
||||||
pipelines: 'pipelines-list',
|
pipelines: 'pipelines-list',
|
||||||
|
jobsDetail: 'jobs-detail',
|
||||||
};
|
};
|
||||||
|
|
|
@ -77,4 +77,6 @@ export const fetchJobs = ({ dispatch }, stage) => {
|
||||||
export const toggleStageCollapsed = ({ commit }, stageId) =>
|
export const toggleStageCollapsed = ({ commit }, stageId) =>
|
||||||
commit(types.TOGGLE_STAGE_COLLAPSE, stageId);
|
commit(types.TOGGLE_STAGE_COLLAPSE, stageId);
|
||||||
|
|
||||||
|
export const setDetailJob = ({ commit }, job) => commit(types.SET_DETAIL_JOB, job);
|
||||||
|
|
||||||
export default () => {};
|
export default () => {};
|
||||||
|
|
|
@ -7,3 +7,5 @@ export const RECEIVE_JOBS_ERROR = 'RECEIVE_JOBS_ERROR';
|
||||||
export const RECEIVE_JOBS_SUCCESS = 'RECEIVE_JOBS_SUCCESS';
|
export const RECEIVE_JOBS_SUCCESS = 'RECEIVE_JOBS_SUCCESS';
|
||||||
|
|
||||||
export const TOGGLE_STAGE_COLLAPSE = 'TOGGLE_STAGE_COLLAPSE';
|
export const TOGGLE_STAGE_COLLAPSE = 'TOGGLE_STAGE_COLLAPSE';
|
||||||
|
|
||||||
|
export const SET_DETAIL_JOB = 'SET_DETAIL_JOB';
|
||||||
|
|
|
@ -63,4 +63,7 @@ export default {
|
||||||
isCollapsed: stage.id === id ? !stage.isCollapsed : stage.isCollapsed,
|
isCollapsed: stage.id === id ? !stage.isCollapsed : stage.isCollapsed,
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
[types.SET_DETAIL_JOB](state, job) {
|
||||||
|
state.detailJob = job;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,4 +3,5 @@ export default () => ({
|
||||||
isLoadingJobs: false,
|
isLoadingJobs: false,
|
||||||
latestPipeline: null,
|
latestPipeline: null,
|
||||||
stages: [],
|
stages: [],
|
||||||
|
detailJob: null,
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,4 +4,5 @@ export const normalizeJob = job => ({
|
||||||
name: job.name,
|
name: job.name,
|
||||||
status: job.status,
|
status: job.status,
|
||||||
path: job.build_path,
|
path: job.build_path,
|
||||||
|
started: job.started,
|
||||||
});
|
});
|
||||||
|
|
|
@ -22,6 +22,8 @@ export default class Job {
|
||||||
this.$window = $(window);
|
this.$window = $(window);
|
||||||
this.logBytes = 0;
|
this.logBytes = 0;
|
||||||
this.updateDropdown = this.updateDropdown.bind(this);
|
this.updateDropdown = this.updateDropdown.bind(this);
|
||||||
|
this.redirectToJob =
|
||||||
|
this.options.redirectToJob !== undefined ? this.options.redirectToJob : true;
|
||||||
|
|
||||||
this.$buildTrace = $('#build-trace');
|
this.$buildTrace = $('#build-trace');
|
||||||
this.$buildRefreshAnimation = $('.js-build-refresh');
|
this.$buildRefreshAnimation = $('.js-build-refresh');
|
||||||
|
@ -44,31 +46,23 @@ export default class Job {
|
||||||
.off('click', '.js-sidebar-build-toggle')
|
.off('click', '.js-sidebar-build-toggle')
|
||||||
.on('click', '.js-sidebar-build-toggle', this.sidebarOnClick.bind(this));
|
.on('click', '.js-sidebar-build-toggle', this.sidebarOnClick.bind(this));
|
||||||
|
|
||||||
this.$document
|
this.$document.off('click', '.stage-item').on('click', '.stage-item', this.updateDropdown);
|
||||||
.off('click', '.stage-item')
|
|
||||||
.on('click', '.stage-item', this.updateDropdown);
|
|
||||||
|
|
||||||
// add event listeners to the scroll buttons
|
// add event listeners to the scroll buttons
|
||||||
this.$scrollTopBtn
|
this.$scrollTopBtn.off('click').on('click', this.scrollToTop.bind(this));
|
||||||
.off('click')
|
|
||||||
.on('click', this.scrollToTop.bind(this));
|
|
||||||
|
|
||||||
this.$scrollBottomBtn
|
this.$scrollBottomBtn.off('click').on('click', this.scrollToBottom.bind(this));
|
||||||
.off('click')
|
|
||||||
.on('click', this.scrollToBottom.bind(this));
|
|
||||||
|
|
||||||
this.scrollThrottled = _.throttle(this.toggleScroll.bind(this), 100);
|
this.scrollThrottled = _.throttle(this.toggleScroll.bind(this), 100);
|
||||||
|
|
||||||
this.$window
|
this.$window.off('scroll').on('scroll', () => {
|
||||||
.off('scroll')
|
if (!this.isScrolledToBottom()) {
|
||||||
.on('scroll', () => {
|
this.toggleScrollAnimation(false);
|
||||||
if (!this.isScrolledToBottom()) {
|
} else if (this.isScrolledToBottom() && !this.isLogComplete) {
|
||||||
this.toggleScrollAnimation(false);
|
this.toggleScrollAnimation(true);
|
||||||
} else if (this.isScrolledToBottom() && !this.isLogComplete) {
|
}
|
||||||
this.toggleScrollAnimation(true);
|
this.scrollThrottled();
|
||||||
}
|
});
|
||||||
this.scrollThrottled();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.$window
|
this.$window
|
||||||
.off('resize.build')
|
.off('resize.build')
|
||||||
|
@ -79,6 +73,10 @@ export default class Job {
|
||||||
this.getBuildTrace();
|
this.getBuildTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
}
|
||||||
|
|
||||||
initAffixTopArea() {
|
initAffixTopArea() {
|
||||||
/**
|
/**
|
||||||
If the browser does not support position sticky, it returns the position as static.
|
If the browser does not support position sticky, it returns the position as static.
|
||||||
|
@ -102,9 +100,8 @@ export default class Job {
|
||||||
|
|
||||||
const windowHeight = $(window).height();
|
const windowHeight = $(window).height();
|
||||||
if (this.canScroll()) {
|
if (this.canScroll()) {
|
||||||
if (currentPosition > 0 &&
|
if (currentPosition > 0 && scrollHeight - currentPosition !== windowHeight) {
|
||||||
(scrollHeight - currentPosition !== windowHeight)) {
|
// User is in the middle of the log
|
||||||
// User is in the middle of the log
|
|
||||||
|
|
||||||
this.toggleDisableButton(this.$scrollTopBtn, false);
|
this.toggleDisableButton(this.$scrollTopBtn, false);
|
||||||
this.toggleDisableButton(this.$scrollBottomBtn, false);
|
this.toggleDisableButton(this.$scrollBottomBtn, false);
|
||||||
|
@ -169,10 +166,11 @@ export default class Job {
|
||||||
}
|
}
|
||||||
|
|
||||||
getBuildTrace() {
|
getBuildTrace() {
|
||||||
return axios.get(`${this.pagePath}/trace.json`, {
|
return axios
|
||||||
params: { state: this.state },
|
.get(`${this.pagePath}/trace.json`, {
|
||||||
})
|
params: { state: this.state },
|
||||||
.then((res) => {
|
})
|
||||||
|
.then(res => {
|
||||||
const log = res.data;
|
const log = res.data;
|
||||||
|
|
||||||
if (!this.fetchingStatusFavicon) {
|
if (!this.fetchingStatusFavicon) {
|
||||||
|
@ -222,7 +220,7 @@ export default class Job {
|
||||||
this.toggleScrollAnimation(false);
|
this.toggleScrollAnimation(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log.status !== this.buildStatus) {
|
if (log.status !== this.buildStatus && this.redirectToJob) {
|
||||||
visitUrl(this.pagePath);
|
visitUrl(this.pagePath);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1202,7 +1202,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.ide-pipeline-header {
|
.ide-pipeline-header {
|
||||||
min-height: 50px;
|
min-height: 55px;
|
||||||
padding-left: $gl-padding;
|
padding-left: $gl-padding;
|
||||||
padding-right: $gl-padding;
|
padding-right: $gl-padding;
|
||||||
|
|
||||||
|
@ -1222,8 +1222,6 @@
|
||||||
.ci-status-icon {
|
.ci-status-icon {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: 20px;
|
|
||||||
margin-top: -2px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue