diff --git a/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/PipelineSteps/TransformerStepViewModels.cs b/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/PipelineSteps/TransformerStepViewModels.cs index 9990483..9556bca 100644 --- a/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/PipelineSteps/TransformerStepViewModels.cs +++ b/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/PipelineSteps/TransformerStepViewModels.cs @@ -1,5 +1,6 @@ using JdeScoping.ConfigManager.Models; using System.Collections.ObjectModel; +using System.Text.RegularExpressions; using System.Windows.Input; namespace JdeScoping.ConfigManager.ViewModels.PipelineSteps; @@ -278,6 +279,278 @@ public class JdeDateTransformerViewModel : TransformerStepViewModelBase }; } +/// +/// View model for Regex transformer. +/// +public class RegexTransformerViewModel : TransformerStepViewModelBase +{ + private string _columnName = string.Empty; + private string _pattern = string.Empty; + private string? _replacement = string.Empty; + private bool _isFindReplaceMode = true; + private bool _ignoreCase; + private NonMatchBehavior _nonMatchBehavior = NonMatchBehavior.KeepOriginal; + + // Test feature fields + private string _testInput = string.Empty; + private string _testResultValue = string.Empty; + private string _testResultLabel = string.Empty; + private string _testResultIcon = string.Empty; + private string _testResultBackground = string.Empty; + private bool _hasTestResult; + private bool _hasTestError; + private string _testErrorMessage = string.Empty; + + public RegexTransformerViewModel(TransformerModel model, Action onChanged) : base(onChanged) + { + _columnName = model.ColumnName ?? string.Empty; + _pattern = model.Pattern ?? string.Empty; + _replacement = model.Replacement; + _isFindReplaceMode = model.Replacement != null; + _ignoreCase = model.IgnoreCase; + _nonMatchBehavior = model.NonMatchBehavior; + TestPatternCommand = new RelayCommand(ExecuteTestPattern); + } + + public RegexTransformerViewModel(Action onChanged) : base(onChanged) + { + TestPatternCommand = new RelayCommand(ExecuteTestPattern); + } + + public override string TransformerType => "Regex"; + public override string DisplayName => "Regex Transform"; + public override string Icon => "󰑑"; // mdi-regex + public override string Summary => !string.IsNullOrEmpty(_columnName) + ? $"{_columnName}: {(_isFindReplaceMode ? "Replace" : "Extract")}" + : "Configure..."; + + /// Gets or sets the column name to transform. + public string ColumnName + { + get => _columnName; + set + { + if (SetProperty(ref _columnName, value ?? string.Empty)) + { + OnPropertyChanged(nameof(Summary)); + NotifyChanged(); + } + } + } + + /// Gets or sets the regex pattern. + public string Pattern + { + get => _pattern; + set + { + if (SetProperty(ref _pattern, value ?? string.Empty)) + { + ClearTestResult(); + NotifyChanged(); + } + } + } + + /// Gets or sets the replacement string (Find & Replace mode). + public string? Replacement + { + get => _replacement; + set + { + if (SetProperty(ref _replacement, value)) + { + ClearTestResult(); + NotifyChanged(); + } + } + } + + /// Gets or sets whether Find & Replace mode is active. + public bool IsFindReplaceMode + { + get => _isFindReplaceMode; + set + { + if (SetProperty(ref _isFindReplaceMode, value)) + { + OnPropertyChanged(nameof(IsMatchExtractMode)); + OnPropertyChanged(nameof(PatternHelpText)); + OnPropertyChanged(nameof(Summary)); + ClearTestResult(); + NotifyChanged(); + } + } + } + + /// Gets or sets whether Match & Extract mode is active. + public bool IsMatchExtractMode + { + get => !_isFindReplaceMode; + set => IsFindReplaceMode = !value; + } + + /// Gets the help text for the pattern field based on current mode. + public string PatternHelpText => _isFindReplaceMode + ? "Pattern to search for in the column value" + : "Pattern with capture group - first group (parentheses) will be extracted"; + + /// Gets or sets whether matching is case-insensitive. + public bool IgnoreCase + { + get => _ignoreCase; + set + { + if (SetProperty(ref _ignoreCase, value)) + { + ClearTestResult(); + NotifyChanged(); + } + } + } + + /// Gets or sets the behavior when pattern doesn't match. + public NonMatchBehavior NonMatchBehavior + { + get => _nonMatchBehavior; + set + { + if (SetProperty(ref _nonMatchBehavior, value)) + { + ClearTestResult(); + NotifyChanged(); + } + } + } + + // Test feature properties + public string TestInput + { + get => _testInput; + set => SetProperty(ref _testInput, value ?? string.Empty); + } + + public string TestResultValue + { + get => _testResultValue; + set => SetProperty(ref _testResultValue, value); + } + + public string TestResultLabel + { + get => _testResultLabel; + set => SetProperty(ref _testResultLabel, value); + } + + public string TestResultIcon + { + get => _testResultIcon; + set => SetProperty(ref _testResultIcon, value); + } + + public string TestResultBackground + { + get => _testResultBackground; + set => SetProperty(ref _testResultBackground, value); + } + + public bool HasTestResult + { + get => _hasTestResult; + set => SetProperty(ref _hasTestResult, value); + } + + public bool HasTestError + { + get => _hasTestError; + set => SetProperty(ref _hasTestError, value); + } + + public string TestErrorMessage + { + get => _testErrorMessage; + set => SetProperty(ref _testErrorMessage, value); + } + + public ICommand TestPatternCommand { get; } + + private void ExecuteTestPattern() + { + ClearTestResult(); + + if (string.IsNullOrEmpty(_pattern)) + { + HasTestError = true; + TestErrorMessage = "Pattern is required"; + return; + } + + try + { + var options = _ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None; + var regex = new Regex(_pattern, options); + + string result; + bool matched; + + if (_isFindReplaceMode) + { + result = regex.Replace(_testInput, _replacement ?? string.Empty); + matched = regex.IsMatch(_testInput); + } + else + { + var match = regex.Match(_testInput); + if (match.Success && match.Groups.Count > 1) + { + result = match.Groups[1].Value; + matched = true; + } + else + { + matched = false; + result = _nonMatchBehavior switch + { + NonMatchBehavior.ReturnNull => "(null)", + NonMatchBehavior.ReturnEmpty => "(empty)", + _ => _testInput + }; + } + } + + HasTestResult = true; + TestResultValue = result; + TestResultLabel = matched ? "Output" : "No Match"; + TestResultIcon = matched ? "✓" : "—"; + TestResultBackground = matched ? "#22C55E" : "#F59E0B"; + } + catch (RegexParseException ex) + { + HasTestError = true; + TestErrorMessage = ex.Message; + } + } + + private void ClearTestResult() + { + HasTestResult = false; + HasTestError = false; + TestResultValue = string.Empty; + TestResultLabel = string.Empty; + TestErrorMessage = string.Empty; + } + + public override TransformerModel ToModel() => new() + { + Type = TransformerType, + ColumnName = _columnName, + Pattern = _pattern, + Replacement = _isFindReplaceMode ? _replacement : null, + IgnoreCase = _ignoreCase, + NonMatchBehavior = _nonMatchBehavior + }; +} + /// /// Factory methods for creating transformer view models. ///