Commit Graph

1130 Commits

Author SHA1 Message Date
rcourtman abd0b67faa fix: correct node summary counts for VMs, containers, storage, and backups 2025-10-01 16:40:38 +00:00
rcourtman 35c08b9066 fix: remove 'guests' from search placeholder 2025-10-01 16:33:33 +00:00
rcourtman 0e97303431 feat: consistent filter UX across all tabs
- Deselectable radio toggles on all filter tabs
- Blue reset button when filters are active
- Clean search placeholders with help tooltips
- Working tooltips with proper styling on Dashboard tab
- Better placeholder text: "Search or filter guests..."
2025-10-01 16:33:18 +00:00
rcourtman a236244730 feat: improve dashboard filter toggles UX
- Make radio toggles deselectable by clicking active option
- Reset button turns blue when filters are active
- Add auto-start hot-dev in development environment
2025-10-01 16:23:01 +00:00
rcourtman f8b0d21c32 chore: add claude.md to .gitignore 2025-10-01 15:54:48 +00:00
rcourtman 31317738be chore: remove claude.md from repository 2025-10-01 15:54:43 +00:00
rcourtman 49311b1e39 fix: resolve multiple issues from #485
This commit addresses all issues reported in GitHub issue #485:

1. **SMART Status Recognition**
   - Fix disk health check to accept both "PASSED" and "OK" status
   - Previously only "PASSED" was recognized as healthy
   - Location: internal/monitoring/monitor.go:1255

2. **ZFS Spare Device False Alerts**
   - Skip ZFS SPARE devices unless they have actual errors
   - SPARE devices are intentional and should not trigger alerts
   - Updated in two locations:
     - pkg/proxmox/zfs.go:154 (device filtering)
     - internal/alerts/alerts.go:1077 (alert generation)

3. **Memory Display Granularity**
   - Increase byte formatting precision from 0 to 1 decimal place
   - Improves accuracy (e.g., "1.7 GB" instead of "1 GB" for 86% of 2GB)
   - Location: frontend-modern/src/utils/format.ts:3

4. **Custom Alert Rules Evaluation**
   - Add ReevaluateGuestAlert() method for proper threshold reevaluation
   - Add comments explaining custom rules evaluation limitations
   - Next poll cycle will properly clear stale alerts with new thresholds

Additional improvements:
- Fix ZFS pool alert locking to prevent deadlocks
- Prevent discovery service from running in mock mode
- Restore discovery service when exiting mock mode

Fixes #485
2025-10-01 15:53:42 +00:00
rcourtman b0f68933dd docs: clarify SSH temperature usage 2025-10-01 15:26:00 +00:00
rcourtman fa2656c8f0 docs: clarify SSH temperature usage 2025-10-01 15:23:41 +00:00
rcourtman bd9c6444d6 Handle string wearout values from Proxmox disks 2025-10-01 15:06:35 +00:00
rcourtman dc065e75f7 fix: auto-resolve alerts when thresholds increase
Fixes #484

When users increase alert thresholds (either global defaults or
resource-specific overrides), active alerts are now automatically
re-evaluated and resolved if the current metric value is below the
new threshold.

Previously, alerts would remain active even after increasing the
threshold above the current value, requiring manual resolution or
waiting for the metric to drop below the original threshold and
then rise again.

Changes:
- Add reevaluateActiveAlertsLocked() method to check all active
  alerts against updated thresholds
- Call re-evaluation automatically in UpdateConfig()
- Resolve alerts when current value is below new trigger/clear
  threshold
- Handle all resource types: guests (qemu/lxc), nodes, PBS, storage
- Add comprehensive unit tests for threshold update scenarios
2025-10-01 15:02:27 +00:00
rcourtman a6e5a24a77 fix: load mock.env files during config initialization
Ensures PULSE_MOCK_MODE environment variable is set before the mock
package's init() function runs. This allows mock mode to work correctly
when enabled via mock.env or mock.env.local files without requiring an
explicit environment variable to be set at startup.
2025-10-01 14:45:52 +00:00
rcourtman 42f2213932 fix: correct mock node ID format to match real system
Fix mock node IDs to use instance-nodename format (e.g., 'mock-cluster-pve1')
instead of 'node/pve1' format. This matches the real system ID format used
at monitoring/monitor.go:936 and fixes the grouped/list toggle in the dashboard.

Before:
- Clustered: node/pve1, node/pve2, etc.
- Standalone: node/standalone1, node/standalone2

After:
- Clustered: mock-cluster-pve1, mock-cluster-pve2, etc.
- Standalone: standalone1-standalone1, standalone2-standalone2

This allows the dashboard grouping logic to properly match nodes by instance
and display them correctly in grouped view.
2025-10-01 13:47:59 +00:00
rcourtman 1c2431fcf6 refactor: add mock.env to repository with local override support
Make mock mode configuration part of the repository instead of a local-only
file. This ensures consistent mock mode behavior across all environments
(development, CI/CD, demo server) and makes it work out of the box for
new contributors.

Changes:
- Add mock.env to repository with sensible defaults (mock mode OFF by default)
- Support mock.env.local for personal overrides (gitignored)
- Update .gitignore to allow mock.env but exclude .local variants
- Backend loads mock.env then merges mock.env.local overrides
- hot-dev.sh loads both files in correct order

Benefits:
- New developers can clone and use mock mode immediately
- Demo server gets consistent mock configuration
- Personal preferences stay private in .local file
- No surprises - mock mode disabled by default in fresh clones
- CI/CD can use mock mode without custom configuration

Documentation:
- Updated README.md to explain mock.env is in repo
- Enhanced MOCK_MODE.md with local override instructions
- Updated claude.md with new configuration strategy
- Added mock.env.local.example for quick setup

Example workflow:
  git clone <repo>
  npm run mock:on        # Works immediately with repo defaults
  # Or create personal config:
  cp docs/development/mock.env.local.example mock.env.local
  # Edit mock.env.local with your preferences
2025-10-01 13:38:39 +00:00
rcourtman 6f2b6268a4 perf: optimize mock mode state retrieval and JSON encoding
Improve performance when serving /api/state in mock mode by optimizing
alert handling and JSON serialization.

Changes:
- Add UpdateAlertSnapshots() to cache alerts without blocking
- Use lazy population of alert snapshots to avoid lock contention
- Switch to json.Marshal for better performance with large payloads
- Add debug logging to track /api/state performance
- Simplify GetState() logic in mock mode

Performance improvements:
- Eliminates alert manager lock during /api/state requests
- Reduces JSON encoding overhead for large mock datasets
- Ensures sub-second response times even with 7 nodes and 90+ guests

Testing:
- Mock mode returns state instantly without blocking
- Alert snapshots populate correctly on first request
- Debug logs confirm fast execution path
2025-10-01 13:35:49 +00:00
rcourtman 67fc5977d1 feat: add hot-reloadable mock mode with auto-detection
Implement a hot-reloadable mock mode system that works seamlessly in both
development and production environments without requiring manual restarts
or port changes.

Key Features:
- Backend watches mock.env and auto-reloads when changed (via fsnotify + polling)
- npm commands for easy toggling: mock:on, mock:off, mock:status, mock:edit
- Works in both hot-dev mode and systemd deployments
- Reload completes in 2-5 seconds with no manual intervention
- No port changes or process restarts required

Implementation:
- Extended ConfigWatcher to monitor both .env and mock.env
- Added callback system to trigger ReloadableMonitor.Reload()
- Enhanced toggle-mock.sh to support both hot-dev and systemd modes
- Updated hot-dev.sh banner to show mock status and commands
- Created comprehensive documentation in docs/development/MOCK_MODE.md

Testing:
- Backend builds successfully
- Watcher initializes and monitors both files
- npm run mock:on/off toggles successfully
- mock.env updates correctly
- Scripts work in both hot-dev and systemd modes

Documentation:
- Added Mock Mode section to README.md
- Created detailed guide in docs/development/MOCK_MODE.md
- Updated claude.md with mock mode architecture and usage

Mock mode continues to return cached data instantly from memory
(no API calls, no locks, no timeouts), ensuring fast /api/state responses.
2025-10-01 13:35:17 +00:00
rcourtman f30e57e36d feat: add GitHub Actions workflow to auto-update demo server on release 2025-10-01 11:34:53 +00:00
rcourtman aff4e48c1f chore: bump version to v4.17.0 2025-10-01 11:14:47 +00:00
rcourtman d88cce2cfc fix: use AVERAGE instead of average for PBS RRD API cf parameter
Fixes #483 - PBS syslog was being flooded with 400 Bad Request errors
because the cf parameter value 'average' is not in the valid enumeration.
Changed to 'AVERAGE' (all caps) per PBS API specification.
2025-10-01 11:07:36 +00:00
rcourtman c664204b59 feat: add OIDC logout URL support and improve UX
Enhancements for OIDC authentication based on user feedback from issue #327:

1. Add OIDC logout URL support
   - New OIDC_LOGOUT_URL environment variable
   - UI field in OIDC settings panel for logout URL configuration
   - Properly redirects to IdP logout endpoint (e.g., Authentik end-session)
   - Stored in config and returned via security status API

2. Fix redirect URL help text in UI
   - Handle empty defaultRedirect string properly
   - Improved help text when PUBLIC_URL is not set
   - Clarify when auto-detection vs manual config is needed

3. Documentation improvements
   - Add note about using https:// in PUBLIC_URL/OIDC_REDIRECT_URL when behind TLS proxy
   - Document OIDC_LOGOUT_URL environment variable
   - Clarify X-Forwarded-Proto header behavior in OIDC docs
   - Add better guidance for Authentik users on HTTPS setup

4. Frontend improvements
   - Add HS256 signature algorithm error message in Login component
   - Display OIDC logout URL when available

These changes address the remaining OIDC UX issues reported by users,
particularly around logout functionality and reverse proxy configuration.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-01 10:59:22 +00:00
rcourtman 2b4b6a08e1 fix: resolve OIDC authentication issues with DISABLE_AUTH and improve UX
Fixes multiple OIDC authentication issues reported in GitHub issue #327:

1. Fix DISABLE_AUTH=true disabling OIDC sessions
   - Reorder authentication checks to validate proxy auth and OIDC sessions
     before checking DISABLE_AUTH flag
   - Allows OIDC to function even when basic auth is disabled

2. Fix missing username display for OIDC users
   - Add GetSessionUsername() function to look up username from session ID
   - Set X-Authenticated-User header for OIDC authenticated requests
   - Update security status endpoint to return oidcUsername field
   - Display OIDC username in UI header alongside logout button

3. Fix missing logout button for OIDC users
   - Set hasAuth(true) when OIDC session is detected in frontend
   - Update security status endpoint to return OIDC info even when
     DISABLE_AUTH=true
   - Properly initialize WebSocket and load user preferences for OIDC sessions

4. Add documentation for Authentik HS256/RS256 issue
   - Document requirement for RSA signing key in Authentik
   - Add troubleshooting entry for signature algorithm mismatch
   - Provide clear resolution steps in CONFIGURATION.md and OIDC.md

All changes maintain backward compatibility and follow defensive security
practices. X-Forwarded-Proto header handling was verified to be correct.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-01 10:53:19 +00:00
rcourtman b81b7eb641 fix: URL-encode alert IDs in API calls to fix acknowledgement
Alert IDs containing special characters (colons and slashes) were not being
URL-encoded before use in API endpoints, causing the backend to fail to find
and acknowledge alerts. This fixes issue #482.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-01 10:38:22 +00:00
rcourtman 4160d2e68b feat: add SSH key removal option to Quick Setup and fix node deletion
- Enhanced Quick Setup script to detect existing SSH configuration
  - Offers Keep/Remove/Skip options when SSH key already exists
  - Provides clean removal of SSH key from authorized_keys
  - Shows manual removal instructions for lm-sensors package
- Fixed ConfigWatcher panic on double-close during shutdown
- Fixed node deletion to allow removing the last node
  - Added SaveNodesConfigAllowEmpty method for explicit admin actions
  - Fixed deleted node host extraction before removal
- Display Quick Setup command after copying to clipboard
- Improved node name matching for temperature data
  - Handles .lan suffix variations between config and WebSocket state

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-01 10:25:56 +00:00
rcourtman b933e42d5f fix: reactively update temperature data when WebSocket state changes
- Add createEffect to watch for state updates after initial load
- Re-merge temperature data when WebSocket receives node updates
- Temperature badge will now appear after WebSocket connects
- Fixes race condition where Settings loads before WebSocket data arrives
2025-10-01 08:34:45 +00:00
rcourtman f662d47b4a fix: use correct state path for temperature data in Settings
- Changed from currentState.pveNodes/pbsNodes to currentState.nodes
- State API uses unified 'nodes' array for all node types
- Temperature badge should now display correctly
2025-10-01 08:27:47 +00:00
rcourtman b08183dfa0 fix: add safety check for state accessor in Settings
- Check if state is a function before calling it
- Prevents 'state is not a function' error during initialization
- Temperature badge will gracefully fallback if WebSocket not ready
2025-10-01 08:25:55 +00:00
rcourtman 1ef938071a fix: merge temperature data from WebSocket state into Settings node list
- Settings page now merges live temperature data from WebSocket state
- Temperature badge will now appear when SSH monitoring is active
- Fix missing onMount import in GuestRow.tsx

The Settings page loads node config from /api/config/nodes which doesn't
include runtime temperature data. This change merges temperature from the
WebSocket state (which has live monitoring data) so the temperature badge
displays correctly.
2025-10-01 08:21:50 +00:00
rcourtman 2f8cf462bb feat: add temperature monitoring status badge to node cards
- Display green 'Temperature' badge when temperature monitoring is active
- Shows on both PVE and PBS nodes in Settings page
- Badge appears alongside VMs, Containers, Storage, Backups badges
- Only displays when node.temperature.available is true

This provides clear visual feedback that SSH temperature monitoring
was successfully configured during setup.
2025-10-01 08:18:18 +00:00
rcourtman d0f049d373 refactor: improve setup script output professionalism
- Remove excessive emojis and decorative elements
- Use clear, concise language throughout
- Simplify progress indicators to simple checkmarks
- Remove unnecessary tips and verbose explanations
- Improve error message clarity
- Use proper capitalization (not ALL CAPS for emphasis)
- Clean up temperature monitoring prompt to be more direct

The setup script now presents a more professional, enterprise-ready
appearance while maintaining all functionality.
2025-10-01 08:14:49 +00:00
rcourtman fdf0e0b958 feat: automate SSH key generation and embedding in setup scripts
- Add getOrGenerateSSHKey() function that automatically generates SSH keypair if needed
- Embed SSH public key directly in setup scripts (no manual copy/paste required)
- Simplify temperature monitoring setup - user just types 'y' and it's done
- Improves UX: removes manual steps for SSH key setup

Changes:
- internal/api/config_handlers.go: Add SSH key generation and auto-embedding
- frontend-modern/src/components/Settings/NodeModal.tsx: Remove dead setupCode modal code
- Setup script now includes embedded SSH_PUBLIC_KEY variable

User workflow before:
1. Run setup script
2. Prompted to run commands on Pulse server
3. Copy SSH public key manually
4. Paste into setup script
5. Done

User workflow now:
1. Run setup script
2. Type 'y' for temperature monitoring
3. Done (SSH key automatically installed)
2025-10-01 08:10:48 +00:00
rcourtman 524210468f fix: copy command to clipboard when generating PVE quick setup URL
The copy button in Quick Setup for PVE was generating the setup URL
but not actually copying the command to clipboard. Users had to click
the separate 'Copy Command' button after generation.

Fixed to automatically copy the curl command to clipboard immediately
after generating the setup URL, matching the PBS behavior.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-01 07:41:25 +00:00
rcourtman ec1d8b3303 fix: ensure PULSE_DATA_DIR is exported in dev mode and improve sync validation
Additional safeguards to prevent dev/production config conflicts:

1. **hot-dev.sh**: Explicitly export PULSE_DATA_DIR before starting backend
   - Ensures backend always uses /opt/pulse/tmp/dev-config in dev mode
   - Prevents accidental fallback to /etc/pulse
   - Adds logging to show which config directory is being used

2. **sync-production-config.sh**: Smart encryption key handling
   - Never overwrites existing dev encryption key
   - Warns if production key is newer (unusual scenario)
   - Keeps dev key to avoid breaking encrypted configs
   - Adds detailed logging of sync decisions

These changes ensure that when Vite restarts:
- Backend always uses the correct dev-config directory
- Sync script never breaks working dev configuration
- All decisions are logged clearly for debugging

Related to previous commit fixing nodes.enc corruption.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-01 07:33:20 +00:00
rcourtman 27373587c6 fix: prevent nodes.enc corruption and data loss with comprehensive safeguards
This commit addresses critical issues where nodes configuration was being
lost or corrupted, causing user frustration and data loss.

## Changes:

### 1. Sync Script Protection (sync-production-config.sh)
- Never overwrites newer dev config with older production files
- Validates timestamps before syncing
- Shows detailed logging of sync decisions
- Prevents accidental overwrites of working configuration

### 2. Timestamped Backups (persistence.go)
- Creates timestamped backup before EVERY save (e.g., nodes.enc.backup-20251001-073000)
- Maintains "latest" backup for quick recovery
- Auto-cleans old backups (keeps last 10)
- Ensures we can always recover from corruption

### 3. Empty Config Protection (persistence.go)
- BLOCKS attempts to save empty nodes config when existing nodes exist
- Prevents accidental data wipes
- Returns error with clear message about what was blocked

### 4. Enhanced Corruption Recovery (persistence.go)
- Detects "cipher: message authentication failed" errors
- Automatically attempts recovery from backup files
- Renames corrupted files with timestamps for forensics
- Logs detailed recovery process

### 5. Performance Logging (GuestRow.tsx)
- Added timing for individual metadata API calls
- Helps identify performance bottlenecks

## Why This Matters:
Previous behavior allowed:
- Corrupted files to overwrite working configs
- Empty configs to delete all nodes
- No way to recover from corruption
- Race conditions during rapid restarts

New behavior ensures:
- Multiple backup copies always exist
- Corruption auto-recovers from backups
- Empty saves are blocked
- Sync script validates before overwriting

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-01 07:31:50 +00:00
rcourtman 6d517e46b2 fix: add disk object to VM/container API responses
addresses #481

The frontend expects a disk object with {total, used, free, usage} fields
but the backend was only sending flat diskUsed/diskTotal values. This
caused the DISK column to show disk I/O values instead of disk usage.

Added DiskObj field to VMFrontend and ContainerFrontend structs and
populated it in the converters, matching how Memory is already handled.
2025-10-01 07:01:23 +00:00
rcourtman a662bdb9a5 fix: preserve zero values for alert thresholds in UI
addresses #480

Changed from || to ?? operator when loading alert config to properly
handle zero values. Previously, setting a threshold to 0 would revert
to defaults when navigating away due to || treating 0 as falsy.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-01 06:57:09 +00:00
rcourtman 178bb5aa34 fix: clarify alert delay label text
Changed "seconds before triggering" to "seconds above threshold before triggering" to make it clearer that the delay applies to how long a value must stay above the threshold.

addresses #470

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-01 06:55:30 +00:00
rcourtman 9737735cae fix: stable node group sorting in dashboard for duplicate hostnames
addresses #479

when displaying grouped guests in the dashboard, node groups with the same
hostname were being sorted inconsistently, causing the groups to swap
positions on each data refresh.

fixed by adding instance ID as a secondary sort key when node names are
equal. this ensures stable, consistent ordering even when multiple nodes
share the same hostname.
2025-10-01 06:53:15 +00:00
rcourtman c3d9be23a7 fix: use instance ID for node selection filtering across all views
addresses #476

comprehensive fix for duplicate node name handling when users click to
filter by a specific node:

- NodeSummaryTable: pass node.id instead of node.name when user clicks a node
- Dashboard: filter guests by instance ID instead of hostname
- Storage: filter storage by instance ID instead of hostname
- DiskList: filter physical disks by instance ID instead of hostname
- UnifiedBackups: add instance field to UnifiedBackup type and filter by
  instance ID instead of hostname

this ensures that when users select a node with a duplicate hostname, they
only see resources from that specific node, not from all nodes sharing the
same hostname.
2025-09-30 22:21:20 +00:00
rcourtman 6b1a5f76cf fix: use instance ID for grouping/matching in GuestURLs and UnifiedBackups
addresses #476

- GuestURLs: group guests by instance ID instead of hostname
- UnifiedBackups: match snapshots to VMs/containers using instance ID
  instead of hostname when finding guest names

this prevents incorrect grouping and matching when multiple nodes share
the same hostname.
2025-09-30 22:08:48 +00:00
rcourtman 1cf61c3025 fix: hide temperature column when no SSH configured
Only show the temperature column in node tables when at least one node
has SSH configured and temperature monitoring available.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-30 22:02:13 +00:00
rcourtman b47845ecb8 fix: add instance field to backup/snapshot structs for duplicate node names
addresses #476

added Instance field to StorageBackup and GuestSnapshot structs in both
backend and frontend to properly handle nodes with duplicate hostnames.
updated backup and snapshot counting logic to use instance ID instead of
hostname, consistent with the VM/container/storage count fixes.

this completes the fix for #476 - all counts and groupings now use unique
instance IDs instead of hostnames.
2025-09-30 21:57:05 +00:00
rcourtman 312f1b5862 fix: correct VM/container/storage counts for duplicate node names
addresses #476

the node summary table was still using node.name (hostname) to count
VMs, containers, and storage, which caused incorrect counts when multiple
nodes share the same hostname. changed the count logic to use the unique
instance ID (vm.instance === node.id) instead of hostname matching, making
it consistent with the grouping fix in 5180b84d4.
2025-09-30 21:50:12 +00:00
rcourtman 645c97850b fix temperature struct field names in mock generator
fixes build error from using wrong field names (ID/Temperature instead of Core/Temp)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-30 21:42:12 +00:00
rcourtman 286eba9985 add temperature data to mock nodes
addresses mock data not keeping up with new features added in v4.16.0. mock nodes now generate realistic CPU package, core, and NVMe temperatures to match the temperature monitoring feature.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-30 21:36:43 +00:00
rcourtman 86d240e70e chore: bump version to v4.16.0 2025-09-30 21:10:14 +00:00
rcourtman 6bfaa8b79a fix: OIDC redirect URL now respects X-Forwarded-Proto header
Addresses #327 - Users behind reverse proxies (Traefik, nginx, etc) were
experiencing redirect loop issues because the redirect URL was being built
with http:// instead of https:// when X-Forwarded-Proto was set.

Changes:
- Build OIDC redirect URL dynamically from each request instead of at startup
- Respect X-Forwarded-Proto and X-Forwarded-Host headers from reverse proxies
- Update UI help text to clarify auto-detection behavior
- Add debug logging to show how redirect URL is constructed

When redirect URL is not explicitly configured, Pulse now builds it from
the incoming request headers, properly detecting HTTPS when behind a proxy.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-30 21:06:20 +00:00
rcourtman 0778b8f002 fix: display backup-id for PBS host backups instead of 0
addresses #454

PBS host backups (created with standalone proxmox-backup-client) use
the hostname as backup-id (e.g. "delly", "krom-pc") instead of a
numeric VMID. Now the VMID column displays this hostname string for
host backups instead of incorrectly showing 0.

Changes:
- Allow vmid field to be string or number in UnifiedBackup type
- Keep backup-id as string for host backups, numeric for VMs/LXCs
- Update column header to show "VMID/Host" when host backups exist
- Fixed in both code paths: direct PBS API and PVE storage backups
- Sorting and filtering work correctly with both strings and numbers

Also includes security improvement:
- Show setup command to user before copying to clipboard
- Prevents blindly pasting commands without review

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-30 21:02:18 +00:00
rcourtman 386bee1aa6 fix: improve OIDC redirect URL validation and help text
addresses #327

Fixed issues when PUBLIC_URL is not set:
- Better error message explaining how to fix missing redirect URL
- Help text now shows actionable guidance instead of incomplete message
- Hide IdP redirect URL hint when no default is available
2025-09-30 20:33:11 +00:00
rcourtman 6a2b053c7a add URL routing for better navigation
Implements @solidjs/router to provide proper URL-based navigation:
- Main routes: /, /storage, /backups, /alerts, /settings
- Settings sub-routes: /settings/pve, /settings/pbs, /settings/system, etc.
- Browser back/forward buttons now work
- URLs are bookmarkable and shareable
- Clearer indication of current page in URL bar

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-30 20:31:10 +00:00
rcourtman cffd90ac39 fix: storage node grouping not matching Node.ID format
Related to #478

Storage was grouping by storage.instance but Node.ID uses the format
"instance-nodename". This caused node headers to not display in storage
view when grouped by node.

Applied the same fix as Dashboard - group by instance-nodename to match
the Node.ID format from the backend.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-30 20:19:24 +00:00