Web: move Worker status change requests to drop-down

This basically copies the drop-down approach from Flamenco Manager 2.
This commit is contained in:
Sybren A. Stüvel 2022-06-03 13:01:47 +02:00
parent df36d93d7b
commit 375a6666c2
4 changed files with 72 additions and 62 deletions

View File

@ -264,7 +264,7 @@ footer {
margin-left: var(--spacer-sm); margin-left: var(--spacer-sm);
} }
.btn-bar .btn[disabled] { .btn[disabled] {
background-color: transparent; background-color: transparent;
border-color: var(--color-text-muted); border-color: var(--color-text-muted);
color: var(--color-text-muted); color: var(--color-text-muted);
@ -272,12 +272,12 @@ footer {
pointer-events: none; pointer-events: none;
} }
.btn-bar .btn:hover:not([disabled]) { .btn:hover:not([disabled]) {
transition: all 100ms; transition: all 100ms;
color: white; color: white;
} }
.btn-bar .btn:focus { .btn:focus {
/* Make sure the outline is clearly visible inside the button. */ /* Make sure the outline is clearly visible inside the button. */
outline-offset: -0.5em; outline-offset: -0.5em;
} }

View File

@ -1,48 +1,82 @@
<template> <template>
<div class="btn-bar workers"> <select v-model="selectedAction">
<button class="btn wakeup" v-on:click="onButtonWakeup">Wake Up</button> <option value="" selected><template v-if="!hasActiveWorker">Select a Worker</template><template v-else>Choose an Action</template></option>
<button class="btn sleep" v-on:click="onButtonSleep">Sleep</button> <option v-for="(action, key) in WORKER_ACTIONS" :value="key">{{ action.label }}</option>
<button class="btn offline dangerous" v-on:click="onButtonOffline">Offline</button> </select>
</div> <button
:disabled="!canPerformAction"
class="btn"
@click.prevent="performWorkerAction"
>Apply</button>
</template> </template>
<script> <script setup>
import { computed, ref } from 'vue'
import { useWorkers } from '@/stores/workers'; import { useWorkers } from '@/stores/workers';
import { useNotifs } from '@/stores/notifications'; import { useNotifs } from '@/stores/notifications';
import { WorkerMgtApi, WorkerStatusChangeRequest } from '@/manager-api';
import { apiClient } from '@/stores/api-query-count';
export default { /* Freeze to prevent Vue.js from creating getters & setters all over this object.
name: "WorkerActionsBar", * We don't need it to be tracked, as it won't be changed anyway. */
data: () => ({ const WORKER_ACTIONS = Object.freeze({
workers: useWorkers(), offline_lazy: {
notifs: useNotifs(), label: 'Shut Down (after task is finished)',
}), icon: '✝',
computed: { title: 'Shut down the worker after the current task finishes. The worker may automatically restart.',
target_status: 'offline',
lazy: true,
}, },
methods: { offline_immediate: {
onButtonWakeup() { label: 'Shut Down (immediately)',
return this._handleWorkerActionPromise( icon: '✝!',
this.workers.reqStatusAwake()); title: 'Immediately shut down the worker. It may automatically restart.',
target_status: 'offline',
lazy: false,
}, },
onButtonSleep() { asleep_lazy: {
return this._handleWorkerActionPromise( label: 'Send to Sleep (after task is finished)',
this.workers.reqStatusAsleep()); icon: '😴',
title: 'Let the worker sleep after finishing this task.',
target_status: 'asleep',
lazy: true,
}, },
onButtonOffline() { asleep_immediate: {
return this._handleWorkerActionPromise( label: 'Send to Sleep (immediately)',
this.workers.reqStatusOffline()); icon: '😴!',
title: 'Let the worker sleep immediately.',
target_status: 'asleep',
lazy: false,
}, },
wakeup: {
label: 'Wake Up',
icon: '😃',
title: 'Wake the worker up. A sleeping worker can take a minute to respond.',
target_status: 'awake',
lazy: false,
},
});
_handleWorkerActionPromise(promise) { const selectedAction = ref('');
return promise const workers = useWorkers();
.catch((error) => { const hasActiveWorker = computed(() => !!workers.activeWorkerID);
const errorMsg = JSON.stringify(error); // TODO: handle API errors better. const canPerformAction = computed(() => hasActiveWorker && !!selectedAction.value);
this.notifs.add(`Error: ${errorMsg}`); const notifs = useNotifs();
})
}, function performWorkerAction() {
const workerID = workers.activeWorkerID;
if (!workerID) {
notifs.add("Select a Worker before applying an action.");
return;
} }
const api = new WorkerMgtApi(apiClient);
const action = WORKER_ACTIONS[selectedAction.value];
const statuschange = new WorkerStatusChangeRequest(action.target_status, action.lazy);
console.log("Requesting worker status change", statuschange);
api.requestWorkerStatusChange(workerID, statuschange)
.then((result) => notifs.add(`Worker status change to ${action.target_status} confirmed.`))
.catch((error) => notifs.add(`Error requesting worker status change: ${error}`));
} }
</script> </script>
<style scoped>
</style>

View File

@ -74,8 +74,8 @@ export const useNotifs = defineStore('notifications', {
let msg = `Worker ${workerUpdate.name}`; let msg = `Worker ${workerUpdate.name}`;
if (workerUpdate.previous_status && workerUpdate.previous_status != workerUpdate.status) { if (workerUpdate.previous_status && workerUpdate.previous_status != workerUpdate.status) {
msg += ` changed status ${workerUpdate.previous_status}${workerUpdate.status}`; msg += ` changed status ${workerUpdate.previous_status}${workerUpdate.status}`;
this.add(msg);
} }
this.add(msg)
}, },
/* Ensure there is only 1000 items in the history. */ /* Ensure there is only 1000 items in the history. */

View File

@ -1,11 +1,5 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { WorkerMgtApi, WorkerStatusChangeRequest } from '@/manager-api';
import { apiClient } from '@/stores/api-query-count';
const api = new WorkerMgtApi(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 useWorkers = defineStore('workers', { export const useWorkers = defineStore('workers', {
@ -43,23 +37,5 @@ export const useWorkers = defineStore('workers', {
activeWorkerID: "", activeWorkerID: "",
}); });
}, },
reqStatusAwake() { return this.requestStatus("awake"); },
reqStatusAsleep() { return this.requestStatus("asleep"); },
reqStatusOffline() { return this.requestStatus("offline"); },
/**
* Transition the active worker to the new status.
* @param {string} newStatus
* @returns a Promise for the API request.
*/
requestStatus(newStatus) {
if (!this.activeWorkerID) {
console.warn(`requestStatus(${newStatus}) impossible, no active worker ID`);
return;
}
const statuschange = new WorkerStatusChangeRequest(newStatus, false);
return api.requestWorkerStatusChange(this.activeWorkerID, statuschange);
},
}, },
}) })