diff --git a/client/ui-wails/assets/netbird-systemtray-connected-dark.png b/client/ui-wails/assets/netbird-systemtray-connected-dark.png index be38eb0a6..f18a929a0 100644 Binary files a/client/ui-wails/assets/netbird-systemtray-connected-dark.png and b/client/ui-wails/assets/netbird-systemtray-connected-dark.png differ diff --git a/client/ui-wails/assets/netbird-systemtray-connected-macos.png b/client/ui-wails/assets/netbird-systemtray-connected-macos.png index 9c9a76366..ead210250 100644 Binary files a/client/ui-wails/assets/netbird-systemtray-connected-macos.png and b/client/ui-wails/assets/netbird-systemtray-connected-macos.png differ diff --git a/client/ui-wails/assets/netbird-systemtray-connected.ico b/client/ui-wails/assets/netbird-systemtray-connected.ico deleted file mode 100644 index 6ee5335e8..000000000 Binary files a/client/ui-wails/assets/netbird-systemtray-connected.ico and /dev/null differ diff --git a/client/ui-wails/assets/netbird-systemtray-connected.png b/client/ui-wails/assets/netbird-systemtray-connected.png index be38eb0a6..4258a5c1c 100644 Binary files a/client/ui-wails/assets/netbird-systemtray-connected.png and b/client/ui-wails/assets/netbird-systemtray-connected.png differ diff --git a/client/ui-wails/assets/netbird-systemtray-connecting-dark.png b/client/ui-wails/assets/netbird-systemtray-connecting-dark.png new file mode 100644 index 000000000..a665eb61c Binary files /dev/null and b/client/ui-wails/assets/netbird-systemtray-connecting-dark.png differ diff --git a/client/ui-wails/assets/netbird-systemtray-connecting-macos.png b/client/ui-wails/assets/netbird-systemtray-connecting-macos.png index 87d548b9c..0fe7fa0db 100644 Binary files a/client/ui-wails/assets/netbird-systemtray-connecting-macos.png and b/client/ui-wails/assets/netbird-systemtray-connecting-macos.png differ diff --git a/client/ui-wails/assets/netbird-systemtray-connecting.ico b/client/ui-wails/assets/netbird-systemtray-connecting.ico deleted file mode 100644 index a62d16e83..000000000 Binary files a/client/ui-wails/assets/netbird-systemtray-connecting.ico and /dev/null differ diff --git a/client/ui-wails/assets/netbird-systemtray-connecting.png b/client/ui-wails/assets/netbird-systemtray-connecting.png index d97312fec..4f607c997 100644 Binary files a/client/ui-wails/assets/netbird-systemtray-connecting.png and b/client/ui-wails/assets/netbird-systemtray-connecting.png differ diff --git a/client/ui-wails/assets/netbird-systemtray-disconnected-macos.png b/client/ui-wails/assets/netbird-systemtray-disconnected-macos.png index 58e32e690..36b9a488f 100644 Binary files a/client/ui-wails/assets/netbird-systemtray-disconnected-macos.png and b/client/ui-wails/assets/netbird-systemtray-disconnected-macos.png differ diff --git a/client/ui-wails/assets/netbird-systemtray-disconnected.ico b/client/ui-wails/assets/netbird-systemtray-disconnected.ico deleted file mode 100644 index b5bdab507..000000000 Binary files a/client/ui-wails/assets/netbird-systemtray-disconnected.ico and /dev/null differ diff --git a/client/ui-wails/assets/netbird-systemtray-disconnected.png b/client/ui-wails/assets/netbird-systemtray-disconnected.png index a79fd1bed..a92e9ed4c 100644 Binary files a/client/ui-wails/assets/netbird-systemtray-disconnected.png and b/client/ui-wails/assets/netbird-systemtray-disconnected.png differ diff --git a/client/ui-wails/assets/netbird-systemtray-error-dark.png b/client/ui-wails/assets/netbird-systemtray-error-dark.png new file mode 100644 index 000000000..969554b16 Binary files /dev/null and b/client/ui-wails/assets/netbird-systemtray-error-dark.png differ diff --git a/client/ui-wails/assets/netbird-systemtray-error-macos.png b/client/ui-wails/assets/netbird-systemtray-error-macos.png index ce9dc6d1d..9a9998bcf 100644 Binary files a/client/ui-wails/assets/netbird-systemtray-error-macos.png and b/client/ui-wails/assets/netbird-systemtray-error-macos.png differ diff --git a/client/ui-wails/assets/netbird-systemtray-error.ico b/client/ui-wails/assets/netbird-systemtray-error.ico deleted file mode 100644 index f3bb85e21..000000000 Binary files a/client/ui-wails/assets/netbird-systemtray-error.ico and /dev/null differ diff --git a/client/ui-wails/assets/netbird-systemtray-error.png b/client/ui-wails/assets/netbird-systemtray-error.png index 32c61b82d..722342989 100644 Binary files a/client/ui-wails/assets/netbird-systemtray-error.png and b/client/ui-wails/assets/netbird-systemtray-error.png differ diff --git a/client/ui-wails/assets/netbird-systemtray-update-connected-dark.png b/client/ui-wails/assets/netbird-systemtray-update-connected-dark.png new file mode 100644 index 000000000..52ae621ac Binary files /dev/null and b/client/ui-wails/assets/netbird-systemtray-update-connected-dark.png differ diff --git a/client/ui-wails/assets/netbird-systemtray-update-connected-macos.png b/client/ui-wails/assets/netbird-systemtray-update-connected-macos.png index 84cb1c029..8a6b2f2db 100644 Binary files a/client/ui-wails/assets/netbird-systemtray-update-connected-macos.png and b/client/ui-wails/assets/netbird-systemtray-update-connected-macos.png differ diff --git a/client/ui-wails/assets/netbird-systemtray-update-connected.ico b/client/ui-wails/assets/netbird-systemtray-update-connected.ico deleted file mode 100644 index 5b1df668d..000000000 Binary files a/client/ui-wails/assets/netbird-systemtray-update-connected.ico and /dev/null differ diff --git a/client/ui-wails/assets/netbird-systemtray-update-connected.png b/client/ui-wails/assets/netbird-systemtray-update-connected.png index 4b160f888..90bb0b7f1 100644 Binary files a/client/ui-wails/assets/netbird-systemtray-update-connected.png and b/client/ui-wails/assets/netbird-systemtray-update-connected.png differ diff --git a/client/ui-wails/assets/netbird-systemtray-update-disconnected-dark.png b/client/ui-wails/assets/netbird-systemtray-update-disconnected-dark.png new file mode 100644 index 000000000..9e05351f1 Binary files /dev/null and b/client/ui-wails/assets/netbird-systemtray-update-disconnected-dark.png differ diff --git a/client/ui-wails/assets/netbird-systemtray-update-disconnected-macos.png b/client/ui-wails/assets/netbird-systemtray-update-disconnected-macos.png index fb8f8573e..8b190034e 100644 Binary files a/client/ui-wails/assets/netbird-systemtray-update-disconnected-macos.png and b/client/ui-wails/assets/netbird-systemtray-update-disconnected-macos.png differ diff --git a/client/ui-wails/assets/netbird-systemtray-update-disconnected.ico b/client/ui-wails/assets/netbird-systemtray-update-disconnected.ico deleted file mode 100644 index f3a1986fc..000000000 Binary files a/client/ui-wails/assets/netbird-systemtray-update-disconnected.ico and /dev/null differ diff --git a/client/ui-wails/assets/netbird-systemtray-update-disconnected.png b/client/ui-wails/assets/netbird-systemtray-update-disconnected.png index 2e9e1c8b2..3adc39034 100644 Binary files a/client/ui-wails/assets/netbird-systemtray-update-disconnected.png and b/client/ui-wails/assets/netbird-systemtray-update-disconnected.png differ diff --git a/client/ui-wails/build/Taskfile.yml b/client/ui-wails/build/Taskfile.yml index a8262fc49..590d4791b 100644 --- a/client/ui-wails/build/Taskfile.yml +++ b/client/ui-wails/build/Taskfile.yml @@ -110,22 +110,31 @@ tasks: - wails3 generate icons -input appicon.png -macfilename darwin/icons.icns -windowsfilename windows/icon.ico -iconcomposerinput appicon.icon -macassetdir darwin generate:tray:icons: - summary: Rasterize the SVG tray sources to PNG/ICO embedded by the Go side. + summary: Rebuild Windows multi-res .ico files from the per-state PNGs. desc: | - Reads assets/svg/*.svg and writes assets/.png (Linux/macOS - tray) plus assets/.ico (Windows tray). The .ico packs 16/24/32/48 - px frames so Shell_NotifyIcon picks the size matching the user's DPI - instead of poorly downscaling a single large PNG. - Run after editing any SVG; CI runs this before build. + The colored tray PNGs (assets/netbird-systemtray-.png) and the + macOS template variants are committed to the repo as the canonical + source. This task only regenerates the Windows multi-resolution .ico + files from those PNGs by downscaling each to 16/24/32/48 px and + packing them with icotool, so Shell_NotifyIcon picks the frame + matching the user's DPI instead of downscaling a single large PNG. + + Run after replacing any of the colored PNGs (e.g. when copying a new + version of the icons from client/ui/assets). The SVG sources in + assets/svg/ are kept for reference but are not built by default. dir: assets sources: - - "svg/*.svg" + - "netbird-systemtray-connected.png" + - "netbird-systemtray-disconnected.png" + - "netbird-systemtray-connecting.png" + - "netbird-systemtray-error.png" + - "netbird-systemtray-update-connected.png" + - "netbird-systemtray-update-disconnected.png" generates: - - "netbird-systemtray-*.png" - "netbird-systemtray-*.ico" preconditions: - - sh: command -v inkscape >/dev/null 2>&1 - msg: "inkscape is required to rasterize tray SVGs (apt install inkscape)" + - sh: command -v magick >/dev/null 2>&1 || command -v convert >/dev/null 2>&1 + msg: "ImageMagick is required to downscale PNGs (apt install imagemagick)" - sh: command -v icotool >/dev/null 2>&1 msg: "icotool is required to pack tray .ico files (apt install icoutils)" cmds: @@ -133,19 +142,14 @@ tasks: set -euo pipefail tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT + resize=$(command -v magick || echo convert) for state in connected disconnected connecting error update-connected update-disconnected; do - # 64px PNG for Linux tray + macOS-template PNG (per-state) - inkscape --export-type=png --export-width=64 --export-filename="netbird-systemtray-$state.png" "svg/$state.svg" >/dev/null - inkscape --export-type=png --export-width=64 --export-filename="netbird-systemtray-$state-macos.png" "svg/$state-macos.svg" >/dev/null - # multi-resolution .ico for Windows tray for sz in 16 24 32 48; do - inkscape --export-type=png --export-width=$sz --export-filename="$tmp/$state-$sz.png" "svg/$state.svg" >/dev/null + "$resize" "netbird-systemtray-$state.png" -resize ${sz}x${sz} "$tmp/$state-$sz.png" done icotool -c -o "netbird-systemtray-$state.ico" \ "$tmp/$state-16.png" "$tmp/$state-24.png" "$tmp/$state-32.png" "$tmp/$state-48.png" done - # Linux dark-mode variant currently shares the connected artwork. - inkscape --export-type=png --export-width=64 --export-filename="netbird-systemtray-connected-dark.png" "svg/connected.svg" >/dev/null dev:frontend: summary: Runs the frontend in development mode diff --git a/client/ui-wails/icons.go b/client/ui-wails/icons.go index 3f4ec97f2..802377d25 100644 --- a/client/ui-wails/icons.go +++ b/client/ui-wails/icons.go @@ -4,10 +4,12 @@ package main import _ "embed" -// Tray icons embedded from the legacy Fyne UI's asset set so the rewrite has -// something to render until Stage 3 produces SVG sources. Each pair is a -// light-mode PNG and its dark-mode variant; macOS template variants live -// alongside for menubar use. +// Tray icons embedded from the legacy Fyne UI's asset set. Each pair is a +// light-mode PNG and its dark-mode variant; macOS template variants +// (*-macos.png) live alongside for menubar use. Windows uses the same +// PNGs — multi-resolution .ico files looked promising on disk but +// Wails3's Shell_NotifyIcon NIM_MODIFY never redrew them on the running +// tray; PNG single-frame works. //go:embed assets/netbird-systemtray-connected.png var iconConnected []byte diff --git a/client/ui-wails/icons_windows.go b/client/ui-wails/icons_windows.go deleted file mode 100644 index 1e0763770..000000000 --- a/client/ui-wails/icons_windows.go +++ /dev/null @@ -1,29 +0,0 @@ -//go:build windows - -package main - -import _ "embed" - -// Windows tray icons. Wails3 hands these to Shell_NotifyIcon via -// CreateIconFromResourceEx, which picks the frame matching SM_CXSMICON -// (16/32 px depending on DPI). A single high-res PNG forces the OS to -// downscale and the result is fuzzy at tray size — multi-frame .ico files -// avoid that by embedding 16/24/32/48 px raster frames in one resource. - -//go:embed assets/netbird-systemtray-connected.ico -var winIconConnected []byte - -//go:embed assets/netbird-systemtray-disconnected.ico -var winIconDisconnected []byte - -//go:embed assets/netbird-systemtray-connecting.ico -var winIconConnecting []byte - -//go:embed assets/netbird-systemtray-error.ico -var winIconError []byte - -//go:embed assets/netbird-systemtray-update-connected.ico -var winIconUpdateConnected []byte - -//go:embed assets/netbird-systemtray-update-disconnected.ico -var winIconUpdateDisconnected []byte diff --git a/client/ui-wails/main.go b/client/ui-wails/main.go index 480b3b21f..2e351ec91 100644 --- a/client/ui-wails/main.go +++ b/client/ui-wails/main.go @@ -7,17 +7,41 @@ import ( "embed" "flag" "log" + "strings" "github.com/wailsapp/wails/v3/pkg/application" "github.com/wailsapp/wails/v3/pkg/events" "github.com/wailsapp/wails/v3/pkg/services/notifications" "github.com/netbirdio/netbird/client/ui-wails/services" + "github.com/netbirdio/netbird/util" ) //go:embed all:frontend/dist var assets embed.FS +// stringList is a flag.Value that collects repeated string flags. The first +// time the user passes -log-file the seeded default ("console") is dropped; +// subsequent passes append. Lets the user replace or extend the log target +// list without a separate "reset" flag. +type stringList struct { + values []string + userSet bool +} + +func (s *stringList) String() string { + return strings.Join(s.values, ",") +} + +func (s *stringList) Set(v string) error { + if !s.userSet { + s.values = nil + s.userSet = true + } + s.values = append(s.values, v) + return nil +} + func init() { application.RegisterEvent[services.Status](services.EventStatus) application.RegisterEvent[services.SystemEvent](services.EventSystem) @@ -27,8 +51,15 @@ func init() { func main() { daemonAddr := flag.String("daemon-addr", DaemonAddr(), "Daemon gRPC address: unix:///path or tcp://host:port") + logFiles := &stringList{values: []string{"console"}} + flag.Var(logFiles, "log-file", "Log destination. Repeat to log to multiple targets at once, e.g. `--log-file console --log-file Y:/netbird-ui.log`. Each value is one of: console, syslog, or a file path. File destinations are rotated by lumberjack (same as the daemon). Defaults to console.") + logLevel := flag.String("log-level", "info", "Log level: trace|debug|info|warn|error.") flag.Parse() + if err := util.InitLog(*logLevel, logFiles.values...); err != nil { + log.Fatalf("init log: %v", err) + } + conn := NewConn(*daemonAddr) // tray is captured in the SingleInstance callback below; the var is diff --git a/client/ui-wails/services/peers.go b/client/ui-wails/services/peers.go index 093371e39..977cb4f59 100644 --- a/client/ui-wails/services/peers.go +++ b/client/ui-wails/services/peers.go @@ -178,12 +178,17 @@ func (s *Peers) pollLoop(ctx context.Context) { ticker := time.NewTicker(PollInterval) defer ticker.Stop() + first := true for { st, err := s.Get(ctx) if err == nil { + if first { + log.Infof("peers pollLoop: first status ok status=%q peers=%d", st.Status, len(st.Peers)) + first = false + } s.emitter.Emit(EventStatus, st) } else if ctx.Err() == nil { - log.Debugf("status poll: %v", err) + log.Warnf("peers pollLoop: status poll error: %v", err) } select { diff --git a/client/ui-wails/tray.go b/client/ui-wails/tray.go index 91a3625e6..34d785209 100644 --- a/client/ui-wails/tray.go +++ b/client/ui-wails/tray.go @@ -299,8 +299,10 @@ func (t *Tray) onSystemEvent(ev *application.CustomEvent) { func (t *Tray) onUpdateAvailable(ev *application.CustomEvent) { upd, ok := ev.Data.(services.UpdateAvailable) if !ok { + log.Warnf("update event payload not UpdateAvailable: %T", ev.Data) return } + log.Infof("tray onUpdateAvailable: version=%s enforced=%v", upd.Version, upd.Enforced) t.mu.Lock() t.hasUpdate = true t.mu.Unlock() @@ -383,15 +385,14 @@ func (t *Tray) rebuildExitNodes(nodes []string) { } func (t *Tray) applyIcon() { - if runtime.GOOS == "windows" { - t.mu.Lock() - ico := trayIcon(t.connected, t.hasUpdate, t.lastStatus) - t.mu.Unlock() - if ico != nil { - t.tray.SetIcon(ico) - } - return - } + t.mu.Lock() + connected := t.connected + hasUpdate := t.hasUpdate + statusLabel := t.lastStatus + t.mu.Unlock() + + log.Infof("tray applyIcon: connected=%v hasUpdate=%v status=%q goos=%s", + connected, hasUpdate, statusLabel, runtime.GOOS) icon, dark := t.iconForState() if runtime.GOOS == "darwin" { @@ -563,3 +564,4 @@ func titleCase(s string) string { } return strings.ToUpper(s[:1]) + strings.ToLower(s[1:]) } + diff --git a/client/ui-wails/tray_icon_other.go b/client/ui-wails/tray_icon_other.go deleted file mode 100644 index 6e2489929..000000000 --- a/client/ui-wails/tray_icon_other.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build !windows && !android && !ios && !freebsd && !js - -package main - -// trayIcon is unused on non-Windows hosts — Linux feeds setIcon a PNG and -// macOS uses SetTemplateIcon. This stub exists so the compiler is happy and -// callers don't need build tags around references. -func trayIcon(_, _ bool, _ string) []byte { return nil } diff --git a/client/ui-wails/tray_icon_windows.go b/client/ui-wails/tray_icon_windows.go deleted file mode 100644 index 8cd7ec606..000000000 --- a/client/ui-wails/tray_icon_windows.go +++ /dev/null @@ -1,27 +0,0 @@ -//go:build windows - -package main - -import "strings" - -// trayIcon returns the Windows-tray .ico bytes for the given state. The -// other-platform implementation in tray_icon_other.go returns the colored -// PNG instead. Splitting it this way keeps the Linux/macOS paths free of -// .ico artifacts in their //go:embed search and avoids loading large icon -// resources where they aren't used. -func trayIcon(connected, hasUpdate bool, statusLabel string) []byte { - switch { - case strings.EqualFold(statusLabel, "Connecting"): - return winIconConnecting - case strings.EqualFold(statusLabel, "Error"): - return winIconError - case connected && hasUpdate: - return winIconUpdateConnected - case connected: - return winIconConnected - case hasUpdate: - return winIconUpdateDisconnected - default: - return winIconDisconnected - } -}