diff --git a/src/vpn/VpnScreen.tsx b/src/vpn/VpnScreen.tsx index b1e8a00..f79bde2 100644 --- a/src/vpn/VpnScreen.tsx +++ b/src/vpn/VpnScreen.tsx @@ -1551,7 +1551,22 @@ export const VpnScreen = ({ embedded, onShowCredits, wordmark, wordmarkLight }: Headscale form, and showing a second copy here would put two on the screen at once. */} {/* `vm.showManual` forces it open even mid sign-in: for a Headscale node in needsLogin the form is the ONLY way forward, so hiding it there strands the user. */} - {showManual && !vm.needsSetup && (!vm.signingIn || vm.showManual) && vm.authorized !== false ? ( + {/* + `vm.profiles.length === 0` is the third way in, and it exists because of a state the other two + could not describe: a sign-in that got as far as NeedsLogin and no further. + + `signingIn` is then true, so the form is suppressed as "already in progress" — but there is no + profile, nothing is connected, and nothing will ever complete. The screen showed "Waiting for + sign-in" above a toggle bound to `connected` (so it could not move) with no form, no chooser + and no reset. The only exit was deleting the app. + + A node in NeedsLogin with no profile is not signing in. It is stuck, and the way out of stuck + is the form that asks where to connect. + */} + {showManual && + !vm.needsSetup && + (!vm.signingIn || vm.showManual || vm.profiles.length === 0) && + vm.authorized !== false ? ( ) : null}