1fc7792cd1
Rename ConfigManager to ConfigManager.Ui to match the Core/CLI/UI project structure, and split the monolithic test project into Core.Tests, Cli.Tests, and Ui.Tests to align with the source project organization.
787 lines
26 KiB
C#
787 lines
26 KiB
C#
using JdeScoping.DataSync.Configuration;
|
|
using System.Collections.ObjectModel;
|
|
using System.Text.Json;
|
|
using System.Text.RegularExpressions;
|
|
using System.Windows.Input;
|
|
|
|
namespace JdeScoping.ConfigManager.Ui.ViewModels.PipelineSteps;
|
|
|
|
/// <summary>
|
|
/// Base class for transformer step view models.
|
|
/// </summary>
|
|
public abstract class TransformerStepViewModelBase : PipelineStepViewModelBase
|
|
{
|
|
protected static readonly JsonSerializerOptions JsonOptions = new()
|
|
{
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
|
};
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="TransformerStepViewModelBase"/> class.
|
|
/// </summary>
|
|
/// <param name="onChanged">Callback invoked when the transformer changes.</param>
|
|
protected TransformerStepViewModelBase(Action onChanged) : base(onChanged)
|
|
{
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override PipelineStepType StepType => PipelineStepType.Transformer;
|
|
/// <inheritdoc />
|
|
public override string Icon => ""; // mdi-cog-transfer
|
|
|
|
/// <summary>
|
|
/// Gets the transformer type name.
|
|
/// </summary>
|
|
public abstract string TransformerType { get; }
|
|
|
|
/// <summary>
|
|
/// Converts this view model back to a TransformElement.
|
|
/// </summary>
|
|
public abstract TransformElement ToModel();
|
|
|
|
/// <summary>
|
|
/// Helper to create a JsonElement from an object.
|
|
/// </summary>
|
|
/// <param name="config">The object to serialize into a JsonElement.</param>
|
|
/// <returns>A JsonElement containing the serialized configuration.</returns>
|
|
protected static JsonElement CreateConfigElement(object config)
|
|
{
|
|
var json = JsonSerializer.Serialize(config, JsonOptions);
|
|
using var doc = JsonDocument.Parse(json);
|
|
return doc.RootElement.Clone();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// View model for ColumnDrop transformer.
|
|
/// </summary>
|
|
public class ColumnDropTransformerViewModel : TransformerStepViewModelBase
|
|
{
|
|
private string _columnsText;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ColumnDropTransformerViewModel"/> class with an existing configuration.
|
|
/// </summary>
|
|
/// <param name="element">The transform element containing the column configuration.</param>
|
|
/// <param name="onChanged">Callback invoked when the configuration changes.</param>
|
|
public ColumnDropTransformerViewModel(TransformElement element, Action onChanged) : base(onChanged)
|
|
{
|
|
_columnsText = string.Empty;
|
|
if (element.Config.HasValue)
|
|
{
|
|
if (element.Config.Value.TryGetProperty("columns", out var columnsProp) &&
|
|
columnsProp.ValueKind == JsonValueKind.Array)
|
|
{
|
|
var columns = columnsProp.EnumerateArray().Select(c => c.GetString() ?? "").Where(c => !string.IsNullOrEmpty(c));
|
|
_columnsText = string.Join("\n", columns);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ColumnDropTransformerViewModel"/> class with default values.
|
|
/// </summary>
|
|
/// <param name="onChanged">Callback invoked when the configuration changes.</param>
|
|
public ColumnDropTransformerViewModel(Action onChanged) : base(onChanged)
|
|
{
|
|
_columnsText = string.Empty;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override string TransformerType => "ColumnDrop";
|
|
/// <inheritdoc />
|
|
public override string DisplayName => "Column Drop";
|
|
/// <inheritdoc />
|
|
public override string Summary => GetColumnCount() > 0 ? $"Drop {GetColumnCount()} columns" : "No columns";
|
|
|
|
/// <summary>
|
|
/// Gets or sets the columns to drop as newline-separated text.
|
|
/// </summary>
|
|
public string ColumnsText
|
|
{
|
|
get => _columnsText;
|
|
set
|
|
{
|
|
if (SetProperty(ref _columnsText, value ?? string.Empty))
|
|
{
|
|
OnPropertyChanged(nameof(Summary));
|
|
NotifyChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the columns as a list.
|
|
/// </summary>
|
|
public List<string> GetColumns()
|
|
{
|
|
return _columnsText.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList();
|
|
}
|
|
|
|
private int GetColumnCount()
|
|
{
|
|
return _columnsText.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).Length;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override TransformElement ToModel() => new()
|
|
{
|
|
TransformType = TransformerType,
|
|
Config = CreateConfigElement(new { columns = GetColumns() })
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// View model for ColumnRename transformer.
|
|
/// </summary>
|
|
public class ColumnRenameTransformerViewModel : TransformerStepViewModelBase
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ColumnRenameTransformerViewModel"/> class with an existing configuration.
|
|
/// </summary>
|
|
/// <param name="element">The transform element containing the mapping configuration.</param>
|
|
/// <param name="onChanged">Callback invoked when the configuration changes.</param>
|
|
public ColumnRenameTransformerViewModel(TransformElement element, Action onChanged) : base(onChanged)
|
|
{
|
|
Mappings = [];
|
|
if (element.Config.HasValue)
|
|
{
|
|
if (element.Config.Value.TryGetProperty("mappings", out var mappingsProp) &&
|
|
mappingsProp.ValueKind == JsonValueKind.Object)
|
|
{
|
|
foreach (var prop in mappingsProp.EnumerateObject())
|
|
{
|
|
var newName = prop.Value.GetString() ?? "";
|
|
Mappings.Add(new ColumnMappingViewModel(prop.Name, newName, () =>
|
|
{
|
|
OnPropertyChanged(nameof(Summary));
|
|
NotifyChanged();
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
AddMappingCommand = new RelayCommand(AddMapping);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ColumnRenameTransformerViewModel"/> class with default values.
|
|
/// </summary>
|
|
/// <param name="onChanged">Callback invoked when the configuration changes.</param>
|
|
public ColumnRenameTransformerViewModel(Action onChanged) : base(onChanged)
|
|
{
|
|
Mappings = [];
|
|
AddMappingCommand = new RelayCommand(AddMapping);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override string TransformerType => "ColumnRename";
|
|
/// <inheritdoc />
|
|
public override string DisplayName => "Column Rename";
|
|
/// <inheritdoc />
|
|
public override string Summary => Mappings.Count > 0 ? $"Rename {Mappings.Count} columns" : "No mappings";
|
|
|
|
/// <summary>
|
|
/// Gets the collection of column mappings (old name -> new name).
|
|
/// </summary>
|
|
public ObservableCollection<ColumnMappingViewModel> Mappings { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the command to add a new mapping.
|
|
/// </summary>
|
|
public ICommand AddMappingCommand { get; }
|
|
|
|
/// <summary>
|
|
/// Adds a new mapping.
|
|
/// </summary>
|
|
public void AddMapping()
|
|
{
|
|
Mappings.Add(new ColumnMappingViewModel("", "", () =>
|
|
{
|
|
OnPropertyChanged(nameof(Summary));
|
|
NotifyChanged();
|
|
}));
|
|
OnPropertyChanged(nameof(Summary));
|
|
NotifyChanged();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes a mapping.
|
|
/// </summary>
|
|
/// <param name="mapping">The column mapping to remove.</param>
|
|
public void RemoveMapping(ColumnMappingViewModel mapping)
|
|
{
|
|
if (Mappings.Remove(mapping))
|
|
{
|
|
OnPropertyChanged(nameof(Summary));
|
|
NotifyChanged();
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override TransformElement ToModel() => new()
|
|
{
|
|
TransformType = TransformerType,
|
|
Config = CreateConfigElement(new { mappings = Mappings.ToDictionary(m => m.OldName, m => m.NewName) })
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// View model for a column rename mapping.
|
|
/// </summary>
|
|
public class ColumnMappingViewModel : ViewModelBase
|
|
{
|
|
private string _oldName;
|
|
private string _newName;
|
|
private readonly Action _onChanged;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ColumnMappingViewModel"/> class.
|
|
/// </summary>
|
|
/// <param name="oldName">The original column name.</param>
|
|
/// <param name="newName">The new column name.</param>
|
|
/// <param name="onChanged">Callback invoked when the mapping changes.</param>
|
|
public ColumnMappingViewModel(string oldName, string newName, Action onChanged)
|
|
{
|
|
_oldName = oldName;
|
|
_newName = newName;
|
|
_onChanged = onChanged;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the original column name.
|
|
/// </summary>
|
|
public string OldName
|
|
{
|
|
get => _oldName;
|
|
set
|
|
{
|
|
if (SetProperty(ref _oldName, value ?? string.Empty))
|
|
_onChanged();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the new column name.
|
|
/// </summary>
|
|
public string NewName
|
|
{
|
|
get => _newName;
|
|
set
|
|
{
|
|
if (SetProperty(ref _newName, value ?? string.Empty))
|
|
_onChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// View model for JdeDate transformer (converts JDE Julian date/time to DateTime).
|
|
/// </summary>
|
|
public class JdeDateTransformerViewModel : TransformerStepViewModelBase
|
|
{
|
|
private string? _dateColumn;
|
|
private string? _timeColumn;
|
|
private string? _outputColumn;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="JdeDateTransformerViewModel"/> class from a TransformElement.
|
|
/// </summary>
|
|
/// <param name="element">The transform element containing date/time column configuration.</param>
|
|
/// <param name="onChanged">Callback invoked when the configuration changes.</param>
|
|
public JdeDateTransformerViewModel(TransformElement element, Action onChanged) : base(onChanged)
|
|
{
|
|
_dateColumn = null;
|
|
_timeColumn = null;
|
|
_outputColumn = null;
|
|
|
|
if (element.Config.HasValue)
|
|
{
|
|
if (element.Config.Value.TryGetProperty("dateColumn", out var dateProp))
|
|
_dateColumn = dateProp.GetString();
|
|
if (element.Config.Value.TryGetProperty("timeColumn", out var timeProp))
|
|
_timeColumn = timeProp.GetString();
|
|
if (element.Config.Value.TryGetProperty("outputColumn", out var outputProp))
|
|
_outputColumn = outputProp.GetString();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="JdeDateTransformerViewModel"/> class with default values.
|
|
/// </summary>
|
|
/// <param name="onChanged">Callback invoked when the configuration changes.</param>
|
|
public JdeDateTransformerViewModel(Action onChanged) : base(onChanged)
|
|
{
|
|
_dateColumn = null;
|
|
_timeColumn = null;
|
|
_outputColumn = null;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override string TransformerType => "JdeDate";
|
|
/// <inheritdoc />
|
|
public override string DisplayName => "JDE Date Convert";
|
|
/// <inheritdoc />
|
|
public override string Icon => ""; // mdi-calendar
|
|
/// <inheritdoc />
|
|
public override string Summary => !string.IsNullOrEmpty(_outputColumn) ? $"→ {_outputColumn}" : "Configure...";
|
|
|
|
/// <summary>
|
|
/// Gets or sets the date column name.
|
|
/// </summary>
|
|
public string? DateColumn
|
|
{
|
|
get => _dateColumn;
|
|
set
|
|
{
|
|
if (SetProperty(ref _dateColumn, value))
|
|
{
|
|
OnPropertyChanged(nameof(Summary));
|
|
NotifyChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the time column name.
|
|
/// </summary>
|
|
public string? TimeColumn
|
|
{
|
|
get => _timeColumn;
|
|
set
|
|
{
|
|
if (SetProperty(ref _timeColumn, value))
|
|
NotifyChanged();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the output column name.
|
|
/// </summary>
|
|
public string? OutputColumn
|
|
{
|
|
get => _outputColumn;
|
|
set
|
|
{
|
|
if (SetProperty(ref _outputColumn, value))
|
|
{
|
|
OnPropertyChanged(nameof(Summary));
|
|
NotifyChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override TransformElement ToModel() => new()
|
|
{
|
|
TransformType = TransformerType,
|
|
Config = CreateConfigElement(new { dateColumn = _dateColumn, timeColumn = _timeColumn, outputColumn = _outputColumn })
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Specifies behavior when a regex pattern does not match the input value.
|
|
/// </summary>
|
|
public enum NonMatchBehavior
|
|
{
|
|
/// <summary>Keep the original value unchanged.</summary>
|
|
KeepOriginal,
|
|
/// <summary>Return null/DBNull.</summary>
|
|
ReturnNull,
|
|
/// <summary>Return an empty string.</summary>
|
|
ReturnEmpty
|
|
}
|
|
|
|
/// <summary>
|
|
/// View model for Regex transformer.
|
|
/// </summary>
|
|
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;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="RegexTransformerViewModel"/> class from a TransformElement.
|
|
/// </summary>
|
|
/// <param name="element">The transform element containing regex configuration.</param>
|
|
/// <param name="onChanged">Callback invoked when the configuration changes.</param>
|
|
public RegexTransformerViewModel(TransformElement element, Action onChanged) : base(onChanged)
|
|
{
|
|
_columnName = string.Empty;
|
|
_pattern = string.Empty;
|
|
_replacement = null;
|
|
_isFindReplaceMode = true;
|
|
_ignoreCase = false;
|
|
_nonMatchBehavior = NonMatchBehavior.KeepOriginal;
|
|
|
|
if (element.Config.HasValue)
|
|
{
|
|
if (element.Config.Value.TryGetProperty("columnName", out var colProp))
|
|
_columnName = colProp.GetString() ?? string.Empty;
|
|
if (element.Config.Value.TryGetProperty("pattern", out var patternProp))
|
|
_pattern = patternProp.GetString() ?? string.Empty;
|
|
if (element.Config.Value.TryGetProperty("replacement", out var replaceProp))
|
|
{
|
|
_replacement = replaceProp.ValueKind == JsonValueKind.Null ? null : replaceProp.GetString();
|
|
_isFindReplaceMode = _replacement != null;
|
|
}
|
|
else
|
|
{
|
|
// No replacement property means Match & Extract mode
|
|
_replacement = null;
|
|
_isFindReplaceMode = false;
|
|
}
|
|
if (element.Config.Value.TryGetProperty("ignoreCase", out var ignoreProp))
|
|
_ignoreCase = ignoreProp.GetBoolean();
|
|
if (element.Config.Value.TryGetProperty("nonMatchBehavior", out var behaviorProp))
|
|
{
|
|
var behaviorStr = behaviorProp.GetString();
|
|
if (Enum.TryParse<NonMatchBehavior>(behaviorStr, true, out var behavior))
|
|
_nonMatchBehavior = behavior;
|
|
}
|
|
}
|
|
TestPatternCommand = new RelayCommand(ExecuteTestPattern);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="RegexTransformerViewModel"/> class with default values.
|
|
/// </summary>
|
|
/// <param name="onChanged">Callback invoked when the configuration changes.</param>
|
|
public RegexTransformerViewModel(Action onChanged) : base(onChanged)
|
|
{
|
|
TestPatternCommand = new RelayCommand(ExecuteTestPattern);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override string TransformerType => "Regex";
|
|
/// <inheritdoc />
|
|
public override string DisplayName => "Regex Transform";
|
|
/// <inheritdoc />
|
|
public override string Icon => ""; // mdi-regex
|
|
/// <inheritdoc />
|
|
public override string Summary => !string.IsNullOrEmpty(_columnName)
|
|
? $"{_columnName}: {(_isFindReplaceMode ? "Replace" : "Extract")}"
|
|
: "Configure...";
|
|
|
|
/// <summary>Gets or sets the column name to transform.</summary>
|
|
public string ColumnName
|
|
{
|
|
get => _columnName;
|
|
set
|
|
{
|
|
if (SetProperty(ref _columnName, value ?? string.Empty))
|
|
{
|
|
OnPropertyChanged(nameof(Summary));
|
|
NotifyChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets or sets the regex pattern.</summary>
|
|
public string Pattern
|
|
{
|
|
get => _pattern;
|
|
set
|
|
{
|
|
if (SetProperty(ref _pattern, value ?? string.Empty))
|
|
{
|
|
ClearTestResult();
|
|
NotifyChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets or sets the replacement string (Find & Replace mode).</summary>
|
|
public string? Replacement
|
|
{
|
|
get => _replacement;
|
|
set
|
|
{
|
|
if (SetProperty(ref _replacement, value))
|
|
{
|
|
ClearTestResult();
|
|
NotifyChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets or sets whether Find & Replace mode is active.</summary>
|
|
public bool IsFindReplaceMode
|
|
{
|
|
get => _isFindReplaceMode;
|
|
set
|
|
{
|
|
if (SetProperty(ref _isFindReplaceMode, value))
|
|
{
|
|
OnPropertyChanged(nameof(IsMatchExtractMode));
|
|
OnPropertyChanged(nameof(PatternHelpText));
|
|
OnPropertyChanged(nameof(Summary));
|
|
ClearTestResult();
|
|
NotifyChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets or sets whether Match & Extract mode is active.</summary>
|
|
public bool IsMatchExtractMode
|
|
{
|
|
get => !_isFindReplaceMode;
|
|
set => IsFindReplaceMode = !value;
|
|
}
|
|
|
|
/// <summary>Gets the help text for the pattern field based on current mode.</summary>
|
|
public string PatternHelpText => _isFindReplaceMode
|
|
? "Pattern to search for in the column value"
|
|
: "Pattern with capture group - first group (parentheses) will be extracted";
|
|
|
|
/// <summary>Gets or sets whether matching is case-insensitive.</summary>
|
|
public bool IgnoreCase
|
|
{
|
|
get => _ignoreCase;
|
|
set
|
|
{
|
|
if (SetProperty(ref _ignoreCase, value))
|
|
{
|
|
ClearTestResult();
|
|
NotifyChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets or sets the behavior when pattern doesn't match.</summary>
|
|
public NonMatchBehavior NonMatchBehavior
|
|
{
|
|
get => _nonMatchBehavior;
|
|
set
|
|
{
|
|
if (SetProperty(ref _nonMatchBehavior, value))
|
|
{
|
|
ClearTestResult();
|
|
NotifyChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets the available non-match behavior options for binding.</summary>
|
|
public static IReadOnlyList<NonMatchBehavior> NonMatchBehaviorOptions { get; } =
|
|
[NonMatchBehavior.KeepOriginal, NonMatchBehavior.ReturnNull, NonMatchBehavior.ReturnEmpty];
|
|
|
|
// Test feature properties
|
|
/// <summary>
|
|
/// Gets or sets the test input value for pattern testing.
|
|
/// </summary>
|
|
public string TestInput
|
|
{
|
|
get => _testInput;
|
|
set => SetProperty(ref _testInput, value ?? string.Empty);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the result value from pattern testing.
|
|
/// </summary>
|
|
public string TestResultValue
|
|
{
|
|
get => _testResultValue;
|
|
set => SetProperty(ref _testResultValue, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the label describing the test result (e.g., "Output" or "No Match").
|
|
/// </summary>
|
|
public string TestResultLabel
|
|
{
|
|
get => _testResultLabel;
|
|
set => SetProperty(ref _testResultLabel, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the icon for the test result.
|
|
/// </summary>
|
|
public string TestResultIcon
|
|
{
|
|
get => _testResultIcon;
|
|
set => SetProperty(ref _testResultIcon, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the background color for the test result display.
|
|
/// </summary>
|
|
public string TestResultBackground
|
|
{
|
|
get => _testResultBackground;
|
|
set => SetProperty(ref _testResultBackground, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether a test result is available.
|
|
/// </summary>
|
|
public bool HasTestResult
|
|
{
|
|
get => _hasTestResult;
|
|
set => SetProperty(ref _hasTestResult, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether a test error occurred.
|
|
/// </summary>
|
|
public bool HasTestError
|
|
{
|
|
get => _hasTestError;
|
|
set => SetProperty(ref _hasTestError, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the error message from test execution.
|
|
/// </summary>
|
|
public string TestErrorMessage
|
|
{
|
|
get => _testErrorMessage;
|
|
set => SetProperty(ref _testErrorMessage, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the command to execute pattern testing.
|
|
/// </summary>
|
|
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;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override TransformElement ToModel() => new()
|
|
{
|
|
TransformType = TransformerType,
|
|
Config = CreateConfigElement(new
|
|
{
|
|
columnName = _columnName,
|
|
pattern = _pattern,
|
|
replacement = _isFindReplaceMode ? _replacement : null,
|
|
ignoreCase = _ignoreCase,
|
|
nonMatchBehavior = _nonMatchBehavior.ToString()
|
|
})
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Factory methods for creating transformer view models.
|
|
/// </summary>
|
|
public static class TransformerFactory
|
|
{
|
|
/// <summary>
|
|
/// Creates a transformer view model from a TransformElement.
|
|
/// </summary>
|
|
/// <param name="element">The transform element containing configuration.</param>
|
|
/// <param name="onChanged">Callback invoked when the view model changes.</param>
|
|
/// <returns>A transformer view model of the appropriate type, or null if the transformer type is unknown.</returns>
|
|
public static TransformerStepViewModelBase? Create(TransformElement element, Action onChanged)
|
|
{
|
|
return element.TransformType?.ToLowerInvariant() switch
|
|
{
|
|
"columndrop" => new ColumnDropTransformerViewModel(element, onChanged),
|
|
"columnrename" => new ColumnRenameTransformerViewModel(element, onChanged),
|
|
"jdedate" => new JdeDateTransformerViewModel(element, onChanged),
|
|
"regex" => new RegexTransformerViewModel(element, onChanged),
|
|
_ => null // Unknown transformer type
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new transformer view model by type name.
|
|
/// </summary>
|
|
/// <param name="typeName">The type name of the transformer to create.</param>
|
|
/// <param name="onChanged">Callback invoked when the view model changes.</param>
|
|
/// <returns>A new transformer view model of the specified type, or null if the type name is unknown.</returns>
|
|
public static TransformerStepViewModelBase? CreateNew(string typeName, Action onChanged)
|
|
{
|
|
return typeName?.ToLowerInvariant() switch
|
|
{
|
|
"columndrop" => new ColumnDropTransformerViewModel(onChanged),
|
|
"columnrename" => new ColumnRenameTransformerViewModel(onChanged),
|
|
"jdedate" => new JdeDateTransformerViewModel(onChanged),
|
|
"regex" => new RegexTransformerViewModel(onChanged),
|
|
_ => null
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the list of available transformer type names.
|
|
/// </summary>
|
|
public static IReadOnlyList<string> AvailableTypes => ["ColumnDrop", "ColumnRename", "JdeDate", "Regex"];
|
|
}
|