Merge branch 'winh-stop-jobs-modal' into 'master'
Add modal for stopping jobs in admin area Closes #41305 See merge request gitlab-org/gitlab-ce!16283
This commit is contained in:
commit
2af0b083c6
8 changed files with 160 additions and 10 deletions
|
@ -157,6 +157,11 @@ import Activities from './activities';
|
|||
case 'dashboard:todos:index':
|
||||
import('./pages/dashboard/todos/index').then(callDefault).catch(fail);
|
||||
break;
|
||||
case 'admin:jobs:index':
|
||||
import('./pages/admin/jobs/index')
|
||||
.then(callDefault)
|
||||
.catch(fail);
|
||||
break;
|
||||
case 'dashboard:projects:index':
|
||||
case 'dashboard:projects:starred':
|
||||
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>
|
29
app/assets/javascripts/pages/admin/jobs/index/index.js
Normal file
29
app/assets/javascripts/pages/admin/jobs/index/index.js
Normal file
|
@ -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;
|
||||
position: relative;
|
||||
padding: #{3 * $grid-size} #{2 * $grid-size};
|
||||
text-align: left;
|
||||
|
||||
.form-actions {
|
||||
margin: #{2 * $grid-size} #{-2 * $grid-size} #{-2 * $grid-size};
|
||||
|
|
|
@ -20,6 +20,6 @@ class Admin::JobsController < Admin::ApplicationController
|
|||
def cancel_all
|
||||
Ci::Build.running_or_pending.each(&:cancel)
|
||||
|
||||
redirect_to admin_jobs_path
|
||||
redirect_to admin_jobs_path, status: 303
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,7 +9,12 @@
|
|||
|
||||
.nav-controls
|
||||
- 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
|
||||
#{(@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('.row-content-block', text: 'All jobs')
|
||||
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
|
||||
|
||||
|
@ -31,7 +31,7 @@ describe 'Admin Builds' do
|
|||
|
||||
expect(page).to have_selector('.nav-links li.active', text: 'All')
|
||||
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
|
||||
|
@ -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(build3.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
|
||||
|
||||
|
@ -63,7 +63,7 @@ describe 'Admin Builds' do
|
|||
|
||||
expect(page).to have_selector('.nav-links li.active', text: 'Pending')
|
||||
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
|
||||
|
@ -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(build3.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
|
||||
|
||||
|
@ -95,7 +95,7 @@ describe 'Admin Builds' do
|
|||
|
||||
expect(page).to have_selector('.nav-links li.active', text: 'Running')
|
||||
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
|
||||
|
@ -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(build2.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
|
||||
|
||||
|
@ -125,7 +125,7 @@ describe 'Admin Builds' do
|
|||
|
||||
expect(page).to have_selector('.nav-links li.active', text: 'Finished')
|
||||
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
|
||||
|
|
|
@ -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 a new issue