Compare commits

...

2 Commits

Author SHA1 Message Date
Hakan Sariman
4df7940374 [client] Update profile display to include email if available 2025-08-05 18:05:50 +03:00
Hakan Sariman
26a6085c9f [client] Enhance profile management UI with email display and edit functionality 2025-08-05 18:00:45 +03:00
2 changed files with 63 additions and 13 deletions

View File

@@ -424,15 +424,28 @@ func (s *serviceClient) showSettingsUI() {
func (s *serviceClient) getSettingsForm() *widget.Form { func (s *serviceClient) getSettingsForm() *widget.Form {
var activeProfName string var activeProfName string
var activeProfEmail string
activeProf, err := s.profileManager.GetActiveProfile() activeProf, err := s.profileManager.GetActiveProfile()
if err != nil { if err != nil {
log.Errorf("get active profile: %v", err) log.Errorf("get active profile: %v", err)
} else { } else {
activeProfName = activeProf.Name activeProfName = activeProf.Name
// Try to get email from profile state
profileState, err := s.profileManager.GetProfileState(activeProf.Name)
if err == nil && profileState.Email != "" {
activeProfEmail = profileState.Email
}
} }
// Create profile display with email if available
profileDisplay := activeProfName
if activeProfEmail != "" {
profileDisplay = fmt.Sprintf("%s (%s)", activeProfName, activeProfEmail)
}
return &widget.Form{ return &widget.Form{
Items: []*widget.FormItem{ Items: []*widget.FormItem{
{Text: "Profile", Widget: widget.NewLabel(activeProfName)}, {Text: "Profile", Widget: widget.NewLabel(profileDisplay)},
{Text: "Quantum-Resistance", Widget: s.sRosenpassPermissive}, {Text: "Quantum-Resistance", Widget: s.sRosenpassPermissive},
{Text: "Interface Name", Widget: s.iInterfaceName}, {Text: "Interface Name", Widget: s.iInterfaceName},
{Text: "Interface Port", Widget: s.iInterfacePort}, {Text: "Interface Port", Widget: s.iInterfacePort},

View File

@@ -40,12 +40,13 @@ func (s *serviceClient) showProfilesUI() {
list := widget.NewList( list := widget.NewList(
func() int { return len(profiles) }, func() int { return len(profiles) },
func() fyne.CanvasObject { func() fyne.CanvasObject {
// Each item: Selected indicator, Name, spacer, Select, Logout & Remove buttons // Each item: Selected indicator, Name (with email), spacer, Select, Edit (for active), Logout & Remove buttons
return container.NewHBox( return container.NewHBox(
widget.NewLabel(""), // indicator widget.NewLabel(""), // indicator
widget.NewLabel(""), // profile name widget.NewLabel(""), // profile name with email
layout.NewSpacer(), layout.NewSpacer(),
widget.NewButton("Select", nil), widget.NewButton("Select", nil),
widget.NewButton("Edit", nil), // Edit button for active profiles
widget.NewButton("Logout", nil), widget.NewButton("Logout", nil),
widget.NewButton("Remove", nil), widget.NewButton("Remove", nil),
) )
@@ -56,8 +57,9 @@ func (s *serviceClient) showProfilesUI() {
indicator := row.Objects[0].(*widget.Label) indicator := row.Objects[0].(*widget.Label)
nameLabel := row.Objects[1].(*widget.Label) nameLabel := row.Objects[1].(*widget.Label)
selectBtn := row.Objects[3].(*widget.Button) selectBtn := row.Objects[3].(*widget.Button)
logoutBtn := row.Objects[4].(*widget.Button) editBtn := row.Objects[4].(*widget.Button)
removeBtn := row.Objects[5].(*widget.Button) logoutBtn := row.Objects[5].(*widget.Button)
removeBtn := row.Objects[6].(*widget.Button)
profile := profiles[i] profile := profiles[i]
// Show a checkmark if selected // Show a checkmark if selected
@@ -66,7 +68,13 @@ func (s *serviceClient) showProfilesUI() {
} else { } else {
indicator.SetText("") indicator.SetText("")
} }
nameLabel.SetText(profile.Name)
// Display profile name with email if available
displayName := profile.Name
if profile.Email != "" {
displayName = fmt.Sprintf("%s (%s)", profile.Name, profile.Email)
}
nameLabel.SetText(displayName)
// Configure Select/Active button // Configure Select/Active button
selectBtn.SetText(func() string { selectBtn.SetText(func() string {
@@ -127,6 +135,18 @@ func (s *serviceClient) showProfilesUI() {
) )
} }
// Configure Edit button (only for active profiles)
if profile.IsActive {
editBtn.Show()
editBtn.SetText("Edit")
editBtn.OnTapped = func() {
// Open settings window
s.eventHandler.runSelfCommand(s.ctx, "settings", "true")
}
} else {
editBtn.Hide()
}
logoutBtn.Show() logoutBtn.Show()
logoutBtn.SetText("Logout") logoutBtn.SetText("Logout")
logoutBtn.OnTapped = func() { logoutBtn.OnTapped = func() {
@@ -143,7 +163,7 @@ func (s *serviceClient) showProfilesUI() {
if !confirm { if !confirm {
return return
} }
err = s.removeProfile(profile.Name) err = s.removeProfile(profile.Name)
if err != nil { if err != nil {
log.Errorf("failed to remove profile: %v", err) log.Errorf("failed to remove profile: %v", err)
@@ -221,7 +241,7 @@ func (s *serviceClient) showProfilesUI() {
content := container.NewBorder(nil, newBtn, nil, nil, list) content := container.NewBorder(nil, newBtn, nil, nil, list)
s.wProfiles = s.app.NewWindow("NetBird Profiles") s.wProfiles = s.app.NewWindow("NetBird Profiles")
s.wProfiles.SetContent(content) s.wProfiles.SetContent(content)
s.wProfiles.Resize(fyne.NewSize(400, 300)) s.wProfiles.Resize(fyne.NewSize(600, 300))
s.wProfiles.SetOnClosed(s.cancel) s.wProfiles.SetOnClosed(s.cancel)
s.wProfiles.Show() s.wProfiles.Show()
@@ -301,6 +321,7 @@ func (s *serviceClient) removeProfile(profileName string) error {
type Profile struct { type Profile struct {
Name string Name string
IsActive bool IsActive bool
Email string
} }
func (s *serviceClient) getProfiles() ([]Profile, error) { func (s *serviceClient) getProfiles() ([]Profile, error) {
@@ -323,9 +344,17 @@ func (s *serviceClient) getProfiles() ([]Profile, error) {
var profiles []Profile var profiles []Profile
for _, profile := range profilesResp.Profiles { for _, profile := range profilesResp.Profiles {
// Try to get email from profile state
email := ""
profileState, err := s.profileManager.GetProfileState(profile.Name)
if err == nil && profileState.Email != "" {
email = profileState.Email
}
profiles = append(profiles, Profile{ profiles = append(profiles, Profile{
Name: profile.Name, Name: profile.Name,
IsActive: profile.IsActive, IsActive: profile.IsActive,
Email: email,
}) })
} }
@@ -340,21 +369,21 @@ func (s *serviceClient) handleProfileLogout(profileName string, refreshCallback
if !confirm { if !confirm {
return return
} }
conn, err := s.getSrvClient(defaultFailTimeout) conn, err := s.getSrvClient(defaultFailTimeout)
if err != nil { if err != nil {
log.Errorf("failed to get service client: %v", err) log.Errorf("failed to get service client: %v", err)
dialog.ShowError(fmt.Errorf("failed to connect to service"), s.wProfiles) dialog.ShowError(fmt.Errorf("failed to connect to service"), s.wProfiles)
return return
} }
currUser, err := user.Current() currUser, err := user.Current()
if err != nil { if err != nil {
log.Errorf("failed to get current user: %v", err) log.Errorf("failed to get current user: %v", err)
dialog.ShowError(fmt.Errorf("failed to get current user"), s.wProfiles) dialog.ShowError(fmt.Errorf("failed to get current user"), s.wProfiles)
return return
} }
username := currUser.Username username := currUser.Username
_, err = conn.Logout(s.ctx, &proto.LogoutRequest{ _, err = conn.Logout(s.ctx, &proto.LogoutRequest{
ProfileName: &profileName, ProfileName: &profileName,
@@ -365,13 +394,13 @@ func (s *serviceClient) handleProfileLogout(profileName string, refreshCallback
dialog.ShowError(fmt.Errorf("logout failed"), s.wProfiles) dialog.ShowError(fmt.Errorf("logout failed"), s.wProfiles)
return return
} }
dialog.ShowInformation( dialog.ShowInformation(
"Logged Out", "Logged Out",
fmt.Sprintf("Successfully logged out from '%s'", profileName), fmt.Sprintf("Successfully logged out from '%s'", profileName),
s.wProfiles, s.wProfiles,
) )
refreshCallback() refreshCallback()
}, },
s.wProfiles, s.wProfiles,
@@ -457,9 +486,17 @@ func (p *profileMenu) getProfiles() ([]Profile, error) {
var profiles []Profile var profiles []Profile
for _, profile := range profilesResp.Profiles { for _, profile := range profilesResp.Profiles {
// Try to get email from profile state
email := ""
profileState, err := p.profileManager.GetProfileState(profile.Name)
if err == nil && profileState.Email != "" {
email = profileState.Email
}
profiles = append(profiles, Profile{ profiles = append(profiles, Profile{
Name: profile.Name, Name: profile.Name,
IsActive: profile.IsActive, IsActive: profile.IsActive,
Email: email,
}) })
} }