feat(configmanager): add IDialogService interface and AvaloniaDialogService
Add dialog service abstraction for platform-specific dialogs: - IDialogService interface with folder picker, message, confirmation, diff preview, and validation results methods - AvaloniaDialogService implementation using MsBox.Avalonia - Basic implementations for ShowDiffPreviewAsync and ShowValidationResultsAsync (full dialogs to be implemented in Tasks 22-23) - Add MessageBox.Avalonia package reference
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.*" />
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.2.*" Condition="'$(Configuration)' == 'Debug'" />
|
||||
<PackageReference Include="DiffPlex" Version="1.7.*" />
|
||||
<PackageReference Include="MessageBox.Avalonia" Version="3.1.*" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.*" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.*" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.*" />
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
using System.Text;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Platform.Storage;
|
||||
using MsBox.Avalonia;
|
||||
using MsBox.Avalonia.Enums;
|
||||
|
||||
namespace JdeScoping.ConfigManager.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Avalonia implementation of IDialogService using MsBox.Avalonia and platform storage.
|
||||
/// </summary>
|
||||
public class AvaloniaDialogService : IDialogService
|
||||
{
|
||||
private readonly Func<Window?> _getMainWindow;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of AvaloniaDialogService.
|
||||
/// </summary>
|
||||
/// <param name="getMainWindow">Factory function to get the main window for dialogs.</param>
|
||||
public AvaloniaDialogService(Func<Window?> getMainWindow)
|
||||
{
|
||||
_getMainWindow = getMainWindow ?? throw new ArgumentNullException(nameof(getMainWindow));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<string?> ShowFolderPickerAsync(string? title = null)
|
||||
{
|
||||
var window = _getMainWindow();
|
||||
if (window == null)
|
||||
return null;
|
||||
|
||||
var folders = await window.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
Title = title ?? "Select Folder",
|
||||
AllowMultiple = false
|
||||
});
|
||||
|
||||
return folders.Count > 0 ? folders[0].Path.LocalPath : null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task ShowMessageAsync(string title, string message)
|
||||
{
|
||||
var box = MessageBoxManager.GetMessageBoxStandard(title, message, ButtonEnum.Ok, Icon.Info);
|
||||
var window = _getMainWindow();
|
||||
if (window != null)
|
||||
{
|
||||
await box.ShowWindowDialogAsync(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
await box.ShowAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> ShowConfirmationAsync(string title, string message)
|
||||
{
|
||||
var box = MessageBoxManager.GetMessageBoxStandard(title, message, ButtonEnum.YesNo, Icon.Question);
|
||||
var window = _getMainWindow();
|
||||
ButtonResult result;
|
||||
if (window != null)
|
||||
{
|
||||
result = await box.ShowWindowDialogAsync(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = await box.ShowAsync();
|
||||
}
|
||||
return result == ButtonResult.Yes;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> ShowDiffPreviewAsync(string title, DiffResult diff)
|
||||
{
|
||||
// Basic implementation - full diff preview dialog will be implemented in Task 22
|
||||
if (!diff.HasChanges)
|
||||
{
|
||||
await ShowMessageAsync(title, "No changes detected.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var summary = new StringBuilder();
|
||||
summary.AppendLine($"Changes detected: {diff.Insertions} insertion(s), {diff.Deletions} deletion(s)");
|
||||
summary.AppendLine();
|
||||
summary.AppendLine("Do you want to apply these changes?");
|
||||
|
||||
return await ShowConfirmationAsync(title, summary.ToString());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task ShowValidationResultsAsync(ValidationResult appSettingsResult, ValidationResult pipelinesResult)
|
||||
{
|
||||
// Basic implementation - full validation results dialog will be implemented in Task 23
|
||||
var message = new StringBuilder();
|
||||
|
||||
message.AppendLine("=== AppSettings Validation ===");
|
||||
if (appSettingsResult.IsValid)
|
||||
{
|
||||
message.AppendLine("Valid");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var error in appSettingsResult.Errors)
|
||||
{
|
||||
message.AppendLine($"Error: {error}");
|
||||
}
|
||||
}
|
||||
foreach (var warning in appSettingsResult.Warnings)
|
||||
{
|
||||
message.AppendLine($"Warning: {warning}");
|
||||
}
|
||||
|
||||
message.AppendLine();
|
||||
message.AppendLine("=== Pipelines Validation ===");
|
||||
if (pipelinesResult.IsValid)
|
||||
{
|
||||
message.AppendLine("Valid");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var error in pipelinesResult.Errors)
|
||||
{
|
||||
message.AppendLine($"Error: {error}");
|
||||
}
|
||||
}
|
||||
foreach (var warning in pipelinesResult.Warnings)
|
||||
{
|
||||
message.AppendLine($"Warning: {warning}");
|
||||
}
|
||||
|
||||
var title = appSettingsResult.IsValid && pipelinesResult.IsValid
|
||||
? "Validation Passed"
|
||||
: "Validation Issues Found";
|
||||
|
||||
var icon = appSettingsResult.IsValid && pipelinesResult.IsValid ? Icon.Success : Icon.Warning;
|
||||
|
||||
var box = MessageBoxManager.GetMessageBoxStandard(title, message.ToString(), ButtonEnum.Ok, icon);
|
||||
var window = _getMainWindow();
|
||||
if (window != null)
|
||||
{
|
||||
await box.ShowWindowDialogAsync(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
await box.ShowAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
namespace JdeScoping.ConfigManager.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Abstraction for platform-specific dialog operations.
|
||||
/// Enables unit testing of view models that need to show dialogs.
|
||||
/// </summary>
|
||||
public interface IDialogService
|
||||
{
|
||||
/// <summary>
|
||||
/// Shows a folder picker dialog.
|
||||
/// </summary>
|
||||
/// <param name="title">Optional title for the dialog.</param>
|
||||
/// <returns>The selected folder path, or null if cancelled.</returns>
|
||||
Task<string?> ShowFolderPickerAsync(string? title = null);
|
||||
|
||||
/// <summary>
|
||||
/// Shows a message dialog.
|
||||
/// </summary>
|
||||
/// <param name="title">The dialog title.</param>
|
||||
/// <param name="message">The message to display.</param>
|
||||
Task ShowMessageAsync(string title, string message);
|
||||
|
||||
/// <summary>
|
||||
/// Shows a confirmation dialog with Yes/No options.
|
||||
/// </summary>
|
||||
/// <param name="title">The dialog title.</param>
|
||||
/// <param name="message">The confirmation message to display.</param>
|
||||
/// <returns>True if user clicked Yes, false otherwise.</returns>
|
||||
Task<bool> ShowConfirmationAsync(string title, string message);
|
||||
|
||||
/// <summary>
|
||||
/// Shows a diff preview dialog allowing the user to review changes.
|
||||
/// </summary>
|
||||
/// <param name="title">The dialog title.</param>
|
||||
/// <param name="diff">The diff result to display.</param>
|
||||
/// <returns>True if user confirms the changes, false otherwise.</returns>
|
||||
Task<bool> ShowDiffPreviewAsync(string title, DiffResult diff);
|
||||
|
||||
/// <summary>
|
||||
/// Shows validation results for configuration files.
|
||||
/// </summary>
|
||||
/// <param name="appSettingsResult">Validation result for appsettings.json.</param>
|
||||
/// <param name="pipelinesResult">Validation result for pipelines.json.</param>
|
||||
Task ShowValidationResultsAsync(ValidationResult appSettingsResult, ValidationResult pipelinesResult);
|
||||
}
|
||||
Reference in New Issue
Block a user