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.
///