feat(configmanager): add ConnectionStrings editor with test connection support

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.
This commit is contained in:
Joseph Doherty
2026-01-22 11:12:08 -05:00
parent 9bf0c29add
commit db663cc82d
20 changed files with 2508 additions and 2 deletions
@@ -0,0 +1,421 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:JdeScoping.ConfigManager.ViewModels.Forms"
xmlns:models="using:JdeScoping.ConfigManager.Models"
xmlns:local="using:JdeScoping.ConfigManager.Converters"
x:Class="JdeScoping.ConfigManager.Views.Forms.ConnectionStringsFormView"
x:DataType="vm:ConnectionStringsFormViewModel">
<UserControl.Resources>
<!-- SqlServer Provider Template -->
<DataTemplate x:Key="SqlServerTemplate" x:DataType="vm:ConnectionStringEntryViewModel">
<StackPanel Spacing="16">
<!-- Server & Database Row -->
<Grid ColumnDefinitions="*,16,*">
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Server" Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding Server}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="localhost\SQLEXPRESS"/>
<TextBlock Text="Server name or IP with optional instance"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
<StackPanel Grid.Column="2" Spacing="4">
<TextBlock Text="Database" Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding Database}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="ScopingTool"/>
</StackPanel>
</Grid>
<!-- UserId & Password Row -->
<Grid ColumnDefinitions="*,16,*">
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="User Id" Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding UserId}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="sa"/>
</StackPanel>
<StackPanel Grid.Column="2" Spacing="4">
<TextBlock Text="Password" Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<Grid ColumnDefinitions="*,Auto">
<TextBox Grid.Column="0"
Text="{Binding Password}"
PasswordChar="•"
RevealPassword="{Binding IsPasswordVisible}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
<Button Grid.Column="1"
Command="{Binding TogglePasswordVisibilityCommand}"
Background="#3D4550" Foreground="#E6EDF5"
Width="36" Height="36" Margin="8,0,0,0"
CornerRadius="4" Padding="0"
ToolTip.Tip="Show/Hide password">
<TextBlock Text="👁" FontSize="14" HorizontalAlignment="Center"/>
</Button>
</Grid>
</StackPanel>
</Grid>
<!-- Encrypt & TrustServerCertificate Row -->
<Grid ColumnDefinitions="*,16,*">
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Encrypt" Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<ComboBox ItemsSource="{Binding $parent[UserControl].((vm:ConnectionStringsFormViewModel)DataContext).EncryptOptions}"
SelectedItem="{Binding Encrypt}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
HorizontalAlignment="Stretch"/>
<TextBlock Text="Options: True, False, Strict"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
<StackPanel Grid.Column="2" Spacing="4">
<TextBlock Text=" " FontSize="12"/>
<CheckBox IsChecked="{Binding TrustServerCertificate}"
Foreground="#E6EDF5" Height="36"
VerticalContentAlignment="Center">
<TextBlock Text="Trust Server Certificate" Foreground="#E6EDF5"/>
</CheckBox>
<TextBlock Text="Skip certificate validation (dev only)"
Foreground="#FF6B6B" FontSize="11"/>
</StackPanel>
</Grid>
<!-- Timeout & ApplicationName Row -->
<Grid ColumnDefinitions="*,16,*">
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Connection Timeout (seconds)" Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding ConnectionTimeout}"
Minimum="1" Maximum="600"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
<TextBlock Text="Default: 30 seconds"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
<StackPanel Grid.Column="2" Spacing="4">
<TextBlock Text="Application Name" Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding ApplicationName}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="JdeScopingTool"/>
<TextBlock Text="Identifies app in SQL Server logs"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
</Grid>
<!-- Connection String Preview -->
<Border Background="#151920" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="4" Padding="12" Margin="0,8,0,0">
<StackPanel Spacing="8">
<TextBlock Text="CONNECTION STRING PREVIEW"
Foreground="#5C6A7A" FontSize="11" FontWeight="Medium"/>
<TextBlock Text="{Binding GeneratedConnectionString}"
Foreground="#9BA8B8" FontSize="11"
FontFamily="JetBrains Mono"
TextWrapping="Wrap"/>
</StackPanel>
</Border>
</StackPanel>
</DataTemplate>
<!-- Oracle Provider Template -->
<DataTemplate x:Key="OracleTemplate" x:DataType="vm:ConnectionStringEntryViewModel">
<StackPanel Spacing="16">
<!-- Host & Port Row -->
<Grid ColumnDefinitions="*,16,120">
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Host" Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding Host}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="oracle-server.company.com"/>
</StackPanel>
<StackPanel Grid.Column="2" Spacing="4">
<TextBlock Text="Port" Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding Port}"
Minimum="1" Maximum="65535"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
<TextBlock Text="Default: 1521"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
</Grid>
<!-- Service Name -->
<StackPanel Spacing="4">
<TextBlock Text="Service Name" Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding ServiceName}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="JDEPROD"/>
<TextBlock Text="Oracle service name (not SID)"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
<!-- UserId & Password Row -->
<Grid ColumnDefinitions="*,16,*">
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="User Id" Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding UserId}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="jde_readonly"/>
</StackPanel>
<StackPanel Grid.Column="2" Spacing="4">
<TextBlock Text="Password" Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<Grid ColumnDefinitions="*,Auto">
<TextBox Grid.Column="0"
Text="{Binding Password}"
PasswordChar="•"
RevealPassword="{Binding IsPasswordVisible}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
<Button Grid.Column="1"
Command="{Binding TogglePasswordVisibilityCommand}"
Background="#3D4550" Foreground="#E6EDF5"
Width="36" Height="36" Margin="8,0,0,0"
CornerRadius="4" Padding="0"
ToolTip.Tip="Show/Hide password">
<TextBlock Text="👁" FontSize="14" HorizontalAlignment="Center"/>
</Button>
</Grid>
</StackPanel>
</Grid>
<!-- Connection Timeout -->
<StackPanel Spacing="4" MaxWidth="200" HorizontalAlignment="Left">
<TextBlock Text="Connection Timeout (seconds)" Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding ConnectionTimeout}"
Minimum="1" Maximum="600"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
</StackPanel>
<!-- Connection String Preview -->
<Border Background="#151920" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="4" Padding="12" Margin="0,8,0,0">
<StackPanel Spacing="8">
<TextBlock Text="CONNECTION STRING PREVIEW"
Foreground="#5C6A7A" FontSize="11" FontWeight="Medium"/>
<TextBlock Text="{Binding GeneratedConnectionString}"
Foreground="#9BA8B8" FontSize="11"
FontFamily="JetBrains Mono"
TextWrapping="Wrap"/>
</StackPanel>
</Border>
</StackPanel>
</DataTemplate>
<!-- Generic Provider Template -->
<DataTemplate x:Key="GenericTemplate" x:DataType="vm:ConnectionStringEntryViewModel">
<StackPanel Spacing="16">
<!-- Info Banner -->
<Border Background="#1A2233" BorderBrush="#3B82F6" BorderThickness="1"
CornerRadius="4" Padding="12">
<StackPanel Orientation="Horizontal" Spacing="12">
<TextBlock Text="" FontSize="16" Foreground="#3B82F6" VerticalAlignment="Center"/>
<TextBlock Text="Use Generic for unsupported providers or custom connection strings"
Foreground="#9BA8B8" FontSize="12" TextWrapping="Wrap"
VerticalAlignment="Center"/>
</StackPanel>
</Border>
<!-- Connection String TextArea -->
<StackPanel Spacing="4">
<TextBlock Text="Connection String" Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding RawConnectionString}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550"
FontFamily="JetBrains Mono" FontSize="12"
AcceptsReturn="True"
TextWrapping="NoWrap"
MinHeight="120"
Watermark="Data Source=myserver;Initial Catalog=mydb;..."/>
<TextBlock Text="Enter the full connection string"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Spacing="24" MaxWidth="800">
<!-- Header -->
<StackPanel>
<TextBlock Text="Connection Strings"
Foreground="#E6EDF5" FontSize="18" FontWeight="SemiBold"/>
<Border Height="1" Background="#2D3540" Margin="0,12,0,0"/>
</StackPanel>
<!-- Connections List Section -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<StackPanel Spacing="12">
<!-- Section Header with Count Badge -->
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="Connections" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"
VerticalAlignment="Center"/>
<Border Background="#3D4550" CornerRadius="10"
Padding="8,2" VerticalAlignment="Center">
<TextBlock Text="{Binding ConnectionCount}"
Foreground="#9BA8B8" FontSize="11"
FontFamily="JetBrains Mono"/>
</Border>
</StackPanel>
<!-- DataGrid -->
<DataGrid ItemsSource="{Binding Connections}"
SelectedItem="{Binding SelectedConnection}"
SelectionMode="Single"
Height="200"
Background="#0D0F12"
RowBackground="#0D0F12"
BorderBrush="#2D3540"
BorderThickness="1"
GridLinesVisibility="Horizontal"
HorizontalGridLinesBrush="#2D3540"
HeadersVisibility="Column"
AutoGenerateColumns="False"
CanUserReorderColumns="False"
CanUserResizeColumns="True"
CanUserSortColumns="True">
<DataGrid.Columns>
<DataGridTextColumn Header="Name"
Binding="{Binding Name}"
Width="*"
IsReadOnly="True"
Foreground="#E6EDF5"/>
<DataGridTextColumn Header="Provider"
Binding="{Binding ProviderDisplay}"
Width="100"
IsReadOnly="True"
Foreground="#9BA8B8"/>
<DataGridTextColumn Header="Server"
Binding="{Binding ServerDisplay}"
Width="150"
IsReadOnly="True"
Foreground="#9BA8B8"/>
</DataGrid.Columns>
</DataGrid>
<!-- Toolbar -->
<StackPanel Orientation="Horizontal" Spacing="8">
<Button Command="{Binding AddConnectionCommand}"
Background="#3B82F6" Foreground="White"
Padding="12,6" CornerRadius="4">
<TextBlock Text="Add" FontWeight="Medium"/>
</Button>
<Button Command="{Binding DeleteConnectionCommand}"
Background="#DC2626" Foreground="White"
Padding="12,6" CornerRadius="4">
<TextBlock Text="Delete" FontWeight="Medium"/>
</Button>
</StackPanel>
</StackPanel>
</Border>
<!-- Placeholder Section (when no connection is selected) -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="48"
IsVisible="{Binding !HasSelection}">
<TextBlock Text="Select a connection string to edit"
Foreground="#5C6A7A" FontSize="14"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
<!-- Edit Form Section (when a connection is selected) -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16"
IsVisible="{Binding HasSelection}">
<StackPanel Spacing="16">
<!-- Edit Header -->
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="Edit Connection:" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"
VerticalAlignment="Center"/>
<TextBlock Text="{Binding SelectedConnection.Name}"
Foreground="#3B82F6" FontSize="14"
FontFamily="JetBrains Mono"
VerticalAlignment="Center"/>
</StackPanel>
<!-- Name and Provider Fields -->
<Grid ColumnDefinitions="*,16,*">
<!-- Name -->
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Name"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding SelectedConnection.Name}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="ConnectionName"/>
</StackPanel>
<!-- Provider -->
<StackPanel Grid.Column="2" Spacing="4">
<TextBlock Text="Provider"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<ComboBox ItemsSource="{Binding AvailableProviders}"
SelectedItem="{Binding SelectedConnection.Provider}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
HorizontalAlignment="Stretch"/>
</StackPanel>
</Grid>
<!-- Separator -->
<Border Height="1" Background="#2D3540" Margin="0,8"/>
<!-- Provider-specific fields - SqlServer -->
<ContentControl Content="{Binding SelectedConnection}"
ContentTemplate="{StaticResource SqlServerTemplate}"
IsVisible="{Binding SelectedConnection.Provider, Converter={x:Static local:ProviderToVisibilityConverter.SqlServer}}"/>
<!-- Provider-specific fields - Oracle -->
<ContentControl Content="{Binding SelectedConnection}"
ContentTemplate="{StaticResource OracleTemplate}"
IsVisible="{Binding SelectedConnection.Provider, Converter={x:Static local:ProviderToVisibilityConverter.Oracle}}"/>
<!-- Provider-specific fields - Generic -->
<ContentControl Content="{Binding SelectedConnection}"
ContentTemplate="{StaticResource GenericTemplate}"
IsVisible="{Binding SelectedConnection.Provider, Converter={x:Static local:ProviderToVisibilityConverter.Generic}}"/>
</StackPanel>
</Border>
<!-- Action Buttons Section (when a connection is selected) -->
<StackPanel Orientation="Horizontal" Spacing="8"
HorizontalAlignment="Right"
IsVisible="{Binding HasSelection}">
<Button Command="{Binding ValidateConnectionCommand}"
Background="#3D4550" Foreground="#E6EDF5"
Padding="16,8" CornerRadius="4">
<TextBlock Text="Validate" FontWeight="Medium"/>
</Button>
<Button Command="{Binding TestConnectionCommand}"
Background="#10B981" Foreground="White"
Padding="16,8" CornerRadius="4">
<TextBlock Text="Test Connection" FontWeight="Medium"/>
</Button>
</StackPanel>
</StackPanel>
</ScrollViewer>
</UserControl>
@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace JdeScoping.ConfigManager.Views.Forms;
public partial class ConnectionStringsFormView : UserControl
{
public ConnectionStringsFormView()
{
InitializeComponent();
}
}