85 lines
2.3 KiB
Vue
85 lines
2.3 KiB
Vue
<template>
|
|
<div class="app-shell">
|
|
<TopBar />
|
|
<router-view
|
|
:lab-data="labData"
|
|
:lab-status="labStatus"
|
|
:service-data="serviceData"
|
|
:network-data="networkData"
|
|
:metrics-data="metricsData"
|
|
:loading="statusLoading"
|
|
:error="statusError"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { onMounted, onUnmounted, ref } from "vue";
|
|
import TopBar from "./components/TopBar.vue";
|
|
import { fallbackHardware, fallbackServices, fallbackNetwork, fallbackMetrics } from "./data/sample.js";
|
|
|
|
const labData = ref(fallbackHardware());
|
|
const labStatus = ref(null);
|
|
const serviceData = ref(fallbackServices());
|
|
const networkData = ref(fallbackNetwork());
|
|
const metricsData = ref(fallbackMetrics());
|
|
|
|
const statusLoading = ref(true);
|
|
const statusFetching = ref(false);
|
|
const statusError = ref("");
|
|
let pollTimerId = null;
|
|
|
|
async function refreshLabStatus() {
|
|
if (statusFetching.value) return;
|
|
statusFetching.value = true;
|
|
const controller = new AbortController();
|
|
const timeoutId = window.setTimeout(() => controller.abort(), 10000);
|
|
try {
|
|
const resp = await fetch("/api/lab/status", {
|
|
headers: { Accept: "application/json" },
|
|
signal: controller.signal,
|
|
});
|
|
if (!resp.ok) throw new Error(`status ${resp.status}`);
|
|
labStatus.value = await resp.json();
|
|
statusError.value = "";
|
|
} catch (err) {
|
|
labStatus.value = null;
|
|
if (err?.name === "AbortError") {
|
|
statusError.value = "Live data timed out";
|
|
} else {
|
|
statusError.value = "Live data unavailable";
|
|
}
|
|
} finally {
|
|
window.clearTimeout(timeoutId);
|
|
statusLoading.value = false;
|
|
statusFetching.value = false;
|
|
scheduleNextPoll();
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
refreshLabStatus();
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
if (pollTimerId) window.clearTimeout(pollTimerId);
|
|
});
|
|
|
|
function scheduleNextPoll() {
|
|
if (pollTimerId) window.clearTimeout(pollTimerId);
|
|
const delayMs = labStatus.value ? 30000 : 8000;
|
|
pollTimerId = window.setTimeout(refreshLabStatus, delayMs);
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.app-shell {
|
|
min-height: 100vh;
|
|
background: radial-gradient(circle at 8% 12%, rgba(55, 135, 255, 0.08), transparent 20%),
|
|
radial-gradient(circle at 90% 20%, rgba(0, 255, 182, 0.07), transparent 25%),
|
|
radial-gradient(circle at 18% 84%, rgba(255, 75, 135, 0.06), transparent 24%),
|
|
var(--bg-deep);
|
|
color: var(--text-primary);
|
|
}
|
|
</style>
|