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.Fonts.Inter" Version="11.2.*" />
|
||||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.2.*" Condition="'$(Configuration)' == 'Debug'" />
|
<PackageReference Include="Avalonia.Diagnostics" Version="11.2.*" Condition="'$(Configuration)' == 'Debug'" />
|
||||||
<PackageReference Include="DiffPlex" Version="1.7.*" />
|
<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.DependencyInjection" Version="9.0.*" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.*" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.*" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" 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