diff --git a/src/Web/AdminPanel/Pages/CreateConnectServerConfig.razor b/src/Web/AdminPanel/Pages/CreateConnectServerConfig.razor index 10204de..0d89eb6 100644 --- a/src/Web/AdminPanel/Pages/CreateConnectServerConfig.razor +++ b/src/Web/AdminPanel/Pages/CreateConnectServerConfig.razor @@ -11,18 +11,8 @@ @if (this._viewModel is null) { - - @Resources.Loading return; } -@if (this._initState is { }) -{ - - @this._initState - return; -} - - - + diff --git a/src/Web/AdminPanel/Pages/CreateConnectServerConfig.razor.cs b/src/Web/AdminPanel/Pages/CreateConnectServerConfig.razor.cs index 84aebd7..48c4497 100644 --- a/src/Web/AdminPanel/Pages/CreateConnectServerConfig.razor.cs +++ b/src/Web/AdminPanel/Pages/CreateConnectServerConfig.razor.cs @@ -12,6 +12,7 @@ using MUnique.OpenMU.DataModel.Configuration; using MUnique.OpenMU.Interfaces; using MUnique.OpenMU.Persistence; using MUnique.OpenMU.Web.AdminPanel.Properties; +using MUnique.OpenMU.Web.Shared.Services; /// /// Razor page which shows objects of the specified type in a grid. @@ -22,7 +23,7 @@ public partial class CreateConnectServerConfig : ComponentBase, IAsyncDisposable private CancellationTokenSource? _disposeCts; private ConnectServerViewModel? _viewModel; - private string? _initState; + private bool _isProcessing; /// /// Gets or sets the context provider. @@ -54,6 +55,12 @@ public partial class CreateConnectServerConfig : ComponentBase, IAsyncDisposable [Inject] public NavigationManager NavigationManager { get; set; } = null!; + /// + /// Gets or sets the loading overlay service. + /// + [Inject] + public LoadingOverlayService LoadingService { get; set; } = null!; + /// public async ValueTask DisposeAsync() { @@ -86,6 +93,7 @@ public partial class CreateConnectServerConfig : ComponentBase, IAsyncDisposable private async Task LoadDataAsync(CancellationToken cancellationToken) { + using var loading = this.LoadingService.ShowLoadingIndicator(); cancellationToken.ThrowIfCancellationRequested(); var gameConfiguration = await this.DataSource.GetOwnerAsync(default, cancellationToken).ConfigureAwait(true); @@ -134,11 +142,11 @@ public partial class CreateConnectServerConfig : ComponentBase, IAsyncDisposable { try { - var gameConfiguration = await this.DataSource.GetOwnerAsync().ConfigureAwait(false); - + this._isProcessing = true; + var gameConfiguration = await this.DataSource.GetOwnerAsync().ConfigureAwait(true); using var saveContext = this.ContextProvider.CreateNewTypedContext(typeof(DataModel.Configuration.ConnectServerDefinition), true, gameConfiguration); - var existingServerDefinitions = (await saveContext.GetAsync().ConfigureAwait(false)).ToList(); + var existingServerDefinitions = (await saveContext.GetAsync().ConfigureAwait(true)).ToList(); if (existingServerDefinitions.Any(def => def.ServerId == this._viewModel?.ServerId)) { this.ToastService.ShowError(string.Format(Resources.ServerWithIdAlreadyExists, this._viewModel?.ServerId)); @@ -151,20 +159,13 @@ public partial class CreateConnectServerConfig : ComponentBase, IAsyncDisposable return; } - this._initState = Resources.CreatingConfigurationInfo; - await this.InvokeAsync(this.StateHasChanged); - var connectServerDefinition = await this.CreateDefinitionByViewModelAsync(saveContext).ConfigureAwait(false); - this._initState = Resources.SavingConfigurationInfo; - await this.InvokeAsync(this.StateHasChanged); + var connectServerDefinition = await this.CreateDefinitionByViewModelAsync(saveContext).ConfigureAwait(true); var success = await saveContext.SaveChangesAsync().ConfigureAwait(true); - // if success, init new game server instance if (success) { this.ToastService.ShowSuccess(Resources.ConnectionServerConfigurationSaved); - this._initState = Resources.InitializingConnectServerInfo; - await this.InvokeAsync(this.StateHasChanged); - await this.ServerInstanceManager.InitializeConnectServerAsync(connectServerDefinition.ConfigurationId); + await this.ServerInstanceManager.InitializeConnectServerAsync(connectServerDefinition.ConfigurationId).ConfigureAwait(true); this.NavigationManager.NavigateTo("servers"); return; } @@ -175,8 +176,10 @@ public partial class CreateConnectServerConfig : ComponentBase, IAsyncDisposable { this.ToastService.ShowError(string.Format(Resources.UnexpectedErrorOccurred, ex.Message)); } - - this._initState = null; + finally + { + this._isProcessing = false; + } } /// diff --git a/src/Web/AdminPanel/Pages/CreateGameServerConfig.razor b/src/Web/AdminPanel/Pages/CreateGameServerConfig.razor index 7d65e95..f94b64f 100644 --- a/src/Web/AdminPanel/Pages/CreateGameServerConfig.razor +++ b/src/Web/AdminPanel/Pages/CreateGameServerConfig.razor @@ -11,18 +11,8 @@ @if (this._viewModel is null) { - - @Resources.Loading return; } -@if (this._initState is { }) -{ - - @this._initState - return; -} - - - + diff --git a/src/Web/AdminPanel/Pages/CreateGameServerConfig.razor.cs b/src/Web/AdminPanel/Pages/CreateGameServerConfig.razor.cs index 6ec5c8c..a5597d6 100644 --- a/src/Web/AdminPanel/Pages/CreateGameServerConfig.razor.cs +++ b/src/Web/AdminPanel/Pages/CreateGameServerConfig.razor.cs @@ -13,6 +13,7 @@ using MUnique.OpenMU.Interfaces; using MUnique.OpenMU.Persistence; using MUnique.OpenMU.Web.AdminPanel.Properties; using MUnique.OpenMU.Web.Shared.Components.Modal; +using MUnique.OpenMU.Web.Shared.Services; /// /// Razor page that shows objects of the specified type in a grid. @@ -23,7 +24,7 @@ public partial class CreateGameServerConfig : ComponentBase, IAsyncDisposable private CancellationTokenSource? _disposeCts; private GameServerViewModel? _viewModel; - private string? _initState; + private bool _isProcessing; /// /// Gets or sets the context provider. @@ -61,6 +62,12 @@ public partial class CreateGameServerConfig : ComponentBase, IAsyncDisposable [Inject] public NavigationManager NavigationManager { get; set; } = null!; + /// + /// Gets or sets the loading overlay service. + /// + [Inject] + public LoadingOverlayService LoadingService { get; set; } = null!; + /// public async ValueTask DisposeAsync() { @@ -93,6 +100,7 @@ public partial class CreateGameServerConfig : ComponentBase, IAsyncDisposable private async Task LoadDataAsync(CancellationToken cancellationToken) { + using var loading = this.LoadingService.ShowLoadingIndicator(); cancellationToken.ThrowIfCancellationRequested(); var gameConfiguration = await this.DataSource.GetOwnerAsync(default, cancellationToken).ConfigureAwait(true); @@ -150,11 +158,11 @@ public partial class CreateGameServerConfig : ComponentBase, IAsyncDisposable { try { - var gameConfiguration = await this.DataSource.GetOwnerAsync().ConfigureAwait(false); - + this._isProcessing = true; + var gameConfiguration = await this.DataSource.GetOwnerAsync().ConfigureAwait(true); using var saveContext = this.ContextProvider.CreateNewTypedContext(typeof(DataModel.Configuration.GameServerDefinition), true, gameConfiguration); - var existingServerDefinitions = (await saveContext.GetAsync().ConfigureAwait(false)).ToList(); + var existingServerDefinitions = (await saveContext.GetAsync().ConfigureAwait(true)).ToList(); if (existingServerDefinitions.Any(def => def.ServerID == this._viewModel?.ServerId)) { this.ToastService.ShowError(string.Format(Resources.ServerWithIdAlreadyExists, this._viewModel?.ServerId)); @@ -167,20 +175,13 @@ public partial class CreateGameServerConfig : ComponentBase, IAsyncDisposable return; } - this._initState = Resources.CreatingConfigurationInfo; - await this.InvokeAsync(this.StateHasChanged); - var gameServerDefinition = await this.CreateDefinitionByViewModelAsync(saveContext).ConfigureAwait(false); - this._initState = Resources.SavingConfigurationInfo; - await this.InvokeAsync(this.StateHasChanged); + var gameServerDefinition = await this.CreateDefinitionByViewModelAsync(saveContext).ConfigureAwait(true); var success = await saveContext.SaveChangesAsync().ConfigureAwait(true); - // if success, init new game server instance if (success) { this.ToastService.ShowSuccess(Resources.GameServerConfigurationSavedInfo); - this._initState = Resources.InitializingGameServerInfo; - await this.InvokeAsync(this.StateHasChanged); - await this.ServerInstanceManager.InitializeGameServerAsync(gameServerDefinition.ServerID); + await this.ServerInstanceManager.InitializeGameServerAsync(gameServerDefinition.ServerID).ConfigureAwait(true); this.NavigationManager.NavigateTo("servers"); return; } @@ -191,8 +192,10 @@ public partial class CreateGameServerConfig : ComponentBase, IAsyncDisposable { this.ToastService.ShowError(string.Format(Resources.UnexpectedErrorOccurred, ex.Message)); } - - this._initState = null; + finally + { + this._isProcessing = false; + } } /// diff --git a/src/Web/AdminPanel/Pages/EditConfigGrid.razor b/src/Web/AdminPanel/Pages/EditConfigGrid.razor index d3e27db..5648713 100644 --- a/src/Web/AdminPanel/Pages/EditConfigGrid.razor +++ b/src/Web/AdminPanel/Pages/EditConfigGrid.razor @@ -15,8 +15,6 @@ @if (this.ViewModels is null) { - - @Resources.Loading return; } diff --git a/src/Web/AdminPanel/Pages/EditConfigGrid.razor.cs b/src/Web/AdminPanel/Pages/EditConfigGrid.razor.cs index 875eedc..5479006 100644 --- a/src/Web/AdminPanel/Pages/EditConfigGrid.razor.cs +++ b/src/Web/AdminPanel/Pages/EditConfigGrid.razor.cs @@ -80,6 +80,12 @@ public partial class EditConfigGrid : ComponentBase, IAsyncDisposable [Inject] public ILogger Logger { get; set; } = null!; + /// + /// Gets or sets the loading overlay service. + /// + [Inject] + public LoadingOverlayService LoadingService { get; set; } = null!; + /// /// Gets or sets the type. /// @@ -145,6 +151,7 @@ public partial class EditConfigGrid : ComponentBase, IAsyncDisposable private async Task LoadDataAsync(CancellationToken cancellationToken) { + using var loading = this.LoadingService.ShowLoadingIndicator(); cancellationToken.ThrowIfCancellationRequested(); if (this.Type is null) { diff --git a/src/Web/AdminPanel/Pages/Merchants.razor b/src/Web/AdminPanel/Pages/Merchants.razor index 0df9540..25bb04b 100644 --- a/src/Web/AdminPanel/Pages/Merchants.razor +++ b/src/Web/AdminPanel/Pages/Merchants.razor @@ -13,8 +13,6 @@ @if (this.ViewModels is null) { - - @Resources.Loading return; } diff --git a/src/Web/AdminPanel/Pages/Merchants.razor.cs b/src/Web/AdminPanel/Pages/Merchants.razor.cs index 62ca67d..76bd696 100644 --- a/src/Web/AdminPanel/Pages/Merchants.razor.cs +++ b/src/Web/AdminPanel/Pages/Merchants.razor.cs @@ -16,6 +16,7 @@ using MUnique.OpenMU.DataModel.Configuration; using MUnique.OpenMU.DataModel.Entities; using MUnique.OpenMU.Persistence; using MUnique.OpenMU.Web.AdminPanel.Properties; +using MUnique.OpenMU.Web.Shared.Services; /// /// Razor page which shows objects of the specified type in a grid. @@ -68,6 +69,12 @@ public partial class Merchants : ComponentBase, IAsyncDisposable [Inject] public ILogger Logger { get; set; } = null!; + /// + /// Gets or sets the loading overlay service. + /// + [Inject] + public LoadingOverlayService LoadingService { get; set; } = null!; + private IQueryable? ViewModels => this._viewModels?.AsQueryable(); /// @@ -134,6 +141,7 @@ public partial class Merchants : ComponentBase, IAsyncDisposable private async Task LoadDataAsync(CancellationToken cancellationToken) { + using var loading = this.LoadingService.ShowLoadingIndicator(); try { cancellationToken.ThrowIfCancellationRequested(); @@ -192,8 +200,13 @@ public partial class Merchants : ComponentBase, IAsyncDisposable { if (this._persistenceContext?.HasChanges is true) { + var previousMerchantId = this._selectedMerchant?.Id; await this.DataSource.DiscardChangesAsync().ConfigureAwait(true); await this.LoadDataAsync(this._disposeCts?.Token ?? default).ConfigureAwait(true); + if (previousMerchantId is { } id && this._viewModels is not null) + { + this._selectedMerchant = this._viewModels.FirstOrDefault(vm => vm.Id == id); + } } } diff --git a/src/Web/Shared/Components/Form/AutoForm.razor b/src/Web/Shared/Components/Form/AutoForm.razor index f8c0fd8..5862407 100644 --- a/src/Web/Shared/Components/Form/AutoForm.razor +++ b/src/Web/Shared/Components/Form/AutoForm.razor @@ -19,7 +19,13 @@
- + @if (this.OnRefresh != null) { diff --git a/src/Web/Shared/Components/Form/AutoForm.razor.cs b/src/Web/Shared/Components/Form/AutoForm.razor.cs index 122426e..63e04ad 100644 --- a/src/Web/Shared/Components/Form/AutoForm.razor.cs +++ b/src/Web/Shared/Components/Form/AutoForm.razor.cs @@ -35,6 +35,14 @@ public partial class AutoForm [Parameter] public EventCallback OnValidSubmit { get; set; } + /// + /// Gets or sets a value indicating whether the form is in a processing state, + /// e.g. while saving data. When , the save button is + /// disabled and shows a spinner. + /// + [Parameter] + public bool IsProcessing { get; set; } + /// /// Gets or sets the callback invoked when the cancel button is clicked. /// When , the cancel button is not rendered. diff --git a/src/Web/Shared/Components/ItemEdit/ItemEdit.razor b/src/Web/Shared/Components/ItemEdit/ItemEdit.razor index 1d0f2ae..bb6d8b4 100644 --- a/src/Web/Shared/Components/ItemEdit/ItemEdit.razor +++ b/src/Web/Shared/Components/ItemEdit/ItemEdit.razor @@ -201,7 +201,7 @@
@if (this.OnValidSubmit.HasDelegate) { - + } @if (this.OnCancel.HasDelegate)