@@ -53,6 +53,12 @@ public struct AppMenu: View {
53
53
loginToggle
54
54
keepToggle
55
55
Divider ( )
56
+ Group {
57
+ reconnectButton
58
+ disconnectButton
59
+ }
60
+ . disabled ( !isTunnelActionable)
61
+ Divider ( )
56
62
profilesList
57
63
Divider ( )
58
64
aboutButton
@@ -79,6 +85,37 @@ private extension AppMenu {
79
85
Toggle ( Strings . Views. Preferences. keepsInMenu, isOn: $settings. keepsInMenu)
80
86
}
81
87
88
+ var reconnectButton : some View {
89
+ Button ( Strings . Global. Actions. reconnect) {
90
+ Task {
91
+ guard let currentProfileId = tunnel. currentProfile? . id else {
92
+ return
93
+ }
94
+ guard let profile = profileManager. profile ( withId: currentProfileId) else {
95
+ return
96
+ }
97
+ do {
98
+ try await tunnel. disconnect ( )
99
+ try await tunnel. connect ( with: profile)
100
+ } catch {
101
+ pp_log ( . app, . error, " Unable to reconnect to profile \( profile. id) from menu: \( error) " )
102
+ }
103
+ }
104
+ }
105
+ }
106
+
107
+ var disconnectButton : some View {
108
+ Button ( Strings . Global. Actions. disconnect) {
109
+ Task {
110
+ do {
111
+ try await tunnel. disconnect ( )
112
+ } catch {
113
+ pp_log ( . app, . error, " Unable to disconnect from menu: \( error) " )
114
+ }
115
+ }
116
+ }
117
+ }
118
+
82
119
var profilesList : some View {
83
120
Group {
84
121
ForEach ( profileManager. previews, id: \. id, content: profileToggle)
@@ -125,4 +162,10 @@ private extension AppMenu {
125
162
}
126
163
}
127
164
165
+ private extension AppMenu {
166
+ var isTunnelActionable : Bool {
167
+ [ . activating, . active] . contains ( tunnel. status)
168
+ }
169
+ }
170
+
128
171
#endif
0 commit comments