feat(configmanager): add XAML form views for all configuration sections

Add 7 form view pairs implementing the dark theme UI for ConfigManager:
- DataSyncFormView: Sync intervals, performance, and retention settings
- DataAccessFormView: Query timeouts and schema name configuration
- AuthFormView: Cookie name and expiration settings
- LdapFormView: Server URLs, directory structure, and dev options
- SearchFormView: Result limits and timeout configuration
- ExcelExportFormView: Sheet protection, format, timezone, and debug options
- PipelineFormView: Source/Destination/Schedules with collapsible Expanders

All views follow the dark theme colors from configmanager-ui-design.md:
- Background layers: #0D0F12, #151920, #232A35
- Text hierarchy: #E6EDF5, #9BA8B8, #5C6A7A
- Borders: #2D3540, #3D4550
- Accent: #5C9AFF

Task 25 of docs/plans/2026-01-19-configmanager-phases7-9.md
This commit is contained in:
Joseph Doherty
2026-01-19 19:57:51 -05:00
parent 042e036c35
commit 700d62ee74
14 changed files with 996 additions and 0 deletions
@@ -0,0 +1,52 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:JdeScoping.ConfigManager.ViewModels.Forms"
x:Class="JdeScoping.ConfigManager.Views.Forms.AuthFormView"
x:DataType="vm:AuthFormViewModel">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Spacing="24" MaxWidth="600">
<!-- Header -->
<StackPanel>
<TextBlock Text="Authentication Settings"
Foreground="#E6EDF5" FontSize="18" FontWeight="SemiBold"/>
<Border Height="1" Background="#2D3540" Margin="0,12,0,0"/>
</StackPanel>
<!-- Cookie Settings Section -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<StackPanel Spacing="16">
<TextBlock Text="Cookie Settings" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"/>
<!-- Cookie Name -->
<StackPanel Spacing="4">
<TextBlock Text="Cookie Name"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding CookieName}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark=".JdeScoping.Auth"/>
<TextBlock Text="Name of the authentication cookie stored in the browser"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
<!-- Cookie Expiration -->
<StackPanel Spacing="4">
<TextBlock Text="Cookie Expiration (minutes)"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding CookieExpirationMinutes}"
Minimum="1" Maximum="525600"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
<TextBlock Text="How long the authentication cookie remains valid (e.g., 480 = 8 hours, 525600 = 1 year)"
Foreground="#5C6A7A" FontSize="11" TextWrapping="Wrap"/>
</StackPanel>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</UserControl>
@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace JdeScoping.ConfigManager.Views.Forms;
public partial class AuthFormView : UserControl
{
public AuthFormView()
{
InitializeComponent();
}
}
@@ -0,0 +1,120 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:JdeScoping.ConfigManager.ViewModels.Forms"
x:Class="JdeScoping.ConfigManager.Views.Forms.DataAccessFormView"
x:DataType="vm:DataAccessFormViewModel">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Spacing="24" MaxWidth="600">
<!-- Header -->
<StackPanel>
<TextBlock Text="Data Access Settings"
Foreground="#E6EDF5" FontSize="18" FontWeight="SemiBold"/>
<Border Height="1" Background="#2D3540" Margin="0,12,0,0"/>
</StackPanel>
<!-- Query Timeouts Section -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<StackPanel Spacing="16">
<TextBlock Text="Query Timeouts" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"/>
<!-- Default Timeout -->
<StackPanel Spacing="4">
<TextBlock Text="Default Timeout (seconds)"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding DefaultTimeoutSeconds}"
Minimum="5" Maximum="3600"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
<TextBlock Text="Default timeout for all database queries"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
<Grid ColumnDefinitions="*,16,*">
<!-- Lot Usage Timeout -->
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Lot Usage Timeout (s)"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding LotUsageTimeoutSeconds}"
Minimum="5" Maximum="7200"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
</StackPanel>
<!-- MIS Data Timeout -->
<StackPanel Grid.Column="2" Spacing="4">
<TextBlock Text="MIS Data Timeout (s)"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding MisDataTimeoutSeconds}"
Minimum="5" Maximum="7200"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
</StackPanel>
</Grid>
</StackPanel>
</Border>
<!-- Schema Names Section -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<StackPanel Spacing="16">
<TextBlock Text="Schema Names" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"/>
<!-- Production Schema -->
<StackPanel Spacing="4">
<TextBlock Text="Production Schema"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding ProductionSchema}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="dbo"/>
</StackPanel>
<!-- Archive Schema -->
<StackPanel Spacing="4">
<TextBlock Text="Archive Schema"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding ArchiveSchema}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="archive"/>
</StackPanel>
<!-- Stage Schema -->
<StackPanel Spacing="4">
<TextBlock Text="Stage Schema"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding StageSchema}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="stage"/>
</StackPanel>
</StackPanel>
</Border>
<!-- Debug Options Section -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<StackPanel Spacing="16">
<TextBlock Text="Debug Options" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"/>
<CheckBox IsChecked="{Binding EnableDetailedLogging}" Foreground="#E6EDF5">
<TextBlock Text="Enable Detailed Logging" Foreground="#E6EDF5"/>
</CheckBox>
<TextBlock Text="Enables verbose logging for troubleshooting database operations"
Foreground="#5C6A7A" FontSize="11" Margin="24,0,0,0"/>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</UserControl>
@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace JdeScoping.ConfigManager.Views.Forms;
public partial class DataAccessFormView : UserControl
{
public DataAccessFormView()
{
InitializeComponent();
}
}
@@ -0,0 +1,142 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:JdeScoping.ConfigManager.ViewModels.Forms"
x:Class="JdeScoping.ConfigManager.Views.Forms.DataSyncFormView"
x:DataType="vm:DataSyncFormViewModel">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Spacing="24" MaxWidth="600">
<!-- Header -->
<StackPanel>
<TextBlock Text="Data Sync Settings"
Foreground="#E6EDF5" FontSize="18" FontWeight="SemiBold"/>
<Border Height="1" Background="#2D3540" Margin="0,12,0,0"/>
</StackPanel>
<!-- Enable/Disable -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<CheckBox IsChecked="{Binding Enabled}" Foreground="#E6EDF5">
<TextBlock Text="Enable Data Synchronization" Foreground="#E6EDF5"/>
</CheckBox>
</Border>
<!-- Sync Intervals Section -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<StackPanel Spacing="16">
<TextBlock Text="Sync Intervals" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"/>
<!-- Check Interval -->
<StackPanel Spacing="4">
<TextBlock Text="Check Interval (minutes)"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding CheckIntervalMinutes}"
Minimum="1" Maximum="1440"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
<TextBlock Text="How often to check for pending sync operations"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
<!-- Sync Timeout -->
<StackPanel Spacing="4">
<TextBlock Text="Sync Timeout (seconds)"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding SyncTimeoutSeconds}"
Minimum="30" Maximum="3600"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
<TextBlock Text="Maximum time allowed for a single sync operation"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
</StackPanel>
</Border>
<!-- Performance Section -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<StackPanel Spacing="16">
<TextBlock Text="Performance" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"/>
<Grid ColumnDefinitions="*,16,*">
<!-- Max Degree of Parallelism -->
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Max Parallelism"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding MaxDegreeOfParallelism}"
Minimum="1" Maximum="16"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
</StackPanel>
<!-- Batch Size -->
<StackPanel Grid.Column="2" Spacing="4">
<TextBlock Text="Batch Size"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding BatchSize}"
Minimum="100" Maximum="100000"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
</StackPanel>
</Grid>
<!-- Bulk Copy Batch Size -->
<StackPanel Spacing="4">
<TextBlock Text="Bulk Copy Batch Size"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding BulkCopyBatchSize}"
Minimum="100" Maximum="100000"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
<TextBlock Text="Number of rows per bulk copy batch"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
</StackPanel>
</Border>
<!-- Data Retention Section -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<StackPanel Spacing="16">
<TextBlock Text="Data Retention" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"/>
<Grid ColumnDefinitions="*,16,*">
<!-- Lookback Multiplier -->
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Lookback Multiplier"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding LookbackMultiplier}"
Minimum="1.0" Maximum="10.0"
Increment="0.1" FormatString="F1"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
</StackPanel>
<!-- Purge Retention Days -->
<StackPanel Grid.Column="2" Spacing="4">
<TextBlock Text="Purge Retention (days)"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding PurgeRetentionDays}"
Minimum="1" Maximum="365"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
</StackPanel>
</Grid>
<TextBlock Text="Lookback multiplier extends the sync window; retention days controls when old data is purged"
Foreground="#5C6A7A" FontSize="11" TextWrapping="Wrap"/>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</UserControl>
@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace JdeScoping.ConfigManager.Views.Forms;
public partial class DataSyncFormView : UserControl
{
public DataSyncFormView()
{
InitializeComponent();
}
}
@@ -0,0 +1,151 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:JdeScoping.ConfigManager.ViewModels.Forms"
x:Class="JdeScoping.ConfigManager.Views.Forms.ExcelExportFormView"
x:DataType="vm:ExcelExportFormViewModel">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Spacing="24" MaxWidth="600">
<!-- Header -->
<StackPanel>
<TextBlock Text="Excel Export Settings"
Foreground="#E6EDF5" FontSize="18" FontWeight="SemiBold"/>
<Border Height="1" Background="#2D3540" Margin="0,12,0,0"/>
</StackPanel>
<!-- Sheet Protection Section -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<StackPanel Spacing="16">
<TextBlock Text="Sheet Protection" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"/>
<!-- Criteria Sheet Password -->
<StackPanel Spacing="4">
<TextBlock Text="Criteria Sheet Password"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding CriteriaSheetPassword}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
PasswordChar="*"
Watermark="(optional)"/>
<TextBlock Text="Password to protect the search criteria sheet"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
<!-- Data Sheet Password -->
<StackPanel Spacing="4">
<TextBlock Text="Data Sheet Password"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding DataSheetPassword}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
PasswordChar="*"
Watermark="(optional)"/>
<TextBlock Text="Password to protect the data sheet"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
</StackPanel>
</Border>
<!-- Output Format Section -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<StackPanel Spacing="16">
<TextBlock Text="Output Format" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"/>
<!-- Max Rows Per Sheet -->
<StackPanel Spacing="4">
<TextBlock Text="Max Rows Per Sheet"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding MaxRowsPerSheet}"
Minimum="1000" Maximum="1048576"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
<TextBlock Text="Excel limit is 1,048,576 rows per sheet"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
<!-- Default Date Format -->
<StackPanel Spacing="4">
<TextBlock Text="Default Date Format"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding DefaultDateFormat}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="MM/dd/yyyy HH:mm:ss"/>
<TextBlock Text="Format string for date/time values in Excel"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
</StackPanel>
</Border>
<!-- Timezone Section -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<StackPanel Spacing="16">
<TextBlock Text="Timezone" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"/>
<Grid ColumnDefinitions="*,16,Auto">
<!-- Timezone ID -->
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Timezone ID"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding TimezoneId}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="America/Chicago"/>
</StackPanel>
<!-- Timezone Abbreviation -->
<StackPanel Grid.Column="2" Spacing="4" Width="100">
<TextBlock Text="Abbreviation"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding TimezoneAbbreviation}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="CST"/>
</StackPanel>
</Grid>
<TextBlock Text="Used for converting UTC timestamps to local time in exports"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
</Border>
<!-- Debug Options Section -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<StackPanel Spacing="16">
<TextBlock Text="Debug Options" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"/>
<CheckBox IsChecked="{Binding DebugWriteToFile}" Foreground="#E6EDF5">
<TextBlock Text="Write Debug Output to File" Foreground="#E6EDF5"/>
</CheckBox>
<!-- Debug Output Directory -->
<StackPanel Spacing="4" Margin="24,0,0,0">
<TextBlock Text="Debug Output Directory"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding DebugOutputDirectory}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="C:\Temp\ExcelDebug"
IsEnabled="{Binding DebugWriteToFile}"/>
<TextBlock Text="Directory where debug Excel files will be written"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</UserControl>
@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace JdeScoping.ConfigManager.Views.Forms;
public partial class ExcelExportFormView : UserControl
{
public ExcelExportFormView()
{
InitializeComponent();
}
}
@@ -0,0 +1,119 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:JdeScoping.ConfigManager.ViewModels.Forms"
x:Class="JdeScoping.ConfigManager.Views.Forms.LdapFormView"
x:DataType="vm:LdapFormViewModel">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Spacing="24" MaxWidth="600">
<!-- Header -->
<StackPanel>
<TextBlock Text="LDAP Settings"
Foreground="#E6EDF5" FontSize="18" FontWeight="SemiBold"/>
<Border Height="1" Background="#2D3540" Margin="0,12,0,0"/>
</StackPanel>
<!-- Server Configuration Section -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<StackPanel Spacing="16">
<TextBlock Text="Server Configuration" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"/>
<!-- Server URLs -->
<StackPanel Spacing="4">
<TextBlock Text="Server URLs (one per line)"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding ServerUrlsText}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550"
FontFamily="JetBrains Mono"
AcceptsReturn="True"
TextWrapping="NoWrap"
MinHeight="80"
Watermark="ldap://ldap.example.com:389"/>
<TextBlock Text="LDAP server URLs in order of preference for failover"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
<!-- Connection Timeout -->
<StackPanel Spacing="4">
<TextBlock Text="Connection Timeout (seconds)"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding ConnectionTimeoutSeconds}"
Minimum="1" Maximum="300"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
</StackPanel>
</StackPanel>
</Border>
<!-- Directory Structure Section -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<StackPanel Spacing="16">
<TextBlock Text="Directory Structure" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"/>
<!-- Group DN -->
<StackPanel Spacing="4">
<TextBlock Text="Group Distinguished Name (DN)"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding GroupDn}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="CN=AppUsers,OU=Groups,DC=example,DC=com"/>
<TextBlock Text="The group users must belong to for application access"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
<!-- Search Base -->
<StackPanel Spacing="4">
<TextBlock Text="Search Base DN"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding SearchBase}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="OU=Users,DC=example,DC=com"/>
<TextBlock Text="Base DN for user searches"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
</StackPanel>
</Border>
<!-- Development Options Section -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<StackPanel Spacing="16">
<TextBlock Text="Development Options" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"/>
<CheckBox IsChecked="{Binding UseFakeAuth}" Foreground="#E6EDF5">
<TextBlock Text="Use Fake Authentication (Development Only)" Foreground="#FFB84D"/>
</CheckBox>
<TextBlock Text="WARNING: Bypasses LDAP authentication entirely. Never enable in production!"
Foreground="#FF6B6B" FontSize="11" Margin="24,0,0,0" TextWrapping="Wrap"/>
<!-- Admin Bypass Users -->
<StackPanel Spacing="4" Margin="0,8,0,0">
<TextBlock Text="Admin Bypass Users (one per line)"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding AdminBypassUsersText}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550"
FontFamily="JetBrains Mono"
AcceptsReturn="True"
TextWrapping="NoWrap"
MinHeight="60"
Watermark="admin"/>
<TextBlock Text="Users who bypass group membership requirements"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</UserControl>
@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace JdeScoping.ConfigManager.Views.Forms;
public partial class LdapFormView : UserControl
{
public LdapFormView()
{
InitializeComponent();
}
}
@@ -0,0 +1,261 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:JdeScoping.ConfigManager.ViewModels.Forms"
x:Class="JdeScoping.ConfigManager.Views.Forms.PipelineFormView"
x:DataType="vm:PipelineFormViewModel">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Spacing="16" MaxWidth="700">
<!-- Header -->
<StackPanel>
<TextBlock Text="{Binding Name, StringFormat='{}{0} Pipeline'}"
Foreground="#E6EDF5" FontSize="18" FontWeight="SemiBold"/>
<Border Height="1" Background="#2D3540" Margin="0,12,0,0"/>
</StackPanel>
<!-- Source Section (Expander) -->
<Expander IsExpanded="True">
<Expander.Header>
<TextBlock Text="Source" Foreground="#E6EDF5" FontWeight="SemiBold" FontSize="14"/>
</Expander.Header>
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1,0,1,1"
CornerRadius="0,0,6,6" Padding="16">
<StackPanel Spacing="16">
<!-- Connection -->
<StackPanel Spacing="4">
<StackPanel Orientation="Horizontal" Spacing="2">
<TextBlock Text="Connection"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBlock Text="*" Foreground="#FF6B6B" FontSize="12"/>
</StackPanel>
<TextBox Text="{Binding Connection}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="JdeOracle"/>
<TextBlock Text="Name of the connection string to use"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
<!-- Query -->
<StackPanel Spacing="4">
<StackPanel Orientation="Horizontal" Spacing="2">
<TextBlock Text="Query"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBlock Text="*" Foreground="#FF6B6B" FontSize="12"/>
</StackPanel>
<TextBox Text="{Binding Query}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550"
FontFamily="JetBrains Mono" FontSize="12"
AcceptsReturn="True"
TextWrapping="NoWrap"
MinHeight="120"
Watermark="SELECT ... FROM ... WHERE ..."/>
<TextBlock Text="SQL query for incremental updates (use @LastSync parameter)"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
<!-- Mass Query -->
<StackPanel Spacing="4">
<TextBlock Text="Mass Query (Optional)"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding MassQuery}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550"
FontFamily="JetBrains Mono" FontSize="12"
AcceptsReturn="True"
TextWrapping="NoWrap"
MinHeight="80"
Watermark="SELECT ... FROM ... (no date filter)"/>
<TextBlock Text="Alternative query for mass sync (full table reload)"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
</StackPanel>
</Border>
</Expander>
<!-- Schedules Section (Expander) -->
<Expander IsExpanded="False">
<Expander.Header>
<TextBlock Text="Schedules" Foreground="#E6EDF5" FontWeight="SemiBold" FontSize="14"/>
</Expander.Header>
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1,0,1,1"
CornerRadius="0,0,6,6" Padding="16">
<StackPanel Spacing="20">
<!-- Mass Schedule -->
<Border Background="#151920" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="4" Padding="12">
<StackPanel Spacing="12">
<StackPanel Orientation="Horizontal" Spacing="8">
<CheckBox IsChecked="{Binding MassSchedule.Enabled}"/>
<TextBlock Text="Mass Schedule" Foreground="#E6EDF5" FontWeight="Medium"/>
</StackPanel>
<Grid ColumnDefinitions="*,12,*,12,*" IsEnabled="{Binding MassSchedule.Enabled}">
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Interval (min)" Foreground="#9BA8B8" FontSize="11"/>
<NumericUpDown Value="{Binding MassSchedule.IntervalMinutes}"
Minimum="1" Maximum="10080"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="32"
FontFamily="JetBrains Mono" FontSize="12"/>
</StackPanel>
<StackPanel Grid.Column="2" Spacing="4">
<CheckBox IsChecked="{Binding MassSchedule.PrePurge}" Foreground="#9BA8B8">
<TextBlock Text="Pre-Purge" Foreground="#9BA8B8" FontSize="11"/>
</CheckBox>
</StackPanel>
<StackPanel Grid.Column="4" Spacing="4">
<CheckBox IsChecked="{Binding MassSchedule.ReIndex}" Foreground="#9BA8B8">
<TextBlock Text="Re-Index" Foreground="#9BA8B8" FontSize="11"/>
</CheckBox>
</StackPanel>
</Grid>
</StackPanel>
</Border>
<!-- Daily Schedule -->
<Border Background="#151920" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="4" Padding="12">
<StackPanel Spacing="12">
<StackPanel Orientation="Horizontal" Spacing="8">
<CheckBox IsChecked="{Binding DailySchedule.Enabled}"/>
<TextBlock Text="Daily Schedule" Foreground="#E6EDF5" FontWeight="Medium"/>
</StackPanel>
<Grid ColumnDefinitions="*,12,*,12,*" IsEnabled="{Binding DailySchedule.Enabled}">
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Interval (min)" Foreground="#9BA8B8" FontSize="11"/>
<NumericUpDown Value="{Binding DailySchedule.IntervalMinutes}"
Minimum="1" Maximum="1440"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="32"
FontFamily="JetBrains Mono" FontSize="12"/>
</StackPanel>
<StackPanel Grid.Column="2" Spacing="4">
<CheckBox IsChecked="{Binding DailySchedule.PrePurge}" Foreground="#9BA8B8">
<TextBlock Text="Pre-Purge" Foreground="#9BA8B8" FontSize="11"/>
</CheckBox>
</StackPanel>
<StackPanel Grid.Column="4" Spacing="4">
<CheckBox IsChecked="{Binding DailySchedule.ReIndex}" Foreground="#9BA8B8">
<TextBlock Text="Re-Index" Foreground="#9BA8B8" FontSize="11"/>
</CheckBox>
</StackPanel>
</Grid>
</StackPanel>
</Border>
<!-- Hourly Schedule -->
<Border Background="#151920" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="4" Padding="12">
<StackPanel Spacing="12">
<StackPanel Orientation="Horizontal" Spacing="8">
<CheckBox IsChecked="{Binding HourlySchedule.Enabled}"/>
<TextBlock Text="Hourly Schedule" Foreground="#E6EDF5" FontWeight="Medium"/>
</StackPanel>
<Grid ColumnDefinitions="*,12,*,12,*" IsEnabled="{Binding HourlySchedule.Enabled}">
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Interval (min)" Foreground="#9BA8B8" FontSize="11"/>
<NumericUpDown Value="{Binding HourlySchedule.IntervalMinutes}"
Minimum="1" Maximum="60"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="32"
FontFamily="JetBrains Mono" FontSize="12"/>
</StackPanel>
<StackPanel Grid.Column="2" Spacing="4">
<CheckBox IsChecked="{Binding HourlySchedule.PrePurge}" Foreground="#9BA8B8">
<TextBlock Text="Pre-Purge" Foreground="#9BA8B8" FontSize="11"/>
</CheckBox>
</StackPanel>
<StackPanel Grid.Column="4" Spacing="4">
<CheckBox IsChecked="{Binding HourlySchedule.ReIndex}" Foreground="#9BA8B8">
<TextBlock Text="Re-Index" Foreground="#9BA8B8" FontSize="11"/>
</CheckBox>
</StackPanel>
</Grid>
</StackPanel>
</Border>
</StackPanel>
</Border>
</Expander>
<!-- Destination Section (Expander) -->
<Expander IsExpanded="False">
<Expander.Header>
<TextBlock Text="Destination" Foreground="#E6EDF5" FontWeight="SemiBold" FontSize="14"/>
</Expander.Header>
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1,0,1,1"
CornerRadius="0,0,6,6" Padding="16">
<StackPanel Spacing="16">
<!-- Destination Table -->
<StackPanel Spacing="4">
<StackPanel Orientation="Horizontal" Spacing="2">
<TextBlock Text="Destination Table"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBlock Text="*" Foreground="#FF6B6B" FontSize="12"/>
</StackPanel>
<TextBox Text="{Binding DestinationTable}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"
Watermark="dbo.WorkOrder_Curr"/>
<TextBlock Text="Target table in SQL Server (include schema)"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
<!-- Match Columns -->
<StackPanel Spacing="4">
<StackPanel Orientation="Horizontal" Spacing="2">
<TextBlock Text="Match Columns (one per line)"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBlock Text="*" Foreground="#FF6B6B" FontSize="12"/>
</StackPanel>
<TextBox Text="{Binding MatchColumnsText}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550"
FontFamily="JetBrains Mono" FontSize="12"
AcceptsReturn="True"
TextWrapping="NoWrap"
MinHeight="60"
Watermark="OrderNumber&#x0a;OrderType"/>
<TextBlock Text="Columns used to match source rows to existing destination rows"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
<!-- Exclude From Update -->
<StackPanel Spacing="4">
<TextBlock Text="Exclude From Update (one per line)"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding ExcludeFromUpdateText}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550"
FontFamily="JetBrains Mono" FontSize="12"
AcceptsReturn="True"
TextWrapping="NoWrap"
MinHeight="60"
Watermark="CreatedDate&#x0a;CreatedBy"/>
<TextBlock Text="Columns to skip when updating existing rows"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
<!-- Post Scripts -->
<StackPanel Spacing="4">
<TextBlock Text="Post Scripts (one per line)"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<TextBox Text="{Binding PostScriptsText}"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550"
FontFamily="JetBrains Mono" FontSize="12"
AcceptsReturn="True"
TextWrapping="NoWrap"
MinHeight="60"
Watermark="EXEC dbo.UpdateStats @TableName"/>
<TextBlock Text="SQL scripts to execute after sync completes"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
</StackPanel>
</Border>
</Expander>
</StackPanel>
</ScrollViewer>
</UserControl>
@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace JdeScoping.ConfigManager.Views.Forms;
public partial class PipelineFormView : UserControl
{
public PipelineFormView()
{
InitializeComponent();
}
}
@@ -0,0 +1,74 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:JdeScoping.ConfigManager.ViewModels.Forms"
x:Class="JdeScoping.ConfigManager.Views.Forms.SearchFormView"
x:DataType="vm:SearchFormViewModel">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Spacing="24" MaxWidth="600">
<!-- Header -->
<StackPanel>
<TextBlock Text="Search Settings"
Foreground="#E6EDF5" FontSize="18" FontWeight="SemiBold"/>
<Border Height="1" Background="#2D3540" Margin="0,12,0,0"/>
</StackPanel>
<!-- Search Limits Section -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<StackPanel Spacing="16">
<TextBlock Text="Search Limits" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"/>
<!-- Max Result Rows -->
<StackPanel Spacing="4">
<TextBlock Text="Max Result Rows"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding MaxResultRows}"
Minimum="100" Maximum="1000000"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
<TextBlock Text="Maximum number of rows returned by a single search"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
<!-- Max Concurrent Searches -->
<StackPanel Spacing="4">
<TextBlock Text="Max Concurrent Searches"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding MaxConcurrentSearches}"
Minimum="1" Maximum="50"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
<TextBlock Text="Maximum number of searches that can run simultaneously"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
</StackPanel>
</Border>
<!-- Timeout Section -->
<Border Background="#0D0F12" BorderBrush="#2D3540" BorderThickness="1"
CornerRadius="6" Padding="16">
<StackPanel Spacing="16">
<TextBlock Text="Timeout" Foreground="#E6EDF5"
FontWeight="SemiBold" FontSize="14"/>
<!-- Search Timeout -->
<StackPanel Spacing="4">
<TextBlock Text="Search Timeout (seconds)"
Foreground="#9BA8B8" FontSize="12" FontWeight="Medium"/>
<NumericUpDown Value="{Binding TimeoutSeconds}"
Minimum="10" Maximum="3600"
Background="#232A35" Foreground="#E6EDF5"
BorderBrush="#3D4550" Height="36"
FontFamily="JetBrains Mono"/>
<TextBlock Text="Maximum time allowed for a search operation to complete"
Foreground="#5C6A7A" FontSize="11"/>
</StackPanel>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</UserControl>
@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace JdeScoping.ConfigManager.Views.Forms;
public partial class SearchFormView : UserControl
{
public SearchFormView()
{
InitializeComponent();
}
}