debian-mirror-gitlab/app/assets/javascripts/jobs/components/job_app.vue

335 lines
9.3 KiB
Vue
Raw Normal View History

2018-12-05 23:21:45 +05:30
<script>
2020-03-13 15:44:24 +05:30
import { throttle, isEmpty } from 'lodash';
2018-12-13 13:39:08 +05:30
import { mapGetters, mapState, mapActions } from 'vuex';
2019-02-15 15:39:39 +05:30
import { GlLoadingIcon } from '@gitlab/ui';
2020-03-13 15:44:24 +05:30
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
2018-12-13 13:39:08 +05:30
import { isScrolledToBottom } from '~/lib/utils/scroll_utils';
import { polyfillSticky } from '~/lib/utils/sticky';
import CiHeader from '~/vue_shared/components/header_ci_component.vue';
import Callout from '~/vue_shared/components/callout.vue';
import Icon from '~/vue_shared/components/icon.vue';
import EmptyState from './empty_state.vue';
import EnvironmentsBlock from './environments_block.vue';
import ErasedBlock from './erased_block.vue';
import LogTopBar from './job_log_controllers.vue';
import StuckBlock from './stuck_block.vue';
2019-07-07 11:18:12 +05:30
import UnmetPrerequisitesBlock from './unmet_prerequisites_block.vue';
2018-12-13 13:39:08 +05:30
import Sidebar from './sidebar.vue';
import { sprintf } from '~/locale';
import delayedJobMixin from '../mixins/delayed_job_mixin';
2019-12-04 20:38:33 +05:30
import { isNewJobLogActive } from '../store/utils';
2018-12-13 13:39:08 +05:30
export default {
name: 'JobPageApp',
components: {
CiHeader,
Callout,
EmptyState,
EnvironmentsBlock,
ErasedBlock,
Icon,
2019-12-21 20:55:43 +05:30
Log: () => (isNewJobLogActive() ? import('./log/log.vue') : import('./job_log.vue')),
2018-12-13 13:39:08 +05:30
LogTopBar,
StuckBlock,
2019-07-07 11:18:12 +05:30
UnmetPrerequisitesBlock,
2018-12-13 13:39:08 +05:30
Sidebar,
GlLoadingIcon,
2019-07-07 11:18:12 +05:30
SharedRunner: () => import('ee_component/jobs/components/shared_runner_limit_block.vue'),
2018-12-13 13:39:08 +05:30
},
mixins: [delayedJobMixin],
props: {
runnerSettingsUrl: {
type: String,
required: false,
default: null,
},
2019-10-12 21:52:04 +05:30
variablesSettingsUrl: {
type: String,
required: false,
default: null,
},
2018-12-13 13:39:08 +05:30
runnerHelpUrl: {
type: String,
required: false,
default: null,
},
2019-07-07 11:18:12 +05:30
deploymentHelpUrl: {
type: String,
required: false,
default: null,
},
2018-12-13 13:39:08 +05:30
terminalPath: {
type: String,
required: false,
default: null,
},
2019-10-12 21:52:04 +05:30
projectPath: {
type: String,
required: true,
},
2019-12-04 20:38:33 +05:30
subscriptionsMoreMinutesUrl: {
type: String,
required: false,
default: null,
},
2018-12-13 13:39:08 +05:30
},
computed: {
...mapState([
'isLoading',
'job',
'isSidebarOpen',
'trace',
'isTraceComplete',
'traceSize',
'isTraceSizeVisible',
'isScrollBottomDisabled',
'isScrollTopDisabled',
'isScrolledToBottomBeforeReceivingTrace',
'hasError',
2019-09-04 21:01:54 +05:30
'selectedStage',
2018-12-13 13:39:08 +05:30
]),
...mapGetters([
'headerTime',
2019-07-07 11:18:12 +05:30
'hasUnmetPrerequisitesFailure',
2018-12-13 13:39:08 +05:30
'shouldRenderCalloutMessage',
'shouldRenderTriggeredLabel',
'hasEnvironment',
2019-07-07 11:18:12 +05:30
'shouldRenderSharedRunnerLimitWarning',
2018-12-13 13:39:08 +05:30
'hasTrace',
'emptyStateIllustration',
'isScrollingDown',
'emptyStateAction',
'hasRunnersForProject',
]),
shouldRenderContent() {
return !this.isLoading && !this.hasError;
},
emptyStateTitle() {
const { emptyStateIllustration, remainingTime } = this;
const { title } = emptyStateIllustration;
if (this.isDelayedJob) {
return sprintf(title, { remainingTime });
}
return title;
},
2019-12-21 20:55:43 +05:30
shouldRenderHeaderCallout() {
return this.shouldRenderCalloutMessage && !this.hasUnmetPrerequisitesFailure;
},
2018-12-13 13:39:08 +05:30
},
watch: {
// Once the job log is loaded,
// fetch the stages for the dropdown on the sidebar
job(newVal, oldVal) {
2020-03-13 15:44:24 +05:30
if (isEmpty(oldVal) && !isEmpty(newVal.pipeline)) {
2019-09-04 21:01:54 +05:30
const stages = this.job.pipeline.details.stages || [];
const defaultStage = stages.find(stage => stage && stage.name === this.selectedStage);
if (defaultStage) {
this.fetchJobsForStage(defaultStage);
}
2018-12-13 13:39:08 +05:30
}
if (newVal.archived) {
this.$nextTick(() => {
if (this.$refs.sticky) {
polyfillSticky(this.$refs.sticky);
}
});
}
},
},
created() {
2020-03-13 15:44:24 +05:30
this.throttled = throttle(this.toggleScrollButtons, 100);
2018-12-13 13:39:08 +05:30
window.addEventListener('resize', this.onResize);
window.addEventListener('scroll', this.updateScroll);
},
mounted() {
this.updateSidebar();
},
2020-03-13 15:44:24 +05:30
beforeDestroy() {
this.stopPollingTrace();
this.stopPolling();
2018-12-13 13:39:08 +05:30
window.removeEventListener('resize', this.onResize);
window.removeEventListener('scroll', this.updateScroll);
},
methods: {
...mapActions([
2019-09-04 21:01:54 +05:30
'fetchJobsForStage',
2018-12-13 13:39:08 +05:30
'hideSidebar',
'showSidebar',
'toggleSidebar',
'scrollBottom',
'scrollTop',
2020-03-13 15:44:24 +05:30
'stopPollingTrace',
'stopPolling',
2018-12-13 13:39:08 +05:30
'toggleScrollButtons',
'toggleScrollAnimation',
]),
onResize() {
this.updateSidebar();
this.updateScroll();
2018-12-05 23:21:45 +05:30
},
2018-12-13 13:39:08 +05:30
updateSidebar() {
2020-03-13 15:44:24 +05:30
const breakpoint = bp.getBreakpointSize();
if (breakpoint === 'xs' || breakpoint === 'sm') {
2018-12-13 13:39:08 +05:30
this.hideSidebar();
} else if (!this.isSidebarOpen) {
this.showSidebar();
}
2018-12-05 23:21:45 +05:30
},
2018-12-13 13:39:08 +05:30
updateScroll() {
if (!isScrolledToBottom()) {
this.toggleScrollAnimation(false);
} else if (this.isScrollingDown) {
this.toggleScrollAnimation(true);
}
this.throttled();
},
},
};
2018-12-05 23:21:45 +05:30
</script>
<template>
<div>
<gl-loading-icon
v-if="isLoading"
2020-03-13 15:44:24 +05:30
size="lg"
2018-12-13 13:39:08 +05:30
class="js-job-loading qa-loading-animation prepend-top-20"
2018-12-05 23:21:45 +05:30
/>
2018-12-13 13:39:08 +05:30
<template v-else-if="shouldRenderContent">
<div class="js-job-content build-page">
<!-- Header Section -->
<header>
<div class="js-build-header build-header top-area">
<ci-header
:status="job.status"
:item-id="job.id"
:time="headerTime"
:user="job.user"
:has-sidebar-button="true"
:should-render-triggered-label="shouldRenderTriggeredLabel"
:item-name="__('Job')"
@clickedSidebarButton="toggleSidebar"
/>
</div>
2019-12-21 20:55:43 +05:30
<callout v-if="shouldRenderHeaderCallout">
<div v-html="job.callout_message"></div>
</callout>
2018-12-13 13:39:08 +05:30
</header>
<!-- EO Header Section -->
<!-- Body Section -->
<stuck-block
v-if="job.stuck"
class="js-job-stuck"
:has-no-runners-for-project="hasRunnersForProject"
:tags="job.tags"
:runners-path="runnerSettingsUrl"
/>
2019-07-07 11:18:12 +05:30
<unmet-prerequisites-block
v-if="hasUnmetPrerequisitesFailure"
class="js-job-failed"
:help-path="deploymentHelpUrl"
/>
<shared-runner
v-if="shouldRenderSharedRunnerLimitWarning"
class="js-shared-runner-limit"
:quota-used="job.runners.quota.used"
:quota-limit="job.runners.quota.limit"
:runners-path="runnerHelpUrl"
2019-10-12 21:52:04 +05:30
:project-path="projectPath"
2019-12-04 20:38:33 +05:30
:subscriptions-more-minutes-url="subscriptionsMoreMinutesUrl"
2019-07-07 11:18:12 +05:30
/>
2018-12-13 13:39:08 +05:30
<environments-block
v-if="hasEnvironment"
class="js-job-environment"
:deployment-status="job.deployment_status"
2020-03-13 15:44:24 +05:30
:deployment-cluster="job.deployment_cluster"
2018-12-13 13:39:08 +05:30
:icon-status="job.status"
/>
<erased-block
v-if="job.erased_at"
class="js-job-erased-block"
:user="job.erased_by"
:erased-at="job.erased_at"
/>
2019-02-15 15:39:39 +05:30
<div
2018-12-13 13:39:08 +05:30
v-if="job.archived"
ref="sticky"
2019-03-02 22:35:43 +05:30
class="js-archived-job prepend-top-default archived-job"
:class="{ 'sticky-top border-bottom-0': hasTrace }"
2018-12-13 13:39:08 +05:30
>
2019-02-15 15:39:39 +05:30
<icon name="lock" class="align-text-bottom" />
2018-12-13 13:39:08 +05:30
{{ __('This job is archived. Only the complete pipeline can be retried.') }}
</div>
2019-02-15 15:39:39 +05:30
<!-- job log -->
2019-03-02 22:35:43 +05:30
<div
v-if="hasTrace"
2019-07-31 22:56:46 +05:30
class="build-trace-container position-relative"
2019-03-02 22:35:43 +05:30
:class="{ 'prepend-top-default': !job.archived }"
>
2018-12-13 13:39:08 +05:30
<log-top-bar
:class="{
'sidebar-expanded': isSidebarOpen,
'sidebar-collapsed': !isSidebarOpen,
2019-02-15 15:39:39 +05:30
'has-archived-block': job.archived,
2018-12-13 13:39:08 +05:30
}"
:erase-path="job.erase_path"
:size="traceSize"
:raw-path="job.raw_path"
:is-scroll-bottom-disabled="isScrollBottomDisabled"
:is-scroll-top-disabled="isScrollTopDisabled"
:is-trace-size-visible="isTraceSizeVisible"
:is-scrolling-down="isScrollingDown"
@scrollJobLogTop="scrollTop"
@scrollJobLogBottom="scrollBottom"
/>
2019-02-15 15:39:39 +05:30
<log :trace="trace" :is-complete="isTraceComplete" />
2018-12-05 23:21:45 +05:30
</div>
2018-12-13 13:39:08 +05:30
<!-- EO job log -->
2018-12-05 23:21:45 +05:30
2019-02-15 15:39:39 +05:30
<!-- empty state -->
2018-12-13 13:39:08 +05:30
<empty-state
v-if="!hasTrace"
class="js-job-empty-state"
:illustration-path="emptyStateIllustration.image"
:illustration-size-class="emptyStateIllustration.size"
:title="emptyStateTitle"
:content="emptyStateIllustration.content"
:action="emptyStateAction"
2019-10-12 21:52:04 +05:30
:playable="job.playable"
:scheduled="job.scheduled"
:variables-settings-url="variablesSettingsUrl"
2018-12-05 23:21:45 +05:30
/>
2019-02-15 15:39:39 +05:30
<!-- EO empty state -->
2018-12-05 23:21:45 +05:30
2019-02-15 15:39:39 +05:30
<!-- EO Body Section -->
2018-12-13 13:39:08 +05:30
</div>
2018-12-05 23:21:45 +05:30
</template>
2018-12-13 13:39:08 +05:30
<sidebar
v-if="shouldRenderContent"
class="js-job-sidebar"
:class="{
'right-sidebar-expanded': isSidebarOpen,
2019-02-15 15:39:39 +05:30
'right-sidebar-collapsed': !isSidebarOpen,
2018-12-13 13:39:08 +05:30
}"
:runner-help-url="runnerHelpUrl"
/>
2018-12-05 23:21:45 +05:30
</div>
</template>