Tailscale panel: group machines into My/Tagged/Other and add "/" search - #10511
Open
ssandys wants to merge 6 commits into
Open
Tailscale panel: group machines into My/Tagged/Other and add "/" search#10511ssandys wants to merge 6 commits into
ssandys wants to merge 6 commits into
Conversation
Exit node rows name an identifier, not a friendly label: the value shown must match `tailscale exit-node list`, tsui and the admin console so it can be cross-referenced and typed into `tailscale set --exit-node=`. displayHostName is deliberately left alone -- it prefers the OS hostname, which reads better in the MACHINES list, and its localhost fallback is load-bearing for iOS peers that all report "localhost". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QwrnwejcfKriS8iBcaTcmK
The panel labelled an exit node with its OS hostname, so a machine whose HostName is "Firezone" and DNSName is "ny-exit-node.tailnet.ts.net" showed as "Firezone" -- disagreeing with `tailscale exit-node list`, tsui and the admin console, which all call it "ny-exit-node". Cosmetic only: exitNodeTarget already resolves through peerAddress, which prefers DNSName, so the correct target was always being set. MACHINES rows are deliberately unchanged, with a source guard asserting so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QwrnwejcfKriS8iBcaTcmK
Adds peerGroup/groupPeers so the machine list can be split into My Devices, Tagged Devices and Other Devices. Tagged wins over ownership, matching tsui: a tagged device is owned by the tag, not by whoever enrolled it, so atl-exit-node belongs under Tagged Devices rather than My Devices. No new data plumbing -- peerFromStatus already normalizes UserID and Tags, and parseStatus already exposes selfUserId. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QwrnwejcfKriS8iBcaTcmK
Renders MACHINES as three headed groups instead of one flat alphabetical list. Empty groups hide themselves, so a personal tailnet with no tagged devices shows no stray heading. Cursor bounds move from tailscale.peers to a new orderedPeers, the flat concatenation of the three groups in render order, and each group applies a groupOffset so rowIndex stays unique across group boundaries. Without this, keyboard selection would highlight a different row than the one the cursor is on -- and orderedPeers.length will diverge from tailscale.peers.length once search filtering lands. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QwrnwejcfKriS8iBcaTcmK
peerMatchesQuery searches DisplayName, HostName, DNSName, OS and every Tailscale IP. Matching the MagicDNS name matters: hostname and DNS name diverge (a machine named "Firezone" answers to ny-exit-node), so a hostname-only search would miss the name the user knows it by. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QwrnwejcfKriS8iBcaTcmK
Press / in the panel to filter machines by name, MagicDNS name or IP. Filtering runs before grouping, so empty groups hide themselves instead of leaving three headings over an empty list. Also fixes the blocked binding on PanelKeyCatcher, which only covered the copy menu. PanelKeyCatcher uses Keys.priority: Keys.BeforeItem and consumes h/j/k/l/x as navigation, so its header documents that a panel with an inline editor must set blocked: <editor>.activeFocus. That was never done for the Mullvad region search, so typing j/k/h/l/x into it moved the panel cursor instead of entering text. Both fields are covered now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QwrnwejcfKriS8iBcaTcmK
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #10509
The MACHINES list rendered every online peer in one flat alphabetical list. On the tailnet this was developed against that is 135 rows, of which exactly one is a machine belonging to the user — the rest are tagged infrastructure and colleagues' devices.
Both changes match
tsuibehaviour.Grouping
Splits the list into My Devices / Tagged Devices / Other Devices. Tagged wins over ownership, matching
tsui: a tagged device is owned by the tag, not by whoever enrolled it, soatl-exit-nodesits under Tagged Devices. Empty groups hide themselves, so a personal tailnet with no tagged devices shows no stray heading.tsuiuses only My Devices and Tagged Devices, but peers belonging to other users fall outside both, so a third group keeps everything reachable rather than silently hiding rows the panel shows today.No new data plumbing —
peerFromStatusalready normalizesUserIDandTags, andparseStatusalready exposesselfUserId.Cursor bounds move from
tailscale.peersto a neworderedPeers, the flat concatenation of the three groups in render order, with a per-groupgroupOffsetsorowIndexstays unique across boundaries. Without this, keyboard selection would highlight a different row than the cursor is on.Search
/opens a search field filtering on name, MagicDNS name, OS and IP. Filtering runs before grouping, so empty groups collapse instead of leaving three headings over an empty list.Matching the MagicDNS name matters: hostname and DNS name diverge (see #10508), so a hostname-only search would miss the name the user knows the machine by.
Also fixes a pre-existing bug
PanelKeyCatcherusesKeys.priority: Keys.BeforeItemand consumesh/j/k/l/xas navigation. Its header documents that a panel with an inline editor must setblocked: <editor>.activeFocus.Panel.qmlset onlyblocked: root.copyMenuOpen, so the existing Mullvad region search field never had this guard — typingj/k/h/l/xinto it moved the panel cursor instead of entering text. Both fields are covered now.I have no Mullvad exit nodes on my tailnet, so that half is correct by the component's documented contract but unverified at runtime.
Tests
24 new assertions in
test/shell.d/tailscale-test.shcovering grouping and filtering, including tagged-beats-ownership, order preservation and degenerate input.Verified on a live tailnet: groups render with correct membership and counts summing to
tailscale.peers.length;/opens search; typingalexenters as literal text (chosen becauselandxare navigation keys — it exercises theblockedfix); no-match shows an empty state; Escape closes search without closing the panel.🤖 Generated with Claude Code
https://claude.ai/code/session_01QwrnwejcfKriS8iBcaTcmK