Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-09-20 16:18:24 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-09-20 16:18:24 +0300
commit0653e08efd039a5905f3fa4f6e9cef9f5d2f799c (patch)
tree4dcc884cf6d81db44adae4aa99f8ec1233a41f55 /app/assets/javascripts/jobs
parent744144d28e3e7fddc117924fef88de5d9674fe4c (diff)
Add latest changes from gitlab-org/gitlab@14-3-stable-eev14.3.0-rc42
Diffstat (limited to 'app/assets/javascripts/jobs')
-rw-r--r--app/assets/javascripts/jobs/components/job_app.vue8
-rw-r--r--app/assets/javascripts/jobs/components/table/cells/actions_cell.vue183
-rw-r--r--app/assets/javascripts/jobs/components/table/constants.js23
-rw-r--r--app/assets/javascripts/jobs/components/table/event_hub.js3
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/fragments/job.fragment.graphql3
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/mutations/job_cancel.mutation.graphql10
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/mutations/job_play.mutation.graphql10
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/mutations/job_retry.mutation.graphql10
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql10
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql1
-rw-r--r--app/assets/javascripts/jobs/components/table/index.js5
-rw-r--r--app/assets/javascripts/jobs/components/table/jobs_table.vue2
-rw-r--r--app/assets/javascripts/jobs/components/table/jobs_table_app.vue10
13 files changed, 273 insertions, 5 deletions
diff --git a/app/assets/javascripts/jobs/components/job_app.vue b/app/assets/javascripts/jobs/components/job_app.vue
index fa9ee56c049..059772e8cb9 100644
--- a/app/assets/javascripts/jobs/components/job_app.vue
+++ b/app/assets/javascripts/jobs/components/job_app.vue
@@ -5,7 +5,7 @@ import { throttle, isEmpty } from 'lodash';
import { mapGetters, mapState, mapActions } from 'vuex';
import CodeQualityWalkthrough from '~/code_quality_walkthrough/components/step.vue';
import { isScrolledToBottom } from '~/lib/utils/scroll_utils';
-import { sprintf } from '~/locale';
+import { __, sprintf } from '~/locale';
import CiHeader from '~/vue_shared/components/header_ci_component.vue';
import delayedJobMixin from '../mixins/delayed_job_mixin';
import EmptyState from './empty_state.vue';
@@ -126,6 +126,9 @@ export default {
shouldRenderCodeQualityWalkthrough() {
return this.job.status.group === 'failed-with-warnings';
},
+ itemName() {
+ return sprintf(__('Job %{jobName}'), { jobName: this.job.name });
+ },
},
watch: {
// Once the job log is loaded,
@@ -205,12 +208,11 @@ export default {
<div class="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')"
+ :item-name="itemName"
@clickedSidebarButton="toggleSidebar"
/>
</div>
diff --git a/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue b/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue
index 376482b0319..6b3a4424a5b 100644
--- a/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue
+++ b/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue
@@ -1,14 +1,195 @@
<script>
+import { GlButton, GlButtonGroup, GlModal, GlModalDirective, GlSprintf } from '@gitlab/ui';
+import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
+import {
+ ACTIONS_DOWNLOAD_ARTIFACTS,
+ ACTIONS_START_NOW,
+ ACTIONS_UNSCHEDULE,
+ ACTIONS_PLAY,
+ ACTIONS_RETRY,
+ CANCEL,
+ GENERIC_ERROR,
+ JOB_SCHEDULED,
+ PLAY_JOB_CONFIRMATION_MESSAGE,
+ RUN_JOB_NOW_HEADER_TITLE,
+} from '../constants';
+import eventHub from '../event_hub';
+import cancelJobMutation from '../graphql/mutations/job_cancel.mutation.graphql';
+import playJobMutation from '../graphql/mutations/job_play.mutation.graphql';
+import retryJobMutation from '../graphql/mutations/job_retry.mutation.graphql';
+import unscheduleJobMutation from '../graphql/mutations/job_unschedule.mutation.graphql';
+
export default {
+ ACTIONS_DOWNLOAD_ARTIFACTS,
+ ACTIONS_START_NOW,
+ ACTIONS_UNSCHEDULE,
+ ACTIONS_PLAY,
+ ACTIONS_RETRY,
+ CANCEL,
+ GENERIC_ERROR,
+ PLAY_JOB_CONFIRMATION_MESSAGE,
+ RUN_JOB_NOW_HEADER_TITLE,
+ jobRetry: 'jobRetry',
+ jobCancel: 'jobCancel',
+ jobPlay: 'jobPlay',
+ jobUnschedule: 'jobUnschedule',
+ playJobModalId: 'play-job-modal',
+ components: {
+ GlButton,
+ GlButtonGroup,
+ GlCountdown,
+ GlModal,
+ GlSprintf,
+ },
+ directives: {
+ GlModalDirective,
+ },
+ inject: {
+ admin: {
+ default: false,
+ },
+ },
props: {
job: {
type: Object,
required: true,
},
},
+ computed: {
+ artifactDownloadPath() {
+ return this.job.artifacts?.nodes[0]?.downloadPath;
+ },
+ canReadJob() {
+ return this.job.userPermissions?.readBuild;
+ },
+ isActive() {
+ return this.job.active;
+ },
+ manualJobPlayable() {
+ return this.job.playable && !this.admin && this.job.manualJob;
+ },
+ isRetryable() {
+ return this.job.retryable;
+ },
+ isScheduled() {
+ return this.job.status === JOB_SCHEDULED;
+ },
+ scheduledAt() {
+ return this.job.scheduledAt;
+ },
+ currentJobActionPath() {
+ return this.job.detailedStatus?.action?.path;
+ },
+ currentJobMethod() {
+ return this.job.detailedStatus?.action?.method;
+ },
+ shouldDisplayArtifacts() {
+ return this.job.userPermissions?.readJobArtifacts && this.job.artifacts?.nodes.length > 0;
+ },
+ },
+ methods: {
+ async postJobAction(name, mutation) {
+ try {
+ const {
+ data: {
+ [name]: { errors },
+ },
+ } = await this.$apollo.mutate({
+ mutation,
+ variables: { id: this.job.id },
+ });
+ if (errors.length > 0) {
+ this.reportFailure();
+ } else {
+ eventHub.$emit('jobActionPerformed');
+ }
+ } catch {
+ this.reportFailure();
+ }
+ },
+ reportFailure() {
+ const toastProps = {
+ text: this.$options.GENERIC_ERROR,
+ variant: 'danger',
+ };
+
+ this.$toast.show(toastProps.text, {
+ variant: toastProps.variant,
+ });
+ },
+ cancelJob() {
+ this.postJobAction(this.$options.jobCancel, cancelJobMutation);
+ },
+ retryJob() {
+ this.postJobAction(this.$options.jobRetry, retryJobMutation);
+ },
+ playJob() {
+ this.postJobAction(this.$options.jobPlay, playJobMutation);
+ },
+ unscheduleJob() {
+ this.postJobAction(this.$options.jobUnschedule, unscheduleJobMutation);
+ },
+ },
};
</script>
<template>
- <div></div>
+ <gl-button-group>
+ <template v-if="canReadJob">
+ <gl-button v-if="isActive" icon="cancel" :title="$options.CANCEL" @click="cancelJob()" />
+ <template v-else-if="isScheduled">
+ <gl-button icon="planning" disabled data-testid="countdown">
+ <gl-countdown :end-date-string="scheduledAt" />
+ </gl-button>
+ <gl-button
+ v-gl-modal-directive="$options.playJobModalId"
+ icon="play"
+ :title="$options.ACTIONS_START_NOW"
+ data-testid="play-scheduled"
+ />
+ <gl-modal
+ :modal-id="$options.playJobModalId"
+ :title="$options.RUN_JOB_NOW_HEADER_TITLE"
+ @primary="playJob()"
+ >
+ <gl-sprintf :message="$options.PLAY_JOB_CONFIRMATION_MESSAGE">
+ <template #job_name>{{ job.name }}</template>
+ </gl-sprintf>
+ </gl-modal>
+ <gl-button
+ icon="time-out"
+ :title="$options.ACTIONS_UNSCHEDULE"
+ data-testid="unschedule"
+ @click="unscheduleJob()"
+ />
+ </template>
+ <template v-else>
+ <!--Note: This is the manual job play button -->
+ <gl-button
+ v-if="manualJobPlayable"
+ icon="play"
+ :title="$options.ACTIONS_PLAY"
+ data-testid="play"
+ @click="playJob()"
+ />
+ <gl-button
+ v-else-if="isRetryable"
+ icon="repeat"
+ :title="$options.ACTIONS_RETRY"
+ :method="currentJobMethod"
+ data-testid="retry"
+ @click="retryJob()"
+ />
+ </template>
+ </template>
+ <gl-button
+ v-if="shouldDisplayArtifacts"
+ icon="download"
+ :title="$options.ACTIONS_DOWNLOAD_ARTIFACTS"
+ :href="artifactDownloadPath"
+ rel="nofollow"
+ download
+ data-testid="download-artifacts"
+ />
+ </gl-button-group>
</template>
diff --git a/app/assets/javascripts/jobs/components/table/constants.js b/app/assets/javascripts/jobs/components/table/constants.js
index 7e973a34e5c..e5d1bc01cbf 100644
--- a/app/assets/javascripts/jobs/components/table/constants.js
+++ b/app/assets/javascripts/jobs/components/table/constants.js
@@ -1,3 +1,5 @@
+import { s__, __ } from '~/locale';
+
export const GRAPHQL_PAGE_SIZE = 30;
export const initialPaginationState = {
@@ -7,3 +9,24 @@ export const initialPaginationState = {
first: GRAPHQL_PAGE_SIZE,
last: null,
};
+
+/* Error constants */
+export const POST_FAILURE = 'post_failure';
+export const DEFAULT = 'default';
+
+/* Job Status Constants */
+export const JOB_SCHEDULED = 'SCHEDULED';
+
+/* i18n */
+export const ACTIONS_DOWNLOAD_ARTIFACTS = __('Download artifacts');
+export const ACTIONS_START_NOW = s__('DelayedJobs|Start now');
+export const ACTIONS_UNSCHEDULE = s__('DelayedJobs|Unschedule');
+export const ACTIONS_PLAY = __('Play');
+export const ACTIONS_RETRY = __('Retry');
+
+export const CANCEL = __('Cancel');
+export const GENERIC_ERROR = __('An error occurred while making the request.');
+export const PLAY_JOB_CONFIRMATION_MESSAGE = s__(
+ `DelayedJobs|Are you sure you want to run %{job_name} immediately? This job will run automatically after its timer finishes.`,
+);
+export const RUN_JOB_NOW_HEADER_TITLE = s__('DelayedJobs|Run the delayed job now?');
diff --git a/app/assets/javascripts/jobs/components/table/event_hub.js b/app/assets/javascripts/jobs/components/table/event_hub.js
new file mode 100644
index 00000000000..e31806ad199
--- /dev/null
+++ b/app/assets/javascripts/jobs/components/table/event_hub.js
@@ -0,0 +1,3 @@
+import createEventHub from '~/helpers/event_hub_factory';
+
+export default createEventHub();
diff --git a/app/assets/javascripts/jobs/components/table/graphql/fragments/job.fragment.graphql b/app/assets/javascripts/jobs/components/table/graphql/fragments/job.fragment.graphql
new file mode 100644
index 00000000000..06b065a86ce
--- /dev/null
+++ b/app/assets/javascripts/jobs/components/table/graphql/fragments/job.fragment.graphql
@@ -0,0 +1,3 @@
+fragment Job on CiJob {
+ id
+}
diff --git a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_cancel.mutation.graphql b/app/assets/javascripts/jobs/components/table/graphql/mutations/job_cancel.mutation.graphql
new file mode 100644
index 00000000000..20935514d51
--- /dev/null
+++ b/app/assets/javascripts/jobs/components/table/graphql/mutations/job_cancel.mutation.graphql
@@ -0,0 +1,10 @@
+#import "../fragments/job.fragment.graphql"
+
+mutation cancelJob($id: CiBuildID!) {
+ jobCancel(input: { id: $id }) {
+ job {
+ ...Job
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_play.mutation.graphql b/app/assets/javascripts/jobs/components/table/graphql/mutations/job_play.mutation.graphql
new file mode 100644
index 00000000000..c94b045ac40
--- /dev/null
+++ b/app/assets/javascripts/jobs/components/table/graphql/mutations/job_play.mutation.graphql
@@ -0,0 +1,10 @@
+#import "../fragments/job.fragment.graphql"
+
+mutation playJob($id: CiBuildID!) {
+ jobPlay(input: { id: $id }) {
+ job {
+ ...Job
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_retry.mutation.graphql b/app/assets/javascripts/jobs/components/table/graphql/mutations/job_retry.mutation.graphql
new file mode 100644
index 00000000000..6e51f9a20fa
--- /dev/null
+++ b/app/assets/javascripts/jobs/components/table/graphql/mutations/job_retry.mutation.graphql
@@ -0,0 +1,10 @@
+#import "../fragments/job.fragment.graphql"
+
+mutation retryJob($id: CiBuildID!) {
+ jobRetry(input: { id: $id }) {
+ job {
+ ...Job
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql b/app/assets/javascripts/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql
new file mode 100644
index 00000000000..8be8c42f3c3
--- /dev/null
+++ b/app/assets/javascripts/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql
@@ -0,0 +1,10 @@
+#import "../fragments/job.fragment.graphql"
+
+mutation unscheduleJob($id: CiBuildID!) {
+ jobUnschedule(input: { id: $id }) {
+ job {
+ ...Job
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql b/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql
index 68c6584cda6..c8763d4767e 100644
--- a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql
+++ b/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql
@@ -69,6 +69,7 @@ query getJobs(
stuck
userPermissions {
readBuild
+ readJobArtifacts
}
}
}
diff --git a/app/assets/javascripts/jobs/components/table/index.js b/app/assets/javascripts/jobs/components/table/index.js
index 05d6ebfd6d6..f24daf90815 100644
--- a/app/assets/javascripts/jobs/components/table/index.js
+++ b/app/assets/javascripts/jobs/components/table/index.js
@@ -1,9 +1,12 @@
+import { GlToast } from '@gitlab/ui';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import JobsTableApp from '~/jobs/components/table/jobs_table_app.vue';
import createDefaultClient from '~/lib/graphql';
+import { parseBoolean } from '~/lib/utils/common_utils';
Vue.use(VueApollo);
+Vue.use(GlToast);
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
@@ -22,6 +25,7 @@ export default (containerId = 'js-jobs-table') => {
jobStatuses,
pipelineEditorPath,
emptyStateSvgPath,
+ admin,
} = containerEl.dataset;
return new Vue({
@@ -33,6 +37,7 @@ export default (containerId = 'js-jobs-table') => {
pipelineEditorPath,
jobStatuses: JSON.parse(jobStatuses),
jobCounts: JSON.parse(jobCounts),
+ admin: parseBoolean(admin),
},
render(createElement) {
return createElement(JobsTableApp);
diff --git a/app/assets/javascripts/jobs/components/table/jobs_table.vue b/app/assets/javascripts/jobs/components/table/jobs_table.vue
index 076c0e78b11..298c99c4162 100644
--- a/app/assets/javascripts/jobs/components/table/jobs_table.vue
+++ b/app/assets/javascripts/jobs/components/table/jobs_table.vue
@@ -141,7 +141,7 @@ export default {
</template>
<template #cell(actions)="{ item }">
- <actions-cell :job="item" />
+ <actions-cell class="gl-float-right" :job="item" />
</template>
</gl-table>
</template>
diff --git a/app/assets/javascripts/jobs/components/table/jobs_table_app.vue b/app/assets/javascripts/jobs/components/table/jobs_table_app.vue
index 2061b1f1eb2..c786d35ac68 100644
--- a/app/assets/javascripts/jobs/components/table/jobs_table_app.vue
+++ b/app/assets/javascripts/jobs/components/table/jobs_table_app.vue
@@ -2,6 +2,7 @@
import { GlAlert, GlPagination, GlSkeletonLoader } from '@gitlab/ui';
import { __ } from '~/locale';
import { GRAPHQL_PAGE_SIZE, initialPaginationState } from './constants';
+import eventHub from './event_hub';
import GetJobs from './graphql/queries/get_jobs.query.graphql';
import JobsTable from './jobs_table.vue';
import JobsTableEmptyState from './jobs_table_empty_state.vue';
@@ -74,7 +75,16 @@ export default {
return Boolean(this.prevPage || this.nextPage) && !this.$apollo.loading;
},
},
+ mounted() {
+ eventHub.$on('jobActionPerformed', this.handleJobAction);
+ },
+ beforeDestroy() {
+ eventHub.$off('jobActionPerformed', this.handleJobAction);
+ },
methods: {
+ handleJobAction() {
+ this.$apollo.queries.jobs.refetch({ statuses: this.scope });
+ },
fetchJobsByStatus(scope) {
this.scope = scope;