Files
community-plugins/tailscale/widget.luau
T
Dave HammerandGitHub 1abe67bd4b Add davemhammer/tailscale (#307)
Tailscale status, peers, exit nodes, and preference toggles for Noctalia v5.
2026-08-08 20:22:15 -04:00

112 lines
2.9 KiB
Luau
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
--!nonstrict
local PANEL_ID = "davemhammer/tailscale:manager"
local STATE_KEY = "ts_snapshot"
local COMMAND_KEY = "ts_command"
-- Brand mark (Simple Icons Tailscale 3×3 dots), tinted for connection state.
local COLOR_CONNECTED = "#73c936"
local COLOR_DISCONNECTED = "on_surface_variant"
local ICON_ON = "assets/tailscale-green.png"
local ICON_OFF = "assets/tailscale-grey.png"
local snapshot = noctalia.state.get(STATE_KEY) or {
available = false,
running = false,
onlineCount = 0,
peerCount = 0,
backendState = "",
exitNode = "",
error = "",
installed = false,
}
local requestId = 0
local function render()
local available = snapshot.available == true
local running = snapshot.running == true
local online = tonumber(snapshot.onlineCount) or 0
local total = tonumber(snapshot.peerCount) or 0
local showCounts = noctalia.getConfig("show_counts") ~= false
local exitNode = tostring(snapshot.exitNode or "")
local hasExit = exitNode ~= ""
-- Connected = green logo, stopped = grey logo (never red).
local color = running and COLOR_CONNECTED or COLOR_DISCONNECTED
local children = {
ui.image({
path = running and ICON_ON or ICON_OFF,
width = 16,
height = 16,
fit = "contain",
}),
}
if showCounts and available then
table.insert(children, ui.label({
text = `{online}/{total}`,
fontWeight = "bold",
color = "on_surface",
}))
if hasExit then
table.insert(children, ui.glyph({
name = "world",
size = 12,
color = (snapshot.exitNodeOnline and COLOR_CONNECTED) or COLOR_DISCONNECTED,
}))
end
table.insert(children, ui.box({
width = 7,
height = 7,
radius = 4,
fill = color,
}))
end
local container = barWidget.isVertical() and ui.column or ui.row
barWidget.render(container({ gap = 5, align = "center" }, children))
if not snapshot.installed then
barWidget.setTooltip(noctalia.tr("widget.tooltip_missing"))
elseif not available then
barWidget.setTooltip(noctalia.tr("widget.tooltip_down", {
error = tostring(snapshot.error or "unknown"),
}))
elseif not running then
barWidget.setTooltip(noctalia.tr("widget.tooltip_stopped", { total = total }))
else
barWidget.setTooltip(noctalia.tr("widget.tooltip_ok", {
state = tostring(snapshot.backendState or "Running"),
online = online,
total = total,
exit = hasExit and exitNode or "—",
}))
end
end
noctalia.state.watch(STATE_KEY, function(value)
if type(value) == "table" then
snapshot = value
render()
end
end)
noctalia.setUpdateInterval(8000)
render()
function update()
render()
end
function onClick()
noctalia.togglePanel(PANEL_ID)
end
function onRightClick()
requestId += 1
noctalia.state.set(COMMAND_KEY, { action = "refresh", requestId = `widget-{requestId}` })
noctalia.notify(noctalia.tr("title"), noctalia.tr("widget.refresh_requested"))
end