Adds a new ConnectionStrings section to ConfigManager allowing users to manage database connection strings with provider selection, connection testing, and visual feedback for connection state.
13 KiB
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
namespace JdeScoping.ConfigManager.Models;
/// <summary>
/// Database provider types supported by the ConnectionStrings editor.
/// </summary>
public enum ConnectionProvider
{
Generic,
SqlServer,
Oracle
}
Verification: Build succeeds.
Task 2: Create ConnectionStringEntry model
File: NEW/src/Utils/JdeScoping.ConfigManager/Models/ConnectionStringEntry.cs
namespace JdeScoping.ConfigManager.Models;
/// <summary>
/// Represents a single connection string entry with provider-specific fields.
/// </summary>
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; }
/// <summary>
/// Generates the connection string based on the Provider type.
/// </summary>
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<string>();
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<string>();
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
namespace JdeScoping.ConfigManager.Models;
/// <summary>
/// Configuration section for connection strings.
/// </summary>
public class ConnectionStringsSection
{
public List<ConnectionStringEntry> 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:
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
GeneratedConnectionStringcomputed propertyIsPasswordVisibletoggle propertyTogglePasswordVisibilityCommandProviderDisplayandServerDisplayfor table columns
Key implementation details:
- Constructor takes
ConnectionStringEntry modelandAction 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<ConnectionStringEntryViewModel>SelectedConnection : ConnectionStringEntryViewModel?HasSelection : bool(computed from SelectedConnection != null)ConnectionCount : int(computed from Connections.Count)AvailableProviders : IReadOnlyList<ConnectionProvider>EncryptOptions : IReadOnlyList<string>= ["True", "False", "Strict"]
Commands:
AddConnectionCommand- creates new entry with default name "NewConnection", selects itDeleteConnectionCommand- requires confirmation via IDialogService, removes selectedValidateConnectionCommand- validates syntax, shows result via IDialogServiceTestConnectionCommand- tests actual connection, shows modal result
Constructor takes:
ConnectionStringsSection modelAction onChangedIDialogService dialogService
Verification: Build succeeds.
Task 7: Create IConnectionTestService interface and implementation
File: NEW/src/Utils/JdeScoping.ConfigManager/Services/IConnectionTestService.cs
namespace JdeScoping.ConfigManager.Services;
public interface IConnectionTestService
{
Task<ConnectionTestResult> 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.SqlClientfor SqlServer - Uses
Oracle.ManagedDataAccess.Clientfor 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:
- Header section ("Connection Strings" with separator)
- Connections list section:
- DataGrid with Name, Provider, Server columns
- Height="200", selection mode single
- Toolbar with Add, Delete buttons
- Placeholder section (when no selection):
- "Select a connection string to edit" text
- Edit form section (when selection exists):
- Name + Provider fields (always visible)
- ContentControl with DataTemplates for provider-specific fields
- 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:
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:
-
In
BuildSettingsNodes()method, add ConnectionStrings node:new TreeNodeViewModel("ConnectionStrings", "🔗", TreeNodeType.SettingsSection) { SectionKey = "ConnectionStrings" } -
In
LoadFormViewModelForNode()method, add case for ConnectionStrings:"ConnectionStrings" => new ConnectionStringsFormViewModel( _appSettingsConfig!.ConnectionStrings, MarkCurrentNodeModified, _dialogService, _connectionTestService), -
Register
IConnectionTestServicein 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_ProducesCorrectFormatGenerateConnectionString_SqlServer_OmitsDefaultTimeoutGenerateConnectionString_Oracle_ProducesEZConnectFormatGenerateConnectionString_Generic_ReturnsRawStringDefaultValues_AreCorrect
File: NEW/tests/JdeScoping.ConfigManager.Tests/ViewModels/Forms/ConnectionStringEntryViewModelTests.cs
Test cases:
Constructor_InitializesFromModelPropertyChange_UpdatesModelPropertyChange_InvokesOnChangedTogglePasswordVisibility_TogglesIsPasswordVisibleProviderDisplay_ReturnsCorrectStringServerDisplay_ReturnsServerForSqlServerServerDisplay_ReturnsHostForOracleServerDisplay_ReturnsDashForGeneric
File: NEW/tests/JdeScoping.ConfigManager.Tests/ViewModels/Forms/ConnectionStringsFormViewModelTests.cs
Test cases:
Constructor_InitializesFromModelAddConnection_CreatesNewEntryAndSelectsItDeleteConnection_RemovesSelectedEntrySelectedConnection_UpdatesHasSelectionHasSelection_IsFalseWhenNothingSelectedConnectionCount_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:
dotnet build NEW/JdeScoping.slnx- should succeeddotnet test NEW/JdeScoping.slnx- all tests should pass- 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