From d927b462b618c562a9a213f653bed3e1d0a8d61e Mon Sep 17 00:00:00 2001
From: MacRimi
Date: Thu, 5 Mar 2026 20:44:51 +0100
Subject: [PATCH] Update notification service
---
AppImage/components/storage-overview.tsx | 175 ++++++++++++++++++++++-
AppImage/scripts/flask_server.py | 67 ++++++++-
AppImage/scripts/health_monitor.py | 47 +++++-
AppImage/scripts/health_persistence.py | 45 ++++++
AppImage/scripts/notification_events.py | 10 ++
5 files changed, 329 insertions(+), 15 deletions(-)
diff --git a/AppImage/components/storage-overview.tsx b/AppImage/components/storage-overview.tsx
index 69edecb4..9bbb5602 100644
--- a/AppImage/components/storage-overview.tsx
+++ b/AppImage/components/storage-overview.tsx
@@ -2,7 +2,7 @@
import { useEffect, useState } from "react"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
-import { HardDrive, Database, AlertTriangle, CheckCircle2, XCircle, Square, Thermometer, Archive, Info, Clock } from "lucide-react"
+import { HardDrive, Database, AlertTriangle, CheckCircle2, XCircle, Square, Thermometer, Archive, Info, Clock, Usb } from "lucide-react"
import { Badge } from "@/components/ui/badge"
import { Progress } from "@/components/ui/progress"
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
@@ -42,6 +42,8 @@ interface DiskInfo {
error_type?: string // 'io' | 'filesystem'
}
observations_count?: number
+ connection_type?: 'usb' | 'sata' | 'nvme' | 'sas' | 'internal' | 'unknown'
+ removable?: boolean
}
interface DiskObservation {
@@ -421,21 +423,26 @@ export function StorageOverview() {
const getDiskTypesBreakdown = () => {
if (!storageData || !storageData.disks) {
- return { nvme: 0, ssd: 0, hdd: 0 }
+ return { nvme: 0, ssd: 0, hdd: 0, usb: 0 }
}
let nvme = 0
let ssd = 0
let hdd = 0
+ let usb = 0
storageData.disks.forEach((disk) => {
+ if (disk.connection_type === 'usb') {
+ usb++
+ return
+ }
const diskType = getDiskType(disk.name, disk.rotation_rate)
if (diskType === "NVMe") nvme++
else if (diskType === "SSD") ssd++
else if (diskType === "HDD") hdd++
})
- return { nvme, ssd, hdd }
+ return { nvme, ssd, hdd, usb }
}
const getWearProgressColor = (wearPercent: number): string => {
@@ -623,6 +630,12 @@ export function StorageOverview() {
{diskTypesBreakdown.hdd} HDD
>
)}
+ {diskTypesBreakdown.usb > 0 && (
+ <>
+ {(diskTypesBreakdown.nvme > 0 || diskTypesBreakdown.ssd > 0 || diskTypesBreakdown.hdd > 0) && ", "}
+ {diskTypesBreakdown.usb} USB
+ >
+ )}
{diskHealthBreakdown.normal} normal
@@ -780,7 +793,7 @@ export function StorageOverview() {
)}
- {/* Physical Disks */}
+ {/* Physical Disks (internal only) */}
@@ -790,7 +803,7 @@ export function StorageOverview() {
- {storageData.disks.map((disk) => (
+ {storageData.disks.filter(d => d.connection_type !== 'usb').map((disk) => (
+ {/* External Storage (USB) */}
+ {storageData.disks.filter(d => d.connection_type === 'usb').length > 0 && (
+
+
+
+
+ External Storage (USB)
+
+
+
+
+ {storageData.disks.filter(d => d.connection_type === 'usb').map((disk) => (
+
+ {/* Mobile card */}
+
handleDiskClick(disk)}
+ >
+
+
+
+
/dev/{disk.name}
+ USB
+
+
+ {disk.model && disk.model !== "Unknown" && (
+
{disk.model}
+ )}
+
+ {disk.temperature > 0 && (
+
+
+
+ {disk.temperature}°C
+
+
+ )}
+ {getHealthBadge(disk.health)}
+ {disk.observations_count && disk.observations_count > 0 && (
+
+
+ {disk.observations_count}
+
+ )}
+
+
+
+
+
+ {/* Desktop card */}
+
handleDiskClick(disk)}
+ >
+
+
+
+
/dev/{disk.name}
+ USB
+
+
+ {disk.temperature > 0 && (
+
+
+
+ {disk.temperature}°C
+
+
+ )}
+ {getHealthBadge(disk.health)}
+ {disk.observations_count && disk.observations_count > 0 && (
+
+
+ {disk.observations_count}
+
+ )}
+
+
+ {disk.model && disk.model !== "Unknown" && (
+
{disk.model}
+ )}
+
+ {disk.io_errors && disk.io_errors.count > 0 && (
+
+
+
+ {disk.io_errors.error_type === 'filesystem' ? (
+ <>
+
Filesystem corruption detected
+ {disk.io_errors.reason && (
+
{disk.io_errors.reason}
+ )}
+ >
+ ) : (
+ <>
+
{disk.io_errors.count} I/O error{disk.io_errors.count !== 1 ? 's' : ''} in 5 min
+ {disk.io_errors.sample && (
+
{disk.io_errors.sample}
+ )}
+ >
+ )}
+
+
+ )}
+
+
+ {disk.size_formatted && (
+
+
Size
+
{disk.size_formatted}
+
+ )}
+ {disk.smart_status && disk.smart_status !== "unknown" && (
+
+
SMART Status
+
{disk.smart_status}
+
+ )}
+ {disk.power_on_hours !== undefined && disk.power_on_hours > 0 && (
+
+
Power On Time
+
{formatHours(disk.power_on_hours)}
+
+ )}
+ {disk.serial && disk.serial !== "Unknown" && (
+
+
Serial
+
{disk.serial}
+
+ )}
+
+
+
+ ))}
+
+
+
+ )}
+
{/* Disk Details Dialog */}