From 74b78e96b3fb50b15de70f127a067b0e3935f448 Mon Sep 17 00:00:00 2001 From: henrygd Date: Sat, 25 Oct 2025 16:34:32 -0400 Subject: [PATCH] pre release refactoring + update changelog --- agent/smart.go | 12 ++++++------ .../site/src/components/alerts/alert-button.tsx | 2 +- internal/site/src/components/routes/system.tsx | 13 +++++++------ .../src/components/routes/system/smart-table.tsx | 10 +++++++--- internal/site/src/lib/utils.ts | 6 ++++++ supplemental/CHANGELOG.md | 12 ++++++++++++ 6 files changed, 39 insertions(+), 16 deletions(-) diff --git a/agent/smart.go b/agent/smart.go index d51ba36b..dea386e9 100644 --- a/agent/smart.go +++ b/agent/smart.go @@ -46,7 +46,7 @@ func (sm *SmartManager) Refresh() error { scanErr := sm.ScanDevices() if scanErr != nil { - slog.Warn("smartctl scan failed", "err", scanErr) + slog.Debug("smartctl scan failed", "err", scanErr) } devices := sm.devicesSnapshot() @@ -56,7 +56,7 @@ func (sm *SmartManager) Refresh() error { continue } if err := sm.CollectSmart(deviceInfo); err != nil { - slog.Info("smartctl collect failed for device, skipping", "device", deviceInfo.Name, "err", err) + slog.Debug("smartctl collect failed, skipping", "device", deviceInfo.Name, "err", err) collectErr = err } } @@ -220,7 +220,7 @@ func (sm *SmartManager) parseScan(output []byte) bool { scan := &scanOutput{} if err := json.Unmarshal(output, scan); err != nil { - slog.Warn("Failed to parse smartctl scan JSON", "err", err) + slog.Debug("Failed to parse smartctl scan JSON", "err", err) return false } @@ -260,7 +260,7 @@ func (sm *SmartManager) parseSmartForSata(output []byte) (bool, int) { } if data.SerialNumber == "" { - slog.Warn("device has no serial number, skipping", "device", data.Device.Name) + slog.Debug("device has no serial number, skipping", "device", data.Device.Name) return false, data.Smartctl.ExitStatus } @@ -327,7 +327,7 @@ func (sm *SmartManager) parseSmartForNvme(output []byte) (bool, int) { } if data.SerialNumber == "" { - slog.Warn("device has no serial number, skipping", "device", data.Device.Name) + slog.Debug("device has no serial number, skipping", "device", data.Device.Name) return false, data.Smartctl.ExitStatus } @@ -386,7 +386,7 @@ func (sm *SmartManager) detectSmartctl() error { if _, err := exec.LookPath("smartctl"); err == nil { return nil } - return fmt.Errorf("no smartctl found - install smartctl") + return fmt.Errorf("smartctl not found") } // NewSmartManager creates and initializes a new SmartManager diff --git a/internal/site/src/components/alerts/alert-button.tsx b/internal/site/src/components/alerts/alert-button.tsx index 446e516f..472d922d 100644 --- a/internal/site/src/components/alerts/alert-button.tsx +++ b/internal/site/src/components/alerts/alert-button.tsx @@ -26,7 +26,7 @@ export default memo(function AlertsButton({ system }: { system: SystemRecord }) /> - + {opened && } diff --git a/internal/site/src/components/routes/system.tsx b/internal/site/src/components/routes/system.tsx index 7de6a389..86fd1ffe 100644 --- a/internal/site/src/components/routes/system.tsx +++ b/internal/site/src/components/routes/system.tsx @@ -1003,15 +1003,16 @@ export default memo(function SystemDetail({ id }: { id: string }) { )} + {compareSemVer(chartData.agentVersion, parseSemVer("0.15.0")) >= 0 && ( + + )} {containerData.length > 0 && compareSemVer(chartData.agentVersion, parseSemVer("0.14.0")) >= 0 && ( )} - - - {/* add space for tooltip if more than 12 containers */} + {/* add space for tooltip if lots of sensors */} {bottomSpacing > 0 && } ) @@ -1144,7 +1145,7 @@ const ContainersTable = lazy(() => import("../containers-table/containers-table" function LazyContainersTable({ systemId }: { systemId: string }) { const { isIntersecting, ref } = useIntersectionObserver({ rootMargin: "90px" }) return ( -
+
{isIntersecting && }
) @@ -1153,9 +1154,9 @@ function LazyContainersTable({ systemId }: { systemId: string }) { const SmartTable = lazy(() => import("./system/smart-table")) function LazySmartTable({ systemId }: { systemId: string }) { - const { isIntersecting, ref } = useIntersectionObserver() + const { isIntersecting, ref } = useIntersectionObserver({ rootMargin: "90px" }) return ( -
+
{isIntersecting && }
) diff --git a/internal/site/src/components/routes/system/smart-table.tsx b/internal/site/src/components/routes/system/smart-table.tsx index 03cdec33..d01578b4 100644 --- a/internal/site/src/components/routes/system/smart-table.tsx +++ b/internal/site/src/components/routes/system/smart-table.tsx @@ -252,7 +252,7 @@ export const columns: ColumnDef[] = [ ] export default function DisksTable({ systemId }: { systemId: string }) { - const [sorting, setSorting] = React.useState([{ id: "device", desc: false }]) + // const [sorting, setSorting] = React.useState([{ id: "device", desc: false }]) const [columnFilters, setColumnFilters] = React.useState([]) const [rowSelection, setRowSelection] = React.useState({}) const [smartData, setSmartData] = React.useState | undefined>(undefined) @@ -284,19 +284,23 @@ export default function DisksTable({ systemId }: { systemId: string }) { const table = useReactTable({ data: diskData, columns: columns, - onSortingChange: setSorting, + // onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), onRowSelectionChange: setRowSelection, state: { - sorting, + // sorting, columnFilters, rowSelection, }, }) + if (!diskData.length && !columnFilters.length) { + return null + } + return (
diff --git a/internal/site/src/lib/utils.ts b/internal/site/src/lib/utils.ts index 720650d8..3c707077 100644 --- a/internal/site/src/lib/utils.ts +++ b/internal/site/src/lib/utils.ts @@ -367,6 +367,12 @@ export function formatDuration( .join(" ") } +/** Parse semver string into major, minor, and patch numbers + * @example + * const semVer = "1.2.3" + * const { major, minor, patch } = parseSemVer(semVer) + * console.log(major, minor, patch) // 1, 2, 3 +*/ export const parseSemVer = (semVer = ""): SemVer => { // if (semVer.startsWith("v")) { // semVer = semVer.slice(1) diff --git a/supplemental/CHANGELOG.md b/supplemental/CHANGELOG.md index b26510ac..03d7d8df 100644 --- a/supplemental/CHANGELOG.md +++ b/supplemental/CHANGELOG.md @@ -1,3 +1,15 @@ +## 0.15.0 + +- Add initial S.M.A.R.T. support for disk health monitoring. (#962) + +- Add `CONTAINER_DETAILS` environment variable to control access to container logs and info APIs. (#1305) + +- Improve temperature chart by allowing y-axis to start above 0 for better readability. (#1307) + +- Add `henrygd/beszel-agent:alpine` Docker image and include `smartmontools` in all non-base agent images. + +- Improve battery detection logic. (#1287) + ## 0.14.1 - Add `MFA_OTP` environment variable to enable email-based one-time password for users and/or superusers.