From 8b8f38de1b2a09df77171f791f3cbfbc30361c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Papp?= Date: Wed, 6 May 2026 16:55:52 +0200 Subject: [PATCH] [client/ui-wails] Show GUI and daemon versions in the About submenu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restore the legacy Fyne UI's two disabled "GUI: x.y.z" / "Daemon: a.b.c" entries under About so users (and support) can read the running versions from the tray. The GUI line is baked in at build time via version.NetbirdVersion() — the same -ldflags chain the rest of the repo uses. The daemon line starts as "—" and is rewritten in applyStatus on every Status snapshot whose DaemonVersion differs from the last one we recorded, so a daemon restart with a new build (e.g. after an enforced update) updates the menu automatically. Drive-by: rename the local variable that shadowed the version package in handleUpdate so the import resolves cleanly. --- client/ui-wails/tray.go | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/client/ui-wails/tray.go b/client/ui-wails/tray.go index cf7d99c8d..eb4c18586 100644 --- a/client/ui-wails/tray.go +++ b/client/ui-wails/tray.go @@ -16,6 +16,7 @@ import ( "github.com/wailsapp/wails/v3/pkg/services/notifications" "github.com/netbirdio/netbird/client/ui-wails/services" + "github.com/netbirdio/netbird/version" ) // User-facing strings exposed in the tray, OS notifications and the @@ -48,6 +49,12 @@ const ( // menuInstallVersionPrefix is rewritten with the target version when // the management server enforces the update. menuInstallVersionPrefix = "Install version " + // menuGUIVersionFmt and menuDaemonVersionFmt drive the disabled + // version-info entries under About. The daemon line is "—" until the + // first Status snapshot reports the daemon's version. + menuGUIVersionFmt = "GUI: %s" + menuDaemonVersionFmt = "Daemon: %s" + menuVersionUnknown = "—" // OS notifications. notifyUpdateTitle = "NetBird update available" @@ -96,12 +103,13 @@ type Tray struct { window *application.WebviewWindow svc TrayServices - statusItem *application.MenuItem - upItem *application.MenuItem - downItem *application.MenuItem - exitNodeItem *application.MenuItem - networksItem *application.MenuItem - updateItem *application.MenuItem + statusItem *application.MenuItem + upItem *application.MenuItem + downItem *application.MenuItem + exitNodeItem *application.MenuItem + networksItem *application.MenuItem + updateItem *application.MenuItem + daemonVersionItem *application.MenuItem mu sync.Mutex connected bool @@ -110,6 +118,7 @@ type Tray struct { updateEnforced bool exitNodes []string lastStatus string + lastDaemonVersion string notificationsEnabled bool activeProfile string activeUsername string @@ -208,6 +217,11 @@ func (t *Tray) buildMenu() *application.Menu { _ = t.app.Browser.OpenURL(urlGitHubRepo) }) about.Add(menuDocumentation).SetEnabled(false) + // Disabled informational entries: the GUI version is baked in at + // build time via -ldflags, the daemon version comes from the first + // Status snapshot and is updated in applyStatus. + about.Add(fmt.Sprintf(menuGUIVersionFmt, version.NetbirdVersion())).SetEnabled(false) + t.daemonVersionItem = about.Add(fmt.Sprintf(menuDaemonVersionFmt, menuVersionUnknown)).SetEnabled(false) // Hidden until the daemon emits EventUpdateAvailable. The label is // rewritten in onUpdateAvailable to match the legacy Fyne UI: // menuDownloadLatestVersion for opt-in, menuInstallVersionPrefix+version @@ -353,7 +367,7 @@ func (t *Tray) onUpdateAvailable(ev *application.CustomEvent) { func (t *Tray) handleUpdate() { t.mu.Lock() enforced := t.updateEnforced - version := t.updateVersion + updateVersion := t.updateVersion t.mu.Unlock() if !enforced { @@ -366,8 +380,8 @@ func (t *Tray) handleUpdate() { // RPC the /update page is polling. if t.window != nil { url := "/#/update" - if version != "" { - url += "?version=" + version + if updateVersion != "" { + url += "?version=" + updateVersion } t.window.SetURL(url) t.window.Show() @@ -419,8 +433,12 @@ func (t *Tray) applyStatus(st services.Status) { // flag in onSessionExpire. sessionExpiredEnter := strings.EqualFold(st.Status, statusSessionExpired) && !strings.EqualFold(t.lastStatus, statusSessionExpired) + daemonVersionChanged := st.DaemonVersion != "" && st.DaemonVersion != t.lastDaemonVersion t.connected = connected t.lastStatus = st.Status + if daemonVersionChanged { + t.lastDaemonVersion = st.DaemonVersion + } exitNodes := exitNodesFromStatus(st) exitNodesChanged := !equalStrings(exitNodes, t.exitNodes) @@ -442,6 +460,9 @@ func (t *Tray) applyStatus(st services.Status) { if exitNodesChanged { t.rebuildExitNodes(exitNodes) } + if daemonVersionChanged && t.daemonVersionItem != nil { + t.daemonVersionItem.SetLabel(fmt.Sprintf(menuDaemonVersionFmt, st.DaemonVersion)) + } if sessionExpiredEnter { t.handleSessionExpired() }