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