fix: use configured Guest URLs for PVE/PBS/PMG navigation (#870)

- Fix PVE nodes: buildNodeUrl in ProxmoxNodesSection.tsx now prioritizes
  guestURL over host (was ignoring guestURL entirely)
- Add PBS support: GuestURL field added to PBSInstance config, model,
  and API handlers
- Add PMG support: GuestURL field added to PMGInstance config, model,
  and API handlers
- Update NodeSummaryTable to use guestURL for PBS nodes
- Frontend types updated for PBS/PMG guestURL support

The Guest URL setting in node configuration now works correctly across
all node types. When set, it takes priority over the Host URL when
clicking on node names to navigate to the Proxmox/PBS/PMG web UI.

Closes #870
This commit is contained in:
rcourtman
2025-12-22 22:05:25 +00:00
parent 7664e941b0
commit e4732af0f5
8 changed files with 32 additions and 1 deletions
@@ -119,12 +119,23 @@ const nodeToResource = (
* Build management URL for a node
*/
const buildNodeUrl = (node: Node): string | undefined => {
// Prioritize guestURL if available
const guestUrlValue = node.guestURL?.trim();
if (guestUrlValue) {
return guestUrlValue.startsWith('http')
? guestUrlValue
: `https://${guestUrlValue}`;
}
// Fallback to host
const hostValue = node.host?.trim();
if (hostValue) {
return hostValue.startsWith('http')
? hostValue
: `https://${hostValue.includes(':') ? hostValue : `${hostValue}:8006`}`;
}
// Final fallback to node name
if (node.name) {
return `https://${node.name.includes(':') ? node.name : `${node.name}:8006`}`;
}
@@ -499,7 +499,7 @@ export const NodeSummaryTable: Component<NodeSummaryTableProps> = (props) => {
href={
isPVEItem
? node!.guestURL || node!.host || `https://${node!.name}:8006`
: pbs!.host || `https://${pbs!.name}:8007`
: pbs!.guestURL || pbs!.host || `https://${pbs!.name}:8007`
}
target="_blank"
onClick={(e) => e.stopPropagation()}
+2
View File
@@ -635,6 +635,7 @@ export interface PBSInstance {
id: string;
name: string;
host: string;
guestURL?: string; // Optional guest-accessible URL (for navigation)
status: string;
version: string;
cpu: number;
@@ -656,6 +657,7 @@ export interface PMGInstance {
id: string;
name: string;
host: string;
guestURL?: string; // Optional guest-accessible URL (for navigation)
status: string;
version: string;
nodes?: PMGNodeStatus[];
+2
View File
@@ -50,6 +50,7 @@ export interface PBSNodeConfig {
id: string;
name: string;
host: string;
guestURL?: string;
user: string;
hasPassword?: boolean;
hasToken?: boolean;
@@ -70,6 +71,7 @@ export interface PMGNodeConfig {
id: string;
name: string;
host: string;
guestURL?: string;
user: string;
hasPassword?: boolean;
hasToken?: boolean;
+10
View File
@@ -847,6 +847,7 @@ func (h *ConfigHandlers) GetAllNodesForAPI() []NodeResponse {
Type: "pbs",
Name: pbs.Name,
Host: pbs.Host,
GuestURL: pbs.GuestURL,
User: pbs.User,
HasPassword: pbs.Password != "",
TokenName: pbs.TokenName,
@@ -878,6 +879,7 @@ func (h *ConfigHandlers) GetAllNodesForAPI() []NodeResponse {
Type: "pmg",
Name: pmgInst.Name,
Host: pmgInst.Host,
GuestURL: pmgInst.GuestURL,
User: pmgInst.User,
HasPassword: pmgInst.Password != "",
TokenName: pmgInst.TokenName,
@@ -1486,6 +1488,7 @@ func (h *ConfigHandlers) HandleAddNode(w http.ResponseWriter, r *http.Request) {
pbs := config.PBSInstance{
Name: req.Name,
Host: host,
GuestURL: req.GuestURL,
User: pbsUser,
Password: pbsPassword,
TokenName: pbsTokenName,
@@ -1556,6 +1559,7 @@ func (h *ConfigHandlers) HandleAddNode(w http.ResponseWriter, r *http.Request) {
pmgInstance := config.PMGInstance{
Name: req.Name,
Host: host,
GuestURL: req.GuestURL,
User: pmgUser,
Password: pmgPassword,
TokenName: pmgTokenName,
@@ -2030,6 +2034,9 @@ func (h *ConfigHandlers) HandleUpdateNode(w http.ResponseWriter, r *http.Request
}
pbs.Host = host
// Update GuestURL if provided
pbs.GuestURL = req.GuestURL
// Handle authentication updates - only switch auth method if explicitly provided
if req.TokenName != "" && req.TokenValue != "" {
// Switching to token authentication
@@ -2110,6 +2117,9 @@ func (h *ConfigHandlers) HandleUpdateNode(w http.ResponseWriter, r *http.Request
pmgInst.Host = host
}
// Update GuestURL if provided
pmgInst.GuestURL = req.GuestURL
// Handle authentication updates - only switch auth method if explicitly provided
if req.TokenName != "" && req.TokenValue != "" {
// Switching to token authentication
+2
View File
@@ -462,6 +462,7 @@ type ClusterEndpoint struct {
type PBSInstance struct {
Name string
Host string
GuestURL string // Optional guest-accessible URL (for navigation)
User string
Password string
TokenName string
@@ -485,6 +486,7 @@ type PBSInstance struct {
type PMGInstance struct {
Name string
Host string
GuestURL string // Optional guest-accessible URL (for navigation)
User string
Password string
TokenName string
+2
View File
@@ -760,6 +760,7 @@ type PBSInstance struct {
ID string `json:"id"`
Name string `json:"name"`
Host string `json:"host"`
GuestURL string `json:"guestURL,omitempty"` // Optional guest-accessible URL (for navigation)
Status string `json:"status"`
Version string `json:"version"`
CPU float64 `json:"cpu"` // CPU usage percentage
@@ -873,6 +874,7 @@ type PMGInstance struct {
ID string `json:"id"`
Name string `json:"name"`
Host string `json:"host"`
GuestURL string `json:"guestURL,omitempty"` // Optional guest-accessible URL (for navigation)
Status string `json:"status"`
Version string `json:"version"`
Nodes []PMGNodeStatus `json:"nodes,omitempty"`
+2
View File
@@ -7006,6 +7006,7 @@ func (m *Monitor) pollPBSInstance(ctx context.Context, instanceName string, clie
ID: "pbs-" + instanceName,
Name: instanceName,
Host: instanceCfg.Host,
GuestURL: instanceCfg.GuestURL,
Status: "offline",
Version: "unknown",
ConnectionHealth: "unhealthy",
@@ -7336,6 +7337,7 @@ func (m *Monitor) pollPMGInstance(ctx context.Context, instanceName string, clie
ID: "pmg-" + instanceName,
Name: instanceName,
Host: instanceCfg.Host,
GuestURL: instanceCfg.GuestURL,
Status: "offline",
ConnectionHealth: "unhealthy",
LastSeen: now,