From 2327d65260e4d81b06e6eab2e2320bbc4026f481 Mon Sep 17 00:00:00 2001 From: Valentin Rigal <rigal@teklia.com> Date: Thu, 11 Apr 2024 08:19:48 +0000 Subject: [PATCH] Restart task --- src/api/ponos.ts | 2 + src/components/Process/Status/Task.vue | 84 ++++++++++++++++++++------ src/store/process.js | 9 +++ 3 files changed, 78 insertions(+), 17 deletions(-) diff --git a/src/api/ponos.ts b/src/api/ponos.ts index 4e916462a..08dc6d6b0 100644 --- a/src/api/ponos.ts +++ b/src/api/ponos.ts @@ -10,6 +10,8 @@ type TaskUpdateResponse = Pick<Task, 'id' | 'state'> export const updateTask = async (id: UUID, payload: TaskUpdatePayload): Promise<TaskUpdateResponse> => (await axios.patch(`/task/${id}/`, payload)).data +export const restartTask = async (id: UUID): Promise<Task> => (await axios.post(`/task/${id}/restart/`)).data + export const listArtifacts = unique(async (id: UUID): Promise<Artifact[]> => (await axios.get(`/task/${id}/artifacts/`)).data) // List Ponos agents with their status diff --git a/src/components/Process/Status/Task.vue b/src/components/Process/Status/Task.vue index 8238f1e6c..ebb465932 100644 --- a/src/components/Process/Status/Task.vue +++ b/src/components/Process/Status/Task.vue @@ -14,20 +14,23 @@ </a> </div> <Artifacts :task="task" /> - <div v-if="isAdmin" class="control"> + <div class="control"> <button - v-if="['completed', 'failed', 'error', 'stopped'].includes(task.state)" - v-on:click="updateTask('pending')" - class="button is-small is-warning" + v-if="finishedTask" + v-on:click="restartModal = finishedTask" + class="button is-small" > - Restart task + Restart </button> + </div> + <div class="control"> <button - v-if="task.state === 'running'" - v-on:click="updateTask('stopping')" + :disabled="task.state !== 'running' || undefined" + :title="task.state === 'running' ? 'Force stop this task' : 'Task must be running to be stopped'" + v-on:click="task.state === 'running' && updateTask('stopping')" class="button is-small is-danger" > - Stop task + Stop </button> </div> </div> @@ -46,20 +49,46 @@ <Logs :logs="task.logs" /> </div> </div> + <Modal v-model="restartModal" :title="`Restart task ${task.slug}`"> + <span>Restarting the task will cause a clone of the task to be started in place of the current one.</span> + <br /> + <span>Are you sure you want to proceed?</span> + <template v-slot:footer="{ close }"> + <button class="button ml-auto" v-on:click="close">Cancel</button> + <button + class="button is-primary" + :class="{ 'is-loading': restartLoading }" + v-on:click="restart" + > + Restart + </button> + </template> + </Modal> </template> <script> -import { mapActions, mapGetters, mapMutations } from 'vuex' +import { mapActions } from 'pinia' +import { + mapActions as mapVuexActions, + mapGetters as mapVuexGetters, + mapMutations as mapVuexMutations +} from 'vuex' + +import { PROCESS_FINAL_STATES } from '@/config' +import { errorParser } from '@/helpers' +import { useNotificationStore } from '@/stores' import Artifacts from './Artifacts.vue' import Logs from './Logs.vue' import StateTag from '../StateTag.vue' +import Modal from '@/components/Modal.vue' export default { components: { Artifacts, Logs, - StateTag + StateTag, + Modal }, props: { task: { @@ -67,6 +96,10 @@ export default { required: true } }, + data: () => ({ + restartModal: false, + restartLoading: false + }), mounted () { this.startTaskPolling(this.task.id) }, @@ -74,18 +107,35 @@ export default { this.stopTaskPolling(this.task.id) }, computed: { - ...mapGetters('auth', ['isAdmin']) - }, - watch: { - task (newValue, oldValue) { - if (newValue && newValue.id && (!oldValue || oldValue.id !== newValue.id)) this.startTaskPolling(newValue.id) + ...mapVuexGetters('auth', ['isAdmin']), + finishedTask () { + return PROCESS_FINAL_STATES.includes(this.task.state) } }, methods: { - ...mapActions('process', ['startTaskPolling']), - ...mapMutations('process', ['stopTaskPolling']), + ...mapActions(useNotificationStore, ['notify']), + ...mapVuexActions('process', ['startTaskPolling', 'restartTask']), + ...mapVuexMutations('process', ['stopTaskPolling']), updateTask (state) { this.$store.dispatch('process/updateTask', { id: this.task.id, state }) + }, + async restart () { + if (this.restartLoading) return + this.restartLoading = true + try { + await this.restartTask(this.task.id) + this.restartModal = false + this.notify({ type: 'success', text: 'Task has been restarted' }) + } catch (err) { + this.notify({ type: 'error', text: errorParser(err) }) + } finally { + this.restartLoading = false + } + } + }, + watch: { + task (newValue, oldValue) { + if (newValue && newValue.id && (!oldValue || oldValue.id !== newValue.id)) this.startTaskPolling(newValue.id) } } } diff --git a/src/store/process.js b/src/store/process.js index fbeb67fc3..19c63839d 100644 --- a/src/store/process.js +++ b/src/store/process.js @@ -407,6 +407,15 @@ export const actions = { } }, + async restartTask ({ state, commit }, id) { + const processId = state.tasks[id]?.process_id + const newTask = await api.restartTask(id) + commit('setTask', { + ...newTask, + process_id: processId + }) + }, + async getTaskArtifacts ({ commit }, id) { try { const data = await api.listArtifacts(id) -- GitLab