Implement tri-state offline alert configuration (Off/Warning/Critical) for VMs, containers, and Docker containers with individual severity overrides and visual badge breakdown in alerts tab.
Changes:
- Add poweredOffSeverity field to resource models and override types
- Implement tri-state buttons (Off/Warn/Crit) in ResourceTable
- Add separate critical/warning badge counts in alerts tab
- Support per-resource severity overrides with proper defaults
- Include alert delay configuration column in thresholds table
- Update backend to honor per-resource severity levels
- Add proper state persistence in raw override config
activeAlerts from websocket store is a SolidJS Store proxy, not a plain
Record. Spread it to plain object before passing to getAlertStyles to
prevent 't is not a function' error.
Fix 'Cannot read properties of undefined (reading some)' error by
adding safety check before calling .some() on groupedContainers.
The error occurred when groupedContainers() returned undefined in edge
cases, causing .some() to fail. Now explicitly checking for truthy
value and non-empty array before calling .some().
Create DockerRoute component that properly accesses activeAlerts from
WebSocketContext instead of trying to use a non-existent signal.
The issue was that activeAlerts is provided by useWebSocket() as a
Record<string, Alert> store, not available directly in App component
scope. Dashboard and other components use useWebSocket() hook to access
it properly.
Changes:
- Add DockerRoute wrapper component that uses WebSocketContext
- Extract activeAlerts from wsContext along with state
- Pass activeAlerts Record to DockerHosts component correctly
Add null-safety checks and default values to prevent 'Cannot read
properties of undefined' error when accessing alertStyles.
Changes:
- Add comprehensive defaultAlertStyles object with all required properties
- Wrap getAlertStyles call in try-catch with fallback to defaults
- Add optional chaining (?.) when accessing alertStyles properties
- Extract severity to variable before use to avoid repeated null checks
Match the visual alert highlighting used in the Proxmox guest table
(GuestRow) for Docker containers. When a Docker container has an active
unacknowledged alert, the row now displays:
- Colored background (red for critical, yellow for warning)
- 4px colored left border (inset box-shadow)
- Matching severity-based styling
Changes:
- Import getAlertStyles utility and Alert type in DockerHosts component
- Add activeAlerts prop to DockerHostsProps interface
- Add alert styling logic to DockerContainerRow (showAlertHighlight,
alertAccentColor, rowStyle with box-shadow)
- Pass activeAlerts from App.tsx to DockerHosts component
- Thread activeAlerts prop through to all DockerContainerRow instances
This commit addresses issues reported in #470 related to alert duration
tracking, time threshold configuration, and email notification debugging.
Backend Changes:
- Preserve alert StartTime in preserveAlertState() to maintain accurate
duration calculations across monitoring cycles
- Add debug logging to track alert creation times and duration preservation
- Add comprehensive logging to notification pipeline for email delivery
tracking including SMTP config, cooldown status, and delivery attempts
Frontend Changes:
- Add TimeThresholdSettings component to display and configure per-resource-type
alert delays (VMs/Containers, Nodes, Storage, PBS)
- Integrate time threshold UI into Thresholds tab with clear labels explaining
"seconds above threshold before triggering"
- Add informational help text about how alert delays work
Related to #470
Issues fixed:
- Temperature collection was using node name instead of actual hostname/IP
- SSH warnings were contaminating JSON output from sensors command
- ClusterEndpoint IPs were not being utilized for SSH connections
Changes:
1. Use ClusterEndpoint IP/Host for cluster nodes instead of node name
2. Use Host URL from config for standalone nodes
3. Fallback to node name for simple DNS/hosts setups
4. Use cmd.Output() instead of cmd.CombinedOutput() to avoid SSH stderr warnings
This resolves issue #101 where users with FQDNs (e.g., pve2.some.domain)
couldn't collect temperatures, and handles duplicate node names across
multiple Proxmox instances.
Physical disk monitoring is now disabled by default with a clear UI toggle for users who want to enable it.
**The Problem:**
Pulse was polling `/nodes/{node}/disks/list` every 10 seconds to check physical disk SMART data, causing idle HDDs to constantly spin up.
**The Solution:**
- Physical disk monitoring OFF by default (no HDD spin-up)
- New UI toggle in node edit modal under "Advanced monitoring"
- Clear warning: "This will cause HDDs to spin up from standby"
- When enabled, polls every 5 minutes (configurable via PhysicalDiskPollingMinutes)
- Storage pool monitoring (ZFS/LVM) still active and catches most disk failures
**UI Implementation:**
- Added monitorPhysicalDisks checkbox to PVE node settings
- Help text explains HDD spin-up behavior
- Field properly saved/loaded when editing nodes
- Only shown for PVE nodes (not PBS)
**Backend:**
- MonitorPhysicalDisks defaults to false
- Configurable polling interval (default 5 min)
- Interval-based polling with per-instance tracking
- Skips polls when interval hasn't elapsed
Users can now make an informed choice about disk monitoring vs. HDD power management.
Fixes#514
**Issues Fixed:**
1. **Cooldown period not enforced** - Added LastNotified tracking and shouldNotifyAfterCooldown()
- New alerts are notified immediately and LastNotified is set
- Existing alerts re-notify only after cooldown period passes
- Critical escalations bypass cooldown for immediate notification
- Cooldown check respects quiet hours configuration
2. **No re-notification for existing alerts** - Alert updates now check cooldown
- Alerts stuck above threshold now re-notify after cooldown expires
- Level escalation to critical triggers immediate re-notification
- Prevents alert fatigue while ensuring critical issues aren't missed
3. **alertRateLimit memory leak** - Added cleanup in Cleanup() method
- Entries older than 1 hour are removed every 10 minutes
- Empty entries are deleted entirely to prevent map growth
- Prevents unbounded memory consumption
4. **Pending alerts not cleared on threshold disable** - Fixed in reevaluateActiveAlertsLocked()
- When threshold is disabled/removed, pending alerts are now cleared
- Prevents phantom pending state for disabled metrics
- Logged for debugging
**Implementation Details:**
- Added LastNotified field to Alert struct with proper cloning
- Cooldown enforced separately from rate limiting (MaxAlertsHour)
- Quiet hours verified working correctly (non-critical only)
- All changes maintain thread safety with existing mutex patterns
- Remove checkedClass, uncheckedClass, disabledClass, and knobClass props
- Make toggle colors consistent and non-overridable across the entire app
- Prevents inconsistent styling from prop overrides
- Enforces single source of truth for toggle appearance
- Breaking change but no usage found in codebase
- Remove checkedClass/uncheckedClass overrides from all resource row toggles
- Remove custom disabledClass overrides to use consistent defaults
- All toggles now use the improved blue/gray color scheme from TogglePrimitive
- Ensures consistent toggle styling across all table rows
- Change background from bright blue to subtle gray for less visual weight
- Use standard border instead of thick blue border-b-2
- Remove custom red/green toggle colors to use default blue/gray
- Update label from bold blue to semibold gray for consistency
- Increase input text size from text-xs to text-sm for readability
- Add proper focus states with blue ring on inputs
- Add explicit text color for better contrast
- Create shared StatusBadge component with consistent styling
- Replace inline badge implementations in ResourceTable with shared component
- Update badge colors: blue for enabled (not green), gray for disabled (not red)
- Change from rounded-full to rounded-md for more refined appearance
- Remove borders and reduce font weight for cleaner look
- Reduces ~60 lines of duplicate code
- Add header with title and description to schedule tab for better context
- Improve reset button styling with larger text, proper shadow, and better placement
- Change grid breakpoint from lg to xl for better spacing
- Fix iOS toggle to use proper blue/gray colors instead of red/green
- Improve toggle knob positioning using padding instead of absolute positioning
- Add proper shadow and smooth animations to toggle
- Remove borders from toggle for cleaner iOS appearance
- Show red badge with count of unacknowledged alerts on Alerts tab
- Display green checkmark when no unacknowledged alerts exist
- Sync activeAlerts array to state for reactive badge updates
- Filter badge count to only show unacknowledged alerts
The badge provides immediate visibility of pending alerts without
needing to navigate to the Alerts page.
Display the number of active alerts in a red badge on the Alerts tab to give
users immediate visibility of pending issues without needing to navigate to
the Alerts page.
- Add HandleDockerHostRemoved to properly clean up all alerts and tracking
when Docker hosts are removed from config
- Implement pruneStaleDockerAlerts to automatically clear orphaned Docker
alerts during sync cycles
- Clean up restart tracking and exit code maps in addition to state confirmations
- Add comprehensive test coverage for Docker host removal cleanup
- Improve email provider select layout with consistent styling and instruction boxes
- Fix RemoveDockerHost to handle missing hosts gracefully and still clear alerts