Web: implement 'Cancel Job' button

The button calls the 'setJobStatus' API endpoint to set the job status to
`cancel-requested`.
This commit is contained in:
Sybren A. Stüvel 2022-04-21 16:53:20 +02:00
parent 1331d29b10
commit d84efb8c9a
3 changed files with 41 additions and 7 deletions

View File

@ -149,7 +149,7 @@ export default {
--footer-height: 25px; --footer-height: 25px;
--grid-gap: 4px; --grid-gap: 4px;
--action-bar-height: 3em; --action-bar-height: 2em;
} }
html, html,
@ -232,12 +232,11 @@ footer {
section.action-bar { section.action-bar {
height: var(--action-bar-height); height: var(--action-bar-height);
display: flex;
flex-direction: row;
} }
section.action-bar button.action { section.action-bar button.action {
display: flex;
flex-direction: column;
align-items: center;
padding: 0.1rem 0.75rem; padding: 0.1rem 0.75rem;
border-radius: 0.3rem; border-radius: 0.3rem;
border: thin solid white; border: thin solid white;

View File

@ -1,6 +1,7 @@
<template> <template>
<section class="action-bar jobs"> <section class="action-bar jobs">
<button class="action delete dangerous" :disabled="!jobs.canDelete" v-on:click="onButtonDelete">Delete</button> <button class="action delete dangerous" :disabled="!jobs.canDelete" v-on:click="onButtonDelete">Delete</button>
<button class="action cancel" :disabled="!jobs.canCancel" v-on:click="onButtonCancel">Cancel</button>
</section> </section>
</template> </template>
@ -10,7 +11,6 @@ import { useNotifs } from '@/stores/notifications';
export default { export default {
name: "JobActionsBar", name: "JobActionsBar",
events: ["actionDone", "apiError"],
data: () => ({ data: () => ({
jobs: useJobs(), jobs: useJobs(),
notifs: useNotifs(), notifs: useNotifs(),
@ -29,6 +29,23 @@ export default {
this.notifs.add(`Error: ${errorMsg}`); this.notifs.add(`Error: ${errorMsg}`);
}) })
}, },
onButtonCancel() {
const numJobs = this.jobs.numSelected;
this.jobs.cancelJobs()
.then(() => {
let message;
if (numJobs == 1) {
message = `Job marked for cancellation`;
} else {
message = `${numJobs} jobs marked for cancellation`;
}
this.notifs.add(message);
})
.catch((error) => {
const errorMsg = JSON.stringify(error); // TODO: handle API errors better.
this.notifs.add(`Error: ${errorMsg}`);
})
},
} }
} }

View File

@ -3,6 +3,9 @@ import { defineStore } from 'pinia'
import * as urls from '@/urls' import * as urls from '@/urls'
import * as API from '@/manager-api'; import * as API from '@/manager-api';
const apiClient = new API.ApiClient(urls.api());
const jobsAPI = new API.JobsApi(apiClient);
// 'use' prefix is idiomatic for Pinia stores. // 'use' prefix is idiomatic for Pinia stores.
// See https://pinia.vuejs.org/core-concepts/ // See https://pinia.vuejs.org/core-concepts/
export const useJobs = defineStore('jobs', { export const useJobs = defineStore('jobs', {
@ -17,7 +20,10 @@ export const useJobs = defineStore('jobs', {
return this.selectedJobs.length; return this.selectedJobs.length;
}, },
canDelete() { canDelete() {
return this._anyJobWithStatus(["queued", "paused", "failed", "completed"]) return this._anyJobWithStatus(["queued", "paused", "failed", "completed", "canceled"])
},
canCancel() {
return this._anyJobWithStatus(["queued", "active"])
}, },
}, },
actions: { actions: {
@ -35,13 +41,25 @@ export const useJobs = defineStore('jobs', {
this.activeJob = null; this.activeJob = null;
}, },
// Actions on the selected jobs. /**
* Actions on the selected jobs.
*
* All the action functions return a promise that resolves when the action has been performed.
*
* TODO: actually have these work on all selected jobs. For simplicity, the
* code now assumes that only the active job needs to be operated on.
*/
deleteJobs() { deleteJobs() {
const deletionPromise = new Promise( (resolutionFunc, rejectionFunc) => { const deletionPromise = new Promise( (resolutionFunc, rejectionFunc) => {
rejectionFunc({code: 327, message: "deleting jobs is not implemented in JS yet"}); rejectionFunc({code: 327, message: "deleting jobs is not implemented in JS yet"});
}); });
return deletionPromise; return deletionPromise;
}, },
cancelJobs() {
const statuschange = new API.JobStatusChange("cancel-requested", "requested from web interface");
return jobsAPI.setJobStatus(this.activeJob.id, statuschange);
},
// Internal methods. // Internal methods.
_anyJobWithStatus(statuses) { _anyJobWithStatus(statuses) {
return this.selectedJobs.reduce((foundJob, job) => (foundJob || statuses.includes(job.status)), false); return this.selectedJobs.reduce((foundJob, job) => (foundJob || statuses.includes(job.status)), false);