feat(configmanager): add PipelineFormViewModel and ScheduleFormViewModel

Add form ViewModels for editing pipeline configurations in the ConfigManager.
ScheduleFormViewModel wraps ScheduleModel for schedule editing.
PipelineFormViewModel wraps PipelineModel with schedule sub-ViewModels.
This commit is contained in:
Joseph Doherty
2026-01-19 19:50:20 -05:00
parent 6e2decd21f
commit c3684f5150
3 changed files with 545 additions and 0 deletions
@@ -0,0 +1,172 @@
using JdeScoping.ConfigManager.Models;
namespace JdeScoping.ConfigManager.ViewModels.Forms;
/// <summary>
/// ViewModel for editing a pipeline configuration.
/// </summary>
public class PipelineFormViewModel : ViewModelBase
{
private readonly PipelineModel _model;
private readonly Action _onChanged;
public PipelineFormViewModel(string name, PipelineModel model, Action onChanged)
{
Name = name ?? throw new ArgumentNullException(nameof(name));
_model = model ?? throw new ArgumentNullException(nameof(model));
_onChanged = onChanged ?? throw new ArgumentNullException(nameof(onChanged));
// Initialize schedule view models
_model.Schedules.Mass ??= new ScheduleModel();
_model.Schedules.Daily ??= new ScheduleModel();
_model.Schedules.Hourly ??= new ScheduleModel();
MassSchedule = new ScheduleFormViewModel(_model.Schedules.Mass, _onChanged);
DailySchedule = new ScheduleFormViewModel(_model.Schedules.Daily, _onChanged);
HourlySchedule = new ScheduleFormViewModel(_model.Schedules.Hourly, _onChanged);
}
/// <summary>
/// Gets the pipeline name.
/// </summary>
public string Name { get; }
/// <summary>
/// Gets or sets the source connection name.
/// </summary>
public string Connection
{
get => _model.Source.Connection;
set
{
if (_model.Source.Connection != value)
{
_model.Source.Connection = value;
OnPropertyChanged();
_onChanged();
}
}
}
/// <summary>
/// Gets or sets the source query.
/// </summary>
public string Query
{
get => _model.Source.Query;
set
{
if (_model.Source.Query != value)
{
_model.Source.Query = value;
OnPropertyChanged();
_onChanged();
}
}
}
/// <summary>
/// Gets or sets the optional mass query.
/// </summary>
public string? MassQuery
{
get => _model.Source.MassQuery;
set
{
if (_model.Source.MassQuery != value)
{
_model.Source.MassQuery = value;
OnPropertyChanged();
_onChanged();
}
}
}
/// <summary>
/// Gets or sets the destination table name.
/// </summary>
public string DestinationTable
{
get => _model.Destination.Table;
set
{
if (_model.Destination.Table != value)
{
_model.Destination.Table = value;
OnPropertyChanged();
_onChanged();
}
}
}
/// <summary>
/// Gets or sets the match columns as newline-separated text.
/// </summary>
public string MatchColumnsText
{
get => string.Join("\n", _model.Destination.MatchColumns);
set
{
var columns = value.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (!_model.Destination.MatchColumns.SequenceEqual(columns))
{
_model.Destination.MatchColumns = columns;
OnPropertyChanged();
_onChanged();
}
}
}
/// <summary>
/// Gets or sets the exclude from update columns as newline-separated text.
/// </summary>
public string ExcludeFromUpdateText
{
get => string.Join("\n", _model.Destination.ExcludeFromUpdate);
set
{
var columns = value.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (!_model.Destination.ExcludeFromUpdate.SequenceEqual(columns))
{
_model.Destination.ExcludeFromUpdate = columns;
OnPropertyChanged();
_onChanged();
}
}
}
/// <summary>
/// Gets or sets the post scripts as newline-separated text.
/// </summary>
public string PostScriptsText
{
get => _model.PostScripts != null ? string.Join("\n", _model.PostScripts) : string.Empty;
set
{
var scripts = string.IsNullOrWhiteSpace(value)
? null
: value.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (_model.PostScripts?.SequenceEqual(scripts ?? []) != true)
{
_model.PostScripts = scripts;
OnPropertyChanged();
_onChanged();
}
}
}
/// <summary>
/// Gets the mass schedule view model.
/// </summary>
public ScheduleFormViewModel MassSchedule { get; }
/// <summary>
/// Gets the daily schedule view model.
/// </summary>
public ScheduleFormViewModel DailySchedule { get; }
/// <summary>
/// Gets the hourly schedule view model.
/// </summary>
public ScheduleFormViewModel HourlySchedule { get; }
}
@@ -0,0 +1,86 @@
using JdeScoping.ConfigManager.Models;
namespace JdeScoping.ConfigManager.ViewModels.Forms;
/// <summary>
/// ViewModel for editing a schedule configuration.
/// </summary>
public class ScheduleFormViewModel : ViewModelBase
{
private readonly ScheduleModel _model;
private readonly Action _onChanged;
public ScheduleFormViewModel(ScheduleModel model, Action onChanged)
{
_model = model ?? throw new ArgumentNullException(nameof(model));
_onChanged = onChanged ?? throw new ArgumentNullException(nameof(onChanged));
}
/// <summary>
/// Gets or sets whether this schedule is enabled.
/// </summary>
public bool Enabled
{
get => _model.Enabled;
set
{
if (_model.Enabled != value)
{
_model.Enabled = value;
OnPropertyChanged();
_onChanged();
}
}
}
/// <summary>
/// Gets or sets the interval in minutes.
/// </summary>
public int IntervalMinutes
{
get => _model.IntervalMinutes;
set
{
if (_model.IntervalMinutes != value)
{
_model.IntervalMinutes = value;
OnPropertyChanged();
_onChanged();
}
}
}
/// <summary>
/// Gets or sets whether to purge before sync.
/// </summary>
public bool PrePurge
{
get => _model.PrePurge;
set
{
if (_model.PrePurge != value)
{
_model.PrePurge = value;
OnPropertyChanged();
_onChanged();
}
}
}
/// <summary>
/// Gets or sets whether to reindex after sync.
/// </summary>
public bool ReIndex
{
get => _model.ReIndex;
set
{
if (_model.ReIndex != value)
{
_model.ReIndex = value;
OnPropertyChanged();
_onChanged();
}
}
}
}