Webapp: show farm status in header bar

Show the farm status in the webapp header bar, and respond to farm status
events to update it when necessary.
This commit is contained in:
Sybren A. Stüvel 2024-03-01 22:29:00 +01:00
parent c1a9b1e877
commit 59bf389018
5 changed files with 83 additions and 0 deletions

View File

@ -17,6 +17,7 @@
</li> </li>
</ul> </ul>
</nav> </nav>
<farm-status :status="farmStatus.status()" />
<api-spinner /> <api-spinner />
<span class="app-version"> <span class="app-version">
<a :href="backendURL('/flamenco-addon.zip')">add-on</a> <a :href="backendURL('/flamenco-addon.zip')">add-on</a>
@ -31,8 +32,10 @@ import * as API from '@/manager-api';
import { getAPIClient } from '@/api-client'; import { getAPIClient } from '@/api-client';
import { backendURL } from '@/urls'; import { backendURL } from '@/urls';
import { useSocketStatus } from '@/stores/socket-status'; import { useSocketStatus } from '@/stores/socket-status';
import { useFarmStatus } from '@/stores/farmstatus';
import ApiSpinner from '@/components/ApiSpinner.vue'; import ApiSpinner from '@/components/ApiSpinner.vue';
import FarmStatus from '@/components/FarmStatus.vue';
const DEFAULT_FLAMENCO_NAME = 'Flamenco'; const DEFAULT_FLAMENCO_NAME = 'Flamenco';
const DEFAULT_FLAMENCO_VERSION = 'unknown'; const DEFAULT_FLAMENCO_VERSION = 'unknown';
@ -41,15 +44,18 @@ export default {
name: 'App', name: 'App',
components: { components: {
ApiSpinner, ApiSpinner,
FarmStatus,
}, },
data: () => ({ data: () => ({
flamencoName: DEFAULT_FLAMENCO_NAME, flamencoName: DEFAULT_FLAMENCO_NAME,
flamencoVersion: DEFAULT_FLAMENCO_VERSION, flamencoVersion: DEFAULT_FLAMENCO_VERSION,
backendURL: backendURL, backendURL: backendURL,
farmStatus: useFarmStatus(),
}), }),
mounted() { mounted() {
window.app = this; window.app = this;
this.fetchManagerInfo(); this.fetchManagerInfo();
this.fetchFarmStatus();
const sockStatus = useSocketStatus(); const sockStatus = useSocketStatus();
this.$watch( this.$watch(
@ -71,6 +77,14 @@ export default {
}); });
}, },
fetchFarmStatus() {
const metaAPI = new API.MetaApi(getAPIClient());
metaAPI.getFarmStatus().then((statusReport) => {
const apiStatusReport = API.FarmStatusReport.constructFromObject(statusReport);
this.farmStatus.lastStatusReport = apiStatusReport;
});
},
socketIOReconnect() { socketIOReconnect() {
const metaAPI = new API.MetaApi(getAPIClient()); const metaAPI = new API.MetaApi(getAPIClient());
metaAPI.getVersion().then((version) => { metaAPI.getVersion().then((version) => {

View File

@ -82,6 +82,14 @@
--color-worker-status-testing: hsl(166 100% 46%); --color-worker-status-testing: hsl(166 100% 46%);
--color-worker-status-offline: var(--color-status-canceled); --color-worker-status-offline: var(--color-status-canceled);
--color-farm-status-starting: hsl(68, 100%, 30%);
--color-farm-status-active: var(--color-status-active);
--color-farm-status-idle: var(--color-status-paused);
--color-farm-status-waiting: var(--color-status-soft-failed);
--color-farm-status-asleep: var(--color-worker-status-asleep);
--color-farm-status-inoperative: var(--color-status-failed);
--color-farm-status-unknown: var(--color-status-failed);
--color-connection-lost-text: hsl(0, 90%, 60%); --color-connection-lost-text: hsl(0, 90%, 60%);
--color-connection-lost-bg: hsl(0, 50%, 20%); --color-connection-lost-bg: hsl(0, 50%, 20%);
} }

View File

@ -0,0 +1,35 @@
<template>
<span id="farmstatus" v-if="status"
>Farm status: <span :class="'farm-status-' + status">{{ status }}</span></span
>
</template>
<script setup>
const props = defineProps(['status']);
</script>
<style>
span#farmstatus {
margin: 0 auto;
}
.farm-status-starting {
color: var(--color-farm-status-starting);
}
.farm-status-active {
color: var(--color-farm-status-active);
}
.farm-status-idle {
color: var(--color-farm-status-idle);
}
.farm-status-waiting {
color: var(--color-farm-status-waiting);
}
.farm-status-asleep {
color: var(--color-farm-status-asleep);
}
.farm-status-inoperative,
.farm-status-unknown {
color: var(--color-farm-status-inoperative);
font-weight: bold;
}
</style>

View File

@ -7,6 +7,7 @@ import io from 'socket.io-client';
import { ws } from '@/urls'; import { ws } from '@/urls';
import * as API from '@/manager-api'; import * as API from '@/manager-api';
import { useSocketStatus } from '@/stores/socket-status'; import { useSocketStatus } from '@/stores/socket-status';
import { useFarmStatus } from '@/stores/farmstatus';
const websocketURL = ws(); const websocketURL = ws();
@ -34,6 +35,7 @@ export default {
return { return {
socket: null, socket: null,
sockStatus: useSocketStatus(), sockStatus: useSocketStatus(),
farmStatus: useFarmStatus(),
}; };
}, },
mounted: function () { mounted: function () {
@ -182,6 +184,13 @@ export default {
this.$emit('workerTagUpdate', apiWorkerTagUpdate); this.$emit('workerTagUpdate', apiWorkerTagUpdate);
}); });
this.socket.on('/status', (farmStatusReport) => {
// Convert to API object, in order to have the same parsing of data as
// when we'd do an API call.
const apiFarmStatusReport = API.FarmStatusReport.constructFromObject(farmStatusReport);
this.farmStatus.lastStatusReport = apiFarmStatusReport;
});
// Chat system, useful for debugging. // Chat system, useful for debugging.
this.socket.on('/message', (message) => { this.socket.on('/message', (message) => {
this.$emit('message', message); this.$emit('message', message);

View File

@ -0,0 +1,17 @@
import { defineStore } from 'pinia';
import { FarmStatusReport } from '@/manager-api';
/**
* Keep track of the farm status. This is updated from UpdateListener.vue.
*/
export const useFarmStatus = defineStore('farmStatus', {
state: () => ({
lastStatusReport: new FarmStatusReport(),
}),
actions: {
status() {
return this.lastStatusReport.status;
},
},
});