refactor(configmanager): simplify SecureStore UI with unified info view

Consolidate SecureStoreLockedFormView and SecureStoreUnlockedFormView into
a single SecureStoreInfoFormView that displays store status and metadata.
Simplifies MainWindowViewModel by removing redundant state management.
Also adds design docs for RegexTransformer feature.
This commit is contained in:
Joseph Doherty
2026-01-22 09:40:38 -05:00
parent 5669bac221
commit 9bf0c29add
28 changed files with 2811 additions and 1527 deletions
@@ -157,7 +157,7 @@ public class MainWindowViewModelTests
// Assert
sut.SelectedFormViewModel.ShouldBeOfType<ExcelExportFormViewModel>();
((ExcelExportFormViewModel)sut.SelectedFormViewModel!).TimezoneId.ShouldBe("America/New_York");
((ExcelExportFormViewModel)sut.SelectedFormViewModel!).SelectedTimezone.ShouldBe("America/New_York");
}
[Fact]
@@ -281,9 +281,11 @@ public class MainWindowViewModelTests
sut.LoadConfigForTesting(config, null);
// Assert
sut.TreeNodes.Count.ShouldBe(3); // Settings, Pipelines, and Secure Stores folders
// Without a configured/open SecureStore, only Settings and Pipelines appear
sut.TreeNodes.Count.ShouldBe(2); // Settings, Pipelines (no Secure Store when not configured)
sut.TreeNodes[0].Name.ShouldBe("Settings");
sut.TreeNodes[0].Children.Count.ShouldBe(6); // DataSync, DataAccess, Auth, Ldap, Search, ExcelExport
sut.TreeNodes[1].Name.ShouldBe("Pipelines");
}
[Fact]
@@ -309,6 +311,65 @@ public class MainWindowViewModelTests
sut.TreeNodes[1].Children.Count.ShouldBe(2);
}
[Fact]
public async Task OpenFolderCommand_UsesFilePicker_AndDerivesFolder()
{
// Arrange
var expectedFilePath = "/path/to/folder/appsettings.json";
var expectedFolder = "/path/to/folder";
var config = new ConfigModel();
// Ensure auto-discovery doesn't load config
_autoDiscoveryService.FindConfigFolderAsync().Returns((string?)null);
_dialogService.ShowFilePickerAsync(Arg.Any<string?>())
.Returns(expectedFilePath);
_configFileService.LoadAppSettingsAsync(Arg.Any<string>(), Arg.Any<CancellationToken>())
.Returns(config);
var sut = CreateViewModel();
// Wait for constructor async init to complete
await Task.Delay(50);
_configFileService.ClearReceivedCalls();
// Act
sut.OpenFolderCommand.Execute(null);
// Give async command time to complete
await Task.Delay(100);
// Assert
await _dialogService.Received(1).ShowFilePickerAsync("Select Configuration File");
await _configFileService.Received(1).LoadAppSettingsAsync(
Arg.Is<string>(s => s.Contains(expectedFolder)),
Arg.Any<CancellationToken>());
sut.ConfigFolderPath.ShouldBe(expectedFolder);
}
[Fact]
public async Task OpenFolderCommand_WhenCancelled_DoesNotLoadConfig()
{
// Arrange
// Ensure auto-discovery doesn't load config
_autoDiscoveryService.FindConfigFolderAsync().Returns((string?)null);
_dialogService.ShowFilePickerAsync(Arg.Any<string?>())
.Returns((string?)null);
var sut = CreateViewModel();
var originalPath = sut.ConfigFolderPath;
// Wait for constructor async init to complete
await Task.Delay(50);
_configFileService.ClearReceivedCalls();
// Act
sut.OpenFolderCommand.Execute(null);
// Give async command time to complete
await Task.Delay(100);
// Assert
await _dialogService.Received(1).ShowFilePickerAsync(Arg.Any<string?>());
await _configFileService.DidNotReceive().LoadAppSettingsAsync(Arg.Any<string>(), Arg.Any<CancellationToken>());
sut.ConfigFolderPath.ShouldBe(originalPath);
}
private MainWindowViewModel CreateViewModel()
{
return new MainWindowViewModel(