mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-04-30 11:26:23 +00:00
Update notification service
This commit is contained in:
@@ -147,9 +147,26 @@ export function HealthStatusModal({ open, onOpenChange, getApiUrl }: HealthStatu
|
|||||||
newOverallStatus = fullData.health?.overall || "OK"
|
newOverallStatus = fullData.health?.overall || "OK"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate infoCount: categories with INFO status + dismissed items
|
||||||
|
let infoCount = 0
|
||||||
|
if (response.ok) {
|
||||||
|
const fullData: FullHealthData = await response.clone().json()
|
||||||
|
// Count INFO categories
|
||||||
|
if (fullData.health?.details) {
|
||||||
|
CATEGORIES.forEach(({ key }) => {
|
||||||
|
const cat = fullData.health.details[key as keyof typeof fullData.health.details]
|
||||||
|
if (cat && cat.status?.toUpperCase() === "INFO") {
|
||||||
|
infoCount++
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// Add dismissed items count
|
||||||
|
infoCount += (fullData.dismissed || []).length
|
||||||
|
}
|
||||||
|
|
||||||
// Emit event with the FRESH data from the response, not the stale state
|
// Emit event with the FRESH data from the response, not the stale state
|
||||||
const event = new CustomEvent("healthStatusUpdated", {
|
const event = new CustomEvent("healthStatusUpdated", {
|
||||||
detail: { status: newOverallStatus },
|
detail: { status: newOverallStatus, infoCount },
|
||||||
})
|
})
|
||||||
window.dispatchEvent(event)
|
window.dispatchEvent(event)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import {
|
|||||||
SettingsIcon,
|
SettingsIcon,
|
||||||
Terminal,
|
Terminal,
|
||||||
ShieldCheck,
|
ShieldCheck,
|
||||||
|
Info,
|
||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
import Image from "next/image"
|
import Image from "next/image"
|
||||||
import { ThemeToggle } from "./theme-toggle"
|
import { ThemeToggle } from "./theme-toggle"
|
||||||
@@ -78,6 +79,7 @@ export function ProxmoxDashboard() {
|
|||||||
const [componentKey, setComponentKey] = useState(0)
|
const [componentKey, setComponentKey] = useState(0)
|
||||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
||||||
const [activeTab, setActiveTab] = useState("overview")
|
const [activeTab, setActiveTab] = useState("overview")
|
||||||
|
const [infoCount, setInfoCount] = useState(0)
|
||||||
const [showNavigation, setShowNavigation] = useState(true)
|
const [showNavigation, setShowNavigation] = useState(true)
|
||||||
const [lastScrollY, setLastScrollY] = useState(0)
|
const [lastScrollY, setLastScrollY] = useState(0)
|
||||||
const [showHealthModal, setShowHealthModal] = useState(false)
|
const [showHealthModal, setShowHealthModal] = useState(false)
|
||||||
@@ -158,7 +160,7 @@ export function ProxmoxDashboard() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleHealthStatusUpdate = (event: CustomEvent) => {
|
const handleHealthStatusUpdate = (event: CustomEvent) => {
|
||||||
const { status } = event.detail
|
const { status, infoCount: newInfoCount } = event.detail
|
||||||
let healthStatus: "healthy" | "warning" | "critical"
|
let healthStatus: "healthy" | "warning" | "critical"
|
||||||
|
|
||||||
if (status === "CRITICAL") {
|
if (status === "CRITICAL") {
|
||||||
@@ -173,6 +175,11 @@ export function ProxmoxDashboard() {
|
|||||||
...prev,
|
...prev,
|
||||||
status: healthStatus,
|
status: healthStatus,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
// Update info count (INFO categories + dismissed items)
|
||||||
|
if (typeof newInfoCount === "number") {
|
||||||
|
setInfoCount(newInfoCount)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("healthStatusUpdated", handleHealthStatusUpdate as EventListener)
|
window.addEventListener("healthStatusUpdated", handleHealthStatusUpdate as EventListener)
|
||||||
@@ -350,10 +357,17 @@ export function ProxmoxDashboard() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Badge variant="outline" className={statusColor}>
|
{systemStatus.status === "healthy" && infoCount > 0 ? (
|
||||||
{statusIcon}
|
<Badge variant="outline" className="bg-blue-500/10 text-blue-500 border-blue-500/20">
|
||||||
<span className="ml-1 capitalize">{systemStatus.status}</span>
|
<Info className="h-4 w-4" />
|
||||||
</Badge>
|
<span className="ml-1">{infoCount} info</span>
|
||||||
|
</Badge>
|
||||||
|
) : (
|
||||||
|
<Badge variant="outline" className={statusColor}>
|
||||||
|
{statusIcon}
|
||||||
|
<span className="ml-1 capitalize">{systemStatus.status}</span>
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="text-sm text-muted-foreground whitespace-nowrap">
|
<div className="text-sm text-muted-foreground whitespace-nowrap">
|
||||||
Uptime: {systemStatus.uptime || "N/A"}
|
Uptime: {systemStatus.uptime || "N/A"}
|
||||||
@@ -380,10 +394,17 @@ export function ProxmoxDashboard() {
|
|||||||
|
|
||||||
{/* Mobile Actions */}
|
{/* Mobile Actions */}
|
||||||
<div className="flex lg:hidden items-center gap-2">
|
<div className="flex lg:hidden items-center gap-2">
|
||||||
<Badge variant="outline" className={`${statusColor} text-xs px-2`}>
|
{systemStatus.status === "healthy" && infoCount > 0 ? (
|
||||||
{statusIcon}
|
<Badge variant="outline" className="bg-blue-500/10 text-blue-500 border-blue-500/20 text-xs px-2">
|
||||||
<span className="ml-1 capitalize hidden sm:inline">{systemStatus.status}</span>
|
<Info className="h-4 w-4" />
|
||||||
</Badge>
|
<span className="ml-1">{infoCount}</span>
|
||||||
|
</Badge>
|
||||||
|
) : (
|
||||||
|
<Badge variant="outline" className={`${statusColor} text-xs px-2`}>
|
||||||
|
{statusIcon}
|
||||||
|
<span className="ml-1 capitalize hidden sm:inline">{systemStatus.status}</span>
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
|
|||||||
@@ -1165,7 +1165,7 @@ export function StorageOverview() {
|
|||||||
|
|
||||||
{/* Disk Details Dialog */}
|
{/* Disk Details Dialog */}
|
||||||
<Dialog open={detailsOpen} onOpenChange={setDetailsOpen}>
|
<Dialog open={detailsOpen} onOpenChange={setDetailsOpen}>
|
||||||
<DialogContent className="max-w-2xl max-h-[90vh] overflow-y-auto">
|
<DialogContent className="max-w-2xl max-h-[80vh] sm:max-h-[85vh] overflow-y-auto">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle className="flex items-center gap-2">
|
<DialogTitle className="flex items-center gap-2">
|
||||||
{selectedDisk?.connection_type === 'usb' ? (
|
{selectedDisk?.connection_type === 'usb' ? (
|
||||||
|
|||||||
Reference in New Issue
Block a user