mirror of
https://github.com/donaldzou/WGDashboard
synced 2025-02-26 05:58:47 +00:00
Refactored system status into a class. Added charts
This commit is contained in:
parent
84069ee882
commit
e603af5f24
133
src/dashboard.py
133
src/dashboard.py
@ -2948,74 +2948,77 @@ def API_Email_PreviewBody():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return ResponseObject(False, message=str(e))
|
return ResponseObject(False, message=str(e))
|
||||||
|
|
||||||
|
from modules.SystemStatus import SystemStatus
|
||||||
|
SystemStatus = SystemStatus()
|
||||||
|
|
||||||
@app.get(f'{APP_PREFIX}/api/systemStatus')
|
@app.get(f'{APP_PREFIX}/api/systemStatus')
|
||||||
def API_SystemStatus():
|
def API_SystemStatus():
|
||||||
cpu_percpu = psutil.cpu_percent(interval=0.5, percpu=True)
|
# cpu_percpu = psutil.cpu_percent(interval=0.5, percpu=True)
|
||||||
cpu = psutil.cpu_percent(interval=0.5)
|
# cpu = psutil.cpu_percent(interval=0.5)
|
||||||
memory = psutil.virtual_memory()
|
# memory = psutil.virtual_memory()
|
||||||
swap_memory = psutil.swap_memory()
|
# swap_memory = psutil.swap_memory()
|
||||||
disks = psutil.disk_partitions()
|
# disks = psutil.disk_partitions()
|
||||||
network = psutil.net_io_counters(pernic=True, nowrap=True)
|
# network = psutil.net_io_counters(pernic=True, nowrap=True)
|
||||||
|
#
|
||||||
status = {
|
#
|
||||||
"cpu": {
|
# status = {
|
||||||
"cpu_percent": cpu,
|
# "cpu": {
|
||||||
"cpu_percent_per_cpu": cpu_percpu,
|
# "cpu_percent": cpu,
|
||||||
},
|
# "cpu_percent_per_cpu": cpu_percpu,
|
||||||
"memory": {
|
# },
|
||||||
"virtual_memory": {
|
# "memory": {
|
||||||
"total": memory.total,
|
# "virtual_memory": {
|
||||||
"available": memory.available,
|
# "total": memory.total,
|
||||||
"percent": memory.percent
|
# "available": memory.available,
|
||||||
},
|
# "percent": memory.percent
|
||||||
"swap_memory": {
|
# },
|
||||||
"total": swap_memory.total,
|
# "swap_memory": {
|
||||||
"used": swap_memory.used,
|
# "total": swap_memory.total,
|
||||||
"percent": swap_memory.percent
|
# "used": swap_memory.used,
|
||||||
}
|
# "percent": swap_memory.percent
|
||||||
},
|
# }
|
||||||
"disk": {},
|
# },
|
||||||
"network": {},
|
# "disk": {},
|
||||||
"process": {
|
# "network": {},
|
||||||
"cpu_top_10": [],
|
# "process": {
|
||||||
"memory_top_10": []
|
# "cpu_top_10": [],
|
||||||
}
|
# "memory_top_10": []
|
||||||
}
|
# },
|
||||||
for d in disks:
|
# "SystemStatus": systemStatus
|
||||||
detail = psutil.disk_usage(d.mountpoint)
|
# }
|
||||||
status['disk'][d.mountpoint] = {
|
# for d in disks:
|
||||||
"total": detail.total,
|
# detail = psutil.disk_usage(d.mountpoint)
|
||||||
"used": detail.used,
|
# status['disk'][d.mountpoint] = {
|
||||||
"free": detail.free,
|
# "total": detail.total,
|
||||||
"percent": detail.percent
|
# "used": detail.used,
|
||||||
}
|
# "free": detail.free,
|
||||||
for i in network.keys():
|
# "percent": detail.percent
|
||||||
status["network"][i] = {
|
# }
|
||||||
"byte_sent": network[i].bytes_sent,
|
# for i in network.keys():
|
||||||
"byte_recv": network[i].bytes_recv
|
# status["network"][i] = {
|
||||||
}
|
# "byte_sent": network[i].bytes_sent,
|
||||||
|
# "byte_recv": network[i].bytes_recv
|
||||||
while True:
|
# }
|
||||||
try:
|
#
|
||||||
processes = list(psutil.process_iter())
|
# while True:
|
||||||
status["process"]["cpu_top_10"] = sorted(list(map(lambda x : {
|
# try:
|
||||||
"name": x.name(),
|
# processes = list(psutil.process_iter())
|
||||||
"command": " ".join(x.cmdline()),
|
# status["process"]["cpu_top_10"] = sorted(list(map(lambda x : {
|
||||||
"pid": x.pid,
|
# "name": x.name(),
|
||||||
"cpu_percent": x.cpu_percent()
|
# "command": " ".join(x.cmdline()),
|
||||||
}, processes)), key=lambda x : x['cpu_percent'], reverse=True)[:10]
|
# "pid": x.pid,
|
||||||
status["process"]["memory_top_10"] = sorted(list(map(lambda x : {
|
# "cpu_percent": x.cpu_percent()
|
||||||
"name": x.name(),
|
# }, processes)), key=lambda x : x['cpu_percent'], reverse=True)[:10]
|
||||||
"command": " ".join(x.cmdline()),
|
# status["process"]["memory_top_10"] = sorted(list(map(lambda x : {
|
||||||
"pid": x.pid,
|
# "name": x.name(),
|
||||||
"memory_percent": x.memory_percent()
|
# "command": " ".join(x.cmdline()),
|
||||||
}, processes)), key=lambda x : x['memory_percent'], reverse=True)[:10]
|
# "pid": x.pid,
|
||||||
break
|
# "memory_percent": x.memory_percent()
|
||||||
except Exception as e:
|
# }, processes)), key=lambda x : x['memory_percent'], reverse=True)[:10]
|
||||||
continue
|
# break
|
||||||
return ResponseObject(data=status)
|
# except Exception as e:
|
||||||
|
# continue
|
||||||
|
return ResponseObject(data=SystemStatus)
|
||||||
|
|
||||||
@app.get(f'{APP_PREFIX}/api/protocolsEnabled')
|
@app.get(f'{APP_PREFIX}/api/protocolsEnabled')
|
||||||
def API_ProtocolsEnabled():
|
def API_ProtocolsEnabled():
|
||||||
|
@ -3,7 +3,25 @@ from asyncio.subprocess import Process
|
|||||||
import psutil
|
import psutil
|
||||||
|
|
||||||
class SystemStatus:
|
class SystemStatus:
|
||||||
pass
|
def __init__(self):
|
||||||
|
self.CPU = CPU()
|
||||||
|
self.MemoryVirtual = Memory('virtual')
|
||||||
|
self.MemorySwap = Memory('swap')
|
||||||
|
self.Disks = Disks()
|
||||||
|
self.NetworkInterfaces = NetworkInterfaces()
|
||||||
|
self.Processes = Processes()
|
||||||
|
def toJson(self):
|
||||||
|
return {
|
||||||
|
"CPU": self.CPU,
|
||||||
|
"Memory": {
|
||||||
|
"VirtualMemory": self.MemoryVirtual,
|
||||||
|
"SwapMemory": self.MemorySwap
|
||||||
|
},
|
||||||
|
"Disks": self.Disks,
|
||||||
|
"NetworkInterfaces": self.NetworkInterfaces,
|
||||||
|
"Processes": self.Processes
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class CPU:
|
class CPU:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -11,8 +29,8 @@ class CPU:
|
|||||||
self.cpu_percent_per_cpu: list[float] = []
|
self.cpu_percent_per_cpu: list[float] = []
|
||||||
def getData(self):
|
def getData(self):
|
||||||
try:
|
try:
|
||||||
self.cpu_percent = psutil.cpu_percent(interval=0.5, percpu=True)
|
self.cpu_percent_per_cpu = psutil.cpu_percent(interval=0.5, percpu=True)
|
||||||
self.cpu_percent_per_cpu = psutil.cpu_percent(interval=0.5)
|
self.cpu_percent = psutil.cpu_percent(interval=0.5)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
def toJson(self):
|
def toJson(self):
|
||||||
@ -21,22 +39,37 @@ class CPU:
|
|||||||
|
|
||||||
class Memory:
|
class Memory:
|
||||||
def __init__(self, memoryType: str):
|
def __init__(self, memoryType: str):
|
||||||
self.__memoryType = memoryType
|
self.__memoryType__ = memoryType
|
||||||
self.total = 0
|
self.total = 0
|
||||||
self.available = 0
|
self.available = 0
|
||||||
self.percent = 0
|
self.percent = 0
|
||||||
def getData(self):
|
def getData(self):
|
||||||
if self.__memoryType == "virtual":
|
try:
|
||||||
|
if self.__memoryType__ == "virtual":
|
||||||
memory = psutil.virtual_memory()
|
memory = psutil.virtual_memory()
|
||||||
else:
|
else:
|
||||||
memory = psutil.swap_memory()
|
memory = psutil.swap_memory()
|
||||||
self.total = memory.total
|
self.total = memory.total
|
||||||
self.available = memory.available
|
self.available = memory.available
|
||||||
self.percent = memory.percent
|
self.percent = memory.percent
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
def toJson(self):
|
def toJson(self):
|
||||||
self.getData()
|
self.getData()
|
||||||
return self.__dict__
|
return self.__dict__
|
||||||
|
|
||||||
|
class Disks:
|
||||||
|
def __init__(self):
|
||||||
|
self.disks : list[Disk] = []
|
||||||
|
def getData(self):
|
||||||
|
try:
|
||||||
|
self.disks = list(map(lambda x : Disk(x.mountpoint), psutil.disk_partitions()))
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
def toJson(self):
|
||||||
|
self.getData()
|
||||||
|
return self.disks
|
||||||
|
|
||||||
class Disk:
|
class Disk:
|
||||||
def __init__(self, mountPoint: str):
|
def __init__(self, mountPoint: str):
|
||||||
self.total = 0
|
self.total = 0
|
||||||
@ -45,11 +78,14 @@ class Disk:
|
|||||||
self.percent = 0
|
self.percent = 0
|
||||||
self.mountPoint = mountPoint
|
self.mountPoint = mountPoint
|
||||||
def getData(self):
|
def getData(self):
|
||||||
|
try:
|
||||||
disk = psutil.disk_usage(self.mountPoint)
|
disk = psutil.disk_usage(self.mountPoint)
|
||||||
self.total = disk.total
|
self.total = disk.total
|
||||||
self.free = disk.free
|
self.free = disk.free
|
||||||
self.used = disk.used
|
self.used = disk.used
|
||||||
self.percent = disk.percent
|
self.percent = disk.percent
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
def toJson(self):
|
def toJson(self):
|
||||||
self.getData()
|
self.getData()
|
||||||
return self.__dict__
|
return self.__dict__
|
||||||
@ -58,9 +94,12 @@ class NetworkInterfaces:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.interfaces = {}
|
self.interfaces = {}
|
||||||
def getData(self):
|
def getData(self):
|
||||||
|
try:
|
||||||
network = psutil.net_io_counters(pernic=True, nowrap=True)
|
network = psutil.net_io_counters(pernic=True, nowrap=True)
|
||||||
for i in network.keys():
|
for i in network.keys():
|
||||||
self.interfaces[i] = network[i]._asdict()
|
self.interfaces[i] = network[i]._asdict()
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
def toJson(self):
|
def toJson(self):
|
||||||
self.getData()
|
self.getData()
|
||||||
return self.interfaces
|
return self.interfaces
|
||||||
@ -78,19 +117,21 @@ class Processes:
|
|||||||
self.CPU_Top_10_Processes: list[Processes.Process] = []
|
self.CPU_Top_10_Processes: list[Processes.Process] = []
|
||||||
self.Memory_Top_10_Processes: list[Processes.Process] = []
|
self.Memory_Top_10_Processes: list[Processes.Process] = []
|
||||||
def getData(self):
|
def getData(self):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
processes = list(psutil.process_iter())
|
processes = list(psutil.process_iter())
|
||||||
self.CPU_Top_10_Processes = sorted(list(map(lambda x :
|
self.CPU_Top_10_Processes = sorted(
|
||||||
Processes.Process(x.name(), " ".join(x.cmdline()), x.pid, x.cpu_percent()), processes)),
|
list(map(lambda x : Processes.Process(x.name(), " ".join(x.cmdline()), x.pid, x.cpu_percent()), processes)),
|
||||||
key=lambda x : x.percent, reverse=True)[:10]
|
key=lambda x : x.percent, reverse=True)[:20]
|
||||||
self.Memory_Top_10_Processes = sorted(list(map(lambda x :
|
self.Memory_Top_10_Processes = sorted(
|
||||||
Processes.Process(x.name(), " ".join(x.cmdline()), x.pid, x.memory_percent()), processes)),
|
list(map(lambda x : Processes.Process(x.name(), " ".join(x.cmdline()), x.pid, x.memory_percent()), processes)),
|
||||||
key=lambda x : x.percent, reverse=True)[:10]
|
key=lambda x : x.percent, reverse=True)[:20]
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
continue
|
||||||
def toJson(self):
|
def toJson(self):
|
||||||
self.getData()
|
self.getData()
|
||||||
return {
|
return {
|
||||||
"cpu_top_10": self.CPU_Top_10_Processes,
|
"cpu_top_10": self.CPU_Top_10_Processes,
|
||||||
"memory_top_10": self.Memory_Top_10_Processes
|
"memory_top_10": self.Memory_Top_10_Processes
|
||||||
}
|
}
|
||||||
|
|
||||||
p = Processes()
|
|
||||||
print(p.toJson())
|
|
@ -10,7 +10,7 @@ const props = defineProps(["process", "cpu"])
|
|||||||
<samp>{{process.command ? process.command : process.name}}</samp>
|
<samp>{{process.command ? process.command : process.name}}</samp>
|
||||||
</small>
|
</small>
|
||||||
<small class="ms-auto">
|
<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>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
import {computed, ref} from "vue";
|
import {computed, ref} from "vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
mount: String,
|
mount: Object,
|
||||||
percentage: Number,
|
|
||||||
align: Boolean,
|
align: Boolean,
|
||||||
square: Boolean
|
square: Boolean
|
||||||
})
|
})
|
||||||
@ -19,7 +18,7 @@ const squareHeight = computed(() => {
|
|||||||
<div class="flex-grow-1 square rounded-3 border position-relative"
|
<div class="flex-grow-1 square rounded-3 border position-relative"
|
||||||
@mouseenter="show = true"
|
@mouseenter="show = true"
|
||||||
@mouseleave="show = false"
|
@mouseleave="show = false"
|
||||||
:style="{'background-color': `rgb(25 135 84 / ${percentage}%)`}">
|
:style="{'background-color': `rgb(25 135 84 / ${mount.percent}%)`}">
|
||||||
<Transition name="zoomReversed">
|
<Transition name="zoomReversed">
|
||||||
<div
|
<div
|
||||||
v-if="show"
|
v-if="show"
|
||||||
@ -29,10 +28,10 @@ const squareHeight = computed(() => {
|
|||||||
:class="[align ? 'end-0':'start-0']"
|
:class="[align ? 'end-0':'start-0']"
|
||||||
>
|
>
|
||||||
<small class="text-muted me-2">
|
<small class="text-muted me-2">
|
||||||
<samp>{{mount}}</samp>
|
<samp>{{mount.mountPoint}}</samp>
|
||||||
</small>
|
</small>
|
||||||
<small class="fw-bold">
|
<small class="fw-bold">
|
||||||
{{percentage}}%
|
{{mount.percent}}%
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
@ -7,8 +7,6 @@ import StorageMount from "@/components/systemStatusComponents/storageMount.vue";
|
|||||||
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
||||||
|
|
||||||
const dashboardStore = DashboardConfigurationStore()
|
const dashboardStore = DashboardConfigurationStore()
|
||||||
|
|
||||||
// const data = ref(undefined)
|
|
||||||
let interval = null;
|
let interval = null;
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@ -43,19 +41,19 @@ const data = computed(() => {
|
|||||||
</h6>
|
</h6>
|
||||||
<h6 class="ms-auto">
|
<h6 class="ms-auto">
|
||||||
<span v-if="data">
|
<span v-if="data">
|
||||||
{{ data.cpu.cpu_percent }}%
|
{{ data.CPU.cpu_percent }}%
|
||||||
</span>
|
</span>
|
||||||
<span v-else class="spinner-border spinner-border-sm"></span>
|
<span v-else class="spinner-border spinner-border-sm"></span>
|
||||||
</h6>
|
</h6>
|
||||||
</div>
|
</div>
|
||||||
<div class="progress" role="progressbar" style="height: 6px">
|
<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>
|
||||||
<div class="d-flex mt-2 gap-1">
|
<div class="d-flex mt-2 gap-1">
|
||||||
<CpuCore
|
<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"
|
: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"
|
:core_number="count" :percentage="cpu"
|
||||||
></CpuCore>
|
></CpuCore>
|
||||||
</div>
|
</div>
|
||||||
@ -68,20 +66,20 @@ const data = computed(() => {
|
|||||||
</h6>
|
</h6>
|
||||||
<h6 class="ms-auto">
|
<h6 class="ms-auto">
|
||||||
<span v-if="data">
|
<span v-if="data">
|
||||||
{{ data?.disk['/'].percent }}%
|
{{ data?.Disks.find(x => x.mountPoint === '/').percent }}%
|
||||||
</span>
|
</span>
|
||||||
<span v-else class="spinner-border spinner-border-sm"></span>
|
<span v-else class="spinner-border spinner-border-sm"></span>
|
||||||
</h6>
|
</h6>
|
||||||
</div>
|
</div>
|
||||||
<div class="progress" role="progressbar" style="height: 6px">
|
<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>
|
||||||
<div class="d-flex mt-2 gap-1">
|
<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"
|
v-if="data"
|
||||||
:key="count"
|
:key="disk.mountPoint"
|
||||||
:align="(count + 1) > Math.round(Object.keys(data?.disk).length / 2)"
|
:align="(count + 1) > Math.round(data?.Disks.length / 2)"
|
||||||
:mount="disk" :percentage="data?.disk[disk].percent"
|
:mount="disk"
|
||||||
></StorageMount>
|
></StorageMount>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -93,13 +91,13 @@ const data = computed(() => {
|
|||||||
</h6>
|
</h6>
|
||||||
<h6 class="ms-auto">
|
<h6 class="ms-auto">
|
||||||
<span v-if="data">
|
<span v-if="data">
|
||||||
{{ data?.memory.virtual_memory.percent }}%
|
{{ data?.Memory.VirtualMemory.percent }}%
|
||||||
</span>
|
</span>
|
||||||
<span v-else class="spinner-border spinner-border-sm"></span>
|
<span v-else class="spinner-border spinner-border-sm"></span>
|
||||||
</h6>
|
</h6>
|
||||||
</div>
|
</div>
|
||||||
<div class="progress" role="progressbar" style="height: 6px">
|
<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>
|
</div>
|
||||||
<div class="col-md-6 col-sm-12 col-xl-3">
|
<div class="col-md-6 col-sm-12 col-xl-3">
|
||||||
@ -110,13 +108,13 @@ const data = computed(() => {
|
|||||||
</h6>
|
</h6>
|
||||||
<h6 class="ms-auto">
|
<h6 class="ms-auto">
|
||||||
<span v-if="data">
|
<span v-if="data">
|
||||||
{{ data?.memory.swap_memory.percent }}%
|
{{ data?.Memory.SwapMemory.percent }}%
|
||||||
</span>
|
</span>
|
||||||
<span v-else class="spinner-border spinner-border-sm"></span>
|
<span v-else class="spinner-border spinner-border-sm"></span>
|
||||||
</h6>
|
</h6>
|
||||||
</div>
|
</div>
|
||||||
<div class="progress" role="progressbar" style="height: 6px">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,6 +12,36 @@ const data = computed(() => {
|
|||||||
return dashboardStore.SystemStatus
|
return dashboardStore.SystemStatus
|
||||||
})
|
})
|
||||||
let interval = null;
|
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(() => {
|
onMounted(() => {
|
||||||
getData()
|
getData()
|
||||||
@ -24,11 +54,97 @@ onBeforeUnmount(() => {
|
|||||||
clearInterval(interval)
|
clearInterval(interval)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const historicalChartTimestamp = ref([])
|
||||||
|
const historicalCpuUsage = ref([])
|
||||||
|
const historicalVirtualMemoryUsage = ref([])
|
||||||
|
const historicalSwapMemoryUsage = ref([])
|
||||||
|
let i = 0.1
|
||||||
const getData = () => {
|
const getData = () => {
|
||||||
fetchGet("/api/systemStatus", {}, (res) => {
|
fetchGet("/api/systemStatus", {}, (res) => {
|
||||||
|
historicalChartTimestamp.value.push(dayjs().format("HH:mm:ss A"))
|
||||||
dashboardStore.SystemStatus = res.data
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -36,8 +152,8 @@ const getData = () => {
|
|||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<div class="card rounded-3 h-100 shadow">
|
<div class="card rounded-3 h-100 shadow">
|
||||||
<div class="card-body p-4">
|
<div class="card-body p-4">
|
||||||
<div class="row">
|
<div class="d-flex flex-column gap-3">
|
||||||
<div class="col-sm-12 d-flex flex-column gap-3">
|
<div class="d-flex flex-column gap-3" style="height: 130px">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<h3 class="text-muted mb-0">
|
<h3 class="text-muted mb-0">
|
||||||
<i class="bi bi-cpu-fill me-2"></i>
|
<i class="bi bi-cpu-fill me-2"></i>
|
||||||
@ -45,42 +161,58 @@ const getData = () => {
|
|||||||
</h3>
|
</h3>
|
||||||
<h3 class="ms-auto mb-0">
|
<h3 class="ms-auto mb-0">
|
||||||
<span v-if="data">
|
<span v-if="data">
|
||||||
{{ data.cpu.cpu_percent }}%
|
{{ data.CPU.cpu_percent }}%
|
||||||
</span>
|
</span>
|
||||||
<span v-else class="spinner-border"></span>
|
<span v-else class="spinner-border"></span>
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="progress" role="progressbar" style="height: 10px">
|
<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>
|
||||||
<div class="d-flex gap-1">
|
<div class="d-flex gap-1">
|
||||||
<CpuCore
|
<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"
|
:square="true"
|
||||||
:key="count"
|
: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"
|
:core_number="count" :percentage="cpu"
|
||||||
></CpuCore>
|
></CpuCore>
|
||||||
</div>
|
</div>
|
||||||
<h5 class="mb-0">Processes</h5>
|
</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">
|
<div class="position-relative">
|
||||||
<TransitionGroup name="process">
|
<TransitionGroup name="process">
|
||||||
<Process
|
<Process
|
||||||
:key="p.pid"
|
:key="p.pid"
|
||||||
:cpu="true"
|
:cpu="true"
|
||||||
:process="p" v-for="p in data?.process.cpu_top_10"></Process>
|
:process="p" v-for="p in data?.Processes.cpu_top_10"></Process>
|
||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<div class="card rounded-3 h-100 shadow">
|
<div class="card rounded-3 h-100 shadow">
|
||||||
<div class="card-body p-4">
|
<div class="card-body p-4">
|
||||||
<div class="row">
|
<div class="d-flex flex-column gap-3">
|
||||||
<div class="col-sm-12 d-flex flex-column gap-3">
|
<div class="d-flex flex-column gap-3" style="height: 130px">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<h3 class="text-muted">
|
<h3 class="text-muted">
|
||||||
<i class="bi bi-memory me-2"></i>
|
<i class="bi bi-memory me-2"></i>
|
||||||
@ -88,27 +220,44 @@ const getData = () => {
|
|||||||
</h3>
|
</h3>
|
||||||
<h3 class="ms-auto">
|
<h3 class="ms-auto">
|
||||||
<span v-if="data">
|
<span v-if="data">
|
||||||
{{ data.memory.virtual_memory.percent }}%
|
{{ data?.Memory.VirtualMemory.percent }}%
|
||||||
</span>
|
</span>
|
||||||
<span v-else class="spinner-border"></span>
|
<span v-else class="spinner-border"></span>
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="progress" role="progressbar" style="height: 10px">
|
<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>
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<h6 class="mb-0">Swap Memory</h6>
|
<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>
|
||||||
<div class="progress" role="progressbar" style="height: 10px">
|
<div class="progress" role="progressbar" style="height: 10px">
|
||||||
<div class="progress-bar bg-info-subtle" :style="{width: `${data?.memory.swap_memory.percent}%` }"></div>
|
<div class="progress-bar bg-info-subtle" :style="{width: `${data?.Memory.SwapMemory.percent}%` }"></div>
|
||||||
</div>
|
</div>
|
||||||
<h5 class="mb-0">Processes</h5>
|
</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">
|
<div class="position-relative">
|
||||||
<TransitionGroup name="process">
|
<TransitionGroup name="process">
|
||||||
<Process
|
<Process
|
||||||
:key="p.pid"
|
:key="p.pid"
|
||||||
:process="p" v-for="p in data?.process.memory_top_10">
|
:process="p" v-for="p in data?.Processes.memory_top_10">
|
||||||
</Process>
|
</Process>
|
||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
</div>
|
</div>
|
||||||
@ -116,7 +265,6 @@ const getData = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="card rounded-3 h-100 shadow">
|
<div class="card rounded-3 h-100 shadow">
|
||||||
<div class="card-body p-4 d-flex gap-3 flex-column">
|
<div class="card-body p-4 d-flex gap-3 flex-column">
|
||||||
@ -127,13 +275,13 @@ const getData = () => {
|
|||||||
</h3>
|
</h3>
|
||||||
<h3 class="ms-auto mb-0">
|
<h3 class="ms-auto mb-0">
|
||||||
<span v-if="data">
|
<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>
|
||||||
<span v-else class="spinner-border"></span>
|
<span v-else class="spinner-border"></span>
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="data" class="row g-3">
|
<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">
|
class="col-sm-6 fadeIn">
|
||||||
<div class="d-flex mb-2">
|
<div class="d-flex mb-2">
|
||||||
<h6 class="mb-0">
|
<h6 class="mb-0">
|
||||||
@ -142,22 +290,22 @@ const getData = () => {
|
|||||||
<h6 class="mb-0 ms-auto d-flex gap-2">
|
<h6 class="mb-0 ms-auto d-flex gap-2">
|
||||||
<span class="text-info">
|
<span class="text-info">
|
||||||
<i class="bi bi-arrow-down"></i>
|
<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>
|
||||||
<span class="text-warning">
|
<span class="text-warning">
|
||||||
<i class="bi bi-arrow-up"></i>
|
<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>
|
</span>
|
||||||
|
|
||||||
</h6>
|
</h6>
|
||||||
</div>
|
</div>
|
||||||
<div class="progress" role="progressbar" style="height: 10px">
|
<div class="progress" role="progressbar" style="height: 10px">
|
||||||
<div class="progress-bar bg-info"
|
<div class="progress-bar bg-info"
|
||||||
v-if="data.network[key].byte_recv > 0"
|
v-if="data.NetworkInterfaces[key].byte_recv > 0"
|
||||||
:style="{width: `${(data.network[key].byte_recv / (data.network[key].byte_sent + data.network[key].byte_recv)) * 100}%` }"></div>
|
: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"
|
<div class="progress-bar bg-warning"
|
||||||
v-if="data.network[key].byte_sent > 0"
|
v-if="data.NetworkInterfaces[key].byte_sent > 0"
|
||||||
:style="{width: `${(data.network[key].byte_sent / (data.network[key].byte_sent + data.network[key].byte_recv)) * 100}%` }"></div>
|
:style="{width: `${(data.NetworkInterfaces[key].bytes_sent / (data.NetworkInterfaces[key].byte_sent + data.NetworkInterfaces[key].byte_recv)) * 100}%` }"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -174,28 +322,28 @@ const getData = () => {
|
|||||||
</h3>
|
</h3>
|
||||||
<h3 class="ms-auto mb-0">
|
<h3 class="ms-auto mb-0">
|
||||||
<span v-if="data">
|
<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>
|
||||||
<span v-else class="spinner-border"></span>
|
<span v-else class="spinner-border"></span>
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="row g-3">
|
<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">
|
v-if="data">
|
||||||
<div class="d-flex mb-2">
|
<div class="d-flex mb-2">
|
||||||
<h6 class="mb-0">
|
<h6 class="mb-0">
|
||||||
<samp>{{key}}</samp>
|
<samp>{{disk.mountPoint}}</samp>
|
||||||
</h6>
|
</h6>
|
||||||
<h6 class="mb-0 ms-auto d-flex gap-2">
|
<h6 class="mb-0 ms-auto d-flex gap-2">
|
||||||
<span class="text-success">
|
<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>
|
</span>
|
||||||
</h6>
|
</h6>
|
||||||
</div>
|
</div>
|
||||||
<div class="progress" role="progressbar" style="height: 20px">
|
<div class="progress" role="progressbar" style="height: 20px">
|
||||||
<div class="progress-bar bg-success"
|
<div class="progress-bar bg-success"
|
||||||
:style="{width: `${data.disk[key].percent}%`}">
|
:style="{width: `${disk.percent}%`}">
|
||||||
{{ data.disk[key].percent }}%
|
{{ disk.percent }}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -217,7 +365,7 @@ const getData = () => {
|
|||||||
.process-enter-from,
|
.process-enter-from,
|
||||||
.process-leave-to {
|
.process-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(30px);
|
transform: scale(0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
.process-leave-active {
|
.process-leave-active {
|
||||||
|
Loading…
Reference in New Issue
Block a user