Commit c0d14fbc authored by Jose Ivan Vargas's avatar Jose Ivan Vargas

Merge branch 'pb-disable-retry-after-first-click' into 'master'

Jobs Table - Disable action buttons after first click

See merge request gitlab-org/gitlab!78691
parents ccbf8904 013a90e5
......@@ -58,6 +58,14 @@ export default {
required: true,
},
},
data() {
return {
retryBtnDisabled: false,
cancelBtnDisabled: false,
playManualBtnDisabled: false,
unscheduleBtnDisabled: false,
};
},
computed: {
hasArtifacts() {
return this.job.artifacts.nodes.find((artifact) => artifact.fileType === FILE_TYPE_ARCHIVE);
......@@ -132,15 +140,23 @@ export default {
});
},
cancelJob() {
this.cancelBtnDisabled = true;
this.postJobAction(this.$options.jobCancel, cancelJobMutation);
},
retryJob() {
this.retryBtnDisabled = true;
this.postJobAction(this.$options.jobRetry, retryJobMutation);
},
playJob() {
this.playManualBtnDisabled = true;
this.postJobAction(this.$options.jobPlay, playJobMutation);
},
unscheduleJob() {
this.unscheduleBtnDisabled = true;
this.postJobAction(this.$options.jobUnschedule, unscheduleJobMutation);
},
},
......@@ -155,6 +171,7 @@ export default {
data-testid="cancel-button"
icon="cancel"
:title="$options.CANCEL"
:disabled="cancelBtnDisabled"
@click="cancelJob()"
/>
<template v-else-if="isScheduled">
......@@ -179,6 +196,7 @@ export default {
<gl-button
icon="time-out"
:title="$options.ACTIONS_UNSCHEDULE"
:disabled="unscheduleBtnDisabled"
data-testid="unschedule"
@click="unscheduleJob()"
/>
......@@ -189,6 +207,7 @@ export default {
v-if="manualJobPlayable"
icon="play"
:title="$options.ACTIONS_PLAY"
:disabled="playManualBtnDisabled"
data-testid="play"
@click="playJob()"
/>
......@@ -197,6 +216,7 @@ export default {
icon="repeat"
:title="$options.ACTIONS_RETRY"
:method="currentJobMethod"
:disabled="retryBtnDisabled"
data-testid="retry"
@click="retryJob()"
/>
......
import { GlModal } from '@gitlab/ui';
import { nextTick } from 'vue';
import waitForPromises from 'helpers/wait_for_promises';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import ActionsCell from '~/jobs/components/table/cells/actions_cell.vue';
import JobPlayMutation from '~/jobs/components/table/graphql/mutations/job_play.mutation.graphql';
import JobRetryMutation from '~/jobs/components/table/graphql/mutations/job_retry.mutation.graphql';
import JobUnscheduleMutation from '~/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql';
import JobCancelMutation from '~/jobs/components/table/graphql/mutations/job_cancel.mutation.graphql';
import {
playableJob,
retryableJob,
cancelableJob,
scheduledJob,
cannotRetryJob,
cannotPlayJob,
......@@ -20,6 +23,7 @@ describe('Job actions cell', () => {
const findRetryButton = () => wrapper.findByTestId('retry');
const findPlayButton = () => wrapper.findByTestId('play');
const findCancelButton = () => wrapper.findByTestId('cancel-button');
const findDownloadArtifactsButton = () => wrapper.findByTestId('download-artifacts');
const findCountdownButton = () => wrapper.findByTestId('countdown');
const findPlayScheduledJobButton = () => wrapper.findByTestId('play-scheduled');
......@@ -32,6 +36,7 @@ describe('Job actions cell', () => {
data: { JobUnscheduleMutation: { jobId: scheduledJob.id } },
};
const MUTATION_SUCCESS_PLAY = { data: { JobPlayMutation: { jobId: playableJob.id } } };
const MUTATION_SUCCESS_CANCEL = { data: { JobCancelMutation: { jobId: cancelableJob.id } } };
const $toast = {
show: jest.fn(),
......@@ -88,6 +93,7 @@ describe('Job actions cell', () => {
${findPlayButton} | ${'play'} | ${playableJob}
${findRetryButton} | ${'retry'} | ${retryableJob}
${findDownloadArtifactsButton} | ${'download artifacts'} | ${playableJob}
${findCancelButton} | ${'cancel'} | ${cancelableJob}
`('displays the $action button', ({ button, jobType }) => {
createComponent(jobType);
......@@ -95,9 +101,10 @@ describe('Job actions cell', () => {
});
it.each`
button | mutationResult | action | jobType | mutationFile
${findPlayButton} | ${MUTATION_SUCCESS_PLAY} | ${'play'} | ${playableJob} | ${JobPlayMutation}
${findRetryButton} | ${MUTATION_SUCCESS} | ${'retry'} | ${retryableJob} | ${JobRetryMutation}
button | mutationResult | action | jobType | mutationFile
${findPlayButton} | ${MUTATION_SUCCESS_PLAY} | ${'play'} | ${playableJob} | ${JobPlayMutation}
${findRetryButton} | ${MUTATION_SUCCESS} | ${'retry'} | ${retryableJob} | ${JobRetryMutation}
${findCancelButton} | ${MUTATION_SUCCESS_CANCEL} | ${'cancel'} | ${cancelableJob} | ${JobCancelMutation}
`('performs the $action mutation', ({ button, mutationResult, jobType, mutationFile }) => {
createComponent(jobType, mutationResult);
......@@ -111,6 +118,24 @@ describe('Job actions cell', () => {
});
});
it.each`
button | action | jobType
${findPlayButton} | ${'play'} | ${playableJob}
${findRetryButton} | ${'retry'} | ${retryableJob}
${findCancelButton} | ${'cancel'} | ${cancelableJob}
${findUnscheduleButton} | ${'unschedule'} | ${scheduledJob}
`('disables the $action button after first request', async ({ button, jobType }) => {
createComponent(jobType);
expect(button().props('disabled')).toBe(false);
button().vm.$emit('click');
await waitForPromises();
expect(button().props('disabled')).toBe(true);
});
describe('Scheduled Jobs', () => {
const today = () => new Date('2021-08-31');
......
......@@ -1653,6 +1653,65 @@ export const retryableJob = {
__typename: 'CiJob',
};
export const cancelableJob = {
artifacts: {
nodes: [],
__typename: 'CiJobArtifactConnection',
},
allowFailure: false,
status: 'PENDING',
scheduledAt: null,
manualJob: false,
triggered: null,
createdByTag: false,
detailedStatus: {
id: 'pending-1305-1305',
detailsPath: '/root/lots-of-jobs-project/-/jobs/1305',
group: 'pending',
icon: 'status_pending',
label: 'pending',
text: 'pending',
tooltip: 'pending',
action: {
id: 'Ci::Build-pending-1305',
buttonTitle: 'Cancel this job',
icon: 'cancel',
method: 'post',
path: '/root/lots-of-jobs-project/-/jobs/1305/cancel',
title: 'Cancel',
__typename: 'StatusAction',
},
__typename: 'DetailedStatus',
},
id: 'gid://gitlab/Ci::Build/1305',
refName: 'main',
refPath: '/root/lots-of-jobs-project/-/commits/main',
tags: [],
shortSha: '750605f2',
commitPath: '/root/lots-of-jobs-project/-/commit/750605f29530778cf0912779eba6d073128962a5',
stage: {
id: 'gid://gitlab/Ci::Stage/181',
name: 'deploy',
__typename: 'CiStage',
},
name: 'job_212',
duration: null,
finishedAt: null,
coverage: null,
retryable: false,
playable: false,
cancelable: true,
active: true,
stuck: false,
userPermissions: {
readBuild: true,
readJobArtifacts: true,
updateBuild: true,
__typename: 'JobPermissions',
},
__typename: 'CiJob',
};
export const cannotRetryJob = {
...retryableJob,
userPermissions: { readBuild: true, updateBuild: false, __typename: 'JobPermissions' },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment