diff --git a/apps/docs/docs/widgets/beszel-system-stats/index.ts b/apps/docs/docs/widgets/beszel-system-stats/index.ts index d19ae9154..f320a7ea9 100644 --- a/apps/docs/docs/widgets/beszel-system-stats/index.ts +++ b/apps/docs/docs/widgets/beszel-system-stats/index.ts @@ -10,7 +10,8 @@ export const beszelSystemStatsWidget: WidgetDefinition = { items: [ { name: "Time period", - description: "The time range for chart data. '1 Minute' enables live streaming via PocketBase SSE (requires Beszel agent >= 0.13.0)", + description: + "The time range for chart data. '1 Minute' enables live streaming via PocketBase SSE (requires Beszel agent >= 0.13.0)", values: { type: "select", options: ["1 Minute", "1 Hour", "12 Hours", "24 Hours", "1 Week", "30 Days"], diff --git a/packages/api/src/router/widgets/beszel.ts b/packages/api/src/router/widgets/beszel.ts index c1c0fe7c6..fb1e58b5c 100644 --- a/packages/api/src/router/widgets/beszel.ts +++ b/packages/api/src/router/widgets/beszel.ts @@ -8,10 +8,7 @@ import { beszelStatsRequestHandler, beszelSystemsRequestHandler, } from "@homarr/request-handler/beszel"; -import type { - BeszelAlertsData, - BeszelSystemRow, -} from "@homarr/request-handler/beszel"; +import type { BeszelAlertsData, BeszelSystemRow } from "@homarr/request-handler/beszel"; import { createManyIntegrationMiddleware } from "../../middlewares/integration"; import { createTRPCRouter, publicProcedure } from "../../trpc"; @@ -22,14 +19,10 @@ export const beszelRouter = createTRPCRouter({ .query(async ({ ctx }) => { const results = await Promise.all( ctx.integrations.map(async (integration) => { - const innerHandler = beszelSystemsRequestHandler.handler( - integration, - {}, - ); - const { data, timestamp } = - await innerHandler.getCachedOrUpdatedDataAsync({ - forceUpdate: false, - }); + const innerHandler = beszelSystemsRequestHandler.handler(integration, {}); + const { data, timestamp } = await innerHandler.getCachedOrUpdatedDataAsync({ + forceUpdate: false, + }); return { integrationId: integration.id, integrationName: integration.name, @@ -51,10 +44,7 @@ export const beszelRouter = createTRPCRouter({ timestamp: Date; }>((emit) => { const unsubscribes = ctx.integrations.map((integration) => { - const innerHandler = beszelSystemsRequestHandler.handler( - integration, - {}, - ); + const innerHandler = beszelSystemsRequestHandler.handler(integration, {}); return innerHandler.subscribe((systems) => { emit.next({ integrationId: integration.id, @@ -80,17 +70,11 @@ export const beszelRouter = createTRPCRouter({ .query(async ({ ctx, input }) => { const results = await Promise.all( ctx.integrations.map(async (integration) => { - const alertsHandler = beszelAlertsRequestHandler.handler( - integration, - { - includeHistory: input.includeHistory, - maxHistoryItems: input.maxHistoryItems, - }, - ); - const systemsHandler = beszelSystemsRequestHandler.handler( - integration, - {}, - ); + const alertsHandler = beszelAlertsRequestHandler.handler(integration, { + includeHistory: input.includeHistory, + maxHistoryItems: input.maxHistoryItems, + }); + const systemsHandler = beszelSystemsRequestHandler.handler(integration, {}); const [alertsResult, systemsResult] = await Promise.all([ alertsHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false }), systemsHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false }), @@ -161,8 +145,7 @@ export const beszelRouter = createTRPCRouter({ timePeriod: input.timePeriod, includeDocker: input.includeDocker, }); - const { data, timestamp } = - await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false }); + const { data, timestamp } = await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false }); return { integrationId: integration.id, ...data, updatedAt: timestamp }; }), @@ -187,11 +170,7 @@ export const beszelRouter = createTRPCRouter({ void (async () => { try { const instance = await createIntegrationAsync(integration); - await instance.subscribeRealtimeMetrics( - input.systemId, - (data) => emit.next(data), - abortController.signal, - ); + await instance.subscribeRealtimeMetrics(input.systemId, (data) => emit.next(data), abortController.signal); } catch (error) { if (!abortController.signal.aborted) { emit.error(error instanceof Error ? error : new Error(String(error))); diff --git a/packages/integrations/src/beszel/beszel-integration.ts b/packages/integrations/src/beszel/beszel-integration.ts index d74303164..d0766b7fe 100644 --- a/packages/integrations/src/beszel/beszel-integration.ts +++ b/packages/integrations/src/beszel/beszel-integration.ts @@ -298,7 +298,9 @@ export class BeszelIntegration extends Integration { updated: new Date().toISOString(), }; const containerStats: BeszelContainerStatsRecord | null = - parsed.container && Array.isArray(parsed.container) && (parsed.container as BeszelContainerStats[]).length > 0 + parsed.container && + Array.isArray(parsed.container) && + (parsed.container as BeszelContainerStats[]).length > 0 ? { id: "", system: systemId, diff --git a/packages/request-handler/src/beszel.ts b/packages/request-handler/src/beszel.ts index f3dfc8f44..33777a845 100644 --- a/packages/request-handler/src/beszel.ts +++ b/packages/request-handler/src/beszel.ts @@ -24,10 +24,7 @@ export type { BeszelSystemRow } from "@homarr/integrations/types"; * 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 { +function mapToSystemRow(system: BeszelSystem, details: BeszelSystemDetails | null): BeszelSystemRow { const info = system.info; return { id: system.id, @@ -53,28 +50,25 @@ function mapToSystemRow( }; } -export const beszelSystemsRequestHandler = - createCachedIntegrationRequestHandler< - BeszelSystemRow[], - "beszel" | "mock", - Record - >({ - 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 const beszelSystemsRequestHandler = createCachedIntegrationRequestHandler< + BeszelSystemRow[], + "beszel" | "mock", + Record +>({ + 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[]; @@ -89,9 +83,7 @@ export const beszelAlertsRequestHandler = createCachedIntegrationRequestHandler< async requestAsync(integration, input) { const instance = await createIntegrationAsync(integration); const alerts = await instance.getAlertsAsync(); - const history = input.includeHistory - ? await instance.getAlertHistoryAsync(undefined, input.maxHistoryItems) - : []; + const history = input.includeHistory ? await instance.getAlertHistoryAsync(undefined, input.maxHistoryItems) : []; return { alerts, history }; }, cacheDuration: dayjs.duration(15, "seconds"), @@ -120,15 +112,9 @@ export const beszelStatsRequestHandler = createCachedIntegrationRequestHandler< 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 systemStats = await instance.getSystemStatsAsync(input.systemId, config.type, config.perPage); const containerStats = input.includeDocker - ? await instance - .getContainerStatsAsync(input.systemId, config.type, config.perPage) - .catch(() => []) + ? await instance.getContainerStatsAsync(input.systemId, config.type, config.perPage).catch(() => []) : []; return { systemStats, containerStats }; }, diff --git a/packages/widgets/src/beszel/_shared/chart.tsx b/packages/widgets/src/beszel/_shared/chart.tsx index 14c6a64f0..02c3c728d 100644 --- a/packages/widgets/src/beszel/_shared/chart.tsx +++ b/packages/widgets/src/beszel/_shared/chart.tsx @@ -6,14 +6,10 @@ import type { AreaChartProps } from "@mantine/charts"; import { AreaChart } from "@mantine/charts"; import dayjs from "dayjs"; -import type { - BeszelContainerStatsRecord, - BeszelSystemStatsRecord, -} from "@homarr/integrations/types"; +import type { BeszelContainerStatsRecord, BeszelSystemStatsRecord } from "@homarr/integrations/types"; const formatTime = (timestamp: string) => dayjs(timestamp).format("HH:mm"); -const formatTimeLive = (timestamp: string) => - dayjs(timestamp).format("HH:mm:ss"); +const formatTimeLive = (timestamp: string) => dayjs(timestamp).format("HH:mm:ss"); const yAxisBase = { tickMargin: 0, tick: { fontSize: 10 } } as const; @@ -39,10 +35,7 @@ export const ChartPanel = ({ title, subtitle, children }: ChartPanelProps) => ( ); -type BeszelAreaChartProps = Omit< - AreaChartProps, - "dataKey" | "curveType" | "withDots" | "withXAxis" | "withYAxis" -> & { +type BeszelAreaChartProps = Omit & { yAxisFormatter: (value: number) => string; yAxisDomain?: [number, string]; }; @@ -96,10 +89,7 @@ export const useSystemChartData = ( })); }, [systemStats, mapFn, live]); -export const useContainerNames = ( - containerStats: BeszelContainerStatsRecord[] | undefined, - max = 15, -) => +export const useContainerNames = (containerStats: BeszelContainerStatsRecord[] | undefined, max = 15) => useMemo(() => { if (!containerStats?.length) return []; const names = new Set(); @@ -111,9 +101,7 @@ export const useContainerNames = ( return [...names].slice(0, max); }, [containerStats, max]); -type ContainerExtractor = ( - container: BeszelContainerStatsRecord["stats"][number] | undefined, -) => number; +type ContainerExtractor = (container: BeszelContainerStatsRecord["stats"][number] | undefined) => number; // c = CPU (%), m = memory (MB), b = bandwidth [sent,recv] (bytes/s), ns/nr = legacy net (bytes/s) const MB = 1024 * 1024;