Commit 6d7df4f8 authored by Clement Ho's avatar Clement Ho

Merge branch '41297-new-design-for-cancel-stop-pipeline-confirmation' into 'master'

Resolve "New design for cancel / stop pipeline confirmation"

Closes #41297

See merge request gitlab-org/gitlab-ce!16813
parents 66695ce2 97f08c65
...@@ -152,14 +152,14 @@ export default { ...@@ -152,14 +152,14 @@ export default {
showLeaveGroupModal(group, parentGroup) { showLeaveGroupModal(group, parentGroup) {
this.targetGroup = group; this.targetGroup = group;
this.targetParentGroup = parentGroup; this.targetParentGroup = parentGroup;
this.showModal = true; this.updateModal = true;
this.groupLeaveConfirmationMessage = s__(`GroupsTree|Are you sure you want to leave the "${group.fullName}" group?`); this.groupLeaveConfirmationMessage = s__(`GroupsTree|Are you sure you want to leave the "${group.fullName}" group?`);
}, },
hideLeaveGroupModal() { hideLeaveGroupModal() {
this.showModal = false; this.updateModal = false;
}, },
leaveGroup() { leaveGroup() {
this.showModal = false; this.updateModal = false;
this.targetGroup.isBeingRemoved = true; this.targetGroup.isBeingRemoved = true;
this.service.leaveGroup(this.targetGroup.leavePath) this.service.leaveGroup(this.targetGroup.leavePath)
.then(res => res.json()) .then(res => res.json())
......
...@@ -31,10 +31,9 @@ ...@@ -31,10 +31,9 @@
type: String, type: String,
required: true, required: true,
}, },
confirmActionMessage: { id: {
type: String, type: Number,
required: false, required: true,
default: '',
}, },
}, },
data() { data() {
...@@ -49,11 +48,10 @@ ...@@ -49,11 +48,10 @@
}, },
methods: { methods: {
onClick() { onClick() {
if (this.confirmActionMessage !== '' && confirm(this.confirmActionMessage)) { eventHub.$emit('actionConfirmationModal', {
this.makeRequest(); id: this.id,
} else if (this.confirmActionMessage === '') { callback: this.makeRequest,
this.makeRequest(); });
}
}, },
makeRequest() { makeRequest() {
this.isLoading = true; this.isLoading = true;
......
<script> <script>
import pipelinesTableRowComponent from './pipelines_table_row.vue'; import pipelinesTableRowComponent from './pipelines_table_row.vue';
import stopConfirmationModal from './stop_confirmation_modal.vue';
import retryConfirmationModal from './retry_confirmation_modal.vue';
/** /**
* Pipelines Table Component. * Pipelines Table Component.
...@@ -9,6 +11,8 @@ ...@@ -9,6 +11,8 @@
export default { export default {
components: { components: {
pipelinesTableRowComponent, pipelinesTableRowComponent,
stopConfirmationModal,
retryConfirmationModal,
}, },
props: { props: {
pipelines: { pipelines: {
...@@ -70,5 +74,7 @@ ...@@ -70,5 +74,7 @@
:auto-devops-help-path="autoDevopsHelpPath" :auto-devops-help-path="autoDevopsHelpPath"
:view-type="viewType" :view-type="viewType"
/> />
<stop-confirmation-modal />
<retry-confirmation-modal />
</div> </div>
</template> </template>
...@@ -305,6 +305,9 @@ ...@@ -305,6 +305,9 @@
css-class="js-pipelines-retry-button btn-default btn-retry" css-class="js-pipelines-retry-button btn-default btn-retry"
title="Retry" title="Retry"
icon="repeat" icon="repeat"
:id="pipeline.id"
data-toggle="modal"
data-target="#retry-confirmation-modal"
/> />
<async-button-component <async-button-component
...@@ -313,7 +316,9 @@ ...@@ -313,7 +316,9 @@
css-class="js-pipelines-cancel-button btn-remove" css-class="js-pipelines-cancel-button btn-remove"
title="Cancel" title="Cancel"
icon="close" icon="close"
confirm-action-message="Are you sure you want to cancel this pipeline?" :id="pipeline.id"
data-toggle="modal"
data-target="#stop-confirmation-modal"
/> />
</div> </div>
</div> </div>
......
<script>
import modal from '~/vue_shared/components/modal.vue';
import { s__, sprintf } from '~/locale';
import eventHub from '../event_hub';
export default {
components: {
modal,
},
data() {
return {
id: '',
callback: () => {},
};
},
computed: {
title() {
return sprintf(s__('Pipeline|Retry pipeline #%{id}?'), {
id: `'${this.id}'`,
}, false);
},
text() {
return sprintf(s__('Pipeline|You’re about to retry pipeline %{id}.'), {
id: `<strong>#${this.id}</strong>`,
}, false);
},
primaryButtonLabel() {
return s__('Pipeline|Retry pipeline');
},
},
created() {
eventHub.$on('actionConfirmationModal', this.updateModal);
},
beforeDestroy() {
eventHub.$off('actionConfirmationModal', this.updateModal);
},
methods: {
updateModal(action) {
this.id = action.id;
this.callback = action.callback;
},
onSubmit() {
this.callback();
},
},
};
</script>
<template>
<modal
id="retry-confirmation-modal"
:title="title"
:text="text"
kind="danger"
:primary-button-label="primaryButtonLabel"
@submit="onSubmit"
>
<template
slot="body"
slot-scope="props"
>
<p v-html="props.text"></p>
</template>
</modal>
</template>
<script>
import modal from '~/vue_shared/components/modal.vue';
import { s__, sprintf } from '~/locale';
import eventHub from '../event_hub';
export default {
components: {
modal,
},
data() {
return {
id: '',
callback: () => {},
};
},
computed: {
title() {
return sprintf(s__('Pipeline|Stop pipeline #%{id}?'), {
id: `'${this.id}'`,
}, false);
},
text() {
return sprintf(s__('Pipeline|You’re about to stop pipeline %{id}.'), {
id: `<strong>#${this.id}</strong>`,
}, false);
},
primaryButtonLabel() {
return s__('Pipeline|Stop pipeline');
},
},
created() {
eventHub.$on('actionConfirmationModal', this.updateModal);
},
beforeDestroy() {
eventHub.$off('actionConfirmationModal', this.updateModal);
},
methods: {
updateModal(action) {
this.id = action.id;
this.callback = action.callback;
},
onSubmit() {
this.callback();
},
},
};
</script>
<template>
<modal
id="stop-confirmation-modal"
:title="title"
:text="text"
kind="danger"
:primary-button-label="primaryButtonLabel"
@submit="onSubmit"
>
<template
slot="body"
slot-scope="props"
>
<p v-html="props.text"></p>
</template>
</modal>
</template>
...@@ -109,7 +109,8 @@ describe 'Pipelines', :js do ...@@ -109,7 +109,8 @@ describe 'Pipelines', :js do
context 'when canceling' do context 'when canceling' do
before do before do
accept_confirm { find('.js-pipelines-cancel-button').click } find('.js-pipelines-cancel-button').click
find('.js-primary-button').click
wait_for_requests wait_for_requests
end end
...@@ -140,6 +141,7 @@ describe 'Pipelines', :js do ...@@ -140,6 +141,7 @@ describe 'Pipelines', :js do
context 'when retrying' do context 'when retrying' do
before do before do
find('.js-pipelines-retry-button').click find('.js-pipelines-retry-button').click
find('.js-primary-button').click
wait_for_requests wait_for_requests
end end
...@@ -238,7 +240,8 @@ describe 'Pipelines', :js do ...@@ -238,7 +240,8 @@ describe 'Pipelines', :js do
context 'when canceling' do context 'when canceling' do
before do before do
accept_alert { find('.js-pipelines-cancel-button').click } find('.js-pipelines-cancel-button').click
find('.js-primary-button').click
end end
it 'indicates that pipeline was canceled' do it 'indicates that pipeline was canceled' do
......
...@@ -268,10 +268,10 @@ describe('AppComponent', () => { ...@@ -268,10 +268,10 @@ describe('AppComponent', () => {
it('updates props which show modal confirmation dialog', () => { it('updates props which show modal confirmation dialog', () => {
const group = Object.assign({}, mockParentGroupItem); const group = Object.assign({}, mockParentGroupItem);
expect(vm.showModal).toBeFalsy(); expect(vm.updateModal).toBeFalsy();
expect(vm.groupLeaveConfirmationMessage).toBe(''); expect(vm.groupLeaveConfirmationMessage).toBe('');
vm.showLeaveGroupModal(group, mockParentGroupItem); vm.showLeaveGroupModal(group, mockParentGroupItem);
expect(vm.showModal).toBeTruthy(); expect(vm.updateModal).toBeTruthy();
expect(vm.groupLeaveConfirmationMessage).toBe(`Are you sure you want to leave the "${group.fullName}" group?`); expect(vm.groupLeaveConfirmationMessage).toBe(`Are you sure you want to leave the "${group.fullName}" group?`);
}); });
}); });
...@@ -280,9 +280,9 @@ describe('AppComponent', () => { ...@@ -280,9 +280,9 @@ describe('AppComponent', () => {
it('hides modal confirmation which is shown before leaving the group', () => { it('hides modal confirmation which is shown before leaving the group', () => {
const group = Object.assign({}, mockParentGroupItem); const group = Object.assign({}, mockParentGroupItem);
vm.showLeaveGroupModal(group, mockParentGroupItem); vm.showLeaveGroupModal(group, mockParentGroupItem);
expect(vm.showModal).toBeTruthy(); expect(vm.updateModal).toBeTruthy();
vm.hideLeaveGroupModal(); vm.hideLeaveGroupModal();
expect(vm.showModal).toBeFalsy(); expect(vm.updateModal).toBeFalsy();
}); });
}); });
...@@ -307,7 +307,7 @@ describe('AppComponent', () => { ...@@ -307,7 +307,7 @@ describe('AppComponent', () => {
spyOn($, 'scrollTo'); spyOn($, 'scrollTo');
vm.leaveGroup(); vm.leaveGroup();
expect(vm.showModal).toBeFalsy(); expect(vm.updateModal).toBeFalsy();
expect(vm.targetGroup.isBeingRemoved).toBeTruthy(); expect(vm.targetGroup.isBeingRemoved).toBeTruthy();
expect(vm.service.leaveGroup).toHaveBeenCalledWith(vm.targetGroup.leavePath); expect(vm.service.leaveGroup).toHaveBeenCalledWith(vm.targetGroup.leavePath);
setTimeout(() => { setTimeout(() => {
...@@ -475,7 +475,7 @@ describe('AppComponent', () => { ...@@ -475,7 +475,7 @@ describe('AppComponent', () => {
it('renders modal confirmation dialog', () => { it('renders modal confirmation dialog', () => {
vm.groupLeaveConfirmationMessage = 'Are you sure you want to leave the "foo" group?'; vm.groupLeaveConfirmationMessage = 'Are you sure you want to leave the "foo" group?';
vm.showModal = true; vm.updateModal = true;
const modalDialogEl = vm.$el.querySelector('.modal'); const modalDialogEl = vm.$el.querySelector('.modal');
expect(modalDialogEl).not.toBe(null); expect(modalDialogEl).not.toBe(null);
expect(modalDialogEl.querySelector('.modal-title').innerText.trim()).toBe('Are you sure?'); expect(modalDialogEl.querySelector('.modal-title').innerText.trim()).toBe('Are you sure?');
......
...@@ -15,6 +15,7 @@ describe('Pipelines Async Button', () => { ...@@ -15,6 +15,7 @@ describe('Pipelines Async Button', () => {
title: 'Foo', title: 'Foo',
icon: 'repeat', icon: 'repeat',
cssClass: 'bar', cssClass: 'bar',
id: 123,
}, },
}).$mount(); }).$mount();
}); });
...@@ -38,9 +39,8 @@ describe('Pipelines Async Button', () => { ...@@ -38,9 +39,8 @@ describe('Pipelines Async Button', () => {
describe('With confirm dialog', () => { describe('With confirm dialog', () => {
it('should call the service when confimation is positive', () => { it('should call the service when confimation is positive', () => {
spyOn(window, 'confirm').and.returnValue(true); eventHub.$on('actionConfirmationModal', (data) => {
eventHub.$on('postAction', (endpoint) => { expect(data.id).toEqual(123);
expect(endpoint).toEqual('/foo');
}); });
component = new AsyncButtonComponent({ component = new AsyncButtonComponent({
...@@ -49,7 +49,7 @@ describe('Pipelines Async Button', () => { ...@@ -49,7 +49,7 @@ describe('Pipelines Async Button', () => {
title: 'Foo', title: 'Foo',
icon: 'fa fa-foo', icon: 'fa fa-foo',
cssClass: 'bar', cssClass: 'bar',
confirmActionMessage: 'bar', id: 123,
}, },
}).$mount(); }).$mount();
......
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