mirror of
https://github.com/ajnart/homarr.git
synced 2026-02-28 01:10:54 +01:00
feat: system resources widget (#3538)
* feat: add system resources widget * Update packages/widgets/src/system-resources/index.ts Co-authored-by: Andre Silva <32734153+Aandree5@users.noreply.github.com> * fix: system resources not updating * refactor: improve logic in component * fix: tooltip overflow * feat: add label with last value * feat: hide label when hovering * fix: formatting * fix: lint * fix: formatting * fix: wrong redis channel used for opnsense --------- Co-authored-by: Andre Silva <32734153+Aandree5@users.noreply.github.com> Co-authored-by: Meier Lukas <meierschlumpf@gmail.com>
This commit is contained in:
@@ -7,7 +7,7 @@ import { z } from "zod";
|
||||
|
||||
import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server";
|
||||
|
||||
import { createChannelEventHistory } from "../../../redis/src/lib/channel";
|
||||
import { createChannelEventHistoryOld } from "../../../redis/src/lib/channel";
|
||||
import type { IntegrationTestingInput } from "../base/integration";
|
||||
import { Integration } from "../base/integration";
|
||||
import { TestConnectionError } from "../base/test-connection/test-connection-error";
|
||||
@@ -32,14 +32,16 @@ export class DashDotIntegration extends Integration implements ISystemHealthMoni
|
||||
const cpuLoad = await this.getCurrentCpuLoadAsync();
|
||||
const memoryLoad = await this.getCurrentMemoryLoadAsync();
|
||||
const storageLoad = await this.getCurrentStorageLoadAsync();
|
||||
const networkLoad = await this.getCurrentNetworkLoadAsync();
|
||||
|
||||
const channel = this.getChannel();
|
||||
const history = await channel.getSliceUntilTimeAsync(dayjs().subtract(15, "minutes").toDate());
|
||||
|
||||
return {
|
||||
cpuUtilization: cpuLoad.sumLoad,
|
||||
memUsed: `${memoryLoad.loadInBytes}`,
|
||||
memAvailable: `${info.maxAvailableMemoryBytes - memoryLoad.loadInBytes}`,
|
||||
memUsedInBytes: memoryLoad.loadInBytes,
|
||||
memAvailableInBytes: info.maxAvailableMemoryBytes - memoryLoad.loadInBytes,
|
||||
network: networkLoad,
|
||||
fileSystem: info.storage
|
||||
.filter((_, index) => storageLoad[index] !== -1) // filter out undermoutned drives, they display as -1 in the load API
|
||||
.map((storage, index) => ({
|
||||
@@ -113,8 +115,13 @@ export class DashDotIntegration extends Integration implements ISystemHealthMoni
|
||||
};
|
||||
}
|
||||
|
||||
private async getCurrentNetworkLoadAsync() {
|
||||
const response = await fetchWithTrustedCertificatesAsync(this.url("/load/network"));
|
||||
return await networkLoadApi.parseAsync(await response.json());
|
||||
}
|
||||
|
||||
private getChannel() {
|
||||
return createChannelEventHistory<z.infer<typeof cpuLoadPerCoreApiList>>(
|
||||
return createChannelEventHistoryOld<z.infer<typeof cpuLoadPerCoreApiList>>(
|
||||
`integration:${this.integration.id}:history:cpu`,
|
||||
100,
|
||||
);
|
||||
@@ -130,6 +137,11 @@ const memoryLoadApi = z.object({
|
||||
load: z.number().min(0),
|
||||
});
|
||||
|
||||
const networkLoadApi = z.object({
|
||||
up: z.number().min(0),
|
||||
down: z.number().min(0),
|
||||
});
|
||||
|
||||
const internalServerInfoApi = z.object({
|
||||
os: z.object({
|
||||
distro: z.string(),
|
||||
|
||||
@@ -4,9 +4,13 @@ export interface SystemHealthMonitoring {
|
||||
version: string;
|
||||
cpuModelName: string;
|
||||
cpuUtilization: number;
|
||||
memUsed: string;
|
||||
memAvailable: string;
|
||||
memUsedInBytes: number;
|
||||
memAvailableInBytes: number;
|
||||
uptime: number;
|
||||
network: {
|
||||
up: number;
|
||||
down: number;
|
||||
} | null;
|
||||
loadAverage: {
|
||||
"1min": number;
|
||||
"5min": number;
|
||||
|
||||
@@ -7,9 +7,13 @@ export class SystemHealthMonitoringMockService implements ISystemHealthMonitorin
|
||||
version: "1.0.0",
|
||||
cpuModelName: "Mock CPU",
|
||||
cpuUtilization: Math.random(),
|
||||
memUsed: (4 * 1024 * 1024 * 1024).toString(), // 4 GB in bytes
|
||||
memAvailable: (8 * 1024 * 1024 * 1024).toString(), // 8 GB in bytes
|
||||
memUsedInBytes: 4 * 1024 * 1024 * 1024, // 4 GB in bytes
|
||||
memAvailableInBytes: 8 * 1024 * 1024 * 1024, // 8 GB in bytes
|
||||
availablePkgUpdates: 0,
|
||||
network: {
|
||||
up: 1024 * 16,
|
||||
down: 1024 * 16 * 6,
|
||||
},
|
||||
rebootRequired: false,
|
||||
cpuTemp: Math.floor(Math.random() * 100), // Random temperature between 0 and 99
|
||||
uptime: Math.floor(Math.random() * 1000000), // Random uptime in seconds
|
||||
|
||||
@@ -69,9 +69,11 @@ export class OpenMediaVaultIntegration extends Integration implements ISystemHea
|
||||
version: systemResult.data.response.version,
|
||||
cpuModelName: systemResult.data.response.cpuModelName ?? "Unknown CPU",
|
||||
cpuUtilization: systemResult.data.response.cpuUtilization,
|
||||
memUsed: systemResult.data.response.memUsed,
|
||||
memAvailable: systemResult.data.response.memAvailable,
|
||||
memUsedInBytes: Number(systemResult.data.response.memUsed),
|
||||
memAvailableInBytes: Number(systemResult.data.response.memAvailable),
|
||||
uptime: systemResult.data.response.uptime,
|
||||
/* real-time traffic monitoring is not available over the RPC API from OMV */
|
||||
network: null,
|
||||
loadAverage: {
|
||||
"1min": systemResult.data.response.loadAverage["1min"],
|
||||
"5min": systemResult.data.response.loadAverage["5min"],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server";
|
||||
import { ParseError, ResponseError } from "@homarr/common/server";
|
||||
import { createChannelEventHistory } from "@homarr/redis";
|
||||
|
||||
import { createChannelEventHistoryOld } from "../../../redis/src/lib/channel";
|
||||
import { HandleIntegrationErrors } from "../base/errors/decorator";
|
||||
import type { IntegrationTestingInput } from "../base/integration";
|
||||
import { Integration } from "../base/integration";
|
||||
@@ -64,7 +64,7 @@ export class OPNsenseIntegration extends Integration implements FirewallSummaryI
|
||||
}
|
||||
|
||||
private getInterfacesChannel() {
|
||||
return createChannelEventHistory<FirewallInterface[]>(`integration:${this.integration.id}:interfaces`, 15);
|
||||
return createChannelEventHistoryOld<FirewallInterface[]>(`integration:${this.integration.id}:interfaces`, 15);
|
||||
}
|
||||
|
||||
public async getFirewallInterfacesAsync(): Promise<FirewallInterfacesSummary[]> {
|
||||
|
||||
Reference in New Issue
Block a user