Resolve "Remove modal box confirmation when retrying a pipeline"
This commit is contained in:
parent
27d0c42986
commit
feb9caab90
9 changed files with 124 additions and 241 deletions
|
@ -1,95 +0,0 @@
|
|||
<script>
|
||||
/* eslint-disable no-alert */
|
||||
|
||||
import eventHub from '../event_hub';
|
||||
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
|
||||
import icon from '../../vue_shared/components/icon.vue';
|
||||
import tooltip from '../../vue_shared/directives/tooltip';
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
tooltip,
|
||||
},
|
||||
components: {
|
||||
loadingIcon,
|
||||
icon,
|
||||
},
|
||||
props: {
|
||||
endpoint: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
cssClass: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
pipelineId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
buttonClass() {
|
||||
return `btn ${this.cssClass}`;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// We're using eventHub to listen to the modal here instead of
|
||||
// using props because it would would make the parent components
|
||||
// much more complex to keep track of the loading state of each button
|
||||
eventHub.$on('postAction', this.setLoading);
|
||||
},
|
||||
beforeDestroy() {
|
||||
eventHub.$off('postAction', this.setLoading);
|
||||
},
|
||||
methods: {
|
||||
onClick() {
|
||||
eventHub.$emit('openConfirmationModal', {
|
||||
pipelineId: this.pipelineId,
|
||||
endpoint: this.endpoint,
|
||||
type: this.type,
|
||||
});
|
||||
},
|
||||
setLoading(endpoint) {
|
||||
if (endpoint === this.endpoint) {
|
||||
this.isLoading = true;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
v-tooltip
|
||||
type="button"
|
||||
@click="onClick"
|
||||
:class="buttonClass"
|
||||
:title="title"
|
||||
:aria-label="title"
|
||||
data-container="body"
|
||||
data-placement="top"
|
||||
:disabled="isLoading">
|
||||
<icon
|
||||
:name="icon"
|
||||
/>
|
||||
<loading-icon v-if="isLoading" />
|
||||
</button>
|
||||
</template>
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
|
||||
import Modal from '~/vue_shared/components/gl_modal.vue';
|
||||
import { s__, sprintf } from '~/locale';
|
||||
import pipelinesTableRowComponent from './pipelines_table_row.vue';
|
||||
import PipelinesTableRowComponent from './pipelines_table_row.vue';
|
||||
import eventHub from '../event_hub';
|
||||
|
||||
/**
|
||||
|
@ -11,8 +11,8 @@
|
|||
*/
|
||||
export default {
|
||||
components: {
|
||||
pipelinesTableRowComponent,
|
||||
DeprecatedModal,
|
||||
PipelinesTableRowComponent,
|
||||
Modal,
|
||||
},
|
||||
props: {
|
||||
pipelines: {
|
||||
|
@ -37,31 +37,19 @@
|
|||
return {
|
||||
pipelineId: '',
|
||||
endpoint: '',
|
||||
type: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
modalTitle() {
|
||||
return this.type === 'stop' ?
|
||||
sprintf(s__('Pipeline|Stop pipeline #%{pipelineId}?'), {
|
||||
pipelineId: `'${this.pipelineId}'`,
|
||||
}, false) :
|
||||
sprintf(s__('Pipeline|Retry pipeline #%{pipelineId}?'), {
|
||||
pipelineId: `'${this.pipelineId}'`,
|
||||
return sprintf(s__('Pipeline|Stop pipeline #%{pipelineId}?'), {
|
||||
pipelineId: `${this.pipelineId}`,
|
||||
}, false);
|
||||
},
|
||||
modalText() {
|
||||
return this.type === 'stop' ?
|
||||
sprintf(s__('Pipeline|You’re about to stop pipeline %{pipelineId}.'), {
|
||||
pipelineId: `<strong>#${this.pipelineId}</strong>`,
|
||||
}, false) :
|
||||
sprintf(s__('Pipeline|You’re about to retry pipeline %{pipelineId}.'), {
|
||||
return sprintf(s__('Pipeline|You’re about to stop pipeline %{pipelineId}.'), {
|
||||
pipelineId: `<strong>#${this.pipelineId}</strong>`,
|
||||
}, false);
|
||||
},
|
||||
primaryButtonLabel() {
|
||||
return this.type === 'stop' ? s__('Pipeline|Stop pipeline') : s__('Pipeline|Retry pipeline');
|
||||
},
|
||||
},
|
||||
created() {
|
||||
eventHub.$on('openConfirmationModal', this.setModalData);
|
||||
|
@ -73,7 +61,6 @@
|
|||
setModalData(data) {
|
||||
this.pipelineId = data.pipelineId;
|
||||
this.endpoint = data.endpoint;
|
||||
this.type = data.type;
|
||||
},
|
||||
onSubmit() {
|
||||
eventHub.$emit('postAction', this.endpoint);
|
||||
|
@ -120,20 +107,16 @@
|
|||
:auto-devops-help-path="autoDevopsHelpPath"
|
||||
:view-type="viewType"
|
||||
/>
|
||||
<deprecated-modal
|
||||
|
||||
<modal
|
||||
id="confirmation-modal"
|
||||
:title="modalTitle"
|
||||
:text="modalText"
|
||||
kind="danger"
|
||||
:primary-button-label="primaryButtonLabel"
|
||||
:header-title-text="modalTitle"
|
||||
footer-primary-button-variant="danger"
|
||||
:footer-primary-button-text="s__('Pipeline|Stop pipeline')"
|
||||
@submit="onSubmit"
|
||||
>
|
||||
<template
|
||||
slot="body"
|
||||
slot-scope="props"
|
||||
>
|
||||
<p v-html="props.text"></p>
|
||||
</template>
|
||||
</deprecated-modal>
|
||||
<span v-html="modalText"></span>
|
||||
</modal>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
<script>
|
||||
/* eslint-disable no-param-reassign */
|
||||
import asyncButtonComponent from './async_button.vue';
|
||||
import pipelinesActionsComponent from './pipelines_actions.vue';
|
||||
import pipelinesArtifactsComponent from './pipelines_artifacts.vue';
|
||||
import ciBadge from '../../vue_shared/components/ci_badge_link.vue';
|
||||
import pipelineStage from './stage.vue';
|
||||
import pipelineUrl from './pipeline_url.vue';
|
||||
import pipelinesTimeago from './time_ago.vue';
|
||||
import commitComponent from '../../vue_shared/components/commit.vue';
|
||||
import eventHub from '../event_hub';
|
||||
import PipelinesActionsComponent from './pipelines_actions.vue';
|
||||
import PipelinesArtifactsComponent from './pipelines_artifacts.vue';
|
||||
import CiBadge from '../../vue_shared/components/ci_badge_link.vue';
|
||||
import PipelineStage from './stage.vue';
|
||||
import PipelineUrl from './pipeline_url.vue';
|
||||
import PipelinesTimeago from './time_ago.vue';
|
||||
import CommitComponent from '../../vue_shared/components/commit.vue';
|
||||
import LoadingButton from '../../vue_shared/components/loading_button.vue';
|
||||
import Icon from '../../vue_shared/components/icon.vue';
|
||||
|
||||
/**
|
||||
* Pipeline table row.
|
||||
|
@ -16,14 +17,15 @@
|
|||
*/
|
||||
export default {
|
||||
components: {
|
||||
asyncButtonComponent,
|
||||
pipelinesActionsComponent,
|
||||
pipelinesArtifactsComponent,
|
||||
commitComponent,
|
||||
pipelineStage,
|
||||
pipelineUrl,
|
||||
ciBadge,
|
||||
pipelinesTimeago,
|
||||
PipelinesActionsComponent,
|
||||
PipelinesArtifactsComponent,
|
||||
CommitComponent,
|
||||
PipelineStage,
|
||||
PipelineUrl,
|
||||
CiBadge,
|
||||
PipelinesTimeago,
|
||||
LoadingButton,
|
||||
Icon,
|
||||
},
|
||||
props: {
|
||||
pipeline: {
|
||||
|
@ -44,6 +46,12 @@
|
|||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isRetrying: false,
|
||||
isCancelling: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
/**
|
||||
* If provided, returns the commit tag.
|
||||
|
@ -119,8 +127,10 @@
|
|||
if (this.pipeline.ref) {
|
||||
return Object.keys(this.pipeline.ref).reduce((accumulator, prop) => {
|
||||
if (prop === 'path') {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
accumulator.ref_url = this.pipeline.ref[prop];
|
||||
} else {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
accumulator[prop] = this.pipeline.ref[prop];
|
||||
}
|
||||
return accumulator;
|
||||
|
@ -216,6 +226,21 @@
|
|||
return this.viewType === 'child';
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleCancelClick() {
|
||||
this.isCancelling = true;
|
||||
|
||||
eventHub.$emit('openConfirmationModal', {
|
||||
pipelineId: this.pipeline.id,
|
||||
endpoint: this.pipeline.cancel_path,
|
||||
});
|
||||
},
|
||||
handleRetryClick() {
|
||||
this.isRetrying = true;
|
||||
eventHub.$emit('retryPipeline', this.pipeline.retry_path);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
|
@ -287,7 +312,8 @@
|
|||
|
||||
<div
|
||||
v-if="displayPipelineActions"
|
||||
class="table-section section-20 table-button-footer pipeline-actions">
|
||||
class="table-section section-20 table-button-footer pipeline-actions"
|
||||
>
|
||||
<div class="btn-group table-action-buttons">
|
||||
<pipelines-actions-component
|
||||
v-if="pipeline.details.manual_actions.length"
|
||||
|
@ -300,29 +326,27 @@
|
|||
:artifacts="pipeline.details.artifacts"
|
||||
/>
|
||||
|
||||
<async-button-component
|
||||
<loading-button
|
||||
v-if="pipeline.flags.retryable"
|
||||
:endpoint="pipeline.retry_path"
|
||||
css-class="js-pipelines-retry-button btn-default btn-retry"
|
||||
title="Retry"
|
||||
icon="repeat"
|
||||
:pipeline-id="pipeline.id"
|
||||
data-toggle="modal"
|
||||
data-target="#confirmation-modal"
|
||||
type="retry"
|
||||
/>
|
||||
@click="handleRetryClick"
|
||||
container-class="js-pipelines-retry-button btn btn-default btn-retry"
|
||||
:loading="isRetrying"
|
||||
:disabled="isRetrying"
|
||||
>
|
||||
<icon name="repeat" />
|
||||
</loading-button>
|
||||
|
||||
<async-button-component
|
||||
<loading-button
|
||||
v-if="pipeline.flags.cancelable"
|
||||
:endpoint="pipeline.cancel_path"
|
||||
css-class="js-pipelines-cancel-button btn-remove"
|
||||
title="Stop"
|
||||
icon="close"
|
||||
:pipeline-id="pipeline.id"
|
||||
@click="handleCancelClick"
|
||||
data-toggle="modal"
|
||||
data-target="#confirmation-modal"
|
||||
type="stop"
|
||||
/>
|
||||
container-class="js-pipelines-cancel-button btn btn-remove"
|
||||
:loading="isCancelling"
|
||||
:disabled="isCancelling"
|
||||
>
|
||||
<icon name="close" />
|
||||
</loading-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -53,10 +53,12 @@ export default {
|
|||
});
|
||||
|
||||
eventHub.$on('postAction', this.postAction);
|
||||
eventHub.$on('retryPipeline', this.postAction);
|
||||
eventHub.$on('clickedDropdown', this.updateTable);
|
||||
},
|
||||
beforeDestroy() {
|
||||
eventHub.$off('postAction', this.postAction);
|
||||
eventHub.$off('retryPipeline', this.postAction);
|
||||
eventHub.$off('clickedDropdown', this.updateTable);
|
||||
},
|
||||
destroyed() {
|
||||
|
|
|
@ -70,12 +70,14 @@
|
|||
/>
|
||||
</transition>
|
||||
<transition name="fade">
|
||||
<slot>
|
||||
<span
|
||||
v-if="label"
|
||||
class="js-loading-button-label"
|
||||
>
|
||||
{{ label }}
|
||||
</span>
|
||||
</slot>
|
||||
</transition>
|
||||
</button>
|
||||
</template>
|
||||
|
|
5
changelogs/unreleased/45715-remove-modal-retry.yml
Normal file
5
changelogs/unreleased/45715-remove-modal-retry.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove modalbox confirmation when retrying a pipeline
|
||||
merge_request: 18879
|
||||
author:
|
||||
type: changed
|
|
@ -125,7 +125,7 @@ describe 'Pipelines', :js do
|
|||
context 'when canceling' do
|
||||
before do
|
||||
find('.js-pipelines-cancel-button').click
|
||||
find('.js-primary-button').click
|
||||
find('.js-modal-primary-action').click
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
|
@ -156,7 +156,6 @@ describe 'Pipelines', :js do
|
|||
context 'when retrying' do
|
||||
before do
|
||||
find('.js-pipelines-retry-button').click
|
||||
find('.js-primary-button').click
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
|
@ -256,7 +255,7 @@ describe 'Pipelines', :js do
|
|||
context 'when canceling' do
|
||||
before do
|
||||
find('.js-pipelines-cancel-button').click
|
||||
find('.js-primary-button').click
|
||||
find('.js-modal-primary-action').click
|
||||
end
|
||||
|
||||
it 'indicates that pipeline was canceled' do
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
import Vue from 'vue';
|
||||
import asyncButtonComp from '~/pipelines/components/async_button.vue';
|
||||
import eventHub from '~/pipelines/event_hub';
|
||||
|
||||
describe('Pipelines Async Button', () => {
|
||||
let component;
|
||||
let AsyncButtonComponent;
|
||||
|
||||
beforeEach(() => {
|
||||
AsyncButtonComponent = Vue.extend(asyncButtonComp);
|
||||
|
||||
component = new AsyncButtonComponent({
|
||||
propsData: {
|
||||
endpoint: '/foo',
|
||||
title: 'Foo',
|
||||
icon: 'repeat',
|
||||
cssClass: 'bar',
|
||||
pipelineId: 123,
|
||||
type: 'explode',
|
||||
},
|
||||
}).$mount();
|
||||
});
|
||||
|
||||
it('should render a button', () => {
|
||||
expect(component.$el.tagName).toEqual('BUTTON');
|
||||
});
|
||||
|
||||
it('should render svg icon', () => {
|
||||
expect(component.$el.querySelector('svg')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should render the provided title', () => {
|
||||
expect(component.$el.getAttribute('data-original-title')).toContain('Foo');
|
||||
expect(component.$el.getAttribute('aria-label')).toContain('Foo');
|
||||
});
|
||||
|
||||
it('should render the provided cssClass', () => {
|
||||
expect(component.$el.getAttribute('class')).toContain('bar');
|
||||
});
|
||||
|
||||
describe('With confirm dialog', () => {
|
||||
it('should call the service when confimation is positive', () => {
|
||||
eventHub.$on('openConfirmationModal', (data) => {
|
||||
expect(data.pipelineId).toEqual(123);
|
||||
expect(data.type).toEqual('explode');
|
||||
});
|
||||
|
||||
component = new AsyncButtonComponent({
|
||||
propsData: {
|
||||
endpoint: '/foo',
|
||||
title: 'Foo',
|
||||
icon: 'fa fa-foo',
|
||||
cssClass: 'bar',
|
||||
pipelineId: 123,
|
||||
type: 'explode',
|
||||
},
|
||||
}).$mount();
|
||||
|
||||
component.$el.click();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,5 +1,6 @@
|
|||
import Vue from 'vue';
|
||||
import tableRowComp from '~/pipelines/components/pipelines_table_row.vue';
|
||||
import eventHub from '~/pipelines/event_hub';
|
||||
|
||||
describe('Pipelines Table Row', () => {
|
||||
const jsonFixtureName = 'pipelines/pipelines.json';
|
||||
|
@ -151,13 +152,37 @@ describe('Pipelines Table Row', () => {
|
|||
|
||||
describe('actions column', () => {
|
||||
beforeEach(() => {
|
||||
component = buildComponent(pipeline);
|
||||
const withActions = Object.assign({}, pipeline);
|
||||
withActions.flags.cancelable = true;
|
||||
withActions.flags.retryable = true;
|
||||
withActions.cancel_path = '/cancel';
|
||||
withActions.retry_path = '/retry';
|
||||
|
||||
component = buildComponent(withActions);
|
||||
});
|
||||
|
||||
it('should render the provided actions', () => {
|
||||
expect(
|
||||
component.$el.querySelectorAll('.table-section:nth-child(6) ul li').length,
|
||||
).toEqual(pipeline.details.manual_actions.length);
|
||||
expect(component.$el.querySelector('.js-pipelines-retry-button')).not.toBeNull();
|
||||
expect(component.$el.querySelector('.js-pipelines-cancel-button')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('emits `retryPipeline` event when retry button is clicked and toggles loading', () => {
|
||||
eventHub.$on('retryPipeline', (endpoint) => {
|
||||
expect(endpoint).toEqual('/retry');
|
||||
});
|
||||
|
||||
component.$el.querySelector('.js-pipelines-retry-button').click();
|
||||
expect(component.isRetrying).toEqual(true);
|
||||
});
|
||||
|
||||
it('emits `openConfirmationModal` event when cancel button is clicked and toggles loading', () => {
|
||||
eventHub.$on('openConfirmationModal', (data) => {
|
||||
expect(data.endpoint).toEqual('/cancel');
|
||||
expect(data.pipelineId).toEqual(pipeline.id);
|
||||
});
|
||||
|
||||
component.$el.querySelector('.js-pipelines-cancel-button').click();
|
||||
expect(component.isCancelling).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue