# ConnectionStrings Editor - Implementation Plan ## Overview Step-by-step implementation guide for adding ConnectionStrings editor to ConfigManager. **Estimated tasks:** 12 tasks in 4 batches --- ## Batch 1: Data Models ### Task 1: Create ConnectionProvider enum **File:** `NEW/src/Utils/JdeScoping.ConfigManager/Models/ConnectionProvider.cs` ```csharp namespace JdeScoping.ConfigManager.Models; /// /// Database provider types supported by the ConnectionStrings editor. /// public enum ConnectionProvider { Generic, SqlServer, Oracle } ``` **Verification:** Build succeeds. --- ### Task 2: Create ConnectionStringEntry model **File:** `NEW/src/Utils/JdeScoping.ConfigManager/Models/ConnectionStringEntry.cs` ```csharp namespace JdeScoping.ConfigManager.Models; /// /// Represents a single connection string entry with provider-specific fields. /// public class ConnectionStringEntry { public string Name { get; set; } = string.Empty; public ConnectionProvider Provider { get; set; } = ConnectionProvider.Generic; // SqlServer fields public string? Server { get; set; } public string? Database { get; set; } public string? UserId { get; set; } public string? Password { get; set; } public string Encrypt { get; set; } = "True"; public bool TrustServerCertificate { get; set; } public int ConnectionTimeout { get; set; } = 30; public string? ApplicationName { get; set; } // Oracle fields public string? Host { get; set; } public int Port { get; set; } = 1521; public string? ServiceName { get; set; } // Generic fields public string? RawConnectionString { get; set; } /// /// Generates the connection string based on the Provider type. /// public string GenerateConnectionString() { return Provider switch { ConnectionProvider.SqlServer => GenerateSqlServerConnectionString(), ConnectionProvider.Oracle => GenerateOracleConnectionString(), ConnectionProvider.Generic => RawConnectionString ?? string.Empty, _ => string.Empty }; } private string GenerateSqlServerConnectionString() { var parts = new List(); if (!string.IsNullOrWhiteSpace(Server)) parts.Add($"Server={Server}"); if (!string.IsNullOrWhiteSpace(Database)) parts.Add($"Database={Database}"); if (!string.IsNullOrWhiteSpace(UserId)) parts.Add($"User Id={UserId}"); if (!string.IsNullOrWhiteSpace(Password)) parts.Add($"Password={Password}"); if (!string.IsNullOrWhiteSpace(Encrypt)) parts.Add($"Encrypt={Encrypt}"); if (TrustServerCertificate) parts.Add("TrustServerCertificate=True"); if (ConnectionTimeout != 30) parts.Add($"Connection Timeout={ConnectionTimeout}"); if (!string.IsNullOrWhiteSpace(ApplicationName)) parts.Add($"Application Name={ApplicationName}"); return string.Join(";", parts); } private string GenerateOracleConnectionString() { var parts = new List(); var host = Host ?? "localhost"; var port = Port > 0 ? Port : 1521; var service = ServiceName ?? ""; parts.Add($"Data Source=//{host}:{port}/{service}"); if (!string.IsNullOrWhiteSpace(UserId)) parts.Add($"User Id={UserId}"); if (!string.IsNullOrWhiteSpace(Password)) parts.Add($"Password={Password}"); if (ConnectionTimeout > 0 && ConnectionTimeout != 30) parts.Add($"Connection Timeout={ConnectionTimeout}"); return string.Join(";", parts); } } ``` **Verification:** Build succeeds. --- ### Task 3: Create ConnectionStringsSection model **File:** `NEW/src/Utils/JdeScoping.ConfigManager/Models/ConnectionStringsSection.cs` ```csharp namespace JdeScoping.ConfigManager.Models; /// /// Configuration section for connection strings. /// public class ConnectionStringsSection { public List Entries { get; set; } = new(); } ``` **Verification:** Build succeeds. --- ### Task 4: Add ConnectionStrings to ConfigModel **File:** `NEW/src/Utils/JdeScoping.ConfigManager/Models/ConfigModel.cs` Add property to existing ConfigModel class: ```csharp public ConnectionStringsSection ConnectionStrings { get; set; } = new(); ``` **Verification:** Build succeeds. --- ## Batch 2: ViewModels ### Task 5: Create ConnectionStringEntryViewModel **File:** `NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/Forms/ConnectionStringEntryViewModel.cs` Create ViewModel that wraps ConnectionStringEntry with: - All properties exposed with change notification - `GeneratedConnectionString` computed property - `IsPasswordVisible` toggle property - `TogglePasswordVisibilityCommand` - `ProviderDisplay` and `ServerDisplay` for table columns Key implementation details: - Constructor takes `ConnectionStringEntry model` and `Action onChanged` - All setters call `OnPropertyChanged()` and `_onChanged()` - When Provider changes, also notify `GeneratedConnectionString` - ServerDisplay returns Server (SqlServer), Host (Oracle), or "-" (Generic) **Verification:** Build succeeds. --- ### Task 6: Create ConnectionStringsFormViewModel **File:** `NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/Forms/ConnectionStringsFormViewModel.cs` Create main ViewModel with: - `Connections : ObservableCollection` - `SelectedConnection : ConnectionStringEntryViewModel?` - `HasSelection : bool` (computed from SelectedConnection != null) - `ConnectionCount : int` (computed from Connections.Count) - `AvailableProviders : IReadOnlyList` - `EncryptOptions : IReadOnlyList` = ["True", "False", "Strict"] Commands: - `AddConnectionCommand` - creates new entry with default name "NewConnection", selects it - `DeleteConnectionCommand` - requires confirmation via IDialogService, removes selected - `ValidateConnectionCommand` - validates syntax, shows result via IDialogService - `TestConnectionCommand` - tests actual connection, shows modal result Constructor takes: - `ConnectionStringsSection model` - `Action onChanged` - `IDialogService dialogService` **Verification:** Build succeeds. --- ### Task 7: Create IConnectionTestService interface and implementation **File:** `NEW/src/Utils/JdeScoping.ConfigManager/Services/IConnectionTestService.cs` ```csharp namespace JdeScoping.ConfigManager.Services; public interface IConnectionTestService { Task TestConnectionAsync(string connectionString, ConnectionProvider provider); } public class ConnectionTestResult { public bool Success { get; init; } public string Message { get; init; } = string.Empty; public TimeSpan? Duration { get; init; } } ``` **File:** `NEW/src/Utils/JdeScoping.ConfigManager/Services/ConnectionTestService.cs` Implementation that: - Uses `Microsoft.Data.SqlClient` for SqlServer - Uses `Oracle.ManagedDataAccess.Client` for Oracle (or stub if not available) - Returns success/failure with timing and error message **Verification:** Build succeeds. --- ## Batch 3: Views (AXAML) ### Task 8: Create ConnectionStringsFormView.axaml **File:** `NEW/src/Utils/JdeScoping.ConfigManager/Views/Forms/ConnectionStringsFormView.axaml` Create view with: 1. Header section ("Connection Strings" with separator) 2. Connections list section: - DataGrid with Name, Provider, Server columns - Height="200", selection mode single - Toolbar with Add, Delete buttons 3. Placeholder section (when no selection): - "Select a connection string to edit" text 4. Edit form section (when selection exists): - Name + Provider fields (always visible) - ContentControl with DataTemplates for provider-specific fields 5. Action buttons section: - Validate, Test Connection buttons Use existing form styling: - Background="#0D0F12", BorderBrush="#2D3540" - Input Background="#232A35" - FontFamily="JetBrains Mono" for values - MaxWidth="800" (wider than other forms for table) **Verification:** Build succeeds and view renders. --- ### Task 9: Create provider-specific DataTemplates Within ConnectionStringsFormView.axaml, create DataTemplates in UserControl.Resources: **SqlServerTemplate:** - Server, Database fields (row) - UserId, Password fields (row, password with reveal button) - Encrypt dropdown, TrustServerCertificate checkbox (row) - ConnectionTimeout, ApplicationName fields (row) - Connection string preview box **OracleTemplate:** - Host, Port fields (row) - ServiceName field - UserId, Password fields (row, password with reveal button) - ConnectionTimeout field - Connection string preview box **GenericTemplate:** - Info banner explaining generic usage - Connection String multiline TextBox Use ContentControl with binding to switch templates based on Provider. **Verification:** Build succeeds, templates render correctly. --- ### Task 10: Create ConnectionStringsFormView.axaml.cs code-behind **File:** `NEW/src/Utils/JdeScoping.ConfigManager/Views/Forms/ConnectionStringsFormView.axaml.cs` Standard Avalonia code-behind: ```csharp using Avalonia.Controls; namespace JdeScoping.ConfigManager.Views.Forms; public partial class ConnectionStringsFormView : UserControl { public ConnectionStringsFormView() { InitializeComponent(); } } ``` **Verification:** Build succeeds. --- ## Batch 4: Integration & Tests ### Task 11: Integrate into MainWindowViewModel **File:** `NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/MainWindowViewModel.cs` Updates needed: 1. In `BuildSettingsNodes()` method, add ConnectionStrings node: ```csharp new TreeNodeViewModel("ConnectionStrings", "🔗", TreeNodeType.SettingsSection) { SectionKey = "ConnectionStrings" } ``` 2. In `LoadFormViewModelForNode()` method, add case for ConnectionStrings: ```csharp "ConnectionStrings" => new ConnectionStringsFormViewModel( _appSettingsConfig!.ConnectionStrings, MarkCurrentNodeModified, _dialogService, _connectionTestService), ``` 3. Register `IConnectionTestService` in DI (App.axaml.cs or Program.cs) **Verification:** - Build succeeds - ConnectionStrings appears in Settings tree - Clicking node shows form --- ### Task 12: Add unit tests **File:** `NEW/tests/JdeScoping.ConfigManager.Tests/Models/ConnectionStringEntryTests.cs` Test cases: - `GenerateConnectionString_SqlServer_ProducesCorrectFormat` - `GenerateConnectionString_SqlServer_OmitsDefaultTimeout` - `GenerateConnectionString_Oracle_ProducesEZConnectFormat` - `GenerateConnectionString_Generic_ReturnsRawString` - `DefaultValues_AreCorrect` **File:** `NEW/tests/JdeScoping.ConfigManager.Tests/ViewModels/Forms/ConnectionStringEntryViewModelTests.cs` Test cases: - `Constructor_InitializesFromModel` - `PropertyChange_UpdatesModel` - `PropertyChange_InvokesOnChanged` - `TogglePasswordVisibility_TogglesIsPasswordVisible` - `ProviderDisplay_ReturnsCorrectString` - `ServerDisplay_ReturnsServerForSqlServer` - `ServerDisplay_ReturnsHostForOracle` - `ServerDisplay_ReturnsDashForGeneric` **File:** `NEW/tests/JdeScoping.ConfigManager.Tests/ViewModels/Forms/ConnectionStringsFormViewModelTests.cs` Test cases: - `Constructor_InitializesFromModel` - `AddConnection_CreatesNewEntryAndSelectsIt` - `DeleteConnection_RemovesSelectedEntry` - `SelectedConnection_UpdatesHasSelection` - `HasSelection_IsFalseWhenNothingSelected` - `ConnectionCount_ReflectsCollectionSize` **Verification:** All tests pass. --- ## Summary | Batch | Tasks | Description | |-------|-------|-------------| | 1 | 1-4 | Data models (ConnectionProvider, ConnectionStringEntry, ConnectionStringsSection, ConfigModel update) | | 2 | 5-7 | ViewModels (ConnectionStringEntryViewModel, ConnectionStringsFormViewModel, IConnectionTestService) | | 3 | 8-10 | Views (ConnectionStringsFormView, DataTemplates, code-behind) | | 4 | 11-12 | Integration (MainWindowViewModel, DI registration) and unit tests | ## Post-Implementation Verification After all tasks complete: 1. `dotnet build NEW/JdeScoping.slnx` - should succeed 2. `dotnet test NEW/JdeScoping.slnx` - all tests should pass 3. Run ConfigManager app: - Open a config folder - Navigate to Settings → ConnectionStrings - Add a new SqlServer connection - Fill in fields, verify preview updates - Test connection works - Save config, verify appsettings.json updated