mirror of
https://github.com/henrygd/beszel.git
synced 2025-12-26 13:00:23 +00:00
Compare commits
1 Commits
nvml
...
1365-extra
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de1ad26fc2 |
@@ -166,6 +166,7 @@ func (a *Agent) gatherStats(cacheTimeMs uint16) *system.CombinedData {
|
||||
}
|
||||
|
||||
data.Stats.ExtraFs = make(map[string]*system.FsStats)
|
||||
data.Info.ExtraFsPct = make(map[string]system.ExtraFsInfo)
|
||||
for name, stats := range a.fsStats {
|
||||
if !stats.Root && stats.DiskTotal > 0 {
|
||||
// Use custom name if available, otherwise use device name
|
||||
@@ -174,6 +175,11 @@ func (a *Agent) gatherStats(cacheTimeMs uint16) *system.CombinedData {
|
||||
key = stats.Name
|
||||
}
|
||||
data.Stats.ExtraFs[key] = stats
|
||||
// Add percentage info to Info struct for dashboard
|
||||
if stats.DiskTotal > 0 {
|
||||
pct := (stats.DiskUsed / stats.DiskTotal) * 100
|
||||
data.Info.ExtraFsPct[key] = system.ExtraFsInfo{DiskPct: pct}
|
||||
}
|
||||
}
|
||||
}
|
||||
slog.Debug("Extra FS", "data", data.Stats.ExtraFs)
|
||||
|
||||
@@ -99,6 +99,11 @@ type FsStats struct {
|
||||
MaxDiskWriteBytes uint64 `json:"wbm,omitempty" cbor:"-"`
|
||||
}
|
||||
|
||||
// ExtraFsInfo contains summary info for extra filesystems in the system info
|
||||
type ExtraFsInfo struct {
|
||||
DiskPct float64 `json:"dp" cbor:"0,keyasint"`
|
||||
}
|
||||
|
||||
type NetIoStats struct {
|
||||
BytesRecv uint64
|
||||
BytesSent uint64
|
||||
@@ -146,6 +151,7 @@ type Info struct {
|
||||
// TODO: remove load fields in future release in favor of load avg array
|
||||
LoadAvg [3]float64 `json:"la,omitempty" cbor:"19,keyasint"`
|
||||
ConnectionType ConnectionType `json:"ct,omitempty" cbor:"20,keyasint,omitempty,omitzero"`
|
||||
ExtraFsPct map[string]ExtraFsInfo `json:"efsp,omitempty" cbor:"21,keyasint,omitempty"`
|
||||
}
|
||||
|
||||
// Final data structure to return to the hub
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
WifiIcon,
|
||||
} from "lucide-react"
|
||||
import { memo, useMemo, useRef, useState } from "react"
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip"
|
||||
import { isReadOnlyUser, pb } from "@/lib/api"
|
||||
import { ConnectionType, connectionTypeLabels, MeterState, SystemStatus } from "@/lib/enums"
|
||||
import { $longestSystemNameLen, $userSettings } from "@/lib/stores"
|
||||
@@ -153,7 +154,7 @@ export default function SystemsTableColumns(viewMode: "table" | "grid"): ColumnD
|
||||
accessorFn: ({ info }) => info.dp,
|
||||
id: "disk",
|
||||
name: () => t`Disk`,
|
||||
cell: TableCellWithMeter,
|
||||
cell: DiskCellWithMultiple,
|
||||
Icon: HardDriveIcon,
|
||||
header: sortableHeader,
|
||||
},
|
||||
@@ -354,6 +355,92 @@ function TableCellWithMeter(info: CellContext<SystemRecord, unknown>) {
|
||||
)
|
||||
}
|
||||
|
||||
function DiskCellWithMultiple(info: CellContext<SystemRecord, unknown>) {
|
||||
const { info: sysInfo, status } = info.row.original
|
||||
const rootDiskPct = sysInfo.dp
|
||||
const extraFsData = sysInfo.efsp
|
||||
const extraFsCount = extraFsData ? Object.keys(extraFsData).length : 0
|
||||
|
||||
const threshold = getMeterState(rootDiskPct)
|
||||
const meterClass = cn(
|
||||
"h-full",
|
||||
(status !== SystemStatus.Up && STATUS_COLORS.paused) ||
|
||||
(threshold === MeterState.Good && STATUS_COLORS.up) ||
|
||||
(threshold === MeterState.Warn && STATUS_COLORS.pending) ||
|
||||
STATUS_COLORS.down
|
||||
)
|
||||
|
||||
// No extra disks - show simple meter
|
||||
if (extraFsCount === 0) {
|
||||
return (
|
||||
<div className="flex gap-2 items-center tabular-nums tracking-tight w-full">
|
||||
<span className="min-w-8 shrink-0">{decimalString(rootDiskPct, rootDiskPct >= 10 ? 1 : 2)}%</span>
|
||||
<span className="flex-1 min-w-8 grid bg-muted h-[1em] rounded-sm overflow-hidden">
|
||||
<span className={meterClass} style={{ width: `${rootDiskPct}%` }}></span>
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// Has extra disks - show with tooltip
|
||||
return (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div className="flex flex-col gap-0.5 w-full cursor-help relative z-10">
|
||||
<div className="flex gap-2 items-center tabular-nums tracking-tight">
|
||||
<span className="min-w-8 shrink-0">{decimalString(rootDiskPct, rootDiskPct >= 10 ? 1 : 2)}%</span>
|
||||
<span className="flex-1 min-w-8 grid bg-muted h-[1em] rounded-sm overflow-hidden">
|
||||
<span className={meterClass} style={{ width: `${rootDiskPct}%` }}></span>
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-[0.7rem] text-muted-foreground ps-0.5">+{extraFsCount} more</div>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right" className="max-w-xs">
|
||||
<div className="flex flex-col gap-2 py-1">
|
||||
<div className="flex items-center gap-2 text-xs font-medium">
|
||||
<HardDriveIcon className="size-3" />
|
||||
<span>{t`All Disks`}</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<div className="text-[0.65rem] text-muted-foreground uppercase tracking-wider">{t`Root`}</div>
|
||||
<div className="flex gap-2 items-center tabular-nums text-xs">
|
||||
<span className="min-w-7">{decimalString(rootDiskPct, rootDiskPct >= 10 ? 1 : 2)}%</span>
|
||||
<span className="flex-1 min-w-12 grid bg-muted/50 h-1.5 rounded-sm overflow-hidden">
|
||||
<span className={meterClass} style={{ width: `${rootDiskPct}%` }}></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{extraFsData && Object.entries(extraFsData).map(([name, fs]) => {
|
||||
const pct = fs.dp
|
||||
const fsThreshold = getMeterState(pct)
|
||||
const fsMeterClass = cn(
|
||||
"h-full",
|
||||
(status !== SystemStatus.Up && STATUS_COLORS.paused) ||
|
||||
(fsThreshold === MeterState.Good && STATUS_COLORS.up) ||
|
||||
(fsThreshold === MeterState.Warn && STATUS_COLORS.pending) ||
|
||||
STATUS_COLORS.down
|
||||
)
|
||||
return (
|
||||
<div key={name} className="flex flex-col gap-0.5">
|
||||
<div className="text-[0.65rem] text-muted-foreground uppercase tracking-wider truncate">{name}</div>
|
||||
<div className="flex gap-2 items-center tabular-nums text-xs">
|
||||
<span className="min-w-7">{decimalString(pct, pct >= 10 ? 1 : 2)}%</span>
|
||||
<span className="flex-1 min-w-12 grid bg-muted/50 h-1.5 rounded-sm overflow-hidden">
|
||||
<span className={fsMeterClass} style={{ width: `${pct}%` }}></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
export function IndicatorDot({ system, className }: { system: SystemRecord; className?: ClassValue }) {
|
||||
className ||= STATUS_COLORS[system.status as keyof typeof STATUS_COLORS] || ""
|
||||
return (
|
||||
|
||||
7
internal/site/src/types.d.ts
vendored
7
internal/site/src/types.d.ts
vendored
@@ -77,6 +77,13 @@ export interface SystemInfo {
|
||||
os?: Os
|
||||
/** connection type */
|
||||
ct?: ConnectionType
|
||||
/** extra filesystem percentages */
|
||||
efsp?: Record<string, ExtraFsInfo>
|
||||
}
|
||||
|
||||
export interface ExtraFsInfo {
|
||||
/** disk percent */
|
||||
dp: number
|
||||
}
|
||||
|
||||
export interface SystemStats {
|
||||
|
||||
Reference in New Issue
Block a user