[client] Add netbird ui improvements (#3222)

This commit is contained in:
Viktor Liu
2025-02-21 16:29:21 +01:00
committed by GitHub
parent f00a997167
commit b307298b2f
30 changed files with 1984 additions and 1529 deletions

View File

@@ -148,22 +148,24 @@ type serviceClient struct {
icError []byte
// systray menu items
mStatus *systray.MenuItem
mUp *systray.MenuItem
mDown *systray.MenuItem
mAdminPanel *systray.MenuItem
mSettings *systray.MenuItem
mAbout *systray.MenuItem
mVersionUI *systray.MenuItem
mVersionDaemon *systray.MenuItem
mUpdate *systray.MenuItem
mQuit *systray.MenuItem
mRoutes *systray.MenuItem
mAllowSSH *systray.MenuItem
mAutoConnect *systray.MenuItem
mEnableRosenpass *systray.MenuItem
mNotifications *systray.MenuItem
mAdvancedSettings *systray.MenuItem
mStatus *systray.MenuItem
mUp *systray.MenuItem
mDown *systray.MenuItem
mAdminPanel *systray.MenuItem
mSettings *systray.MenuItem
mAbout *systray.MenuItem
mVersionUI *systray.MenuItem
mVersionDaemon *systray.MenuItem
mUpdate *systray.MenuItem
mQuit *systray.MenuItem
mNetworks *systray.MenuItem
mAllowSSH *systray.MenuItem
mAutoConnect *systray.MenuItem
mEnableRosenpass *systray.MenuItem
mNotifications *systray.MenuItem
mAdvancedSettings *systray.MenuItem
mCreateDebugBundle *systray.MenuItem
mExitNode *systray.MenuItem
// application with main windows.
app fyne.App
@@ -200,6 +202,14 @@ type serviceClient struct {
wRoutes fyne.Window
eventManager *event.Manager
exitNodeMu sync.Mutex
mExitNodeItems []menuHandler
}
type menuHandler struct {
*systray.MenuItem
cancel context.CancelFunc
}
// newServiceClient instance constructor
@@ -473,6 +483,9 @@ func (s *serviceClient) updateStatus() error {
status, err := conn.Status(s.ctx, &proto.StatusRequest{})
if err != nil {
log.Errorf("get service status: %v", err)
if s.connected {
s.app.SendNotification(fyne.NewNotification("Error", "Connection to service lost"))
}
s.setDisconnectedStatus()
return err
}
@@ -498,7 +511,8 @@ func (s *serviceClient) updateStatus() error {
s.mStatus.SetTitle("Connected")
s.mUp.Disable()
s.mDown.Enable()
s.mRoutes.Enable()
s.mNetworks.Enable()
go s.updateExitNodes()
systrayIconState = true
} else if status.Status != string(internal.StatusConnected) && s.mUp.Disabled() {
s.setDisconnectedStatus()
@@ -554,7 +568,9 @@ func (s *serviceClient) setDisconnectedStatus() {
s.mStatus.SetTitle("Disconnected")
s.mDown.Disable()
s.mUp.Enable()
s.mRoutes.Disable()
s.mNetworks.Disable()
s.mExitNode.Disable()
go s.updateExitNodes()
}
func (s *serviceClient) onTrayReady() {
@@ -577,10 +593,16 @@ func (s *serviceClient) onTrayReady() {
s.mEnableRosenpass = s.mSettings.AddSubMenuItemCheckbox("Enable Quantum-Resistance", "Enable post-quantum security via Rosenpass", false)
s.mNotifications = s.mSettings.AddSubMenuItemCheckbox("Notifications", "Enable notifications", true)
s.mAdvancedSettings = s.mSettings.AddSubMenuItem("Advanced Settings", "Advanced settings of the application")
s.mCreateDebugBundle = s.mSettings.AddSubMenuItem("Create Debug Bundle", "Create and open debug information bundle")
s.loadSettings()
s.mRoutes = systray.AddMenuItem("Networks", "Open the networks management window")
s.mRoutes.Disable()
s.exitNodeMu.Lock()
s.mExitNode = systray.AddMenuItem("Exit Node", "Select exit node for routing traffic")
s.mExitNode.Disable()
s.exitNodeMu.Unlock()
s.mNetworks = systray.AddMenuItem("Networks", "Open the networks management window")
s.mNetworks.Disable()
systray.AddSeparator()
s.mAbout = systray.AddMenuItem("About", "About")
@@ -599,6 +621,9 @@ func (s *serviceClient) onTrayReady() {
systray.AddSeparator()
s.mQuit = systray.AddMenuItem("Quit", "Quit the client app")
// update exit node menu in case service is already connected
go s.updateExitNodes()
s.update.SetOnUpdateListener(s.onUpdateAvailable)
go func() {
s.getSrvConfig()
@@ -614,6 +639,12 @@ func (s *serviceClient) onTrayReady() {
s.eventManager = event.NewManager(s.app, s.addr)
s.eventManager.SetNotificationsEnabled(s.mNotifications.Checked())
s.eventManager.AddHandler(func(event *proto.SystemEvent) {
if event.Category == proto.SystemEvent_SYSTEM {
s.updateExitNodes()
}
})
go s.eventManager.Start(s.ctx)
go func() {
@@ -628,7 +659,7 @@ func (s *serviceClient) onTrayReady() {
defer s.mUp.Enable()
err := s.menuUpClick()
if err != nil {
s.runSelfCommand("error-msg", err.Error())
s.app.SendNotification(fyne.NewNotification("Error", "Failed to connect to NetBird service"))
return
}
}()
@@ -638,7 +669,7 @@ func (s *serviceClient) onTrayReady() {
defer s.mDown.Enable()
err := s.menuDownClick()
if err != nil {
s.runSelfCommand("error-msg", err.Error())
s.app.SendNotification(fyne.NewNotification("Error", "Failed to connect to NetBird service"))
return
}
}()
@@ -676,6 +707,13 @@ func (s *serviceClient) onTrayReady() {
defer s.getSrvConfig()
s.runSelfCommand("settings", "true")
}()
case <-s.mCreateDebugBundle.ClickedCh:
go func() {
if err := s.createAndOpenDebugBundle(); err != nil {
log.Errorf("Failed to create debug bundle: %v", err)
s.app.SendNotification(fyne.NewNotification("Error", "Failed to create debug bundle"))
}
}()
case <-s.mQuit.ClickedCh:
systray.Quit()
return
@@ -684,10 +722,10 @@ func (s *serviceClient) onTrayReady() {
if err != nil {
log.Errorf("%s", err)
}
case <-s.mRoutes.ClickedCh:
s.mRoutes.Disable()
case <-s.mNetworks.ClickedCh:
s.mNetworks.Disable()
go func() {
defer s.mRoutes.Enable()
defer s.mNetworks.Enable()
s.runSelfCommand("networks", "true")
}()
case <-s.mNotifications.ClickedCh:
@@ -718,7 +756,11 @@ func (s *serviceClient) runSelfCommand(command, arg string) {
return
}
cmd := exec.Command(proc, fmt.Sprintf("--%s=%s", command, arg))
cmd := exec.Command(proc,
fmt.Sprintf("--%s=%s", command, arg),
fmt.Sprintf("--daemon-addr=%s", s.addr),
)
out, err := cmd.CombinedOutput()
if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() == 1 {
log.Errorf("start %s UI: %v, %s", command, err, string(out))
@@ -737,7 +779,11 @@ func normalizedVersion(version string) string {
return versionString
}
func (s *serviceClient) onTrayExit() {}
func (s *serviceClient) onTrayExit() {
for _, item := range s.mExitNodeItems {
item.cancel()
}
}
// getSrvClient connection to the service.
func (s *serviceClient) getSrvClient(timeout time.Duration) (proto.DaemonServiceClient, error) {