11using Coder . Desktop . App . Models ;
22using Coder . Desktop . App . Services ;
3+ using Coder . Desktop . App . Views . Pages ;
34using CommunityToolkit . Mvvm . ComponentModel ;
5+ using CommunityToolkit . Mvvm . Input ;
46using Microsoft . Extensions . Logging ;
7+ using Microsoft . UI . Xaml ;
8+ using Microsoft . UI . Xaml . Controls ;
59using System ;
10+ using System . Collections ;
11+ using System . Collections . Generic ;
12+ using System . Linq ;
13+ using static Coder . Desktop . App . Models . CoderConnectSettings ;
614
715namespace Coder . Desktop . App . ViewModels ;
816
@@ -22,12 +30,19 @@ public partial class SettingsViewModel : ObservableObject
2230private ISettingsManager < CoderConnectSettings > _connectSettingsManager ;
2331private CoderConnectSettings _connectSettings = new CoderConnectSettings ( ) ;
2432private IStartupManager _startupManager ;
33+ private IRpcController _rpcController ;
2534
26- public SettingsViewModel ( ILogger < SettingsViewModel > logger , ISettingsManager < CoderConnectSettings > settingsManager , IStartupManager startupManager )
35+ private Window ? _window ;
36+
37+ public IEnumerable < PortForward > PortForwards => _connectSettings . PortForwards ;
38+
39+ public SettingsViewModel ( ILogger < SettingsViewModel > logger , ISettingsManager < CoderConnectSettings > settingsManager , IStartupManager startupManager ,
40+ IRpcController rpcController )
2741{
2842_connectSettingsManager = settingsManager ;
2943_startupManager = startupManager ;
3044_logger = logger ;
45+ _rpcController = rpcController ;
3146_connectSettings = settingsManager . Read ( ) . GetAwaiter ( ) . GetResult ( ) ;
3247StartOnLogin = startupManager . IsEnabled ( ) ;
3348ConnectOnLaunch = _connectSettings . ConnectOnLaunch ;
@@ -43,6 +58,11 @@ public SettingsViewModel(ILogger<SettingsViewModel> logger, ISettingsManager<Cod
4358}
4459}
4560
61+ public void Initialize ( Window window )
62+ {
63+ _window = window ;
64+ }
65+
4666partial void OnConnectOnLaunchChanged ( bool oldValue , bool newValue )
4767{
4868if ( oldValue == newValue )
@@ -78,4 +98,48 @@ partial void OnStartOnLoginChanged(bool oldValue, bool newValue)
7898_logger . LogError ( $ "Error setting StartOnLogin in registry:{ ex . Message } ") ;
7999}
80100}
101+
102+ [ RelayCommand ]
103+ public async void AddPortForward ( )
104+ {
105+ var rpcModel = _rpcController . GetState ( ) ;
106+ if ( rpcModel . RpcLifecycle != RpcLifecycle . Connected )
107+ {
108+ _logger . LogWarning ( "Cannot add port forward, RPC is not connected." ) ;
109+ return ;
110+ }
111+ var hosts = new List < string > ( rpcModel . Agents . Count ) ;
112+ // Agents will only contain started agents.
113+ foreach ( var agent in rpcModel . Agents )
114+ {
115+ var fqdn = agent . Fqdn
116+ . Select ( a=> a . Trim ( '.' ) )
117+ . Where ( a=> ! string . IsNullOrWhiteSpace ( a ) )
118+ . Aggregate ( ( a , b ) => a . Count ( c=> c == '.' ) < b . Count ( c=> c == '.' ) ? a : b ) ;
119+ if ( string . IsNullOrWhiteSpace ( fqdn ) )
120+ continue ;
121+ hosts . Add ( fqdn ) ;
122+ }
123+ var dialog = new ContentDialog ( ) ;
124+
125+ dialog . XamlRoot = _window ? . Content . XamlRoot ?? throw new InvalidOperationException ( "Window content XamlRoot is null." ) ;
126+ dialog . Style = Application . Current . Resources [ "DefaultContentDialogStyle" ] as Style ;
127+ dialog . Title = "Save your work?" ;
128+ dialog . PrimaryButtonText = "Save" ;
129+ dialog . CloseButtonText = "Cancel" ;
130+ dialog . DefaultButton = ContentDialogButton . Primary ;
131+ dialog . Content = new PortForwardCreation ( hosts ) ;
132+
133+ var result = await dialog . ShowAsync ( ) ;
134+
135+ if ( result == ContentDialogResult . Primary )
136+ {
137+ var portForwardCreation = dialog . Content as PortForwardCreation ;
138+ if ( portForwardCreation != null )
139+ {
140+ _connectSettings . PortForwards . Add ( portForwardCreation . PortForward ) ;
141+ _connectSettingsManager . Write ( _connectSettings ) . GetAwaiter ( ) . GetResult ( ) ;
142+ }
143+ }
144+ }
81145}