From 18d00193328b052094c0c37592098da1e05438f0 Mon Sep 17 00:00:00 2001 From: Zoltan Papp Date: Tue, 26 May 2026 11:23:41 +0200 Subject: [PATCH] tray: drop Networks menu item, make session-expiry row open extend flow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Networks row removed from the tray; Exit Node remains the only routed- state entry. Clicking the "Expires in …" row now opens the SessionAboutToExpire window seeded with the actual remaining seconds, so users can extend the SSO session proactively instead of waiting for the daemon's T-FinalWarningLead auto-prompt. --- client/ui/tray.go | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/client/ui/tray.go b/client/ui/tray.go index 7f0ec2f8a..49f16c063 100644 --- a/client/ui/tray.go +++ b/client/ui/tray.go @@ -116,7 +116,6 @@ type Tray struct { // separators with nothing between them. connectSeparator *application.MenuItem exitNodeItem *application.MenuItem - networksItem *application.MenuItem profileSubmenu *application.Menu profileSubmenuItem *application.MenuItem profileEmailItem *application.MenuItem @@ -276,9 +275,6 @@ func (t *Tray) reapplyMenuState() { if t.exitNodeItem != nil { t.exitNodeItem.SetEnabled(connected) } - if t.networksItem != nil { - t.networksItem.SetEnabled(connected) - } if t.settingsItem != nil { t.settingsItem.SetEnabled(!daemonUnavailable) } @@ -374,8 +370,10 @@ func (t *Tray) buildMenu() *application.Menu { // its account email, and the SSO session deadline read as a single block. // Hidden until applyStatus sees a non-zero SessionExpiresAt on the daemon // Status snapshot — peers without SSO tracking or with login expiry - // disabled never reveal this row. - t.sessionExpiresItem = menu.Add("").SetEnabled(false) + // disabled never reveal this row. Click opens the SessionAboutToExpire + // window so the user can extend the session ahead of the daemon's + // T-FinalWarningLead auto-prompt. + t.sessionExpiresItem = menu.Add("").OnClick(func(*application.Context) { t.openSessionExtendFlow() }) t.sessionExpiresItem.SetHidden(true) // AddSeparator returns no reference, so capture the separator by walking // ItemAt until it returns nil and grabbing the last index. @@ -391,7 +389,6 @@ func (t *Tray) buildMenu() *application.Menu { menu.AddSeparator() t.exitNodeItem = menu.Add(t.loc.T("tray.menu.exitNode")).SetEnabled(false) - t.networksItem = menu.Add(t.loc.T("tray.menu.networks")).OnClick(func(*application.Context) { t.openRoute("/networks") }) menu.AddSeparator() @@ -689,15 +686,12 @@ func (t *Tray) applyStatus(st services.Status) { // two adjacent separators with nothing between them. t.connectSeparator.SetHidden(daemonUnavailable) } - // Exit Node and Resources surface tunnel-routed state, so only - // expose them while the tunnel is up. Settings/Debug-Bundle just - // need the daemon socket reachable. + // Exit Node surfaces tunnel-routed state, so only expose it while + // the tunnel is up. Settings/Debug-Bundle just need the daemon + // socket reachable. if t.exitNodeItem != nil { t.exitNodeItem.SetEnabled(connected) } - if t.networksItem != nil { - t.networksItem.SetEnabled(connected) - } if t.settingsItem != nil { t.settingsItem.SetEnabled(!daemonUnavailable) } @@ -1240,6 +1234,29 @@ func (t *Tray) openSessionAboutToExpire() { t.svc.WindowManager.OpenSessionAboutToExpire(finalWarningCountdownSeconds) } +// openSessionExtendFlow opens the SessionAboutToExpire window seeded with +// the actual remaining time on the cached SSO deadline. Triggered by a +// click on the "Expires in …" tray row so the user can extend the session +// proactively, instead of waiting for the daemon's T-FinalWarningLead +// auto-prompt. Silently no-ops when the deadline is unknown or already +// elapsed — the menu row is hidden in those states anyway. +func (t *Tray) openSessionExtendFlow() { + if t.svc.WindowManager == nil { + return + } + t.mu.Lock() + deadline := t.sessionExpiresAt + t.mu.Unlock() + if deadline.IsZero() { + return + } + seconds := int(time.Until(deadline).Seconds()) + if seconds <= 0 { + return + } + t.svc.WindowManager.OpenSessionAboutToExpire(seconds) +} + // notifyError fires a generic "Error" notification for tray-driven action // failures. Each tray click site already logs the underlying error; this // adds the user-visible toast.