"use client" import { useState, useEffect } from "react" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./ui/card" import { Wrench, Package, Ruler, HeartPulse, Cpu, MemoryStick, HardDrive, CircleDot, Network, Server, Settings2, FileText, RefreshCw, Shield, AlertTriangle, Info, Loader2, Check } from "lucide-react" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select" import { Input } from "./ui/input" import { Badge } from "./ui/badge" import { getNetworkUnit } from "../lib/format-network" import { fetchApi } from "../lib/api-config" interface SuppressionCategory { key: string label: string category: string icon: string hours: number } const SUPPRESSION_OPTIONS = [ { value: "24", label: "24 hours" }, { value: "72", label: "3 days" }, { value: "168", label: "1 week" }, { value: "720", label: "1 month" }, { value: "8760", label: "1 year" }, { value: "custom", label: "Custom" }, { value: "-1", label: "Permanent" }, ] const CATEGORY_ICONS: Record = { cpu: Cpu, memory: MemoryStick, storage: HardDrive, disk: CircleDot, network: Network, vms: Server, services: Settings2, logs: FileText, updates: RefreshCw, security: Shield, } interface ProxMenuxTool { key: string name: string enabled: boolean } export function Settings() { const [proxmenuxTools, setProxmenuxTools] = useState([]) const [loadingTools, setLoadingTools] = useState(true) const [networkUnitSettings, setNetworkUnitSettings] = useState<"Bytes" | "Bits">("Bytes") const [loadingUnitSettings, setLoadingUnitSettings] = useState(true) // Health Monitor suppression settings const [suppressionCategories, setSuppressionCategories] = useState([]) const [loadingHealth, setLoadingHealth] = useState(true) const [savingHealth, setSavingHealth] = useState(null) const [savedHealth, setSavedHealth] = useState(null) const [customValues, setCustomValues] = useState>({}) useEffect(() => { loadProxmenuxTools() getUnitsSettings() loadHealthSettings() }, []) const loadProxmenuxTools = async () => { try { const data = await fetchApi("/api/proxmenux/installed-tools") if (data.success) { setProxmenuxTools(data.installed_tools || []) } } catch (err) { console.error("Failed to load ProxMenux tools:", err) } finally { setLoadingTools(false) } } const changeNetworkUnit = (unit: string) => { const networkUnit = unit as "Bytes" | "Bits" localStorage.setItem("proxmenux-network-unit", networkUnit) setNetworkUnitSettings(networkUnit) window.dispatchEvent(new CustomEvent("networkUnitChanged", { detail: networkUnit })) window.dispatchEvent(new StorageEvent("storage", { key: "proxmenux-network-unit", newValue: networkUnit, url: window.location.href })) } const getUnitsSettings = () => { const networkUnit = getNetworkUnit() setNetworkUnitSettings(networkUnit) setLoadingUnitSettings(false) } const loadHealthSettings = async () => { try { const data = await fetchApi("/api/health/settings") if (data.categories) { setSuppressionCategories(data.categories) } } catch (err) { console.error("Failed to load health settings:", err) } finally { setLoadingHealth(false) } } const getSelectValue = (hours: number, key: string): string => { if (hours === -1) return "-1" const preset = SUPPRESSION_OPTIONS.find(o => o.value === String(hours)) if (preset && preset.value !== "custom") return String(hours) return "custom" } const handleSuppressionChange = async (settingKey: string, value: string) => { if (value === "custom") { // Show custom input -- don't save yet const current = suppressionCategories.find(c => c.key === settingKey) setCustomValues(prev => ({ ...prev, [settingKey]: String(current?.hours || 48) })) // Temporarily mark as custom in state setSuppressionCategories(prev => prev.map(c => c.key === settingKey ? { ...c, hours: -2 } : c) ) return } const hours = parseInt(value, 10) if (isNaN(hours)) return await saveSuppression(settingKey, hours) } const handleCustomSave = async (settingKey: string) => { const raw = customValues[settingKey] const hours = parseInt(raw, 10) if (isNaN(hours) || hours < 1) return await saveSuppression(settingKey, hours) } const saveSuppression = async (settingKey: string, hours: number) => { setSavingHealth(settingKey) try { await fetchApi("/api/health/settings", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ [settingKey]: String(hours) }), }) setSuppressionCategories(prev => prev.map(c => c.key === settingKey ? { ...c, hours } : c) ) // Remove from custom values setCustomValues(prev => { const next = { ...prev } delete next[settingKey] return next }) setSavedHealth(settingKey) setTimeout(() => setSavedHealth(null), 2000) } catch (err) { console.error("Failed to save health setting:", err) } finally { setSavingHealth(null) } } return (

Settings

Manage your dashboard preferences

{/* Network Units Settings */}
Network Units
Change how network traffic is displayed
{loadingUnitSettings ? (
) : (
Network Unit Display
)} {/* Health Monitor Settings */}
Health Monitor
Configure how long dismissed alerts stay suppressed for each category. When you dismiss a warning, it will not reappear until the suppression period expires.
{loadingHealth ? (
) : (
{/* Header */}
Category Suppression Duration
{/* Per-category rows */} {suppressionCategories.map((cat) => { const IconComp = CATEGORY_ICONS[cat.icon] || HeartPulse const isCustomMode = cat.hours === -2 || (cat.key in customValues) const isPermanent = cat.hours === -1 const isLong = cat.hours >= 720 && cat.hours !== -1 const selectVal = isCustomMode ? "custom" : getSelectValue(cat.hours, cat.key) return (
{cat.label} {savingHealth === cat.key && ( )} {savedHealth === cat.key && ( )}
{isCustomMode ? (
setCustomValues(prev => ({ ...prev, [cat.key]: e.target.value }))} placeholder="Hours" /> h
) : ( )}
{/* Warning for Permanent */} {isPermanent && (

Dismissed alerts for {cat.label} will never reappear. {cat.category === "temperature" && ( Note: Critical CPU temperature alerts will still trigger for hardware safety. )}

)} {/* Warning for long custom duration (> 1 month) */} {isLong && !isPermanent && (

Long suppression period. Dismissed alerts for this category will not reappear for an extended time.

)}
) })} {/* Info footer */}

These settings apply when you dismiss a warning from the Health Monitor. Critical CPU temperature alerts always trigger regardless of settings to protect your hardware.

)} {/* ProxMenux Optimizations */}
ProxMenux Optimizations
System optimizations and utilities installed via ProxMenux
{loadingTools ? (
) : proxmenuxTools.length === 0 ? (

No ProxMenux optimizations installed yet

Run ProxMenux to configure system optimizations

) : (
Installed Tools {proxmenuxTools.length} active
{proxmenuxTools.map((tool) => (
{tool.name}
))}
)}
) }