feat: add system metrics dashboard

This commit is contained in:
2026-03-10 15:54:45 +01:00
parent ffe463e130
commit 31e101abbd
4 changed files with 755 additions and 3 deletions

View File

@@ -36,6 +36,21 @@
<Speedtest class="animate-fade-in-up speedtest-card-mobile" style="animation-delay: 150ms" />
</div>
</div>
<div class="metrics-row">
<SystemMetricsChart
:metrics="systemMetrics"
:loading="systemLoading"
class="animate-fade-in-up"
style="animation-delay: 200ms"
/>
<SystemResources
:metrics="systemMetrics"
:loading="systemLoading"
class="animate-fade-in-up"
style="animation-delay: 225ms"
/>
</div>
</div>
<div class="content-aside">
@@ -48,7 +63,7 @@
<script setup lang="ts">
definePageMeta({layout: false})
import {computed, onMounted, ref} from "vue"
import {computed, onBeforeUnmount, onMounted, ref} from "vue"
type DiskSourceResult = {
key: string
@@ -74,11 +89,23 @@ type DiagramItem = {
totalText: string
}
const selectedBackup = ref<string | null>(null)
type SystemMetrics = {
cpuPercent: number
memoryPercent: number
totalMemory: number
usedMemory: number
incomingMbps: number
outgoingMbps: number
sampledAt: string
}
const rawResults = ref<DiskSourceResult[]>([])
const loading = ref(false)
const systemMetrics = ref<SystemMetrics | null>(null)
const systemLoading = ref(true)
const chartRadius = 52
const chartCircumference = 2 * Math.PI * chartRadius
let systemTimer: ReturnType<typeof setInterval> | null = null
const getHostName = (output: string, fallback: string) => {
const hostMatch = output.match(/Name:\s*(.+)/i)
@@ -168,8 +195,27 @@ const runScript = async () => {
}
}
const loadSystemMetrics = async () => {
try {
systemMetrics.value = await $fetch<SystemMetrics>("/api/system")
} catch {
systemMetrics.value = null
} finally {
systemLoading.value = false
}
}
onMounted(() => {
runScript()
loadSystemMetrics()
systemTimer = setInterval(loadSystemMetrics, 2000)
})
onBeforeUnmount(() => {
if (systemTimer) {
clearInterval(systemTimer)
systemTimer = null
}
})
</script>
@@ -229,6 +275,14 @@ onMounted(() => {
align-items: start;
}
.metrics-row {
margin-top: 1.5rem;
display: grid;
grid-template-columns: minmax(0, 1fr) 280px;
gap: 1.5rem;
align-items: start;
}
.grid-left,
.grid-middle,
.grid-right {
@@ -260,7 +314,8 @@ onMounted(() => {
.storage-grid,
.content-grid,
.dashboard-grid {
.dashboard-grid,
.metrics-row {
grid-template-columns: 1fr;
}