diff options
author | Filipa Lacerda <filipa@gitlab.com> | 2018-10-03 15:29:07 +0000 |
---|---|---|
committer | Phil Hughes <me@iamphill.com> | 2018-10-03 15:29:07 +0000 |
commit | 9128e7849dbc064913b52ad427dcfb15386ad23e (patch) | |
tree | 664e0fca75719f1841d06d3e3eb493f6f9347f34 /app/assets/javascripts/jobs | |
parent | 88c1cf676cf02c3fca16093ad8ee5f6cf02dc462 (diff) | |
download | gitlab-ce-9128e7849dbc064913b52ad427dcfb15386ad23e.tar.gz |
Uses Vue app to render part of job show page
Diffstat (limited to 'app/assets/javascripts/jobs')
-rw-r--r-- | app/assets/javascripts/jobs/components/environments_block.vue | 68 | ||||
-rw-r--r-- | app/assets/javascripts/jobs/components/header.vue | 95 | ||||
-rw-r--r-- | app/assets/javascripts/jobs/components/job_app.vue | 99 | ||||
-rw-r--r-- | app/assets/javascripts/jobs/job_details_bundle.js | 7 | ||||
-rw-r--r-- | app/assets/javascripts/jobs/store/getters.js | 42 | ||||
-rw-r--r-- | app/assets/javascripts/jobs/store/index.js | 2 |
6 files changed, 191 insertions, 122 deletions
diff --git a/app/assets/javascripts/jobs/components/environments_block.vue b/app/assets/javascripts/jobs/components/environments_block.vue index ca6386595c7..e6e1d418194 100644 --- a/app/assets/javascripts/jobs/components/environments_block.vue +++ b/app/assets/javascripts/jobs/components/environments_block.vue @@ -12,12 +12,16 @@ type: Object, required: true, }, + iconStatus: { + type: Object, + required: true, + }, }, computed: { environment() { let environmentText; switch (this.deploymentStatus.status) { - case 'latest': + case 'last': environmentText = sprintf( __('This job is the most recent deployment to %{link}.'), { link: this.environmentLink }, @@ -32,7 +36,7 @@ ), { environmentLink: this.environmentLink, - deploymentLink: this.deploymentLink, + deploymentLink: this.deploymentLink(`#${this.lastDeployment.iid}`), }, false, ); @@ -56,11 +60,11 @@ if (this.hasLastDeployment) { environmentText = sprintf( __( - 'This job is creating a deployment to %{environmentLink} and will overwrite the last %{deploymentLink}.', + 'This job is creating a deployment to %{environmentLink} and will overwrite the %{deploymentLink}.', ), { environmentLink: this.environmentLink, - deploymentLink: this.deploymentLink, + deploymentLink: this.deploymentLink(__('latest deployment')), }, false, ); @@ -78,41 +82,57 @@ return environmentText; }, environmentLink() { - return sprintf( - '%{startLink}%{name}%{endLink}', - { - startLink: `<a href="${this.deploymentStatus.environment.path}">`, - name: _.escape(this.deploymentStatus.environment.name), - endLink: '</a>', - }, - false, - ); + if (this.hasEnvironment) { + return sprintf( + '%{startLink}%{name}%{endLink}', + { + startLink: `<a href="${ + this.deploymentStatus.environment.environment_path + }" class="js-environment-link">`, + name: _.escape(this.deploymentStatus.environment.name), + endLink: '</a>', + }, + false, + ); + } + return ''; }, - deploymentLink() { + hasLastDeployment() { + return this.hasEnvironment && this.deploymentStatus.environment.last_deployment; + }, + lastDeployment() { + return this.hasLastDeployment ? this.deploymentStatus.environment.last_deployment : {}; + }, + hasEnvironment() { + return !_.isEmpty(this.deploymentStatus.environment); + }, + lastDeploymentPath() { + return !_.isEmpty(this.lastDeployment.deployable) ? this.lastDeployment.deployable.build_path : ''; + }, + }, + methods: { + deploymentLink(name) { return sprintf( '%{startLink}%{name}%{endLink}', { - startLink: `<a href="${this.lastDeployment.path}">`, - name: _.escape(this.lastDeployment.name), + startLink: `<a href="${this.lastDeploymentPath}" class="js-job-deployment-link">`, + name, endLink: '</a>', }, false, ); }, - hasLastDeployment() { - return this.deploymentStatus.environment.last_deployment; - }, - lastDeployment() { - return this.deploymentStatus.environment.last_deployment; - }, }, }; </script> <template> <div class="prepend-top-default js-environment-container"> <div class="environment-information"> - <ci-icon :status="deploymentStatus.icon" /> - <p v-html="environment"></p> + <ci-icon :status="iconStatus"/> + <p + class="inline append-bottom-0" + v-html="environment" + ></p> </div> </div> </template> diff --git a/app/assets/javascripts/jobs/components/header.vue b/app/assets/javascripts/jobs/components/header.vue deleted file mode 100644 index 63324e68d68..00000000000 --- a/app/assets/javascripts/jobs/components/header.vue +++ /dev/null @@ -1,95 +0,0 @@ -<script> -import ciHeader from '../../vue_shared/components/header_ci_component.vue'; -import callout from '../../vue_shared/components/callout.vue'; - -export default { - name: 'JobHeaderSection', - components: { - ciHeader, - callout, - }, - props: { - job: { - type: Object, - required: true, - }, - isLoading: { - type: Boolean, - required: true, - }, - }, - data() { - return { - actions: this.getActions(), - }; - }, - computed: { - status() { - return this.job && this.job.status; - }, - shouldRenderContent() { - return !this.isLoading && Object.keys(this.job).length; - }, - shouldRenderReason() { - return !!(this.job.status && this.job.callout_message); - }, - /** - * When job has not started the key will be `false` - * When job started the key will be a string with a date. - */ - jobStarted() { - return !this.job.started === false; - }, - headerTime() { - return this.jobStarted ? this.job.started : this.job.created_at; - }, - }, - watch: { - job() { - this.actions = this.getActions(); - }, - }, - methods: { - getActions() { - const actions = []; - - if (this.job.new_issue_path) { - actions.push({ - label: 'New issue', - path: this.job.new_issue_path, - cssClass: 'js-new-issue btn btn-success btn-inverted d-none d-md-block d-lg-block d-xl-block', - type: 'link', - }); - } - return actions; - }, - }, -}; -</script> -<template> - <header> - <div class="js-build-header build-header top-area"> - <ci-header - v-if="shouldRenderContent" - :status="status" - :item-id="job.id" - :time="headerTime" - :user="job.user" - :actions="actions" - :has-sidebar-button="true" - :should-render-triggered-label="jobStarted" - item-name="Job" - /> - <gl-loading-icon - v-if="isLoading" - :size="2" - class="prepend-top-default append-bottom-default" - /> - </div> - - <callout - v-if="shouldRenderReason" - :message="job.callout_message" - /> - </header> -</template> diff --git a/app/assets/javascripts/jobs/components/job_app.vue b/app/assets/javascripts/jobs/components/job_app.vue new file mode 100644 index 00000000000..bac8bd71d64 --- /dev/null +++ b/app/assets/javascripts/jobs/components/job_app.vue @@ -0,0 +1,99 @@ +<script> + import { mapGetters, mapState } from 'vuex'; + import CiHeader from '~/vue_shared/components/header_ci_component.vue'; + import Callout from '~/vue_shared/components/callout.vue'; + import EnvironmentsBlock from './environments_block.vue'; + import ErasedBlock from './erased_block.vue'; + import StuckBlock from './stuck_block.vue'; + + export default { + name: 'JobPageApp', + components: { + CiHeader, + Callout, + EnvironmentsBlock, + ErasedBlock, + StuckBlock, + }, + props: { + runnerHelpUrl: { + type: String, + required: false, + default: null, + }, + }, + computed: { + ...mapState(['isLoading', 'job']), + ...mapGetters([ + 'headerActions', + 'headerTime', + 'shouldRenderCalloutMessage', + 'jobHasStarted', + 'hasEnvironment', + 'isJobStuck', + ]), + }, + }; +</script> +<template> + <div> + <gl-loading-icon + v-if="isLoading" + :size="2" + class="prepend-top-20" + /> + + <template v-else> + <!-- 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" + :actions="headerActions" + :has-sidebar-button="true" + :should-render-triggered-label="jobHasStarted" + :item-name="__('Job')" + /> + </div> + + <callout + v-if="shouldRenderCalloutMessage" + :message="job.callout_message" + /> + </header> + <!-- EO Header Section --> + + <!-- Body Section --> + <stuck-block + v-if="isJobStuck" + class="js-job-stuck" + :has-no-runners-for-project="job.runners.available" + :tags="job.tags" + :runners-path="runnerHelpUrl" + /> + + <environments-block + v-if="hasEnvironment" + :deployment-status="job.deployment_status" + :icon-status="job.status" + /> + + <erased-block + v-if="job.erased" + :user="job.erased_by" + :erased-at="job.erased_at" + /> + + <!--job log --> + <!-- EO job log --> + + <!--empty state --> + <!-- EO empty state --> + + <!-- EO Body Section --> + </template> + </div> +</template> diff --git a/app/assets/javascripts/jobs/job_details_bundle.js b/app/assets/javascripts/jobs/job_details_bundle.js index ae40f4cdf3b..3eb75e72506 100644 --- a/app/assets/javascripts/jobs/job_details_bundle.js +++ b/app/assets/javascripts/jobs/job_details_bundle.js @@ -2,7 +2,7 @@ import _ from 'underscore'; import { mapState, mapActions } from 'vuex'; import Vue from 'vue'; import Job from '../job'; -import JobHeader from './components/header.vue'; +import JobApp from './components/job_app.vue'; import Sidebar from './components/sidebar.vue'; import createStore from './store'; @@ -22,17 +22,18 @@ export default () => { new Vue({ el: '#js-build-header-vue', components: { - JobHeader, + JobApp, }, store, computed: { ...mapState(['job', 'isLoading']), }, render(createElement) { - return createElement('job-header', { + return createElement('job-app', { props: { isLoading: this.isLoading, job: this.job, + runnerHelpUrl: dataset.runnerHelpUrl, }, }); }, diff --git a/app/assets/javascripts/jobs/store/getters.js b/app/assets/javascripts/jobs/store/getters.js new file mode 100644 index 00000000000..62d154ff584 --- /dev/null +++ b/app/assets/javascripts/jobs/store/getters.js @@ -0,0 +1,42 @@ +import _ from 'underscore'; +import { __ } from '~/locale'; + +export const headerActions = state => { + if (state.job.new_issue_path) { + return [ + { + label: __('New issue'), + path: state.job.new_issue_path, + cssClass: + 'js-new-issue btn btn-success btn-inverted d-none d-md-block d-lg-block d-xl-block', + type: 'link', + }, + ]; + } + return []; +}; + +export const headerTime = state => (state.job.started ? state.job.started : state.job.created_at); + +export const shouldRenderCalloutMessage = state => + !_.isEmpty(state.job.status) && !_.isEmpty(state.job.callout_message); + +/** + * When job has not started the key will be `false` + * When job started the key will be a string with a date. + */ +export const jobHasStarted = state => !(state.job.started === false); + +export const hasEnvironment = state => !_.isEmpty(state.job.deployment_status); + +/** + * When the job is pending and there are no available runners + * we need to render the stuck block; + * + * @returns {Boolean} + */ +export const isJobStuck = state => + state.job.status.group === 'pending' && state.job.runners && state.job.runners.available === false; + +// prevent babel-plugin-rewire from generating an invalid default during karma tests +export default () => {}; diff --git a/app/assets/javascripts/jobs/store/index.js b/app/assets/javascripts/jobs/store/index.js index d8f6f56ce61..96e38f9a2fa 100644 --- a/app/assets/javascripts/jobs/store/index.js +++ b/app/assets/javascripts/jobs/store/index.js @@ -2,6 +2,7 @@ import Vue from 'vue'; import Vuex from 'vuex'; import state from './state'; import * as actions from './actions'; +import * as getters from './getters'; import mutations from './mutations'; Vue.use(Vuex); @@ -9,5 +10,6 @@ Vue.use(Vuex); export default () => new Vuex.Store({ actions, mutations, + getters, state: state(), }); |