The Grouped/List toggle buttons in DockerFilter were updating the
external groupingMode state, but DockerUnifiedTable had its own
internal sortKey state for determining whether to show grouped vs
flat view. These two states were completely disconnected.
Added groupingMode prop to DockerUnifiedTable and a createEffect to
sync the external state with the internal sort state.
Fixes#1100
The "New conversation" button wasn't working because the component's
local messages signal was only initialized from the store on mount,
not reactively synced. When newConversation() cleared the store's
messages, the component didn't update.
Added a createEffect that tracks sessionId changes and syncs messages
from the store to the local state, fixing the button.
Fixes#1097
- Add SAML session fields (ProviderID, NameID, SessionIndex) to
SessionData and sessionPersisted structs for persistence
- Add CreateSAMLSession method to store SAML-authenticated sessions
- Add GetSAMLSessionInfo method to retrieve SAML session data
- Update establishSAMLSession to properly store SAML info instead
of delegating to OIDC session creation
- Implement getSAMLSessionInfo to retrieve session info for SLO
This enables proper SAML Single Logout by storing the NameID and
SessionIndex from the SAML assertion, which are required to construct
valid LogoutRequest messages to the IdP.
- Add approval store for tracking AI-suggested changes
- Implement SQLite-backed persistence for approvals
- Add dry-run simulator for testing AI fixes safely
- Support simulated execution with rollback capability
The previous commit fixed namespace disambiguation for backup alerts,
but the Overview display uses SyncGuestBackupTimes to populate backup
timestamps on VMs/Containers. This commit extends the same namespace
matching logic to that function.
Also tightened the matching algorithm to use suffix matching instead
of substring matching, preventing false positives like "pve" matching
"pve-nat".
When multiple PVE instances have VMs with overlapping VMIDs, PBS backups
were being matched to the wrong VM because the code would just use the
first matching guest. Now when a PBS backup has a namespace, it attempts
to match that namespace to the PVE instance name to find the correct VM.
This helps users who have separate PBS instances backing up different
PVE clusters with namespaces like "pve1", "nat", etc.
When running Docker inside an LXC container, gopsutil can read the
Total memory (from cgroup limits) and Free memory correctly, but
returns 0 for Used memory. This caused the display to show "0B / 7GB"
even though memory was being used.
Added a fallback that calculates Used = Total - Free when Used is 0
but Total and Free are valid. This completes the fallback chain for
Docker-in-LXC memory reporting.
Fixes#1075
- Add freebsd-amd64 and freebsd-arm64 to normalizeUnifiedAgentArch()
so the download endpoint serves FreeBSD binaries when requested
- Add FreeBSD/pfSense/OPNsense platform option to agent setup UI
with note about bash installation requirement
- Add FreeBSD test cases to unified_agent_test.go
Fixes installation on pfSense/OPNsense where users were getting 404
errors because the backend didn't recognize the freebsd-amd64 arch
parameter from install.sh.
Fixes#1091 - addresses all three documentation issues reported:
1. Binary path: Changed from /usr/local/bin/pulse-agent (which doesn't
exist in the main image) to /opt/pulse/bin/pulse-agent-linux-amd64
2. PULSE_AGENT_ID: Added to example and documented why it's required
for DaemonSets (prevents token conflicts when all pods share one
API token)
3. Resource visibility flags: Added PULSE_KUBE_INCLUDE_ALL_PODS and
PULSE_KUBE_INCLUDE_ALL_DEPLOYMENTS to example, with explanation
of the default behavior (show only problematic resources)
Also added tolerations, resource requests/limits, and ARM64 note.
The Mattermost webhook template was added to the backend (d1979552)
but the frontend service dropdown wasn't updated, so users couldn't
select Mattermost as a service type.
Adds mattermost to:
- serviceName mapping
- service selection array
- service description ternary
Fixes#1084
Kiosk mode (?kiosk=1) now hides the filter panel on all main views:
- Proxmox dashboard (already supported)
- Docker hosts page (added)
- Hosts overview page (added)
This ensures a clean display when using token auth for dashboard/kiosk
displays without the search and filter controls visible.
Follow-up fix for #1055
Add a dedicated Mattermost webhook template that uses Markdown formatting
in the text field. Unlike Slack (which supports blocks), Mattermost only
renders the "text" field, so this template includes:
- Emoji indicators for alert severity (🚨 critical, ⚠️ warning, ℹ️ info)
- Bold resource name and node
- Markdown table with all alert details
- Link to view alert in Pulse
This provides much more context than the previous Slack template's
fallback text which only showed "Pulse Alert: Critical - <HOSTNAME>".
Addresses #1084
Previously, kiosk mode (?kiosk=1) was only read from URL params on each
render. When navigating to different sections or refreshing, the kiosk
param was lost and the filter panel would reappear.
Now kiosk mode is persisted to sessionStorage when detected from URL,
similar to how API tokens are handled. This makes it survive:
- Navigation between dashboard sections (Docker, Ceph, etc.)
- Page refreshes
- The URL cleanup that removes the token parameter
To exit kiosk mode, users can either:
- Close the browser tab (clears sessionStorage)
- Navigate to the URL with ?kiosk=false
Fixes follow-up bug reported in #1055
Previously, when some cluster endpoints were unreachable (e.g., backup
nodes intentionally offline), the cluster was marked as "degraded" even
though the Proxmox cluster itself was healthy and had quorum.
Now the connection health check queries the Proxmox cluster's actual
quorum status. A cluster is only marked "degraded" if it has lost
quorum (not enough votes for consensus), which is the actual indicator
of cluster instability.
This means:
- Cluster with quorum + some nodes offline = "healthy"
- Cluster without quorum = "degraded" (warning)
- All endpoints down = "error"
Fixes#1085
SolidJS components only run once - early returns based on signals don't
re-render when those signals change. The license check spinner was
getting stuck because checkingLicense() was evaluated once at mount
time, and even though setCheckingLicense(false) was called after the
API response, the component didn't re-render.
Converted early returns to nested <Show> components which properly track
signal changes and update the UI when checkingLicense becomes false.
Fixes#1076
When multiple PVE nodes have the same hostname (e.g., both named "pve"),
auto-linking would incorrectly link all host agents to the first matching
node, causing temperature and sensor data to be mixed/duplicated.
Changes:
- findLinkedProxmoxEntity now detects hostname collisions and refuses
to auto-link, logging a warning instead
- Added manual link API endpoint (POST /api/agents/host/link) so users
can explicitly link agents to the correct nodes
- Added State.LinkHostAgentToNode for bidirectional manual linking
Fixes#1081
The previous fix (4ff9e58c) added a fallback for TotalMemoryBytes in
the agent when Docker's info.MemTotal returns 0 in LXC environments.
However, the server was not using TotalMemoryBytes to populate the
memory.Total field - it only used gopsutil's Memory.TotalBytes.
When gopsutil also fails to read memory in the LXC container, the
frontend would see memory.Total=0 and wouldn't fall back to
totalMemoryBytes due to JavaScript's nullish coalescing (??) only
triggering on null/undefined, not on 0.
This fix ensures the server uses TotalMemoryBytes as a fallback for
memory.Total when gopsutil returns 0, providing a complete fix chain:
1. Agent: Falls back to gopsutil when Docker returns 0
2. Server: Falls back to TotalMemoryBytes when gopsutil returns 0
Fixes#1075
Previous LLM sessions incorrectly inserted fake URLs (pulse.sh/pro and
yourpulse.io/pro) for the Pro upgrade links. Neither domain exists.
Replaced all 34 instances with the correct URL: https://pulserelay.pro/Fixes#1077
Tables in Settings → Agents were not expanding to fill the container
width when full-width mode was enabled. Added `w-full` class to all
tables (Managed Agents, Kubernetes Clusters, and removed host tables)
so they properly expand in full-width layouts.
Fixes#1080
When Docker daemon runs inside an LXC container, it may report 0 for
MemTotal because it can't read the cgroup memory limits correctly.
This caused the UI to show "0B / 7GB" and trigger false alerts with
overflow percentages (214748364799.6%).
The fix checks if Docker's info.MemTotal is 0 and falls back to
gopsutil's /proc/meminfo reading (snapshot.Memory.TotalBytes) which
works correctly in LXC environments.
Fixes#1075
The /api/license/features endpoint was only returning AI and agent
profile features, but was missing Team & Compliance features:
- sso (basic SSO/OIDC)
- advanced_sso (SAML, multi-provider)
- rbac (role-based access control)
- audit_logging (enterprise audit logs)
- advanced_reporting (PDF/CSV reports)
This caused Pro users to see "Upgrade to Pro" buttons on SSO, Roles,
and Audit Log panels even though their license included these features.
Fixes#1077
Previously, Docker environments would skip update checks entirely and
always show "running latest version". Now Docker users will see when
a new version is available (though the update mechanism is still
docker pull, not the automatic updater).
Fixes#1074
When visiting Pulse with ?token=xxx, the frontend now:
1. Extracts the token from the URL
2. Stores it in sessionStorage for subsequent requests
3. Removes it from the URL for security (browser history)
This enables kiosk/dashboard mode via URL tokens without needing
cookie persistence.
Fixes#1055
When cluster node validation fails (because cluster-reported IPs are on
an internal network unreachable from Pulse), the fallback path was not
applying subnet preference logic. This caused Pulse to continue trying
to connect to internal cluster IPs instead of management network IPs.
Now the fallback path queries node network interfaces via the initial
connection and sets IPOverride to an IP on the same network as the
original connection, just like the validated node path does.
Fixes#929
Previously, when memory ballooning was active on a VM, Pulse would use
the balloon value as the total memory instead of the configured MaxMem.
This caused confusing displays where a 4GB VM with 1GB balloon would
show "94% (966MB/1GB)" instead of "24% (966MB/4GB)".
The balloon value is still tracked in memory.balloon for the frontend's
yellow balloon marker visualization, but no longer replaces the total.
Fixes#1070
For RAIDZ pools, zpool ALLOC includes parity overhead, but users expect
to see actual data usage. Now using dataset Used value (from statfs)
when RAIDZ is detected, matching the existing fix for total capacity.
Fixes the second part of #1052 where used capacity was inflated.
- Replace 'enterprise authentication' with 'team authentication'
- Replace 'Enterprise Insights' with 'Advanced Insights'
- Deprecate isEnterprise() in favor of isPro() and hasFeature()
- Update Settings.tsx to use isPro() for badge visibility