Rework the CONNECTIONS section
- Label each connection with its tailnet and account rather than the nickname alone. `tailscale switch --list --json` carries both, and on a multi-tailnet setup the nickname is the least useful field — "andre" says nothing about which tailnet you would be switching to. Renders as "headscale.pertento.ai (andre)", falling back through tailnet, then account, then profile id when a field is missing. - Mark the active connection with colour instead of a filled background: brand yellow on its label, currentFill cleared. The theme sets selected-border-width to 0, so clearing the fill leaves nothing drawn. Hover still highlights through `fill`, so the row keeps its affordance. Exit-node and Mullvad-region rows are untouched and still fill. - Sort the active connection to the top. Done in parseAccounts rather than at render time: the keyboard cursor indexes into tailscale.accounts, so sorting only in the view would leave j/k acting on a different row than the highlighted one. Array.sort is stable, so the remaining profiles keep the CLI's order. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -57,11 +57,25 @@ function osIcon(os) {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Stock returned the nickname alone, which on a multi-tailnet setup is the
|
||||
// least useful field — "andre" and "pastilhas" say nothing about which tailnet
|
||||
// you would be switching to. `tailscale switch --list --json` carries both, so
|
||||
// show the tailnet with the account in parentheses:
|
||||
//
|
||||
// headscale.pertento.ai (andre)
|
||||
// offscale.pastilhas.dev (pastilhas)
|
||||
//
|
||||
// Falls back through the same chain as before when a field is absent, so a
|
||||
// profile with no tailnet still renders something meaningful.
|
||||
function accountLabel(account) {
|
||||
if (!account) return "Unknown account"
|
||||
if (account.nickname) return String(account.nickname)
|
||||
if (account.tailnet) return String(account.tailnet)
|
||||
if (account.account) return String(account.account)
|
||||
|
||||
var tailnet = String(account.tailnet || "").trim()
|
||||
var who = String(account.account || account.nickname || "").trim()
|
||||
|
||||
if (tailnet !== "" && who !== "") return tailnet + " (" + who + ")"
|
||||
if (tailnet !== "") return tailnet
|
||||
if (who !== "") return who
|
||||
return String(account.id || "Unknown account")
|
||||
}
|
||||
|
||||
@@ -292,6 +306,19 @@ function parseAccounts(raw) {
|
||||
if (account.selected === true) selected = account
|
||||
}
|
||||
}
|
||||
|
||||
// Active connection first, everything else in the order the CLI listed it.
|
||||
// Sorted here rather than in the view so the Repeater and the keyboard
|
||||
// cursor (accountIndex) index into the same ordering — sorting only at
|
||||
// render time would leave j/k selecting a different row than the one
|
||||
// highlighted. Array.sort is stable, so the unselected profiles keep their
|
||||
// relative order.
|
||||
next.sort(function(left, right) {
|
||||
var l = left.selected === true ? 0 : 1
|
||||
var r = right.selected === true ? 0 : 1
|
||||
return l - r
|
||||
})
|
||||
|
||||
return {
|
||||
accounts: next,
|
||||
selectedAccountId: selected ? String(selected.id || "") : "",
|
||||
|
||||
@@ -854,7 +854,12 @@ Panel {
|
||||
current: selectedAccount
|
||||
foreground: root.foreground
|
||||
fill: root.hoverFill
|
||||
currentFill: root.selectedFill
|
||||
// No filled background on the active connection — it reads as the brand
|
||||
// yellow on its label instead (see the Text below). `current` also selects
|
||||
// the "selected" border spec, but the theme sets selected-border-width to
|
||||
// 0, so clearing the fill leaves nothing drawn. Hover still highlights
|
||||
// through `fill`, so the row keeps its affordance.
|
||||
currentFill: "transparent"
|
||||
|
||||
implicitHeight: accountInner.implicitHeight + Style.spacing.xl
|
||||
|
||||
@@ -888,7 +893,9 @@ Panel {
|
||||
|
||||
Text {
|
||||
text: accountRow.accountText
|
||||
color: root.foreground
|
||||
// The active connection is marked by colour rather than a filled
|
||||
// background: brand yellow here, themed white for the others.
|
||||
color: accountRow.selectedAccount ? root.accent : root.foreground
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: Style.font.body
|
||||
font.bold: accountRow.selectedAccount
|
||||
|
||||
Reference in New Issue
Block a user