mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-22 01:11:40 +00:00
## Description Upgrades to Vue 3 and necessary associated dependencies. Also fixes some issues with the layout and adds validation for object detection models. Closes #885, closes #1943, closes #1449. ## Meta Merge checklist: - [x] Pull Request title is [short, imperative summary](https://cbea.ms/git-commit/) of proposed changes - [x] The description documents the _what_ and _why_ - [ ] If this PR changes behavior or adds a feature, user documentation is updated - [ ] If this PR touches photon-serde, all messages have been regenerated and hashes have not changed unexpectedly - [ ] If this PR touches configuration, this is backwards compatible with settings back to v2024.3.1 - [ ] If this PR touches pipeline settings or anything related to data exchange, the frontend typing is updated - [ ] If this PR addresses a bug, a regression test for it is added --------- Co-authored-by: Matt M <matthew.morley.ca@gmail.com> Co-authored-by: Gold856 <117957790+Gold856@users.noreply.github.com> Co-authored-by: samfreund <techguy763@gmail.com>
295 lines
7.5 KiB
Vue
295 lines
7.5 KiB
Vue
<script setup lang="ts">
|
|
import { useSettingsStore } from "@/stores/settings/GeneralSettingsStore";
|
|
import { computed, onBeforeMount, ref } from "vue";
|
|
import { useStateStore } from "@/stores/StateStore";
|
|
|
|
interface MetricItem {
|
|
header: string;
|
|
value?: string;
|
|
}
|
|
|
|
const generalMetrics = computed<MetricItem[]>(() => {
|
|
const stats = [
|
|
{
|
|
header: "Version",
|
|
value: useSettingsStore().general.version || "Unknown"
|
|
},
|
|
{
|
|
header: "Hardware Model",
|
|
value: useSettingsStore().general.hardwareModel || "Unknown"
|
|
},
|
|
{
|
|
header: "Platform",
|
|
value: useSettingsStore().general.hardwarePlatform || "Unknown"
|
|
},
|
|
|
|
{
|
|
header: "GPU Acceleration",
|
|
value: useSettingsStore().general.gpuAcceleration || "Unknown"
|
|
}
|
|
];
|
|
|
|
if (!useSettingsStore().network.networkingDisabled) {
|
|
stats.push({
|
|
header: "IP Address",
|
|
value: useSettingsStore().metrics.ipAddress || "Unknown"
|
|
});
|
|
}
|
|
|
|
return stats;
|
|
});
|
|
|
|
const platformMetrics = computed<MetricItem[]>(() => {
|
|
const stats = [
|
|
{
|
|
header: "CPU Temp",
|
|
value: useSettingsStore().metrics.cpuTemp === undefined ? "Unknown" : `${useSettingsStore().metrics.cpuTemp}°C`
|
|
},
|
|
{
|
|
header: "CPU Usage",
|
|
value: useSettingsStore().metrics.cpuUtil === undefined ? "Unknown" : `${useSettingsStore().metrics.cpuUtil}%`
|
|
},
|
|
{
|
|
header: "CPU Memory Usage",
|
|
value:
|
|
useSettingsStore().metrics.ramUtil === undefined || useSettingsStore().metrics.cpuMem === undefined
|
|
? "Unknown"
|
|
: `${useSettingsStore().metrics.ramUtil || "Unknown"}MB of ${useSettingsStore().metrics.cpuMem}MB`
|
|
},
|
|
{
|
|
header: "GPU Memory Usage",
|
|
value:
|
|
useSettingsStore().metrics.gpuMemUtil === undefined || useSettingsStore().metrics.gpuMem === undefined
|
|
? "Unknown"
|
|
: `${useSettingsStore().metrics.gpuMemUtil}MB of ${useSettingsStore().metrics.gpuMem}MB`
|
|
},
|
|
{
|
|
header: "CPU Throttling",
|
|
value: useSettingsStore().metrics.cpuThr || "Unknown"
|
|
},
|
|
{
|
|
header: "CPU Uptime",
|
|
value: useSettingsStore().metrics.cpuUptime || "Unknown"
|
|
},
|
|
{
|
|
header: "Disk Usage",
|
|
value: useSettingsStore().metrics.diskUtilPct || "Unknown"
|
|
}
|
|
];
|
|
|
|
if (useSettingsStore().metrics.npuUsage) {
|
|
stats.push({
|
|
header: "NPU Usage",
|
|
value: useSettingsStore().metrics.npuUsage || "Unknown"
|
|
});
|
|
}
|
|
|
|
return stats;
|
|
});
|
|
|
|
const metricsLastFetched = ref("Never");
|
|
const fetchMetrics = () => {
|
|
useSettingsStore()
|
|
.requestMetricsUpdate()
|
|
.catch((error) => {
|
|
if (error.request) {
|
|
useStateStore().showSnackbarMessage({
|
|
color: "error",
|
|
message: "Unable to fetch metrics! The backend didn't respond."
|
|
});
|
|
} else {
|
|
useStateStore().showSnackbarMessage({
|
|
color: "error",
|
|
message: "An error occurred while trying to fetch metrics."
|
|
});
|
|
}
|
|
})
|
|
.finally(() => {
|
|
const pad = (num: number): string => {
|
|
return String(num).padStart(2, "0");
|
|
};
|
|
|
|
const date = new Date();
|
|
metricsLastFetched.value = `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
|
|
});
|
|
};
|
|
|
|
onBeforeMount(() => {
|
|
fetchMetrics();
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<v-card class="mb-3" style="background-color: #006492">
|
|
<v-card-title class="pl-6" style="display: flex; justify-content: space-between">
|
|
<span class="pt-2 pb-2">Stats</span>
|
|
<v-btn variant="text" @click="fetchMetrics">
|
|
<v-icon start class="open-icon">mdi-reload</v-icon>
|
|
Last Fetched: {{ metricsLastFetched }}
|
|
</v-btn>
|
|
</v-card-title>
|
|
<v-card-text class="pa-6 pt-0 pb-3">
|
|
<v-card-subtitle class="pa-0" style="font-size: 16px">General Metrics</v-card-subtitle>
|
|
<v-table class="metrics-table mt-3">
|
|
<thead>
|
|
<tr>
|
|
<th
|
|
v-for="(item, itemIndex) in generalMetrics"
|
|
:key="itemIndex"
|
|
class="metric-item metric-item-title"
|
|
:class="{
|
|
tl: itemIndex === 0,
|
|
tr: itemIndex === generalMetrics.length - 1,
|
|
t: 0 < itemIndex && itemIndex < generalMetrics.length - 1
|
|
}"
|
|
>
|
|
{{ item.header }}
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td
|
|
v-for="(item, itemIndex) in generalMetrics"
|
|
:key="itemIndex"
|
|
class="metric-item"
|
|
:class="{
|
|
bl: itemIndex === 0,
|
|
br: itemIndex === generalMetrics.length - 1,
|
|
b: 0 < itemIndex && itemIndex < generalMetrics.length - 1
|
|
}"
|
|
>
|
|
{{ item.value }}
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</v-table>
|
|
</v-card-text>
|
|
<v-card-text class="pa-6 pt-4">
|
|
<v-card-subtitle class="pa-0 pb-1" style="font-size: 16px">Hardware Metrics</v-card-subtitle>
|
|
<v-table class="metrics-table mt-3">
|
|
<thead>
|
|
<tr>
|
|
<th
|
|
v-for="(item, itemIndex) in platformMetrics"
|
|
:key="itemIndex"
|
|
class="metric-item metric-item-title"
|
|
:class="{
|
|
tl: itemIndex === 0,
|
|
tr: itemIndex === platformMetrics.length - 1,
|
|
t: 0 < itemIndex && itemIndex < platformMetrics.length - 1
|
|
}"
|
|
>
|
|
{{ item.header }}
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td
|
|
v-for="(item, itemIndex) in platformMetrics"
|
|
:key="itemIndex"
|
|
class="metric-item"
|
|
:class="{
|
|
bl: itemIndex === 0,
|
|
br: itemIndex === platformMetrics.length - 1,
|
|
b: 0 < itemIndex && itemIndex < platformMetrics.length - 1
|
|
}"
|
|
>
|
|
<span v-if="useSettingsStore().metrics.cpuUtil !== undefined">{{ item.value }}</span>
|
|
<span v-else>---</span>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</v-table>
|
|
</v-card-text>
|
|
</v-card>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.metrics-table {
|
|
width: 100%;
|
|
text-align: center;
|
|
}
|
|
|
|
.t {
|
|
border-top: 1px solid white;
|
|
border-right: 1px solid white;
|
|
}
|
|
|
|
.b {
|
|
border-bottom: 1px solid white;
|
|
border-right: 1px solid white;
|
|
}
|
|
|
|
.tl {
|
|
border-top: 1px solid white;
|
|
border-left: 1px solid white;
|
|
border-right: 1px solid white;
|
|
border-top-left-radius: 5px;
|
|
}
|
|
|
|
.tr {
|
|
border-top: 1px solid white;
|
|
border-right: 1px solid white;
|
|
border-top-right-radius: 5px;
|
|
}
|
|
|
|
.bl {
|
|
border-bottom: 1px solid white;
|
|
border-left: 1px solid white;
|
|
border-right: 1px solid white;
|
|
border-bottom-left-radius: 5px;
|
|
}
|
|
|
|
.br {
|
|
border-bottom: 1px solid white;
|
|
border-right: 1px solid white;
|
|
border-bottom-right-radius: 5px;
|
|
}
|
|
|
|
.metric-item {
|
|
font-size: 16px !important;
|
|
padding: 1px 15px 1px 10px;
|
|
border-right: 1px solid;
|
|
font-weight: normal;
|
|
color: white !important;
|
|
text-align: center !important;
|
|
}
|
|
|
|
.metric-item-title {
|
|
font-size: 18px !important;
|
|
text-decoration: underline;
|
|
text-decoration-color: #ffd843;
|
|
}
|
|
|
|
.v-table {
|
|
thead,
|
|
tbody {
|
|
background-color: #006492;
|
|
}
|
|
|
|
:hover {
|
|
tbody > tr {
|
|
background-color: #005281 !important;
|
|
}
|
|
}
|
|
|
|
::-webkit-scrollbar {
|
|
width: 0;
|
|
height: 0.55em;
|
|
border-radius: 5px;
|
|
}
|
|
|
|
::-webkit-scrollbar-track {
|
|
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
|
|
border-radius: 10px;
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb {
|
|
background-color: #ffd843;
|
|
border-radius: 10px;
|
|
}
|
|
}
|
|
</style>
|