Replace all ternary operators with if/else, &&/||, or early returns. Remove unused noAnimation constant that caused lint error. Fix variable shadowing in tooltip deduplication loop.
129 lines
4.5 KiB
TypeScript
129 lines
4.5 KiB
TypeScript
import dayjs from "dayjs";
|
|
|
|
import { createIntegrationAsync } from "@homarr/integrations";
|
|
import type {
|
|
BeszelAlert,
|
|
BeszelAlertHistory,
|
|
BeszelContainerStatsRecord,
|
|
BeszelSystem,
|
|
BeszelSystemDetails,
|
|
BeszelSystemRow,
|
|
BeszelSystemStatsRecord,
|
|
} from "@homarr/integrations/types";
|
|
|
|
import { createCachedIntegrationRequestHandler } from "./lib/cached-integration-request-handler";
|
|
|
|
export type { BeszelSystemRow } from "@homarr/integrations/types";
|
|
|
|
/**
|
|
* Maps raw Beszel API responses (BeszelSystem + BeszelSystemDetails) into a
|
|
* normalized BeszelSystemRow for widget consumption.
|
|
*
|
|
* BeszelSystemInfo uses short field names (see beszel-types.ts for full docs):
|
|
* cpu=CPU%, mp=memory%, dp=disk%, g=GPU%, la=loadAvg, u=uptime(s), v=version,
|
|
* bb=bandwidth(bytes/s), b=bandwidth(Mbps legacy), dt=disk temp, bat=battery,
|
|
* sv=[running,total] services, h=hostname, m=CPU model, c=cores, ct=threads
|
|
*/
|
|
function mapToSystemRow(system: BeszelSystem, details: BeszelSystemDetails | null): BeszelSystemRow {
|
|
const info = system.info;
|
|
return {
|
|
id: system.id,
|
|
name: system.name,
|
|
status: system.status,
|
|
cpu: info.cpu,
|
|
memory: info.mp,
|
|
disk: info.dp,
|
|
gpu: info.g ?? 0,
|
|
loadAvg: info.la ?? null,
|
|
// bb = bytes/s (newer), b = Mbps (legacy, multiply to get bytes/s)
|
|
netBytes: info.bb ?? (info.b ?? 0) * 1_000_000,
|
|
temp: info.dt ?? null,
|
|
battery: info.bat ?? null,
|
|
services: info.sv?.[0] ?? 0,
|
|
uptime: info.u,
|
|
agentVersion: info.v,
|
|
hostname: details?.hostname ?? info.h ?? system.name,
|
|
cpuModel: details?.cpu ?? info.m ?? "Unknown",
|
|
cores: details?.cores ?? info.ct ?? info.c ?? 1,
|
|
memoryTotal: details?.memory ?? 0,
|
|
osName: details?.os_name ?? "",
|
|
};
|
|
}
|
|
|
|
export const beszelSystemsRequestHandler = createCachedIntegrationRequestHandler<
|
|
BeszelSystemRow[],
|
|
"beszel" | "mock",
|
|
Record<string, never>
|
|
>({
|
|
async requestAsync(integration) {
|
|
const instance = await createIntegrationAsync(integration);
|
|
const systems = await instance.getSystemsAsync();
|
|
const enriched = await Promise.all(
|
|
systems.map(async (system) => {
|
|
const details = await instance.getSystemDetailsAsync(system.id).catch(() => null);
|
|
return mapToSystemRow(system, details);
|
|
}),
|
|
);
|
|
return enriched;
|
|
},
|
|
cacheDuration: dayjs.duration(5, "seconds"),
|
|
queryKey: "beszelSystems",
|
|
});
|
|
|
|
export interface BeszelAlertsData {
|
|
alerts: BeszelAlert[];
|
|
history: BeszelAlertHistory[];
|
|
}
|
|
|
|
export const beszelAlertsRequestHandler = createCachedIntegrationRequestHandler<
|
|
BeszelAlertsData,
|
|
"beszel" | "mock",
|
|
{ includeHistory: boolean; maxHistoryItems: number }
|
|
>({
|
|
async requestAsync(integration, input) {
|
|
const instance = await createIntegrationAsync(integration);
|
|
const alerts = await instance.getAlertsAsync();
|
|
const history = input.includeHistory ? await instance.getAlertHistoryAsync(undefined, input.maxHistoryItems) : [];
|
|
return { alerts, history };
|
|
},
|
|
cacheDuration: dayjs.duration(15, "seconds"),
|
|
queryKey: "beszelAlerts",
|
|
});
|
|
|
|
const timePeriodConfig: Record<string, { type: string; perPage: number; cacheSeconds: number }> = {
|
|
"1m": { type: "1m", perPage: 60, cacheSeconds: 5 },
|
|
"1h": { type: "1m", perPage: 60, cacheSeconds: 60 },
|
|
"12h": { type: "10m", perPage: 72, cacheSeconds: 300 },
|
|
"24h": { type: "20m", perPage: 72, cacheSeconds: 600 },
|
|
"1w": { type: "120m", perPage: 84, cacheSeconds: 1800 },
|
|
"30d": { type: "480m", perPage: 90, cacheSeconds: 3600 },
|
|
};
|
|
|
|
export interface BeszelStatsData {
|
|
systemStats: BeszelSystemStatsRecord[];
|
|
containerStats: BeszelContainerStatsRecord[];
|
|
}
|
|
|
|
export const beszelStatsRequestHandler = createCachedIntegrationRequestHandler<
|
|
BeszelStatsData,
|
|
"beszel" | "mock",
|
|
{ systemId: string; timePeriod: string; includeDocker: boolean }
|
|
>({
|
|
async requestAsync(integration, input) {
|
|
const config = timePeriodConfig[input.timePeriod] ?? { type: "1m", perPage: 60, cacheSeconds: 60 };
|
|
const instance = await createIntegrationAsync(integration);
|
|
const systemStats = await instance.getSystemStatsAsync(input.systemId, config.type, config.perPage);
|
|
const containerStats = input.includeDocker
|
|
? await instance.getContainerStatsAsync(input.systemId, config.type, config.perPage).catch(() => [])
|
|
: [];
|
|
return { systemStats, containerStats };
|
|
},
|
|
cacheDuration: dayjs.duration(60, "seconds"),
|
|
queryKey: "beszelStats",
|
|
cacheDurationForInput(input) {
|
|
const config = timePeriodConfig[input.timePeriod];
|
|
if (!config) return undefined;
|
|
return dayjs.duration(config.cacheSeconds, "seconds");
|
|
},
|
|
});
|