diff --git a/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/Forms/DataSyncFormViewModel.cs b/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/Forms/DataSyncFormViewModel.cs
new file mode 100644
index 0000000..a42e415
--- /dev/null
+++ b/NEW/src/Utils/JdeScoping.ConfigManager/ViewModels/Forms/DataSyncFormViewModel.cs
@@ -0,0 +1,155 @@
+using JdeScoping.ConfigManager.Models;
+
+namespace JdeScoping.ConfigManager.ViewModels.Forms;
+
+///
+/// ViewModel for editing DataSync configuration section.
+///
+public class DataSyncFormViewModel : ViewModelBase
+{
+ private readonly DataSyncSection _model;
+ private readonly Action _onChanged;
+
+ public DataSyncFormViewModel(DataSyncSection model, Action onChanged)
+ {
+ _model = model ?? throw new ArgumentNullException(nameof(model));
+ _onChanged = onChanged ?? throw new ArgumentNullException(nameof(onChanged));
+ }
+
+ ///
+ /// Gets or sets whether data synchronization is enabled.
+ ///
+ public bool Enabled
+ {
+ get => _model.Enabled;
+ set
+ {
+ if (_model.Enabled != value)
+ {
+ _model.Enabled = value;
+ OnPropertyChanged();
+ _onChanged();
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the check interval in minutes.
+ ///
+ public int CheckIntervalMinutes
+ {
+ get => (int)_model.CheckInterval.TotalMinutes;
+ set
+ {
+ var newValue = TimeSpan.FromMinutes(value);
+ if (_model.CheckInterval != newValue)
+ {
+ _model.CheckInterval = newValue;
+ OnPropertyChanged();
+ _onChanged();
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the maximum degree of parallelism.
+ ///
+ public int MaxDegreeOfParallelism
+ {
+ get => _model.MaxDegreeOfParallelism;
+ set
+ {
+ if (_model.MaxDegreeOfParallelism != value)
+ {
+ _model.MaxDegreeOfParallelism = value;
+ OnPropertyChanged();
+ _onChanged();
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the batch size for sync operations.
+ ///
+ public int BatchSize
+ {
+ get => _model.BatchSize;
+ set
+ {
+ if (_model.BatchSize != value)
+ {
+ _model.BatchSize = value;
+ OnPropertyChanged();
+ _onChanged();
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the bulk copy batch size.
+ ///
+ public int BulkCopyBatchSize
+ {
+ get => _model.BulkCopyBatchSize;
+ set
+ {
+ if (_model.BulkCopyBatchSize != value)
+ {
+ _model.BulkCopyBatchSize = value;
+ OnPropertyChanged();
+ _onChanged();
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the lookback multiplier.
+ ///
+ public double LookbackMultiplier
+ {
+ get => _model.LookbackMultiplier;
+ set
+ {
+ if (Math.Abs(_model.LookbackMultiplier - value) > 0.001)
+ {
+ _model.LookbackMultiplier = value;
+ OnPropertyChanged();
+ _onChanged();
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the purge retention days.
+ ///
+ public int PurgeRetentionDays
+ {
+ get => _model.PurgeRetentionDays;
+ set
+ {
+ if (_model.PurgeRetentionDays != value)
+ {
+ _model.PurgeRetentionDays = value;
+ OnPropertyChanged();
+ _onChanged();
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the sync timeout in seconds.
+ ///
+ public int SyncTimeoutSeconds
+ {
+ get => _model.SyncTimeoutSeconds;
+ set
+ {
+ if (_model.SyncTimeoutSeconds != value)
+ {
+ _model.SyncTimeoutSeconds = value;
+ OnPropertyChanged();
+ _onChanged();
+ }
+ }
+ }
+}
diff --git a/NEW/tests/JdeScoping.ConfigManager.Tests/ViewModels/Forms/DataSyncFormViewModelTests.cs b/NEW/tests/JdeScoping.ConfigManager.Tests/ViewModels/Forms/DataSyncFormViewModelTests.cs
new file mode 100644
index 0000000..e6dceaa
--- /dev/null
+++ b/NEW/tests/JdeScoping.ConfigManager.Tests/ViewModels/Forms/DataSyncFormViewModelTests.cs
@@ -0,0 +1,76 @@
+using JdeScoping.ConfigManager.Models;
+using JdeScoping.ConfigManager.ViewModels.Forms;
+
+namespace JdeScoping.ConfigManager.Tests.ViewModels.Forms;
+
+public class DataSyncFormViewModelTests
+{
+ [Fact]
+ public void Constructor_InitializesFromModel()
+ {
+ // Arrange
+ var model = new DataSyncSection
+ {
+ Enabled = true,
+ MaxDegreeOfParallelism = 8,
+ BatchSize = 25000
+ };
+
+ // Act
+ var sut = new DataSyncFormViewModel(model, () => { });
+
+ // Assert
+ sut.Enabled.ShouldBeTrue();
+ sut.MaxDegreeOfParallelism.ShouldBe(8);
+ sut.BatchSize.ShouldBe(25000);
+ }
+
+ [Fact]
+ public void PropertyChange_UpdatesModel()
+ {
+ // Arrange
+ var model = new DataSyncSection { MaxDegreeOfParallelism = 4 };
+ var sut = new DataSyncFormViewModel(model, () => { });
+
+ // Act
+ sut.MaxDegreeOfParallelism = 16;
+
+ // Assert
+ model.MaxDegreeOfParallelism.ShouldBe(16);
+ }
+
+ [Fact]
+ public void PropertyChange_InvokesOnChanged()
+ {
+ // Arrange
+ var model = new DataSyncSection();
+ var changedInvoked = false;
+ var sut = new DataSyncFormViewModel(model, () => changedInvoked = true);
+
+ // Act
+ sut.BatchSize = 10000;
+
+ // Assert
+ changedInvoked.ShouldBeTrue();
+ }
+
+ [Fact]
+ public void PropertyChange_RaisesPropertyChanged()
+ {
+ // Arrange
+ var model = new DataSyncSection();
+ var sut = new DataSyncFormViewModel(model, () => { });
+ var propertyChangedRaised = false;
+ sut.PropertyChanged += (s, e) =>
+ {
+ if (e.PropertyName == nameof(DataSyncFormViewModel.LookbackMultiplier))
+ propertyChangedRaised = true;
+ };
+
+ // Act
+ sut.LookbackMultiplier = 2.5;
+
+ // Assert
+ propertyChangedRaised.ShouldBeTrue();
+ }
+}