Skip to content

internal/ui, internal/tsutil: add exit node selection preference and self page exit node row - #345

Open
DeedleFake wants to merge 13 commits into
masterfrom
exit-node-selection
Open

DeedleFake wants to merge 13 commits into
masterfrom
exit-node-selection

Conversation

@DeedleFake

@DeedleFake DeedleFake commented Oct 15, 2026 •

Copy link
Copy Markdown
Owner

Builds on #344 and changes how its automatic exit node option works.

  • A preference instead of a switch. Preferences > General has an Exit Node option: Previous exit node (the default) or Recommended exit node. It applies only when you turn exit node use on from Trayscale's menu or tray, so changing it never connects you to an exit node by itself. Previous gets back the node you last used, even if Recommended picked it.
  • An exit node row on the self page. The first row in Options shows the exit node in use, None, Waiting for an exit node while Recommended hasn't picked one yet, or Unavailable when the node you chose is no longer visible to this device. Click the row to open the node's page. For a Mullvad node, it opens the Mullvad page with the node's country expanded and the node in view.

Coder created this PR.

Expose tailscaled's automatic exit-node mode on the self page, together
with the current node. Keep selection in the daemon so it survives
closing Trayscale. Leaving automatic mode preserves a resolved node;
explicitly selecting or clearing a node disables automatic selection.

Apply changes off the GTK main loop, cancel pending work when the page
is destroyed, and keep old status updates from cancelling toggle
animations. Add preference, error-handling, UI-state, and animation
regression tests.

Extend tsharness with opt-in recommendation eligibility and document
the feature and its isolated verification path.

Co-authored-by: Codex <noreply@openai.com>
@DeedleFake DeedleFake self-assigned this Oct 15, 2026
@itsAnchorpoint

Copy link
Copy Markdown
Contributor

Thanks for building on this! I like separating the selection preference from actually turning exit-node use on. The subtitle makes when it applies clear, and opening the current node from the self page is a useful addition.

Codex checked e9cb693 against an isolated tsharness with real tailscaled 1.104.1. Changing either preference left the connection untouched; Recommended worked through both the application menu action and the tray menu; Previous after Recommended restored the same resolved node with automatic mode cleared. Opening an ordinary peer and revealing/focusing a Mullvad node also worked. The ordinary test suite passed locally.

Two follow-ups came out of the checks:

  • Could we retain the returned-preferences check in useAutoExitNode? It currently discards the result of EditPrefs. A diagnostic LocalAPI test returning HTTP 200 with {}, null, or unchanged manual preferences makes SetUseExitNode(..., true, SelectRecommendedExitNode) return nil even though automatic mode was not applied. Checking for non-nil prefs and AutoExitNode == ipn.AnyExitNode catches this; the diagnostic and existing exit-node tests pass with that guard restored.
  • Could the self-page row keep a waiting state? With tsharness running without -suggest-exit-nodes, enabling Recommended leaves AutoExitNode=any and ExitNodeID=auto:any. The menu correctly shows exit-node use enabled, but the self-page row says None. Waiting for an exit node would distinguish this from exit-node use being off.

The revised interaction makes sense to me; these points concern confirmation and status feedback rather than the overall design.

@DeedleFake

Copy link
Copy Markdown
Owner Author
* Could we retain the returned-preferences check in `useAutoExitNode`? It currently discards the result of `EditPrefs`. A diagnostic LocalAPI test returning HTTP 200 with `{}`, `null`, or unchanged manual preferences makes `SetUseExitNode(..., true, SelectRecommendedExitNode)` return nil even though automatic mode was not applied. Checking for non-nil prefs and `AutoExitNode == ipn.AnyExitNode` catches this; the diagnostic and existing exit-node tests pass with that guard restored.

This can only ever happen in artificial circumstances. The real tailscaled never returns that with any version that Trayscale is otherwise compatible with.

* Could the self-page row keep a waiting state? With tsharness running without `-suggest-exit-nodes`, enabling Recommended leaves `AutoExitNode=any` and `ExitNodeID=auto:any`. The menu correctly shows exit-node use enabled, but the self-page row says `None`. `Waiting for an exit node` would distinguish this from exit-node use being off.

I made some changes for this and a related possible error. It now says "Unavailable" if the node disappears out from under it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants