Add modal for stopping jobs in admin area
This commit is contained in:
parent
3b13159d9c
commit
76f16bbf71
|
@ -157,6 +157,11 @@ import Activities from './activities';
|
||||||
case 'dashboard:todos:index':
|
case 'dashboard:todos:index':
|
||||||
import('./pages/dashboard/todos/index').then(callDefault).catch(fail);
|
import('./pages/dashboard/todos/index').then(callDefault).catch(fail);
|
||||||
break;
|
break;
|
||||||
|
case 'admin:jobs:index':
|
||||||
|
import('./pages/admin/jobs/index')
|
||||||
|
.then(callDefault)
|
||||||
|
.catch(fail);
|
||||||
|
break;
|
||||||
case 'dashboard:projects:index':
|
case 'dashboard:projects:index':
|
||||||
case 'dashboard:projects:starred':
|
case 'dashboard:projects:starred':
|
||||||
import('./pages/dashboard/projects')
|
import('./pages/dashboard/projects')
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
<script>
|
||||||
|
import axios from '~/lib/utils/axios_utils';
|
||||||
|
import Flash from '~/flash';
|
||||||
|
import modal from '~/vue_shared/components/modal.vue';
|
||||||
|
import { s__ } from '~/locale';
|
||||||
|
import { redirectTo } from '~/lib/utils/url_utility';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
modal,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
text() {
|
||||||
|
return s__('AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running.');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onSubmit() {
|
||||||
|
return axios.post(this.url)
|
||||||
|
.then((response) => {
|
||||||
|
// follow the rediect to refresh the page
|
||||||
|
redirectTo(response.request.responseURL);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
Flash(s__('AdminArea|Stopping jobs failed'));
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<modal
|
||||||
|
id="stop-jobs-modal"
|
||||||
|
:title="s__('AdminArea|Stop all jobs?')"
|
||||||
|
:text="text"
|
||||||
|
kind="danger"
|
||||||
|
:primary-button-label="s__('AdminArea|Stop jobs')"
|
||||||
|
@submit="onSubmit" />
|
||||||
|
</template>
|
|
@ -0,0 +1,29 @@
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
import Translate from '~/vue_shared/translate';
|
||||||
|
|
||||||
|
import stopJobsModal from './components/stop_jobs_modal.vue';
|
||||||
|
|
||||||
|
Vue.use(Translate);
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const stopJobsButton = document.getElementById('stop-jobs-button');
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-new
|
||||||
|
new Vue({
|
||||||
|
el: '#stop-jobs-modal',
|
||||||
|
components: {
|
||||||
|
stopJobsModal,
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
stopJobsButton.classList.remove('disabled');
|
||||||
|
},
|
||||||
|
render(createElement) {
|
||||||
|
return createElement('stop-jobs-modal', {
|
||||||
|
props: {
|
||||||
|
url: stopJobsButton.dataset.url,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
|
@ -12,6 +12,7 @@
|
||||||
min-height: $modal-body-height;
|
min-height: $modal-body-height;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: #{3 * $grid-size} #{2 * $grid-size};
|
padding: #{3 * $grid-size} #{2 * $grid-size};
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
.form-actions {
|
.form-actions {
|
||||||
margin: #{2 * $grid-size} #{-2 * $grid-size} #{-2 * $grid-size};
|
margin: #{2 * $grid-size} #{-2 * $grid-size} #{-2 * $grid-size};
|
||||||
|
|
|
@ -20,6 +20,6 @@ class Admin::JobsController < Admin::ApplicationController
|
||||||
def cancel_all
|
def cancel_all
|
||||||
Ci::Build.running_or_pending.each(&:cancel)
|
Ci::Build.running_or_pending.each(&:cancel)
|
||||||
|
|
||||||
redirect_to admin_jobs_path
|
redirect_to admin_jobs_path, status: 303
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,7 +9,12 @@
|
||||||
|
|
||||||
.nav-controls
|
.nav-controls
|
||||||
- if @all_builds.running_or_pending.any?
|
- if @all_builds.running_or_pending.any?
|
||||||
= link_to 'Cancel all', cancel_all_admin_jobs_path, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
|
#stop-jobs-modal
|
||||||
|
|
||||||
|
%button#stop-jobs-button.btn.btn-danger{ data: { toggle: 'modal',
|
||||||
|
target: '#stop-jobs-modal',
|
||||||
|
url: cancel_all_admin_jobs_path } }
|
||||||
|
= s_('AdminArea|Stop all jobs')
|
||||||
|
|
||||||
.row-content-block.second-block
|
.row-content-block.second-block
|
||||||
#{(@scope || 'all').capitalize} jobs
|
#{(@scope || 'all').capitalize} jobs
|
||||||
|
|
|
@ -21,7 +21,7 @@ describe 'Admin Builds' do
|
||||||
expect(page).to have_selector('.nav-links li.active', text: 'All')
|
expect(page).to have_selector('.nav-links li.active', text: 'All')
|
||||||
expect(page).to have_selector('.row-content-block', text: 'All jobs')
|
expect(page).to have_selector('.row-content-block', text: 'All jobs')
|
||||||
expect(page.all('.build-link').size).to eq(4)
|
expect(page.all('.build-link').size).to eq(4)
|
||||||
expect(page).to have_link 'Cancel all'
|
expect(page).to have_button 'Stop all jobs'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ describe 'Admin Builds' do
|
||||||
|
|
||||||
expect(page).to have_selector('.nav-links li.active', text: 'All')
|
expect(page).to have_selector('.nav-links li.active', text: 'All')
|
||||||
expect(page).to have_content 'No jobs to show'
|
expect(page).to have_content 'No jobs to show'
|
||||||
expect(page).not_to have_link 'Cancel all'
|
expect(page).not_to have_button 'Stop all jobs'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -51,7 +51,7 @@ describe 'Admin Builds' do
|
||||||
expect(page.find('.build-link')).not_to have_content(build2.id)
|
expect(page.find('.build-link')).not_to have_content(build2.id)
|
||||||
expect(page.find('.build-link')).not_to have_content(build3.id)
|
expect(page.find('.build-link')).not_to have_content(build3.id)
|
||||||
expect(page.find('.build-link')).not_to have_content(build4.id)
|
expect(page.find('.build-link')).not_to have_content(build4.id)
|
||||||
expect(page).to have_link 'Cancel all'
|
expect(page).to have_button 'Stop all jobs'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ describe 'Admin Builds' do
|
||||||
|
|
||||||
expect(page).to have_selector('.nav-links li.active', text: 'Pending')
|
expect(page).to have_selector('.nav-links li.active', text: 'Pending')
|
||||||
expect(page).to have_content 'No jobs to show'
|
expect(page).to have_content 'No jobs to show'
|
||||||
expect(page).not_to have_link 'Cancel all'
|
expect(page).not_to have_button 'Stop all jobs'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -83,7 +83,7 @@ describe 'Admin Builds' do
|
||||||
expect(page.find('.build-link')).not_to have_content(build2.id)
|
expect(page.find('.build-link')).not_to have_content(build2.id)
|
||||||
expect(page.find('.build-link')).not_to have_content(build3.id)
|
expect(page.find('.build-link')).not_to have_content(build3.id)
|
||||||
expect(page.find('.build-link')).not_to have_content(build4.id)
|
expect(page.find('.build-link')).not_to have_content(build4.id)
|
||||||
expect(page).to have_link 'Cancel all'
|
expect(page).to have_button 'Stop all jobs'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ describe 'Admin Builds' do
|
||||||
|
|
||||||
expect(page).to have_selector('.nav-links li.active', text: 'Running')
|
expect(page).to have_selector('.nav-links li.active', text: 'Running')
|
||||||
expect(page).to have_content 'No jobs to show'
|
expect(page).to have_content 'No jobs to show'
|
||||||
expect(page).not_to have_link 'Cancel all'
|
expect(page).not_to have_button 'Stop all jobs'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -113,7 +113,7 @@ describe 'Admin Builds' do
|
||||||
expect(page.find('.build-link')).not_to have_content(build1.id)
|
expect(page.find('.build-link')).not_to have_content(build1.id)
|
||||||
expect(page.find('.build-link')).not_to have_content(build2.id)
|
expect(page.find('.build-link')).not_to have_content(build2.id)
|
||||||
expect(page.find('.build-link')).to have_content(build3.id)
|
expect(page.find('.build-link')).to have_content(build3.id)
|
||||||
expect(page).to have_link 'Cancel all'
|
expect(page).to have_button 'Stop all jobs'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ describe 'Admin Builds' do
|
||||||
|
|
||||||
expect(page).to have_selector('.nav-links li.active', text: 'Finished')
|
expect(page).to have_selector('.nav-links li.active', text: 'Finished')
|
||||||
expect(page).to have_content 'No jobs to show'
|
expect(page).to have_content 'No jobs to show'
|
||||||
expect(page).to have_link 'Cancel all'
|
expect(page).to have_button 'Stop all jobs'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
import axios from '~/lib/utils/axios_utils';
|
||||||
|
import stopJobsModal from '~/pages/admin/jobs/index/components/stop_jobs_modal.vue';
|
||||||
|
import * as urlUtility from '~/lib/utils/url_utility';
|
||||||
|
|
||||||
|
import mountComponent from '../../../../../helpers/vue_mount_component_helper';
|
||||||
|
|
||||||
|
describe('stop_jobs_modal.vue', () => {
|
||||||
|
const props = {
|
||||||
|
url: `${gl.TEST_HOST}/stop_jobs_modal.vue/stopAll`,
|
||||||
|
};
|
||||||
|
let vm;
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vm.$destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const Component = Vue.extend(stopJobsModal);
|
||||||
|
vm = mountComponent(Component, props);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('onSubmit', () => {
|
||||||
|
it('stops jobs and redirects to overview page', (done) => {
|
||||||
|
const responseURL = `${gl.TEST_HOST}/stop_jobs_modal.vue/jobs`;
|
||||||
|
const redirectSpy = spyOn(urlUtility, 'redirectTo');
|
||||||
|
spyOn(axios, 'post').and.callFake((url) => {
|
||||||
|
expect(url).toBe(props.url);
|
||||||
|
return Promise.resolve({
|
||||||
|
request: {
|
||||||
|
responseURL,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
vm.onSubmit()
|
||||||
|
.then(() => {
|
||||||
|
expect(redirectSpy).toHaveBeenCalledWith(responseURL);
|
||||||
|
})
|
||||||
|
.then(done)
|
||||||
|
.catch(done.fail);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays error if stopping jobs failed', (done) => {
|
||||||
|
const dummyError = new Error('stopping jobs failed');
|
||||||
|
const redirectSpy = spyOn(urlUtility, 'redirectTo');
|
||||||
|
spyOn(axios, 'post').and.callFake((url) => {
|
||||||
|
expect(url).toBe(props.url);
|
||||||
|
return Promise.reject(dummyError);
|
||||||
|
});
|
||||||
|
|
||||||
|
vm.onSubmit()
|
||||||
|
.then(done.fail)
|
||||||
|
.catch((error) => {
|
||||||
|
expect(error).toBe(dummyError);
|
||||||
|
expect(redirectSpy).not.toHaveBeenCalled();
|
||||||
|
})
|
||||||
|
.then(done)
|
||||||
|
.catch(done.fail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue