mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2025-09-04 02:41:14 +00:00
Refactored system status into a class. Added charts
This commit is contained in:
@@ -10,7 +10,7 @@ const props = defineProps(["process", "cpu"])
|
||||
<samp>{{process.command ? process.command : process.name}}</samp>
|
||||
</small>
|
||||
<small class="ms-auto">
|
||||
{{cpu ? process.cpu_percent : (Math.round((process.memory_percent + Number.EPSILON) * 10) / 10)}}%
|
||||
{{(Math.round((process.percent + Number.EPSILON) * 10) / 10)}}%
|
||||
</small>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -2,8 +2,7 @@
|
||||
import {computed, ref} from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
mount: String,
|
||||
percentage: Number,
|
||||
mount: Object,
|
||||
align: Boolean,
|
||||
square: Boolean
|
||||
})
|
||||
@@ -19,7 +18,7 @@ const squareHeight = computed(() => {
|
||||
<div class="flex-grow-1 square rounded-3 border position-relative"
|
||||
@mouseenter="show = true"
|
||||
@mouseleave="show = false"
|
||||
:style="{'background-color': `rgb(25 135 84 / ${percentage}%)`}">
|
||||
:style="{'background-color': `rgb(25 135 84 / ${mount.percent}%)`}">
|
||||
<Transition name="zoomReversed">
|
||||
<div
|
||||
v-if="show"
|
||||
@@ -29,10 +28,10 @@ const squareHeight = computed(() => {
|
||||
:class="[align ? 'end-0':'start-0']"
|
||||
>
|
||||
<small class="text-muted me-2">
|
||||
<samp>{{mount}}</samp>
|
||||
<samp>{{mount.mountPoint}}</samp>
|
||||
</small>
|
||||
<small class="fw-bold">
|
||||
{{percentage}}%
|
||||
{{mount.percent}}%
|
||||
</small>
|
||||
</div>
|
||||
</Transition>
|
||||
|
@@ -7,8 +7,6 @@ import StorageMount from "@/components/systemStatusComponents/storageMount.vue";
|
||||
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
||||
|
||||
const dashboardStore = DashboardConfigurationStore()
|
||||
|
||||
// const data = ref(undefined)
|
||||
let interval = null;
|
||||
|
||||
onMounted(() => {
|
||||
@@ -43,19 +41,19 @@ const data = computed(() => {
|
||||
</h6>
|
||||
<h6 class="ms-auto">
|
||||
<span v-if="data">
|
||||
{{ data.cpu.cpu_percent }}%
|
||||
{{ data.CPU.cpu_percent }}%
|
||||
</span>
|
||||
<span v-else class="spinner-border spinner-border-sm"></span>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="progress" role="progressbar" style="height: 6px">
|
||||
<div class="progress-bar" :style="{width: `${data?.cpu.cpu_percent}%` }"></div>
|
||||
<div class="progress-bar" :style="{width: `${data?.CPU.cpu_percent}%` }"></div>
|
||||
</div>
|
||||
<div class="d-flex mt-2 gap-1">
|
||||
<CpuCore
|
||||
v-for="(cpu, count) in data?.cpu.cpu_percent_per_cpu"
|
||||
v-for="(cpu, count) in data?.CPU.cpu_percent_per_cpu"
|
||||
:key="count"
|
||||
:align="(count + 1) > Math.round(data?.cpu.cpu_percent_per_cpu.length / 2)"
|
||||
:align="(count + 1) > Math.round(data?.CPU.cpu_percent_per_cpu.length / 2)"
|
||||
:core_number="count" :percentage="cpu"
|
||||
></CpuCore>
|
||||
</div>
|
||||
@@ -68,20 +66,20 @@ const data = computed(() => {
|
||||
</h6>
|
||||
<h6 class="ms-auto">
|
||||
<span v-if="data">
|
||||
{{ data?.disk['/'].percent }}%
|
||||
{{ data?.Disks.find(x => x.mountPoint === '/').percent }}%
|
||||
</span>
|
||||
<span v-else class="spinner-border spinner-border-sm"></span>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="progress" role="progressbar" style="height: 6px">
|
||||
<div class="progress-bar bg-success" :style="{width: `${data?.disk['/'].percent}%` }"></div>
|
||||
<div class="progress-bar bg-success" :style="{width: `${data?.Disks.find(x => x.mountPoint === '/').percent}%` }"></div>
|
||||
</div>
|
||||
<div class="d-flex mt-2 gap-1">
|
||||
<StorageMount v-for="(disk, count) in Object.keys(data?.disk)"
|
||||
<StorageMount v-for="(disk, count) in data?.Disks"
|
||||
v-if="data"
|
||||
:key="count"
|
||||
:align="(count + 1) > Math.round(Object.keys(data?.disk).length / 2)"
|
||||
:mount="disk" :percentage="data?.disk[disk].percent"
|
||||
:key="disk.mountPoint"
|
||||
:align="(count + 1) > Math.round(data?.Disks.length / 2)"
|
||||
:mount="disk"
|
||||
></StorageMount>
|
||||
</div>
|
||||
</div>
|
||||
@@ -93,13 +91,13 @@ const data = computed(() => {
|
||||
</h6>
|
||||
<h6 class="ms-auto">
|
||||
<span v-if="data">
|
||||
{{ data?.memory.virtual_memory.percent }}%
|
||||
{{ data?.Memory.VirtualMemory.percent }}%
|
||||
</span>
|
||||
<span v-else class="spinner-border spinner-border-sm"></span>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="progress" role="progressbar" style="height: 6px">
|
||||
<div class="progress-bar bg-info" :style="{width: `${data?.memory.virtual_memory.percent}%` }"></div>
|
||||
<div class="progress-bar bg-info" :style="{width: `${data?.Memory.VirtualMemory.percent}%` }"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-12 col-xl-3">
|
||||
@@ -110,13 +108,13 @@ const data = computed(() => {
|
||||
</h6>
|
||||
<h6 class="ms-auto">
|
||||
<span v-if="data">
|
||||
{{ data?.memory.swap_memory.percent }}%
|
||||
{{ data?.Memory.SwapMemory.percent }}%
|
||||
</span>
|
||||
<span v-else class="spinner-border spinner-border-sm"></span>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="progress" role="progressbar" style="height: 6px">
|
||||
<div class="progress-bar bg-warning" :style="{width: `${data?.memory.swap_memory.percent}%` }"></div>
|
||||
<div class="progress-bar bg-warning" :style="{width: `$ data?.Memory.SwapMemory.percent}%` }"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -12,6 +12,36 @@ const data = computed(() => {
|
||||
return dashboardStore.SystemStatus
|
||||
})
|
||||
let interval = null;
|
||||
import {
|
||||
Chart,
|
||||
LineElement,
|
||||
BarElement,
|
||||
BarController,
|
||||
LineController,
|
||||
LinearScale,
|
||||
Legend,
|
||||
Title,
|
||||
Tooltip,
|
||||
CategoryScale,
|
||||
PointElement,
|
||||
Filler
|
||||
} from 'chart.js';
|
||||
import {Line} from "vue-chartjs";
|
||||
import dayjs from "dayjs";
|
||||
import {GetLocale} from "@/utilities/locale.js";
|
||||
Chart.register(
|
||||
LineElement,
|
||||
BarElement,
|
||||
BarController,
|
||||
LineController,
|
||||
LinearScale,
|
||||
Legend,
|
||||
Title,
|
||||
Tooltip,
|
||||
CategoryScale,
|
||||
PointElement,
|
||||
Filler
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
getData()
|
||||
@@ -24,11 +54,97 @@ onBeforeUnmount(() => {
|
||||
clearInterval(interval)
|
||||
})
|
||||
|
||||
const historicalChartTimestamp = ref([])
|
||||
const historicalCpuUsage = ref([])
|
||||
const historicalVirtualMemoryUsage = ref([])
|
||||
const historicalSwapMemoryUsage = ref([])
|
||||
let i = 0.1
|
||||
const getData = () => {
|
||||
fetchGet("/api/systemStatus", {}, (res) => {
|
||||
historicalChartTimestamp.value.push(dayjs().format("HH:mm:ss A"))
|
||||
dashboardStore.SystemStatus = res.data
|
||||
historicalCpuUsage.value.push(res.data.CPU.cpu_percent)
|
||||
historicalVirtualMemoryUsage.value.push(res.data.Memory.VirtualMemory.percent)
|
||||
historicalSwapMemoryUsage.value.push(res.data.Memory.SwapMemory.percent)
|
||||
})
|
||||
}
|
||||
|
||||
const chartOption = computed(() => {
|
||||
return {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: true
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: (tooltipItem) => {
|
||||
return `${tooltipItem.formattedValue}%`
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
ticks: {
|
||||
display: false,
|
||||
},
|
||||
grid: {
|
||||
display: false
|
||||
},
|
||||
},
|
||||
y:{
|
||||
ticks: {
|
||||
callback: (val, index) => {
|
||||
return `${val}%`
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
display: false
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
const cpuHistoricalChartData = computed(() => {
|
||||
return {
|
||||
labels: [...historicalChartTimestamp.value],
|
||||
datasets: [
|
||||
{
|
||||
label: GetLocale('CPU Usage'),
|
||||
data: [...historicalCpuUsage.value],
|
||||
fill: 'start',
|
||||
backgroundColor: '#0d6efd50',
|
||||
borderColor: '#0d6efd',
|
||||
tension: 0
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
const memoryHistoricalChartData = computed(() => {
|
||||
return {
|
||||
labels: [...historicalChartTimestamp.value],
|
||||
datasets: [
|
||||
{
|
||||
label: GetLocale('Memory Usage'),
|
||||
data: [...historicalVirtualMemoryUsage.value],
|
||||
fill: 1,
|
||||
borderColor: '#0dcaf0',
|
||||
backgroundColor: '#0dcaf050',
|
||||
tension: 0
|
||||
},
|
||||
{
|
||||
label: GetLocale('Swap Memory Usage'),
|
||||
data: [...historicalSwapMemoryUsage.value],
|
||||
fill: 'start',
|
||||
backgroundColor: '#ffc10750',
|
||||
borderColor: '#ffc107',
|
||||
tension: 0
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -36,8 +152,8 @@ const getData = () => {
|
||||
<div class="col-sm-6">
|
||||
<div class="card rounded-3 h-100 shadow">
|
||||
<div class="card-body p-4">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 d-flex flex-column gap-3">
|
||||
<div class="d-flex flex-column gap-3">
|
||||
<div class="d-flex flex-column gap-3" style="height: 130px">
|
||||
<div class="d-flex align-items-center">
|
||||
<h3 class="text-muted mb-0">
|
||||
<i class="bi bi-cpu-fill me-2"></i>
|
||||
@@ -45,32 +161,48 @@ const getData = () => {
|
||||
</h3>
|
||||
<h3 class="ms-auto mb-0">
|
||||
<span v-if="data">
|
||||
{{ data.cpu.cpu_percent }}%
|
||||
{{ data.CPU.cpu_percent }}%
|
||||
</span>
|
||||
<span v-else class="spinner-border"></span>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="progress" role="progressbar" style="height: 10px">
|
||||
<div class="progress-bar" :style="{width: `${data?.cpu.cpu_percent}%` }"></div>
|
||||
<div class="progress-bar" :style="{width: `${data?.CPU.cpu_percent}%` }"></div>
|
||||
</div>
|
||||
<div class="d-flex gap-1">
|
||||
<CpuCore
|
||||
v-for="(cpu, count) in data?.cpu.cpu_percent_per_cpu"
|
||||
v-for="(cpu, count) in data?.CPU.cpu_percent_per_cpu"
|
||||
:square="true"
|
||||
:key="count"
|
||||
:align="(count + 1) > Math.round(data?.cpu.cpu_percent_per_cpu.length / 2)"
|
||||
:align="(count + 1) > Math.round(data?.CPU.cpu_percent_per_cpu.length / 2)"
|
||||
:core_number="count" :percentage="cpu"
|
||||
></CpuCore>
|
||||
</div>
|
||||
<h5 class="mb-0">Processes</h5>
|
||||
<div class="position-relative">
|
||||
<TransitionGroup name="process">
|
||||
<Process
|
||||
:key="p.pid"
|
||||
:cpu="true"
|
||||
:process="p" v-for="p in data?.process.cpu_top_10"></Process>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
</div>
|
||||
<Line
|
||||
:options="chartOption"
|
||||
:data="cpuHistoricalChartData"
|
||||
style="width: 100%; height: 200px; max-height: 200px"
|
||||
></Line>
|
||||
<div class="d-flex align-items-center">
|
||||
<h5 class="mb-0">
|
||||
<LocaleText t="Processes"></LocaleText>
|
||||
</h5>
|
||||
<h6 class="mb-0 ms-auto text-muted">
|
||||
<small>
|
||||
<LocaleText t="CPU Usage"></LocaleText>
|
||||
</small>
|
||||
</h6>
|
||||
|
||||
</div>
|
||||
<hr class="my-1">
|
||||
<div class="position-relative">
|
||||
<TransitionGroup name="process">
|
||||
<Process
|
||||
:key="p.pid"
|
||||
:cpu="true"
|
||||
:process="p" v-for="p in data?.Processes.cpu_top_10"></Process>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -79,8 +211,8 @@ const getData = () => {
|
||||
<div class="col-sm-6">
|
||||
<div class="card rounded-3 h-100 shadow">
|
||||
<div class="card-body p-4">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 d-flex flex-column gap-3">
|
||||
<div class="d-flex flex-column gap-3">
|
||||
<div class="d-flex flex-column gap-3" style="height: 130px">
|
||||
<div class="d-flex align-items-center">
|
||||
<h3 class="text-muted">
|
||||
<i class="bi bi-memory me-2"></i>
|
||||
@@ -88,31 +220,47 @@ const getData = () => {
|
||||
</h3>
|
||||
<h3 class="ms-auto">
|
||||
<span v-if="data">
|
||||
{{ data.memory.virtual_memory.percent }}%
|
||||
{{ data?.Memory.VirtualMemory.percent }}%
|
||||
</span>
|
||||
<span v-else class="spinner-border"></span>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="progress" role="progressbar" style="height: 10px">
|
||||
<div class="progress-bar bg-info" :style="{width: `${data?.memory.virtual_memory.percent}%` }"></div>
|
||||
<div class="progress-bar bg-info" :style="{width: `${data?.Memory.VirtualMemory.percent}%` }"></div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
<h6 class="mb-0">Swap Memory</h6>
|
||||
<h6 class="mb-0 ms-auto">{{data?.memory.swap_memory.percent}}%</h6>
|
||||
<h6 class="mb-0 ms-auto">{{data?.Memory.SwapMemory.percent}}%</h6>
|
||||
</div>
|
||||
<div class="progress" role="progressbar" style="height: 10px">
|
||||
<div class="progress-bar bg-info-subtle" :style="{width: `${data?.memory.swap_memory.percent}%` }"></div>
|
||||
</div>
|
||||
<h5 class="mb-0">Processes</h5>
|
||||
<div class="position-relative">
|
||||
<TransitionGroup name="process">
|
||||
<Process
|
||||
:key="p.pid"
|
||||
:process="p" v-for="p in data?.process.memory_top_10">
|
||||
</Process>
|
||||
</TransitionGroup>
|
||||
<div class="progress-bar bg-info-subtle" :style="{width: `${data?.Memory.SwapMemory.percent}%` }"></div>
|
||||
</div>
|
||||
</div>
|
||||
<Line
|
||||
:options="chartOption"
|
||||
:data="memoryHistoricalChartData"
|
||||
style="width: 100%; height: 200px; max-height: 200px"
|
||||
></Line>
|
||||
<div class="d-flex align-items-center">
|
||||
<h5 class="mb-0">
|
||||
<LocaleText t="Processes"></LocaleText>
|
||||
</h5>
|
||||
<h6 class="mb-0 ms-auto text-muted">
|
||||
<small>
|
||||
<LocaleText t="Memory Usage"></LocaleText>
|
||||
</small>
|
||||
</h6>
|
||||
|
||||
</div>
|
||||
<hr class="my-1">
|
||||
<div class="position-relative">
|
||||
<TransitionGroup name="process">
|
||||
<Process
|
||||
:key="p.pid"
|
||||
:process="p" v-for="p in data?.Processes.memory_top_10">
|
||||
</Process>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -127,13 +275,13 @@ const getData = () => {
|
||||
</h3>
|
||||
<h3 class="ms-auto mb-0">
|
||||
<span v-if="data">
|
||||
<LocaleText :t="Object.keys(data.network).length + ' Interface' + (Object.keys(data.network).length > 1 ? 's':'')"></LocaleText>
|
||||
<LocaleText :t="Object.keys(data.NetworkInterfaces).length + ' Interface' + (Object.keys(data.NetworkInterfaces).length > 1 ? 's':'')"></LocaleText>
|
||||
</span>
|
||||
<span v-else class="spinner-border"></span>
|
||||
</h3>
|
||||
</div>
|
||||
<div v-if="data" class="row g-3">
|
||||
<div v-for="(key, index) in Object.keys(data.network).sort()"
|
||||
<div v-for="(key, index) in Object.keys(data.NetworkInterfaces).sort()"
|
||||
class="col-sm-6 fadeIn">
|
||||
<div class="d-flex mb-2">
|
||||
<h6 class="mb-0">
|
||||
@@ -142,22 +290,22 @@ const getData = () => {
|
||||
<h6 class="mb-0 ms-auto d-flex gap-2">
|
||||
<span class="text-info">
|
||||
<i class="bi bi-arrow-down"></i>
|
||||
{{ Math.round((data.network[key].byte_recv / 1024000000 + Number.EPSILON) * 10000) / 10000}} GB
|
||||
{{ Math.round((data.NetworkInterfaces[key].bytes_recv / 1024000000 + Number.EPSILON) * 10000) / 10000}} GB
|
||||
</span>
|
||||
<span class="text-warning">
|
||||
<i class="bi bi-arrow-up"></i>
|
||||
{{ Math.round((data.network[key].byte_sent / 1024000000 + Number.EPSILON) * 10000) / 10000}} GB
|
||||
{{ Math.round((data.NetworkInterfaces[key].bytes_sent / 1024000000 + Number.EPSILON) * 10000) / 10000}} GB
|
||||
</span>
|
||||
|
||||
</h6>
|
||||
</div>
|
||||
<div class="progress" role="progressbar" style="height: 10px">
|
||||
<div class="progress-bar bg-info"
|
||||
v-if="data.network[key].byte_recv > 0"
|
||||
:style="{width: `${(data.network[key].byte_recv / (data.network[key].byte_sent + data.network[key].byte_recv)) * 100}%` }"></div>
|
||||
v-if="data.NetworkInterfaces[key].byte_recv > 0"
|
||||
:style="{width: `${(data.NetworkInterfaces[key].bytes_recv / (data.NetworkInterfaces[key].byte_sent + data.NetworkInterfaces[key].byte_recv)) * 100}%` }"></div>
|
||||
<div class="progress-bar bg-warning"
|
||||
v-if="data.network[key].byte_sent > 0"
|
||||
:style="{width: `${(data.network[key].byte_sent / (data.network[key].byte_sent + data.network[key].byte_recv)) * 100}%` }"></div>
|
||||
v-if="data.NetworkInterfaces[key].byte_sent > 0"
|
||||
:style="{width: `${(data.NetworkInterfaces[key].bytes_sent / (data.NetworkInterfaces[key].byte_sent + data.NetworkInterfaces[key].byte_recv)) * 100}%` }"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -174,28 +322,28 @@ const getData = () => {
|
||||
</h3>
|
||||
<h3 class="ms-auto mb-0">
|
||||
<span v-if="data">
|
||||
<LocaleText :t="Object.keys(data.disk).length + ' Partition' + (Object.keys(data.disk).length > 1 ? 's':'')"></LocaleText>
|
||||
<LocaleText :t="data.Disks.length + ' Partition' + (data.Disks.length > 1 ? 's':'')"></LocaleText>
|
||||
</span>
|
||||
<span v-else class="spinner-border"></span>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="row g-3">
|
||||
<div v-for="(key, index) in Object.keys(data.disk).sort()" class="col-sm-6 fadeIn"
|
||||
<div v-for="disk in data.Disks" class="col-sm-6 fadeIn"
|
||||
v-if="data">
|
||||
<div class="d-flex mb-2">
|
||||
<h6 class="mb-0">
|
||||
<samp>{{key}}</samp>
|
||||
<samp>{{disk.mountPoint}}</samp>
|
||||
</h6>
|
||||
<h6 class="mb-0 ms-auto d-flex gap-2">
|
||||
<span class="text-success">
|
||||
{{ Math.round((data.disk[key].used / 1024000000 + Number.EPSILON) * 100) / 100}} / {{ Math.round((data.disk[key].total / 1024000000 + Number.EPSILON) * 100) / 100}} GB Used
|
||||
{{ Math.round((disk.used / 1024000000 + Number.EPSILON) * 100) / 100}} / {{ Math.round((disk.total / 1024000000 + Number.EPSILON) * 100) / 100}} GB Used
|
||||
</span>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="progress" role="progressbar" style="height: 20px">
|
||||
<div class="progress-bar bg-success"
|
||||
:style="{width: `${data.disk[key].percent}%`}">
|
||||
{{ data.disk[key].percent }}%
|
||||
:style="{width: `${disk.percent}%`}">
|
||||
{{ disk.percent }}%
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -217,7 +365,7 @@ const getData = () => {
|
||||
.process-enter-from,
|
||||
.process-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transform: scale(0.9);
|
||||
}
|
||||
|
||||
.process-leave-active {
|
||||
|
Reference in New Issue
Block a user