mirror of
https://github.com/netbirdio/netbird.git
synced 2026-07-21 07:51:29 +02:00
[client] Add "Deselect All" Menu Item to Exit Node Menu (#3877)
* [client] Enhance exit node menu functionality with deselect all option * Hide exit nodes before removal in recreateExitNodeMenu * recreateExitNodeMenu adding mutex locks * Refetch exit nodes after deselecting all in exit node menu
This commit is contained in:
@@ -235,9 +235,11 @@ type serviceClient struct {
|
||||
|
||||
eventManager *event.Manager
|
||||
|
||||
exitNodeMu sync.Mutex
|
||||
mExitNodeItems []menuHandler
|
||||
logFile string
|
||||
exitNodeMu sync.Mutex
|
||||
mExitNodeItems []menuHandler
|
||||
exitNodeStates []exitNodeState
|
||||
mExitNodeDeselectAll *systray.MenuItem
|
||||
logFile string
|
||||
}
|
||||
|
||||
type menuHandler struct {
|
||||
@@ -1035,11 +1037,11 @@ func (s *serviceClient) updateConfig() error {
|
||||
lazyConnectionEnabled := s.mLazyConnEnabled.Checked()
|
||||
|
||||
loginRequest := proto.LoginRequest{
|
||||
IsUnixDesktopClient: runtime.GOOS == "linux" || runtime.GOOS == "freebsd",
|
||||
ServerSSHAllowed: &sshAllowed,
|
||||
RosenpassEnabled: &rosenpassEnabled,
|
||||
DisableAutoConnect: &disableAutoStart,
|
||||
DisableNotifications: ¬ificationsDisabled,
|
||||
IsUnixDesktopClient: runtime.GOOS == "linux" || runtime.GOOS == "freebsd",
|
||||
ServerSSHAllowed: &sshAllowed,
|
||||
RosenpassEnabled: &rosenpassEnabled,
|
||||
DisableAutoConnect: &disableAutoStart,
|
||||
DisableNotifications: ¬ificationsDisabled,
|
||||
LazyConnectionEnabled: &lazyConnectionEnabled,
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -33,6 +34,11 @@ const (
|
||||
|
||||
type filter string
|
||||
|
||||
type exitNodeState struct {
|
||||
id string
|
||||
selected bool
|
||||
}
|
||||
|
||||
func (s *serviceClient) showNetworksUI() {
|
||||
s.wNetworks = s.app.NewWindow("Networks")
|
||||
s.wNetworks.SetOnClosed(s.cancel)
|
||||
@@ -357,18 +363,45 @@ func (s *serviceClient) updateExitNodes() {
|
||||
}
|
||||
|
||||
func (s *serviceClient) recreateExitNodeMenu(exitNodes []*proto.Network) {
|
||||
var exitNodeIDs []exitNodeState
|
||||
for _, node := range exitNodes {
|
||||
exitNodeIDs = append(exitNodeIDs, exitNodeState{
|
||||
id: node.ID,
|
||||
selected: node.Selected,
|
||||
})
|
||||
}
|
||||
|
||||
sort.Slice(exitNodeIDs, func(i, j int) bool {
|
||||
return exitNodeIDs[i].id < exitNodeIDs[j].id
|
||||
})
|
||||
if slices.Equal(s.exitNodeStates, exitNodeIDs) {
|
||||
log.Debug("Exit node menu already up to date")
|
||||
return
|
||||
}
|
||||
|
||||
for _, node := range s.mExitNodeItems {
|
||||
node.cancel()
|
||||
node.Hide()
|
||||
node.Remove()
|
||||
}
|
||||
s.mExitNodeItems = nil
|
||||
if s.mExitNodeDeselectAll != nil {
|
||||
s.mExitNodeDeselectAll.Remove()
|
||||
s.mExitNodeDeselectAll = nil
|
||||
}
|
||||
|
||||
if runtime.GOOS == "linux" || runtime.GOOS == "freebsd" {
|
||||
s.mExitNode.Remove()
|
||||
s.mExitNode = systray.AddMenuItem("Exit Node", exitNodeMenuDescr)
|
||||
}
|
||||
|
||||
var showDeselectAll bool
|
||||
|
||||
for _, node := range exitNodes {
|
||||
if node.Selected {
|
||||
showDeselectAll = true
|
||||
}
|
||||
|
||||
menuItem := s.mExitNode.AddSubMenuItemCheckbox(
|
||||
node.ID,
|
||||
fmt.Sprintf("Use exit node %s", node.ID),
|
||||
@@ -383,6 +416,32 @@ func (s *serviceClient) recreateExitNodeMenu(exitNodes []*proto.Network) {
|
||||
go s.handleChecked(ctx, node.ID, menuItem)
|
||||
}
|
||||
|
||||
s.exitNodeStates = exitNodeIDs
|
||||
|
||||
if showDeselectAll {
|
||||
s.mExitNode.AddSeparator()
|
||||
deselectAllItem := s.mExitNode.AddSubMenuItem("Deselect All", "Deselect All")
|
||||
s.mExitNodeDeselectAll = deselectAllItem
|
||||
go func() {
|
||||
for {
|
||||
_, ok := <-deselectAllItem.ClickedCh
|
||||
if !ok {
|
||||
// channel closed: exit the goroutine
|
||||
return
|
||||
}
|
||||
exitNodes, err := s.handleExitNodeMenuDeselectAll()
|
||||
if err != nil {
|
||||
log.Warnf("failed to handle deselect all exit nodes: %v", err)
|
||||
} else {
|
||||
s.exitNodeMu.Lock()
|
||||
s.recreateExitNodeMenu(exitNodes)
|
||||
s.exitNodeMu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
}()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *serviceClient) getExitNodes(conn proto.DaemonServiceClient) ([]*proto.Network, error) {
|
||||
@@ -420,6 +479,37 @@ func (s *serviceClient) handleChecked(ctx context.Context, id string, item *syst
|
||||
}
|
||||
}
|
||||
|
||||
func (s *serviceClient) handleExitNodeMenuDeselectAll() ([]*proto.Network, error) {
|
||||
conn, err := s.getSrvClient(defaultFailTimeout)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get client: %v", err)
|
||||
}
|
||||
|
||||
exitNodes, err := s.getExitNodes(conn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get exit nodes: %v", err)
|
||||
}
|
||||
|
||||
var ids []string
|
||||
for _, e := range exitNodes {
|
||||
if e.Selected {
|
||||
ids = append(ids, e.ID)
|
||||
}
|
||||
}
|
||||
|
||||
// deselect selected exit nodes
|
||||
if err := s.deselectOtherExitNodes(conn, ids); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
updatedExitNodes, err := s.getExitNodes(conn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("re-fetch exit nodes: %v", err)
|
||||
}
|
||||
|
||||
return updatedExitNodes, nil
|
||||
}
|
||||
|
||||
// Add function to toggle exit node selection
|
||||
func (s *serviceClient) toggleExitNode(nodeID string, item *systray.MenuItem) error {
|
||||
conn, err := s.getSrvClient(defaultFailTimeout)
|
||||
|
||||
Reference in New Issue
Block a user