mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-07-30 20:38:22 +00:00
update 1.2.2.2 beta
This commit is contained in:
Binary file not shown.
@@ -1 +1 @@
|
|||||||
df043f28424d41dbb31b91cd525daafa4c0e7604334c8adbd5ed51c34f0727ff ProxMenux-1.2.2.2-beta.AppImage
|
24f4dac2561773ea88bd1eb866ce25e7908d54435932ea3a3f265f3e6fe1ecc0 ProxMenux-1.2.2.2-beta.AppImage
|
||||||
|
|||||||
@@ -6,10 +6,12 @@
|
|||||||
// on Storage and in blue on Backups — same datastore, two different
|
// on Storage and in blue on Backups — same datastore, two different
|
||||||
// signals.
|
// signals.
|
||||||
//
|
//
|
||||||
// Thresholds: < 75 % green, 75–89 % amber, ≥ 90 % red. Matches the
|
// Thresholds: < 75 % blue (normal — no alert), 75–89 % amber,
|
||||||
// existing Storage page palette and the "Free" text colour on the
|
// ≥ 90 % red. Matches the Storage page palette: the normal state
|
||||||
// Backups page (which was already amber/red, just disconnected from
|
// stays on the project's brand blue and only switches to amber/red
|
||||||
// the bar).
|
// when the operator should look at it. Green is reserved for OK
|
||||||
|
// signals where green has meaning (SMART status, wear level), not
|
||||||
|
// for ambient bars.
|
||||||
|
|
||||||
export type UsageBarColor = {
|
export type UsageBarColor = {
|
||||||
/** Inline `background` value for SVG / style={} consumers. */
|
/** Inline `background` value for SVG / style={} consumers. */
|
||||||
@@ -21,10 +23,12 @@ export type UsageBarColor = {
|
|||||||
textClass: string
|
textClass: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const GREEN: UsageBarColor = {
|
const BLUE: UsageBarColor = {
|
||||||
hex: "#22c55e",
|
hex: "#3b82f6",
|
||||||
bgClass: "bg-green-500",
|
bgClass: "bg-blue-500",
|
||||||
textClass: "text-green-500",
|
// No text-blue override for the "Free" counter — at normal usage
|
||||||
|
// the foreground colour reads better than tinted text.
|
||||||
|
textClass: "",
|
||||||
}
|
}
|
||||||
const AMBER: UsageBarColor = {
|
const AMBER: UsageBarColor = {
|
||||||
hex: "#f59e0b",
|
hex: "#f59e0b",
|
||||||
@@ -40,5 +44,5 @@ const RED: UsageBarColor = {
|
|||||||
export function getStorageUsageColor(percent: number): UsageBarColor {
|
export function getStorageUsageColor(percent: number): UsageBarColor {
|
||||||
if (percent >= 90) return RED
|
if (percent >= 90) return RED
|
||||||
if (percent >= 75) return AMBER
|
if (percent >= 75) return AMBER
|
||||||
return GREEN
|
return BLUE
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3581,6 +3581,15 @@ def _smart_default_payload() -> dict:
|
|||||||
'family': None,
|
'family': None,
|
||||||
'sata_version': None,
|
'sata_version': None,
|
||||||
'form_factor': None,
|
'form_factor': None,
|
||||||
|
# Internal flag — True if smartctl confirmed the disk type
|
||||||
|
# (HDD with RPM, or SSD via "Solid State Device" / JSON
|
||||||
|
# rotation_rate=0). Stripped before the dict reaches the API.
|
||||||
|
# Drives the kernel /sys/.../rotational fallback: that path is
|
||||||
|
# only safe when smartctl had NO opinion, because USB-SATA
|
||||||
|
# enclosures (ASM105x etc.) advertise rotational=1 to the
|
||||||
|
# kernel even when the drive behind them is an SSD that
|
||||||
|
# smartctl can correctly identify via SAT passthrough.
|
||||||
|
'_rotation_known': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3716,6 +3725,7 @@ def _get_smart_data_uncached(disk_name):
|
|||||||
|
|
||||||
if 'rotation_rate' in data:
|
if 'rotation_rate' in data:
|
||||||
smart_data['rotation_rate'] = data['rotation_rate']
|
smart_data['rotation_rate'] = data['rotation_rate']
|
||||||
|
smart_data['_rotation_known'] = True
|
||||||
|
|
||||||
|
|
||||||
# Extract SMART status
|
# Extract SMART status
|
||||||
@@ -3909,19 +3919,17 @@ def _get_smart_data_uncached(disk_name):
|
|||||||
# print(f"[v0] Found serial: {smart_data['serial']}")
|
# print(f"[v0] Found serial: {smart_data['serial']}")
|
||||||
pass
|
pass
|
||||||
|
|
||||||
elif line.startswith('Rotation Rate:') and smart_data['rotation_rate'] == 0:
|
elif line.startswith('Rotation Rate:') and not smart_data['_rotation_known']:
|
||||||
rate_str = line.split(':', 1)[1].strip()
|
rate_str = line.split(':', 1)[1].strip()
|
||||||
if 'rpm' in rate_str.lower():
|
if 'rpm' in rate_str.lower():
|
||||||
try:
|
try:
|
||||||
smart_data['rotation_rate'] = int(rate_str.split()[0])
|
smart_data['rotation_rate'] = int(rate_str.split()[0])
|
||||||
# print(f"[v0] Found rotation rate: {smart_data['rotation_rate']} RPM")
|
smart_data['_rotation_known'] = True
|
||||||
pass
|
|
||||||
except (ValueError, IndexError):
|
except (ValueError, IndexError):
|
||||||
pass
|
pass
|
||||||
elif 'Solid State Device' in rate_str:
|
elif 'Solid State Device' in rate_str:
|
||||||
smart_data['rotation_rate'] = 0 # SSD
|
smart_data['rotation_rate'] = 0 # SSD
|
||||||
# print(f"[v0] Found SSD (no rotation)")
|
smart_data['_rotation_known'] = True
|
||||||
pass
|
|
||||||
|
|
||||||
# SMART status detection
|
# SMART status detection
|
||||||
elif 'SMART overall-health self-assessment test result:' in line:
|
elif 'SMART overall-health self-assessment test result:' in line:
|
||||||
@@ -4132,21 +4140,27 @@ def _get_smart_data_uncached(disk_name):
|
|||||||
elif temp > warn:
|
elif temp > warn:
|
||||||
smart_data['health'] = 'warning'
|
smart_data['health'] = 'warning'
|
||||||
|
|
||||||
# CHANGE: Use -1 to indicate HDD with unknown RPM instead of inventing 7200 RPM
|
# Fallback: ask the kernel only when smartctl had no opinion.
|
||||||
# Fallback: Check kernel's rotational flag if smartctl didn't provide rotation_rate
|
# USB-SATA enclosures (ASM105x family etc.) advertise
|
||||||
# This fixes detection for older disks that don't report RPM via smartctl
|
# rotational=1 to the kernel even when there's an SSD behind
|
||||||
if smart_data['rotation_rate'] == 0:
|
# them, so trusting /sys here without first checking what
|
||||||
|
# smartctl said would flip a correctly-identified SSD back to
|
||||||
|
# HDD. The previous condition (`rotation_rate == 0`) couldn't
|
||||||
|
# tell "smartctl confirmed SSD" from "smartctl never spoke",
|
||||||
|
# which is what bit the OCZ-SOLID2 behind an ASM105x dock on
|
||||||
|
# the lab host (sdd showed as HDD in the UI while smartctl
|
||||||
|
# was reporting it as SSD).
|
||||||
|
if not smart_data['_rotation_known']:
|
||||||
try:
|
try:
|
||||||
rotational_path = f"/sys/block/{disk_name}/queue/rotational"
|
rotational_path = f"/sys/block/{disk_name}/queue/rotational"
|
||||||
if os.path.exists(rotational_path):
|
if os.path.exists(rotational_path):
|
||||||
with open(rotational_path, 'r') as f:
|
with open(rotational_path, 'r') as f:
|
||||||
rotational = int(f.read().strip())
|
rotational = int(f.read().strip())
|
||||||
if rotational == 1:
|
if rotational == 1:
|
||||||
# Disk is rotational (HDD), use -1 to indicate "HDD but RPM unknown"
|
smart_data['rotation_rate'] = -1 # HDD, RPM unknown
|
||||||
smart_data['rotation_rate'] = -1
|
except Exception:
|
||||||
# If rotational == 0, it's an SSD, keep rotation_rate as 0
|
pass
|
||||||
except Exception as e:
|
smart_data.pop('_rotation_known', None)
|
||||||
pass # If we can't read the file, leave rotation_rate as is
|
|
||||||
|
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
|
|||||||
Reference in New Issue
Block a user