Restores v4.22.0-rc.6 wider page layout (110rem/1760px max-width) and implements responsive column widths for dashboard table. Name column and progress bars scale wider on xl screens while small columns (Type, VMID, I/O metrics) stay compact. This better utilizes screen space without creating wasteful empty gaps.
Add green checkmark icon to "No active alerts" empty state for better visual feedback. Separate mock and production data directories to prevent contamination. Mock mode now uses /opt/pulse/tmp/mock-data while production uses /etc/pulse. Update toggle script to dynamically set data directory based on mode.
Add debug logging to track prop changes and hasCustomGlobalDefaults checks in ResourceTable. Fix quick tips documentation to use 0 instead of -1 for disabling alerts. Add factory defaults and reset support for PBS Servers section. Reorder PBS section to appear before Guests section.
Corrected to match v4.21.0 exactly:
- Width: 95% (not 98%)
- Max-width: 80rem/1280px (not 120rem/1920px)
- No horizontal padding on shell
- Fixed 0.75rem (12px) panel padding
This restores the more condensed, narrower layout from v4.21.0.
Adjusted container width and padding to reduce whitespace:
- Increased max-width from 110rem (1760px) to 120rem (1920px)
- Reduced shell horizontal padding from 20-52px to 8-16px
- Reduced panel padding from 12-24px to 8-12px
Maintains responsive behavior while matching the condensed feel of v4.21.0.
When global defaults differ from factory defaults:
- Show blue "Custom" badge next to "Global Defaults" label
- Show red trash bin icon in Actions column
- Clicking trash bin resets to factory defaults
- Matches existing pattern used for individual resource rows
- Add tooltips to threshold inputs explaining -1 disables alerts
- Add help banner at top of thresholds page with usage tips
- Add FAQ entry documenting how to disable specific metrics
- Add reset to defaults button for each threshold table
- Define factory default constants for all resource types
- Reset button restores defaults and marks form as unsaved
The Alerts page was redirecting any path that didn't exactly match the expected tab path. This prevented threshold sub-tabs (/alerts/thresholds/proxmox, /docker, /mail-gateway) from working.
Modified the path validation logic to allow sub-paths under /alerts/thresholds/ to pass through without triggering redirects.
Implement proper URL-based navigation for threshold sub-tabs (Proxmox, Docker, Mail Gateway). This enables bookmarking specific tabs and provides browser history integration.
Changes:
- Add route-based tab state management with useLocation
- Implement tab navigation using useNavigate
- Auto-redirect /alerts/thresholds to /alerts/thresholds/proxmox
- Add cursor-pointer CSS to improve UX
Backend was loading system settings from disk on every HTTP request
causing massive log spam and UI responsiveness issues. System settings
are now cached at startup and reloaded only when updated.
Also fixed tab cursor showing text cursor instead of pointer cursor.
Changes:
- Cache system settings in Router struct with mutex protection
- Load settings once at startup instead of on every request
- Add reloadSystemSettings() method to refresh cache when settings change
- Hook up cache reload in config handlers after successful save
- Add cursor-pointer to tab CSS classes for proper hover cursor
Replaced 4 separate PMG threshold tables with a single unified table containing all 16 columns. Each PMG instance now appears once instead of four times, with a single global defaults row.
Changes:
- Consolidated Queue/Deferred, Hold/Oldest, Spam/Virus, and Growth tables into one
- Removed index() === 0 workaround for offline alerts column
- Added 16 PMG tooltips with clear warn vs crit differentiation
- Warning tooltips emphasize early detection and monitoring
- Critical tooltips emphasize urgency and required action
This improves UX by eliminating duplicate instance rows and making threshold severity levels immediately clear to operators.
Each of the 4 PMG threshold tables was showing its own offline alerts column, resulting in 4 duplicate toggles per instance. Now only the first table displays the offline alerts column since the setting is per-instance, not per-threshold-group.
Adds dedicated PMG sub-tab under Alerts → Configuration with comprehensive
threshold management for all 7 PMG alert types:
- Queue depth monitoring (total, deferred, hold)
- Message age tracking (oldest message warnings)
- Quarantine monitoring (spam/virus absolute thresholds)
- Quarantine growth detection (percentage and minimum thresholds)
ThresholdsTable.tsx changes:
- Add PMG tab to threshold table with 16 editable threshold columns
- Implement PMG column groups for organized display (4 groups of 4 columns)
- Add PMG global defaults with normalization and mapping
- Support per-instance threshold overrides
- Include connectivity toggle support
Alerts.tsx changes:
- Add PMGTab component with 4 organized sections using SettingsPanel
- Create pmgThresholds signal with default values matching backend
- Wire PMG threshold loading from backend config
- Include pmgDefaults in config save payload
- Add PMG to AlertTab type and tab navigation
- Render PMGTab following same pattern as other configuration tabs
Backend alert logic (already implemented in alerts.go) monitors:
- Offline detection (3-poll confirmation)
- Queue depths with per-node outlier detection
- Oldest message age tracking
- Quarantine backlog with growth rate detection
- Spam/virus rate anomaly detection with 24h baseline
Ensuring numeric values are parsed using a consistent locale.
Fixes an issue where printf failed under non-C locales (e.g. fr_FR) due to the use of . as a decimal separator.
Backend:
- Handle 'no releases found' error gracefully instead of returning 500
- Return proper response indicating no updates available for the channel
- Fixes the 500 error when checking for updates on development versions
Frontend:
- Detect when backend enters 'restarting' phase during updates
- Show 'Pulse is restarting...' message instead of getting stuck on 'Initializing...'
- Implement health check polling with exponential backoff (2s → 15s max)
- Auto-reload page when backend becomes healthy again
- Improve messaging: inform users page will reload automatically
This fixes the stuck update modal issue where users would see
'Initializing...' forever when the backend restarted during updates.
Closes all data leakage paths in the sanitized diagnostics export:
- Rebuild nodeStatus from sanitized nodes to prevent name leakage
- Sanitize storage entries (nodes arrays, nodeIds, instance, storage field)
- Sanitize activeAlerts (id, resourceId, resourceName, node, instance)
- Sanitize nested physicalDisks and vmDiskCheck data in nodes array
The sanitized export now properly redacts all sensitive data including
IP addresses, hostnames, node names, instance names, and storage names
while preserving the data structure for debugging purposes.
The Update History panel was never populated for Manager updates and
only works with InstallShAdapter (systemd deployments). For a home lab
tool, this adds unnecessary UI clutter.
Removed:
- Update History tab from Administration section
- UpdateHistoryPanel import and component usage
The UpdateHistoryPanel.tsx file remains for potential future use with
InstallShAdapter, but is no longer visible in the main Settings UI.
The update history infrastructure (history.go, UI panel) already exists
and is used by InstallShAdapter. However, for a home lab monitoring tool,
tracking every update in the Manager is overkill.
Removed:
- History field and initialization from Manager
- Event tracking in ApplyUpdate function
- Update history population on success/failure
The history.go file and UI panel remain for InstallShAdapter usage,
but the main Manager update path is now simpler and more focused.
Fixed 12 critical issues in the update system:
Critical bugs:
- Cache invalidation when channel auto-detected vs explicitly provided
- Data race on cache access (added proper RWMutex locking)
- Incorrect error handling when already on latest version
Security improvements:
- Command injection prevention with version string validation
- Symlink vulnerabilities in backup/restore (replaced cp with safe Go implementations)
- SHA256 checksum verification for downloads
- Improved backup completeness (now includes binary and VERSION file)
Quality improvements:
- Channel-keyed cache map instead of single cache value
- Update history tracking with event IDs and rollback support
- Cleanup of old temp directories (24+ hours)
- Proper resource cleanup with Close() method
- Auto-detect update channel from current version when config is empty
(RC users automatically get RC updates, stable users get stable)
- Add background update checker that runs on startup and hourly
- Add GetCachedUpdateInfo() method to return cached update info
- Update /api/version endpoint to include updateAvailable from cache
- Fixes issue where RC users on rc.4 weren't seeing rc.5 updates
This ensures RC testers continue receiving RC notifications while
stable users stay on the stable channel, all without explicit config.
Adds TestMemoryStatusEffectiveAvailable_RegressionIssue435 with 5 test scenarios
covering all memory calculation edge cases reported in GitHub issue #435:
1. Proxmox 8.x with 'available' field (most common)
2. Older Proxmox with 'avail' field
3. Derived calculation from free+buffers+cached
4. Real user case: 86% displayed when actual usage was 42%
5. Missing all cache fields (fallback behavior)
Tests verify EffectiveAvailable() correctly returns cache-aware memory values
and calculates realistic usage percentages that exclude reclaimable cache.
These tests ensure future changes don't regress the cache-aware behavior
that was fixed in v4.15.0-rc.3.
- Fix update history using hardcoded /var/lib/pulse instead of configured data dir
- Skip mock.env watching in Docker environments to avoid 'no such file' errors
Fixes issue #529
Update History Path:
- Modified NewUpdateHandlers to accept dataDir parameter
- Pass r.config.DataPath from router (honors PULSE_DATA_DIR=/data in Docker)
- Maintains backward compatibility with default /var/lib/pulse when empty
Mock Env Watcher:
- Check PULSE_DOCKER env var and skip mock.env watching if true
- Only watch /opt/pulse/mock.env if directory exists (not in containers)
- Guard all mock.env operations to prevent errors when path is empty
- Clean up log messages to only show mock_env_path when actually watching
- Strip trailing slash from PULSE_URL in install script to prevent double-slash URLs
- Add path normalization in router for defense-in-depth on public endpoint matching
- Fixes issue #528 where users copying URLs with trailing slashes got 401 errors
The install script now normalizes PULSE_URL with ${PULSE_URL%/} before concatenating
with /download/pulse-docker-agent, preventing https://example.com//download URLs.
The router normalization provides additional resilience for path matching, though the
existing path traversal check already blocks double slashes at ServeHTTP level.
This commit addresses 6 critical security and UX issues in Docker agent
token handling identified through code review:
**High Priority Fixes:**
1. Fix stale token in command preview - Changed DockerAgents to use
getInstallCommandTemplate() that always returns placeholder, allowing
CommandBuilder to handle all token substitution reactively. Command
preview now updates live as user types.
2. Fix misleading "multiple tokens" messaging - Updated token generation
modal to accurately reflect single-token backend model with red warning:
"This will immediately invalidate your existing token". Prevents operators
from unknowingly breaking active Docker agents.
3. Close proxy auth bypass vulnerability - Both HandleRegenerateAPIToken
and HandleValidateAPIToken now explicitly reject requests when proxy auth
is configured but validation fails (returns 401). Prevents unauthenticated
access when proxy auth is enabled.
**Medium Priority Fixes:**
4. Disable buttons when no stored token - "Use This Token" and "Copy" buttons
now properly disabled with contextual tooltips when browser hasn't saved
a token, eliminating confusing silent no-ops.
5. Improve frontend error handling - Token validation now distinguishes
between authentication errors (401/403), rate limiting (429), network
failures, and actual invalid tokens. No longer mislabels auth failures
as "invalid token".
**Low Priority Fixes:**
6. Add authentication to validate-token endpoint - Endpoint now requires
admin authentication (same as regenerate-token), preventing unauthenticated
token guessing oracle despite rate limiting.
**New Component:**
- CommandBuilder.tsx: Interactive command builder with live preview,
state-based visual cues, inline token generation, and validation
**Security Impact:**
- Closes unauthenticated validation surface
- Enforces proper proxy auth gating
- Prevents accidental exposure of security model
- Rate limiting maintained (10 attempts/min)
**UX Impact:**
- Clear, accurate error messages
- Live-updating command preview
- Contextual token management
- Disabled states prevent confusion
Reviewed and verified by both Claude Code and Codex with no regressions found.
- Add missing postfix queue endpoint to PMG test mock server
- Add 'pmg' to DiscoveredServer type in Settings.tsx
- Fix potentially undefined object in UpdateBanner.tsx
- Remove unused imports and variables in Dashboard.tsx, MailGateway.tsx, NodeSummaryTable.tsx
The "View History" button in UpdateProgressModal now properly navigates
to /settings/updates instead of just closing the modal.
This completes the update flow UX - users can now seamlessly transition
from update completion to viewing the full audit log.
Implements full update UX based on adapter system:
Components:
- UpdateConfirmationModal: Shows version jump, prerequisites, root warning, acknowledgement checkbox
- UpdateProgressModal: Real-time polling of /api/updates/status with progress bar and stage display
- UpdateHistoryPanel: Settings tab showing full audit log with filtering and status badges
- UpdateBanner: Enhanced with Apply button for automated deployments, manual instructions accordion with copy buttons
Features:
- Automated deployments: Single-click "Apply Update" button launches confirmation modal
- Manual deployments: Displays instruction steps with individual copy buttons
- Progress tracking: Polls status every 2s during updates, shows success/error states
- History: Dedicated Settings → Update History tab with filterable table
- Banner integration: Shows "Manual steps required" badge for non-automated deployments
All components use proper SolidJS signals and effects, fully typed with TypeScript.
Add TypeScript interfaces and API methods for new update system:
**New Types:**
- UpdatePlan: Deployment-specific update plan with canAutoUpdate flag
- UpdateHistoryEntry: Complete audit log entry with all metadata
**New API Methods:**
- getUpdatePlan(version, channel?) - Get deployment-specific update plan
- getUpdateHistory(limit?, status?) - List update history with filters
- getUpdateHistoryEntry(eventId) - Get specific history entry details
These types match the backend Go structs and enable frontend
integration with the adapter-based update system.
Next: Implement UI components (confirmation modal, progress modal,
update banner enhancements, settings history panel).
Wire up the adapter-based update system to HTTP API:
**Enhanced UpdateHandlers:**
- Initialize UpdateHistory and UpdaterRegistry
- Register all deployment adapters (systemd, proxmoxve, docker, aur)
- Handlers now have access to history and updater registry
**New API Endpoints:**
- GET /api/updates/plan?version=X - Get update plan for deployment
* Returns canAutoUpdate, instructions, prerequisites, estimated time
* Deployment-specific based on detected type
- GET /api/updates/history?limit=N&status=X - List update history
* Supports filtering by status (success/failed/in_progress)
* Returns audit log entries with full metadata
- GET /api/updates/history/entry?id=X - Get specific history entry
* Retrieve detailed information about past update
**Existing Endpoints Still Work:**
- GET /api/updates/check - Check for available updates
- POST /api/updates/apply - Apply update (legacy manager)
- GET /api/updates/status - Get current update status
The system now supports both:
- Legacy update flow (existing install.sh wrapper in manager.go)
- New adapter-based flow (prepared for frontend integration)
Next: Frontend components to consume new endpoints.
Add infrastructure for deployment-agnostic update management:
**Update History (Audit Log):**
- JSONL-based audit log (/var/lib/pulse/update-history.jsonl)
- Tracks all update attempts with full metadata
- In-memory cache for fast queries
- Schema designed for future DB migration
**Updater Interface:**
- Defines contract for deployment-specific update logic
- SupportsApply(), PrepareUpdate(), Execute(), Rollback()
- Registry pattern for managing multiple adapters
- Progress callbacks for real-time UI updates
**Adapters Implemented:**
- InstallShAdapter: Wraps install.sh (systemd/LXC)
* Full automation support
* Captures stdout/stderr to log files
* Parses backup paths from output
* Maintains install.sh as single source of truth
- DockerUpdater: Instruction-only (manual)
- AURUpdater: Instruction-only (package manager)
Key design decisions:
- install.sh remains unchanged (backward compatible)
- All update mechanisms funnel through adapters
- Audit log records all updates (manual + automated)
- Thin wrapper approach - no logic duplication
Next: Wire up API endpoints and frontend integration.
Implement smart update checking that shows appropriate updates based on user's current version:
- RC users now see both newer RC releases AND newer stable releases
- Stable users continue to see only stable releases (RCs filtered out)
- Both channels use version-aware filtering (only show updates > current version)
Key changes:
- Modified getLatestReleaseForChannel to accept currentVer parameter
- Removed /releases/latest shortcut; both channels now fetch all releases
- RC channel tracks both newest RC and newest stable, returns highest
- Stable channel filters prereleases and returns first stable > currentVer
- Added comprehensive test suite with 15 test cases
Respects semver ordering where 4.22.0 > 4.22.0-rc.3 per RFC.
Consulted with Codex for architectural direction.
Remove PMG instances from the Overview (dashboard) page to keep it
focused solely on PVE resources (VMs and containers). This provides
better separation of concerns, with each Proxmox product type having
its dedicated view:
- Overview tab: PVE nodes, VMs, and containers
- Mail Gateway tab: PMG instances with detailed metrics
- Storage tab: Storage resources
- Backups tab: PBS and backup data
Changes:
- Remove pmgInstances prop from NodeSummaryTable component
- Remove PMG type checks and rendering logic from node table
- Update UnifiedNodeSelector to match new interface
- Clean up PMG-related imports and type definitions
Add comprehensive PMG monitoring with mail statistics, queue depth tracking,
spam distribution analysis, and quarantine monitoring. Includes full discovery
support and UI consistency improvements across all Proxmox products.
Backend:
- Add pkg/pmg package with complete API client for PMG operations
- Implement mail statistics collection (inbound/outbound, spam, virus, bounces)
- Add queue depth monitoring (active, deferred, hold, incoming queues)
- Support spam score distribution and quarantine totals
- Add PMG-specific discovery logic to differentiate from PVE on port 8006
- Extend mock data generator with realistic PMG instances and metrics
- Add PMG node configuration support in config system
Frontend:
- Create MailGateway.tsx component with detailed PMG dashboard
- Display mail flow statistics with time-series charts
- Show queue depth with color-coded warnings (>50 messages or >30min age)
- Add spam distribution histogram and quarantine status
- Support cluster node status with individual queue monitoring
- Add PMG to network discovery with purple branding and mail icon
- Implement conditional navigation (hide PMG tab when no instances configured)
- Standardize discovery UI controls across PVE/PBS/PMG settings pages
API:
- Add /api/config/pmg endpoints for node configuration
- Support PMG-specific monitoring toggles (mail stats, queues, quarantine)
- Extend system settings with PMG configuration options
Discovery:
- Detect PMG vs PVE on shared port 8006 using /api2/json/statistics/mail endpoint
- Return 'pmg' type for mail gateway servers in discovery results
- Update DiscoveryModal to display PMG servers with appropriate styling
This completes ecosystem monitoring support for all three Proxmox products:
Proxmox VE, Proxmox Backup Server, and Proxmox Mail Gateway.