refactor(ui/shared): introduce IDialogService + DialogHost
Eliminates the per-page <ConfirmDialog @ref="_confirmDialog" ConfirmButtonClass="btn-danger" /> boilerplate. Pages now inject IDialogService and call ConfirmAsync(title, message, danger: true) programmatically. New scoped service holds a single active dialog (throws on nested calls), with a global DialogHost mounted once in MainLayout that renders the modal markup, owns body scroll-lock via Bootstrap's modal-open class, traps focus on the modal element, and handles Escape-to-cancel. Same service also exposes PromptAsync, used to replace the bespoke NewFolderDialog. Both ConfirmDialog and NewFolderDialog components are deleted — their callers (~13 pages across Admin/Design/Deployment /Monitoring) now go through the service. DiffDialog stays as-is — different use case (before/after content). bUnit tests in TopologyPageTests, DataConnectionsPageTests, and TemplatesPageTests register IDialogService in their service collection. Also: a top-of-file Razor comment on Sites.razor pointing future implementers at it as the reference list-page pattern.
This commit is contained in:
@@ -10,10 +10,10 @@
|
||||
@inject TemplateFolderService TemplateFolderService
|
||||
@inject AuthenticationStateProvider AuthStateProvider
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IDialogService Dialog
|
||||
|
||||
<div class="container-fluid mt-3">
|
||||
<ToastNotification @ref="_toast" />
|
||||
<ConfirmDialog @ref="_confirmDialog" ConfirmButtonClass="btn-danger" />
|
||||
|
||||
<RenameFolderDialog @bind-IsVisible="_showRenameFolderDialog"
|
||||
FolderId="_renameFolderId"
|
||||
@@ -21,11 +21,6 @@
|
||||
ErrorMessage="@_renameFolderError"
|
||||
OnSubmit="SubmitRenameFolder" />
|
||||
|
||||
<NewFolderDialog @bind-IsVisible="_showNewFolderDialog"
|
||||
ParentFolderId="_newFolderParentId"
|
||||
ErrorMessage="@_newFolderError"
|
||||
OnSubmit="SubmitNewFolder" />
|
||||
|
||||
<MoveTemplateDialog @bind-IsVisible="_showMoveTemplateDialog"
|
||||
TemplateId="_moveTemplateId"
|
||||
TemplateName="@_moveTemplateName"
|
||||
@@ -112,7 +107,6 @@
|
||||
private string? _errorMessage;
|
||||
|
||||
private ToastNotification _toast = default!;
|
||||
private ConfirmDialog _confirmDialog = default!;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
@@ -345,32 +339,24 @@
|
||||
}
|
||||
};
|
||||
|
||||
// New-folder dialog state
|
||||
private bool _showNewFolderDialog;
|
||||
private int? _newFolderParentId;
|
||||
private string? _newFolderError;
|
||||
|
||||
private void OpenNewFolderDialog(int? parentFolderId)
|
||||
// New-folder dialog: replaced the dedicated <NewFolderDialog> component with
|
||||
// IDialogService.PromptAsync. Validation failures surface via toast instead of
|
||||
// inline error text — the prompt UI doesn't have a slot for an error message.
|
||||
private async Task OpenNewFolderDialog(int? parentFolderId)
|
||||
{
|
||||
_newFolderParentId = parentFolderId;
|
||||
_newFolderError = null;
|
||||
_showNewFolderDialog = true;
|
||||
}
|
||||
var name = await Dialog.PromptAsync("New folder", "Folder name", placeholder: "Folder name");
|
||||
if (string.IsNullOrWhiteSpace(name)) return;
|
||||
|
||||
private async Task SubmitNewFolder((int? ParentFolderId, string Name) req)
|
||||
{
|
||||
_newFolderError = null;
|
||||
var user = await GetCurrentUserAsync();
|
||||
var result = await TemplateFolderService.CreateFolderAsync(req.Name, req.ParentFolderId, user);
|
||||
var result = await TemplateFolderService.CreateFolderAsync(name.Trim(), parentFolderId, user);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
_showNewFolderDialog = false;
|
||||
_toast.ShowSuccess($"Folder '{result.Value.Name}' created.");
|
||||
await LoadTemplatesAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
_newFolderError = result.Error;
|
||||
_toast.ShowError(result.Error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,7 +483,7 @@
|
||||
|
||||
private async Task DeleteFolder(int folderId, string label)
|
||||
{
|
||||
var confirmed = await _confirmDialog.ShowAsync($"Delete folder '{label}'?", "Delete Folder");
|
||||
var confirmed = await Dialog.ConfirmAsync("Delete Folder", $"Delete folder '{label}'?", danger: true);
|
||||
if (!confirmed) return;
|
||||
|
||||
var user = await GetCurrentUserAsync();
|
||||
@@ -515,9 +501,10 @@
|
||||
|
||||
private async Task DeleteTemplate(Template template)
|
||||
{
|
||||
var confirmed = await _confirmDialog.ShowAsync(
|
||||
var confirmed = await Dialog.ConfirmAsync(
|
||||
"Delete Template",
|
||||
$"Delete template '{template.Name}'? This will fail if instances or child templates reference it.",
|
||||
"Delete Template");
|
||||
danger: true);
|
||||
if (!confirmed) return;
|
||||
|
||||
try
|
||||
|
||||
Reference in New Issue
Block a user