diff --git a/beszel/site/src/components/systems-table/systems-table-columns.tsx b/beszel/site/src/components/systems-table/systems-table-columns.tsx
index ead56c1..28e0244 100644
--- a/beszel/site/src/components/systems-table/systems-table-columns.tsx
+++ b/beszel/site/src/components/systems-table/systems-table-columns.tsx
@@ -22,6 +22,7 @@ import {
decimalString,
formatBytes,
formatTemperature,
+ getMeterState,
isReadOnlyUser,
parseSemVer,
} from "@/lib/utils"
@@ -53,6 +54,7 @@ import {
} from "../ui/alert-dialog"
import { buttonVariants } from "../ui/button"
import { t } from "@lingui/core/macro"
+import { MeterState } from "@/lib/enums"
/**
* @param viewMode - "table" or "grid"
@@ -98,7 +100,7 @@ export default function SystemsTableColumns(viewMode: "table" | "grid"): ColumnD
accessorFn: ({ info }) => info.cpu,
id: "cpu",
name: () => t`CPU`,
- cell: CellFormatter,
+ cell: TableCellWithMeter,
Icon: CpuIcon,
header: sortableHeader,
},
@@ -107,7 +109,7 @@ export default function SystemsTableColumns(viewMode: "table" | "grid"): ColumnD
accessorFn: ({ info }) => info.mp,
id: "memory",
name: () => t`Memory`,
- cell: CellFormatter,
+ cell: TableCellWithMeter,
Icon: MemoryStickIcon,
header: sortableHeader,
},
@@ -115,7 +117,7 @@ export default function SystemsTableColumns(viewMode: "table" | "grid"): ColumnD
accessorFn: ({ info }) => info.dp,
id: "disk",
name: () => t`Disk`,
- cell: CellFormatter,
+ cell: TableCellWithMeter,
Icon: HardDriveIcon,
header: sortableHeader,
},
@@ -123,7 +125,7 @@ export default function SystemsTableColumns(viewMode: "table" | "grid"): ColumnD
accessorFn: ({ info }) => info.g,
id: "gpu",
name: () => "GPU",
- cell: CellFormatter,
+ cell: TableCellWithMeter,
Icon: GpuIcon,
header: sortableHeader,
},
@@ -157,17 +159,18 @@ export default function SystemsTableColumns(viewMode: "table" | "grid"): ColumnD
return null
}
- function getDotColor() {
- const normalized = max / (sysInfo.t ?? 1)
- if (status !== "up") return "bg-primary/30"
- if (normalized < 0.7) return "bg-green-500"
- if (normalized < 1) return "bg-yellow-500"
- return "bg-red-600"
- }
+ const normalizedLoad = max / (sysInfo.t ?? 1)
+ const threshold = getMeterState(normalizedLoad * 100)
return (
-
+
{loadAverages?.map((la, i) => (
{decimalString(la, la >= 10 ? 1 : 2)}
))}
@@ -280,10 +283,9 @@ function sortableHeader(context: HeaderContext
) {
)
}
-function CellFormatter(info: CellContext) {
- const userSettings = useStore($userSettings)
+function TableCellWithMeter(info: CellContext) {
const val = Number(info.getValue()) || 0
- const { colorWarn = 65, colorCrit = 90 } = userSettings
+ const threshold = getMeterState(val)
return (
{decimalString(val, val >= 10 ? 1 : 2)}%
@@ -292,8 +294,8 @@ function CellFormatter(info: CellContext) {
className={cn(
"absolute inset-0 w-full h-full origin-left",
(info.row.original.status !== "up" && "bg-primary/30") ||
- (val < colorWarn && "bg-green-500") ||
- (val < colorCrit && "bg-yellow-500") ||
+ (threshold === MeterState.Good && "bg-green-500") ||
+ (threshold === MeterState.Warn && "bg-yellow-500") ||
"bg-red-600"
)}
style={{
diff --git a/beszel/site/src/lib/enums.ts b/beszel/site/src/lib/enums.ts
index fc7f45e..6b3bf9b 100644
--- a/beszel/site/src/lib/enums.ts
+++ b/beszel/site/src/lib/enums.ts
@@ -21,3 +21,10 @@ export enum Unit {
Celsius,
Fahrenheit,
}
+
+/** Meter state for color */
+export enum MeterState {
+ Good,
+ Warn,
+ Crit,
+}
diff --git a/beszel/site/src/lib/utils.ts b/beszel/site/src/lib/utils.ts
index 5fc0453..7123b0f 100644
--- a/beszel/site/src/lib/utils.ts
+++ b/beszel/site/src/lib/utils.ts
@@ -20,7 +20,7 @@ import { useEffect, useState } from "react"
import { CpuIcon, HardDriveIcon, MemoryStickIcon, ServerIcon } from "lucide-react"
import { EthernetIcon, HourglassIcon, ThermometerIcon } from "@/components/ui/icons"
import { prependBasePath } from "@/components/router"
-import { Unit } from "./enums"
+import { MeterState, Unit } from "./enums"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
@@ -507,3 +507,9 @@ export const parseSemVer = (semVer = ""): SemVer => {
const parts = semVer.split(".").map(Number)
return { major: parts?.[0] ?? 0, minor: parts?.[1] ?? 0, patch: parts?.[2] ?? 0 }
}
+
+/** Get meter state from 0-100 value. Used for color coding meters. */
+export function getMeterState(value: number): MeterState {
+ const { colorWarn = 65, colorCrit = 90 } = $userSettings.get()
+ return value >= colorCrit ? MeterState.Crit : value >= colorWarn ? MeterState.Warn : MeterState.Good
+}