diff --git a/frontend-modern/src/components/Settings/NodeModal.tsx b/frontend-modern/src/components/Settings/NodeModal.tsx index 725ea39..29a0923 100644 --- a/frontend-modern/src/components/Settings/NodeModal.tsx +++ b/frontend-modern/src/components/Settings/NodeModal.tsx @@ -65,6 +65,7 @@ export const NodeModal: Component = (props) => { const getCleanFormData = (nodeType: 'pve' | 'pbs' | 'pmg' = props.nodeType) => ({ name: '', host: '', + guestURL: '', authType: nodeType === 'pmg' ? 'password' : ('token' as 'password' | 'token'), setupMode: 'auto' as 'auto' | 'manual', user: '', @@ -172,6 +173,7 @@ export const NodeModal: Component = (props) => { setFormData({ name: node.name || '', host: node.host || '', + guestURL: ('guestURL' in node ? node.guestURL : '') || '', authType: node.hasPassword ? 'password' : 'token', setupMode: 'auto', user: username, @@ -211,6 +213,7 @@ export const NodeModal: Component = (props) => { type: props.nodeType, name: normalizedName, host: data.host, + guestURL: data.guestURL, fingerprint: data.fingerprint, verifySSL: data.verifySSL, }; @@ -489,6 +492,28 @@ export const NodeModal: Component = (props) => {

+ +
+ + updateField('guestURL', e.currentTarget.value)} + placeholder={ + props.nodeType === 'pve' + ? 'https://pve.yourdomain.com' + : props.nodeType === 'pbs' + ? 'https://pbs.yourdomain.com' + : 'https://pmg.yourdomain.com' + } + class={controlClass()} + /> +

+ Optional guest-accessible URL for navigation. If specified, this URL will be used when opening the web UI instead of the Host URL. +

+
diff --git a/frontend-modern/src/components/shared/NodeGroupHeader.tsx b/frontend-modern/src/components/shared/NodeGroupHeader.tsx index 5777f0f..ae1d6f9 100644 --- a/frontend-modern/src/components/shared/NodeGroupHeader.tsx +++ b/frontend-modern/src/components/shared/NodeGroupHeader.tsx @@ -9,7 +9,7 @@ interface NodeGroupHeaderProps { export const NodeGroupHeader: Component = (props) => { const isOnline = () => props.node.status === 'online' && (props.node.uptime || 0) > 0; - const nodeUrl = () => props.node.host || `https://${props.node.name}:8006`; + const nodeUrl = () => props.node.guestURL || props.node.host || `https://${props.node.name}:8006`; const displayName = () => getNodeDisplayName(props.node); const showActualName = () => hasAlternateDisplayName(props.node); diff --git a/frontend-modern/src/components/shared/NodeSummaryTable.tsx b/frontend-modern/src/components/shared/NodeSummaryTable.tsx index c9bfc96..dd9534f 100644 --- a/frontend-modern/src/components/shared/NodeSummaryTable.tsx +++ b/frontend-modern/src/components/shared/NodeSummaryTable.tsx @@ -509,7 +509,7 @@ export const NodeSummaryTable: Component = (props) => { 0 { for _, ep := range instanceCfg.ClusterEndpoints { if strings.EqualFold(ep.NodeName, node.Node) { if effective := clusterEndpointEffectiveURL(ep); effective != "" { connectionHost = effective } + if ep.GuestURL != "" { + guestURL = ep.GuestURL + } break } } @@ -4939,6 +4943,7 @@ func (m *Monitor) pollPVEInstance(ctx context.Context, instanceName string, clie DisplayName: displayName, Instance: instanceName, Host: connectionHost, + GuestURL: guestURL, Status: effectiveStatus, Type: "node", CPU: safeFloat(node.CPU), // Already in percentage