Add comprehensive sparkline chart support as an alternative to progress bars
for CPU, Memory, and Disk metrics across all tables.
Features:
- Toggle between bars/trends view modes (persisted to localStorage)
- 30-second sampling with 2-hour retention window using ring buffer
- Canvas-based rendering with shared requestAnimationFrame for efficiency
- Hover tooltips showing exact values and timestamps
- Threshold reference lines (warning/critical) for context
- localStorage persistence survives page refreshes (12-hour max age)
- Dynamic width adaptation to column size
- Namespaced resource IDs prevent collisions
- Lifecycle cleanup prevents memory leaks
Performance optimizations:
- Decoupled sampling from WebSocket handler (6x reduction in recording)
- O(1) ring buffer insertions (no array cloning)
- Batched canvas rendering (single rAF for all sparklines)
- Debounced localStorage writes
- Automatic pruning of removed resources
UI improvements:
- Consistent radio toggle styling matching other filters
- Fixed column widths prevent layout shift during toggle
- Fixed row heights prevent vertical size changes
- Sparklines fill available column width proportionally
After the initial fix, added multiple layers of reliability to ensure updates
ALWAYS auto-refresh, even in edge cases:
1. Fallback polling: GlobalUpdateProgressWatcher now polls /api/updates/status
every 5 seconds as a safety net in case WebSocket events are dropped, missed,
or the tab connects mid-update. This ensures tabs that join late or have
WebSocket issues still detect in-progress updates.
2. Manual reload button: Added "Reload Now" button in UpdateProgressModal that
appears after 5+ health check attempts during restart. Gives users an escape
hatch if auto-reload is delayed (slow DNS, reverse proxy issues, etc.).
3. Already protected: Modal close button only shows when update is complete,
preventing users from accidentally closing it mid-update.
These changes address all failure modes identified:
- Tabs without WebSocket: covered by polling fallback
- Tabs joining mid-update: covered by polling fallback
- Health check delays: covered by manual reload button
- User accidentally closing modal: already prevented
The combination of WebSocket events (primary), polling (fallback), health checks
(restart detection), and manual reload (escape hatch) should make this bulletproof.
Problem: When an update was triggered, only the tab that clicked "Apply Update"
would show the progress modal and auto-refresh after completion. Other open tabs
would remain on the old version indefinitely.
Root cause: The UpdateProgressModal was only shown when explicitly opened via the
UpdateBanner component. WebSocket already broadcasts update:progress events, but
no global listener existed to show the modal in all tabs.
Solution: Added GlobalUpdateProgressWatcher component in App.tsx that:
- Listens to WebSocket updateProgress events globally (in all tabs)
- Filters to only real update-in-progress states (downloading, verifying, extracting,
installing, restarting) to avoid false positives from routine update checks
- Auto-opens the progress modal when an update starts
- Allows manual dismissal after update completes
- Works independently of UpdateBanner visibility (e.g., when banner is dismissed)
The modal's existing health-check and auto-reload logic handles the page refresh
once the backend is healthy again.
- Add NOTIFICATION_AUDIT.md for system analysis
- Add NOTIFICATION_QUICK_REFERENCE.md for quick lookup
- Add NOTIFICATION_SYSTEM_MAP.md for architecture overview
- Fix tab panel missing rounded-tl corner when first tab is active
Related to #636
When authentication is not configured (hasAuth() returns false), the
Settings tab is now automatically hidden from the web interface. This
provides a cleaner monitoring-only view for unauthenticated deployments
where users only need to check the health of their environment.
The Settings icon beside the Alerts tab will only appear when
authentication is properly configured via PULSE_AUTH_USER/PASS,
API tokens, proxy auth, or OIDC.
Changes:
- Modified utilityTabs in App.tsx to conditionally include Settings
based on hasAuth() signal
- Updated CONFIGURATION.md to document this UI behavior
Simplifies the onboarding flow by removing verbose instructions and toggles, consolidating navigation elements, and cleaning up the settings interface. Improves the macOS host agent installer with better Keychain access control and launchd service management.
Windows Host Agent Enhancements:
- Implement native Windows service support using golang.org/x/sys/windows/svc
- Add Windows Event Log integration for troubleshooting
- Create professional PowerShell installation/uninstallation scripts
- Add process termination and retry logic to handle Windows file locking
- Register uninstall endpoint at /uninstall-host-agent.ps1
Host Agent UI Improvements:
- Add expandable drawer to Hosts page (click row to view details)
- Display system info, network interfaces, disks, and temperatures in cards
- Replace status badges with subtle colored indicators
- Remove redundant master-detail sidebar layout
- Add search filtering for hosts
Technical Details:
- service_windows.go: Windows service lifecycle management with graceful shutdown
- service_stub.go: Cross-platform compatibility for non-Windows builds
- install-host-agent.ps1: Full Windows installation with validation
- uninstall-host-agent.ps1: Clean removal with process termination and retries
- HostsOverview.tsx: Expandable row pattern matching Docker/Proxmox pages
Files Added:
- cmd/pulse-host-agent/service_windows.go
- cmd/pulse-host-agent/service_stub.go
- scripts/install-host-agent.ps1
- scripts/uninstall-host-agent.ps1
- frontend-modern/src/components/Hosts/HostsOverview.tsx
- frontend-modern/src/components/Hosts/HostsFilter.tsx
The Windows service now starts reliably with automatic restart on failure,
and the uninstall script handles file locking gracefully without requiring reboots.
Introduces granular permission scopes for API tokens (docker:report, docker:manage, host-agent:report, monitoring:read/write, settings:read/write) allowing tokens to be restricted to minimum required access. Legacy tokens default to full access until scopes are explicitly configured.
Adds standalone host agent for monitoring Linux, macOS, and Windows servers outside Proxmox/Docker estates. New Servers workspace in UI displays uptime, OS metadata, and capacity metrics from enrolled agents.
Includes comprehensive token management UI overhaul with scope presets, inline editing, and visual scope indicators.
Addresses user concern about technical debt: detection code exists only
to handle migration from SSH-in-container to proxy architecture, not to
serve functional purpose of the application.
Changes:
- Add PULSE_LEGACY_DETECTION env var to disable detection without redeployment
- Add explicit removal criteria: v5.0 or <1% detection rate for 30+ days
- Mark all detection code with "MIGRATION SCAFFOLDING" warnings
- Create MIGRATION_SCAFFOLDING.md to track temporary code across codebase
- Document removal instructions for when migration period ends
Backend:
- internal/api/router.go: detectLegacySSH() checks env var and has removal plan
- internal/api/types.go: HealthResponse fields documented as temporary
Frontend:
- src/components/LegacySSHBanner.tsx: Component marked with removal criteria
- src/App.tsx: Banner integration (will be removed with component)
This approach balances user safety during migration (auto-detection catches
rushed admins who skip changelogs) with long-term code cleanliness (explicit
removal plan prevents indefinite technical debt).