Configure how long dismissed alerts stay suppressed for each category.
Changes apply immediately to both existing and future dismissed alerts.
{loadingHealth ? (
setCustomValues(prev => ({ ...prev, [cat.key]: e.target.value }))}
placeholder="Hours"
/>
h
) : (
)}
{/* Notice for Permanent */}
{isPermanent && healthEditMode && (
Alerts for {cat.label} will be permanently suppressed when dismissed.
{cat.category === "temperature" && (
Critical CPU temperature alerts will still trigger for hardware safety.
)}
)}
{/* Notice for long duration (> 1 month) */}
{isLong && healthEditMode && (
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.
)}
{/* Remote Storage Exclusions */}
Remote Storage Exclusions
Exclude remote storages (PBS, NFS, CIFS, etc.) from health monitoring and notifications.
Use this for storages that are intentionally offline or have limited API access.
{loadingStorages ? (
) : remoteStorages.length === 0 ? (
No remote storages detected
PBS, NFS, CIFS, and other remote storages will appear here when configured
Health: When OFF, the storage won't trigger warnings/critical alerts in the Health Monitor.
Alerts: When OFF, no notifications will be sent for this storage.
)}
{/* Network Interface Exclusions */}
Network Interface Exclusions
Exclude network interfaces (bridges, bonds, physical NICs) from health monitoring and notifications.
Use this for interfaces that are intentionally disabled or unused.
{loadingInterfaces ? (
Health: When OFF, the interface won't trigger warnings/critical alerts in the Health Monitor.
Alerts: When OFF, no notifications will be sent for this interface.
)}
{/* Health Monitor Thresholds — placed above Notifications because the
values configured here drive what triggers the notifications below. */}
{/* Notification Settings */}
{/* Issue #195: snippets storage selector. Only renders when more
than one storage advertises content=snippets — on a typical
standalone host with just `local` there's nothing to choose,
so showing an empty selector would be noise. */}
{snippetsCandidates.length > 1 && (
Snippets storage
Where ProxMenux installs hookscripts (e.g. the GPU passthrough guard for VMs/LXCs).
Pick a shared storage in cluster setups so VMs and LXCs migrate cleanly between nodes —
local
is node-specific and breaks migration.
{snippetsSaving && (
Saving…
)}
Existing VMs/LXCs already configured with the previous storage keep working.
Only new GPU passthrough operations (or running "sync hookscripts" on the host)
will use the new selection.
)}
{/* 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
{/* Sprint 12B: count badge that doubles as the trigger
for the multi-select update modal. Only shown when
at least one tool has an available update. */}
{updatesAvailableCount > 0 && (
)}
{proxmenuxTools.map((tool) => {
const clickable = !!tool.has_source
const isDeprecated = !!tool.deprecated
// Sprint 12B: the card turns purple-tinted when an
// update is available — replaces the normal muted
// styling so the user sees at a glance which tools
// need attention. Click on the body still opens the
// source viewer; the small ArrowUpCircle on the right
// is the dedicated update trigger.
const hasUpdate = !!tool.has_update
const baseClasses = hasUpdate
? 'border-purple-500/40 bg-purple-500/10 hover:bg-purple-500/20 hover:border-purple-500/60'
: 'bg-muted/50 border-border hover:bg-muted hover:border-orange-500/40'
return (
{codeModal.functionName && {codeModal.functionName}()}
{codeModal.script && — {codeModal.script}}
{/* Sprint 12B v2: when an update is pending the user
sees `v1.0 → v1.1` so the source viewer matches
the badge in the card. When no update, just the
single installed version. */}
{codeModal.version && codeModal.availableVersion && codeModal.availableVersion !== codeModal.version ? (
v{codeModal.version} → v{codeModal.availableVersion}
) : codeModal.version ? (
v{codeModal.version}
) : null}
{codeModal.source && (
)}
{/* Body */}
{codeModal.loading ? (
) : codeModal.error ? (
{codeModal.error}
) : (
${highlightBash(codeModal.source)}` }}
/>
)}
)}
{/* Sprint 12B: multi-select Update modal — opened from the
"X updates" badge in the Optimizations card header. The user
ticks the tools they want to update, hits Update Selected,
and the wrapper script runs them all in one terminal session. */}
{updateModalOpen && (
setUpdateModalOpen(false)}>
e.stopPropagation()}
>
Available updates
{updatesAvailableCount} {updatesAvailableCount === 1 ? 'optimization' : 'optimizations'} can be updated to a newer version.
{/* Sprint 12B v2: every row is selectable. Legacy bool
entries (no recorded source) default to the auto flow
on update — the previous "pick source first" path
required an extra click for what is in practice always
the same answer. */}
{proxmenuxTools.filter(t => t.has_update).map(tool => {
const isSelected = selectedUpdates.has(tool.key)
return (
)
})}
{selectedUpdates.size} of {updatesAvailableCount} selected
)}
{/* Sprint 12B: terminal that runs the update_post_install_function.sh
wrapper. The wrapper sources the chosen flow script and invokes
one or many functions in sequence (FUNCTIONS_BATCH). On close
we refresh the tools list so the new versions show up. */}
{updateTerminal?.open && (
)}