Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements for the admin panel #525

Merged
merged 1 commit into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Web/AdminPanel/MUnique.OpenMU.Web.AdminPanel.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<ItemGroup>
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
<PackageReference Include="Blazored.Modal" Version="6.0.1" />
<PackageReference Include="Blazored.Toast" Version="4.2.1" />
<PackageReference Include="Blazored.Typeahead" Version="4.7.0" />
<PackageReference Include="BlazorInputFile" Version="0.2.0" />
<PackageReference Include="Mapster" Version="7.4.0" />
Expand Down
18 changes: 9 additions & 9 deletions src/Web/AdminPanel/Pages/CreateConnectServerConfig.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace MUnique.OpenMU.Web.AdminPanel.Pages;

using System.ComponentModel.DataAnnotations;
using System.Threading;
using Blazored.Modal.Services;
using Blazored.Toast.Services;
using Microsoft.AspNetCore.Components;
using MUnique.OpenMU.DataModel.Configuration;
using MUnique.OpenMU.Interfaces;
Expand Down Expand Up @@ -42,10 +42,10 @@ public partial class CreateConnectServerConfig : ComponentBase, IAsyncDisposable
public IDataSource<GameConfiguration> DataSource { get; set; } = null!;

/// <summary>
/// Gets or sets the modal service.
/// Gets or sets the toast service.
/// </summary>
[Inject]
public IModalService ModalService { get; set; } = null!;
public IToastService ToastService { get; set; } = null!;

/// <summary>
/// Gets or sets the navigation manager.
Expand Down Expand Up @@ -131,7 +131,6 @@ private async ValueTask<ConnectServerDefinition> CreateDefinitionByViewModelAsyn

private async Task OnSaveButtonClickAsync()
{
string text;
try
{
var gameConfiguration = await this.DataSource.GetOwnerAsync().ConfigureAwait(false);
Expand All @@ -141,13 +140,13 @@ private async Task OnSaveButtonClickAsync()
var existingServerDefinitions = (await saveContext.GetAsync<ConnectServerDefinition>().ConfigureAwait(false)).ToList();
if (existingServerDefinitions.Any(def => def.ServerId == this._viewModel?.ServerId))
{
await this.ModalService.ShowMessageAsync("Save", $"Server with Id {this._viewModel?.ServerId} already exists. Please use another value.").ConfigureAwait(true);
this.ToastService.ShowError($"Server with Id {this._viewModel?.ServerId} already exists. Please use another value.");
return;
}

if (existingServerDefinitions.Any(def => def.ClientListenerPort == this._viewModel?.NetworkPort))
{
await this.ModalService.ShowMessageAsync("Save", $"A server with tcp port {this._viewModel?.NetworkPort} already exists. Please use another tcp port.").ConfigureAwait(true);
this.ToastService.ShowError($"A server with tcp port {this._viewModel?.NetworkPort} already exists. Please use another tcp port.");
return;
}

Expand All @@ -157,24 +156,25 @@ private async Task OnSaveButtonClickAsync()
this._initState = "Saving Configuration ...";
await this.InvokeAsync(this.StateHasChanged);
var success = await saveContext.SaveChangesAsync().ConfigureAwait(true);
text = success ? "The changes have been saved." : "There were no changes to save.";

// if success, init new game server instance
if (success)
{
this.ToastService.ShowSuccess("The connection server configuration has been saved. Initializing connect server ...");
this._initState = "Initializing Connect Server ...";
await this.InvokeAsync(this.StateHasChanged);
await this.ServerInstanceManager.InitializeConnectServerAsync(connectServerDefinition.ConfigurationId);
this.NavigationManager.NavigateTo("servers");
return;
}

this.ToastService.ShowError("No changes have been saved.");
}
catch (Exception ex)
{
text = $"An unexpected error occurred: {ex.Message}.";
this.ToastService.ShowError($"An unexpected error occurred: {ex.Message}.");
}

await this.ModalService.ShowMessageAsync("Save", text).ConfigureAwait(true);
this._initState = null;
}

Expand Down
18 changes: 13 additions & 5 deletions src/Web/AdminPanel/Pages/CreateGameServerConfig.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace MUnique.OpenMU.Web.AdminPanel.Pages;
using System.ComponentModel.DataAnnotations;
using System.Threading;
using Blazored.Modal.Services;
using Blazored.Toast.Services;
using Microsoft.AspNetCore.Components;
using MUnique.OpenMU.DataModel.Configuration;
using MUnique.OpenMU.Persistence;
Expand Down Expand Up @@ -48,6 +49,12 @@ public partial class CreateGameServerConfig : ComponentBase, IAsyncDisposable
[Inject]
public IModalService ModalService { get; set; } = null!;

/// <summary>
/// Gets or sets the toast service.
/// </summary>
[Inject]
public IToastService ToastService { get; set; } = null!;

/// <summary>
/// Gets or sets the navigation manager.
/// </summary>
Expand Down Expand Up @@ -152,13 +159,13 @@ private async Task OnSaveButtonClickAsync()
var existingServerDefinitions = (await saveContext.GetAsync<GameServerDefinition>().ConfigureAwait(false)).ToList();
if (existingServerDefinitions.Any(def => def.ServerID == this._viewModel?.ServerId))
{
await this.ModalService.ShowMessageAsync("Save", $"Server with Id {this._viewModel?.ServerId} already exists. Please use another value.").ConfigureAwait(true);
this.ToastService.ShowError($"Server with Id {this._viewModel?.ServerId} already exists. Please use another value.");
return;
}

if (existingServerDefinitions.Any(def => def.Endpoints.Any(endpoint => endpoint.NetworkPort == this._viewModel?.NetworkPort)))
{
await this.ModalService.ShowMessageAsync("Save", $"A server with tcp port {this._viewModel?.NetworkPort} already exists. Please use another tcp port.").ConfigureAwait(true);
this.ToastService.ShowError($"A server with tcp port {this._viewModel?.NetworkPort} already exists. Please use another tcp port.");
return;
}

Expand All @@ -168,24 +175,25 @@ private async Task OnSaveButtonClickAsync()
this._initState = "Saving Configuration ...";
await this.InvokeAsync(this.StateHasChanged);
var success = await saveContext.SaveChangesAsync().ConfigureAwait(true);
text = success ? "The changes have been saved." : "There were no changes to save.";

// if success, init new game server instance
if (success)
{
this.ToastService.ShowSuccess("The game server configuration has been saved. Initializing game server ...");
this._initState = "Initializing Game Server ...";
await this.InvokeAsync(this.StateHasChanged);
await this.ServerInstanceManager.InitializeGameServerAsync(gameServerDefinition.ServerID);
this.NavigationManager.NavigateTo("servers");
return;
}

this.ToastService.ShowError("No changes have been saved.");
}
catch (Exception ex)
{
text = $"An unexpected error occurred: {ex.Message}.";
this.ToastService.ShowError($"An unexpected error occurred: {ex.Message}.");
}

await this.ModalService.ShowMessageAsync("Save", text).ConfigureAwait(true);
this._initState = null;
}

Expand Down
18 changes: 12 additions & 6 deletions src/Web/AdminPanel/Pages/EditBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace MUnique.OpenMU.Web.AdminPanel.Pages;
using System.Reflection;
using System.Threading;
using Blazored.Modal.Services;
using Blazored.Toast.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
using Microsoft.AspNetCore.Components.Routing;
Expand Down Expand Up @@ -71,6 +72,12 @@ private enum DataLoadingState
[Inject]
public IModalService ModalService { get; set; } = null!;

/// <summary>
/// Gets or sets the toast service.
/// </summary>
[Inject]
public IToastService ToastService { get; set; } = null!;

/// <summary>
/// Gets or sets the configuration data source.
/// </summary>
Expand Down Expand Up @@ -221,26 +228,25 @@ await this.InvokeAsync(() =>
/// </summary>
protected async Task SaveChangesAsync()
{
string text;
try
{
if (this._persistenceContext is { } context)
{
var success = await context.SaveChangesAsync().ConfigureAwait(true);
text = success ? "The changes have been saved." : "There were no changes to save.";
var text = success ? "The changes have been saved." : "There were no changes to save.";
this.ToastService.ShowSuccess(text);
}
else
{
text = "Failed, context not initialized";
this.ToastService.ShowError("Failed, context not initialized");
}
}
catch (Exception ex)
{
this.Logger?.LogError(ex, $"Error during saving {this.Id}");
text = $"An unexpected error occured: {ex.Message}.";
var text = $"An unexpected error occured: {ex.Message}.";
this.ToastService.ShowError(text);
}

await this.ModalService.ShowMessageAsync("Save", text).ConfigureAwait(true);
}

/// <summary>
Expand Down
5 changes: 4 additions & 1 deletion src/Web/AdminPanel/Pages/EditConfigGrid.razor
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@
var targetUrl = $"edit-config/{this.TypeString}/" + context.Id;
}
<button type="button" class="btn-info" @onclick="@(() => this.NavigationManager.NavigateTo(targetUrl))">Edit</button>
<button type="button" class="btn-danger" @onclick="@(() => this.OnDeleteButtonClickAsync(context))"><span class="oi oi-trash"></span> Delete</button>
</TemplateColumn>
</QuickGrid>
</div>
<Paginator State="@_pagination" />
<Paginator State="@_pagination" />
<hr />
<button type="button" class="btn-outline-primary" @onclick="OnCreateButtonClickAsync"><span class="oi oi-plus"></span> Add New</button>
76 changes: 76 additions & 0 deletions src/Web/AdminPanel/Pages/EditConfigGrid.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ namespace MUnique.OpenMU.Web.AdminPanel.Pages;
using System.Collections;
using System.ComponentModel;
using System.Threading;
using Blazored.Modal;
using Blazored.Modal.Services;
using Blazored.Toast.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.QuickGrid;
using Microsoft.Extensions.Logging;
using MUnique.OpenMU.DataModel.Configuration;
using MUnique.OpenMU.Persistence;
using MUnique.OpenMU.Web.AdminPanel.Components.Form;

/// <summary>
/// Razor page which shows objects of the specified type in a grid.
Expand Down Expand Up @@ -48,6 +53,24 @@ public partial class EditConfigGrid : ComponentBase, IAsyncDisposable
[Inject]
public IPersistenceContextProvider PersistenceContextProvider { get; set; } = null!;

/// <summary>
/// Gets or sets the modal service.
/// </summary>
[Inject]
public IModalService ModalService { get; set; } = null!;

/// <summary>
/// Gets or sets the toast service.
/// </summary>
[Inject]
public IToastService ToastService { get; set; } = null!;

/// <summary>
/// Gets or sets the logger.
/// </summary>
[Inject]
public ILogger<EditConfigGrid> Logger { get; set; } = null!;

/// <summary>
/// Gets or sets the type.
/// </summary>
Expand Down Expand Up @@ -142,6 +165,59 @@ await this.InvokeAsync(async () =>
.Select(assembly => assembly.GetType(this.TypeString)).FirstOrDefault(t => t != null);
}

private async Task OnDeleteButtonClickAsync(ViewModel viewModel)
{
try
{
var dialogResult = await this.ModalService.ShowQuestionAsync("Are you sure?", $"You're about to delete '{viewModel.Name}. Are you sure?");
if (!dialogResult)
{
return;
}

var cancellationToken = this._disposeCts?.Token ?? default;
var gameConfiguration = await this.DataSource.GetOwnerAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
using var deleteContext = this.PersistenceContextProvider.CreateNewContext(gameConfiguration);
deleteContext.Attach(viewModel.Parent);
await deleteContext.DeleteAsync(viewModel.Parent).ConfigureAwait(false);
await deleteContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
this.ToastService.ShowSuccess($"Deleted '{viewModel.Name}' successfully.");
this._viewModels = null;
this._loadTask = Task.Run(() => this.LoadDataAsync(cancellationToken), cancellationToken);
}
catch (Exception ex)
{
this.Logger.LogError(ex, $"Couldn't delete '{viewModel.Name}', probably because it's referenced by another object.");
this.ToastService.ShowError($"Couldn't delete '{viewModel.Name}', probably because it's referenced by another object. For details, see log");
}
}

private async Task OnCreateButtonClickAsync()
{
var cancellationToken = this._disposeCts?.Token ?? default;
var gameConfiguration = await this.DataSource.GetOwnerAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
using var creationContext = this.PersistenceContextProvider.CreateNewContext(gameConfiguration);
var newObject = creationContext.CreateNew(this.Type!);
var parameters = new ModalParameters();
var modalType = typeof(ModalCreateNew<>).MakeGenericType(this.Type!);

parameters.Add(nameof(ModalCreateNew<object>.Item), newObject);
var options = new ModalOptions
{
DisableBackgroundCancel = true,
};

var modal = this.ModalService.Show(modalType, $"Create", parameters, options);
var result = await modal.Result.ConfigureAwait(false);
if (!result.Cancelled)
{
await creationContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
this.ToastService.ShowSuccess("New object successfully created.");
this._viewModels = null;
this._loadTask = Task.Run(() => this.LoadDataAsync(cancellationToken), cancellationToken);
}
}

/// <summary>
/// The view model for the grid.
/// We use this instead of the objects, because it makes the code simpler.
Expand Down
15 changes: 10 additions & 5 deletions src/Web/AdminPanel/Pages/EditMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace MUnique.OpenMU.Web.AdminPanel.Pages;
using System.Reflection;
using System.Threading;
using Blazored.Modal.Services;
using Blazored.Toast.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
using Microsoft.AspNetCore.Components.Routing;
Expand Down Expand Up @@ -41,6 +42,12 @@ public sealed class EditMap : ComponentBase, IDisposable
[Inject]
private IModalService ModalService { get; set; } = null!;

/// <summary>
/// Gets or sets the toast service.
/// </summary>
[Inject]
private IToastService ToastService { get; set; } = null!;

/// <summary>
/// Gets or sets the game configuration.
/// </summary>
Expand Down Expand Up @@ -209,19 +216,17 @@ private async Task LoadDataAsync(CancellationToken cancellationToken)

private async Task SaveChangesAsync()
{
string text;
try
{
var context = await this.GameConfigurationSource.GetContextAsync().ConfigureAwait(true);
var success = await context.SaveChangesAsync().ConfigureAwait(true);
text = success ? "The changes have been saved." : "There were no changes to save.";
var text = success ? "The changes have been saved." : "There were no changes to save.";
this.ToastService.ShowSuccess(text);
}
catch (Exception ex)
{
this.Logger.LogError(ex, $"Error during saving");
text = $"An unexpected error occured: {ex.Message}.";
this.ToastService.ShowError($"An unexpected error occured: {ex.Message}. See logs for more details.");
}

await this.ModalService.ShowMessageAsync("Save", text).ConfigureAwait(true);
}
}
Loading
Loading