diff --git a/Moonlight.Frontend/Implementations/SidebarProvider.cs b/Moonlight.Frontend/Implementations/SidebarProvider.cs index 5017808b..98d729b2 100644 --- a/Moonlight.Frontend/Implementations/SidebarProvider.cs +++ b/Moonlight.Frontend/Implementations/SidebarProvider.cs @@ -30,7 +30,7 @@ public sealed class SidebarProvider : ISidebarProvider { Name = "Users", IconType = typeof(UsersRoundIcon), - Path = "/users", + Path = "/admin/users", IsExactPath = false, Group = "Admin", Order = 10 diff --git a/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor new file mode 100644 index 00000000..55597eb5 --- /dev/null +++ b/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor @@ -0,0 +1,65 @@ +@using Moonlight.Shared.Http.Requests.Users +@using ShadcnBlazor.Dialogs +@using ShadcnBlazor.Extras.Common +@using ShadcnBlazor.Extras.FormHandlers +@using ShadcnBlazor.Inputs +@using ShadcnBlazor.Labels + +@inherits ShadcnBlazor.Extras.Dialogs.DialogBase + + + + Create new user + + + Create a new user by giving it a username and an email address + + + + + + + + + + Username + + + + + Email Address + + + + + + + Save changes + + +@code +{ + [Parameter] public Func OnSubmit { get; set; } + + private CreateUserDto Request; + private FormHandler FormHandler; + + protected override void OnInitialized() + { + Request = new(); + } + + private async Task SubmitAsync() + { + await OnSubmit.Invoke(Request); + + await CloseAsync(); + } +} diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor new file mode 100644 index 00000000..fd2e77a8 --- /dev/null +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor @@ -0,0 +1,68 @@ +@using Moonlight.Frontend.Mappers +@using Moonlight.Shared.Http.Requests.Users +@using Moonlight.Shared.Http.Responses.Users +@using ShadcnBlazor.Dialogs +@using ShadcnBlazor.Extras.Common +@using ShadcnBlazor.Extras.FormHandlers +@using ShadcnBlazor.Inputs +@using ShadcnBlazor.Labels + +@inherits ShadcnBlazor.Extras.Dialogs.DialogBase + + + + Update @User.Username + + + Update the user by giving it a username and an email address + + + + + + + + + + Username + + + + + Email Address + + + + + + + Save changes + + +@code +{ + [Parameter] public Func OnSubmit { get; set; } + [Parameter] public UserDto User { get; set; } + + private UpdateUserDto Request; + private FormHandler FormHandler; + + protected override void OnInitialized() + { + Request = UserMapper.ToUpdate(User); + } + + private async Task SubmitAsync() + { + await OnSubmit.Invoke(Request); + + await CloseAsync(); + } +} diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Index.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/Index.razor index ab5a4dbd..f1c42b9f 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Index.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/Index.razor @@ -19,10 +19,6 @@ API & API Keys - - - Roles - Diagnose @@ -46,9 +42,6 @@ - - - diff --git a/Moonlight.Frontend/UI/Admin/Views/Users/Create.razor b/Moonlight.Frontend/UI/Admin/Views/Users/Create.razor deleted file mode 100644 index 35d7f0eb..00000000 --- a/Moonlight.Frontend/UI/Admin/Views/Users/Create.razor +++ /dev/null @@ -1,91 +0,0 @@ -@page "/users/create" - -@using LucideBlazor -@using ShadcnBlazor.Buttons -@using ShadcnBlazor.Labels -@using ShadcnBlazor.Cards -@using ShadcnBlazor.Extras.FormHandlers -@using ShadcnBlazor.Extras.Toasts -@using ShadcnBlazor.Inputs -@using Moonlight.Shared.Http.Requests.Users - -@inject HttpClient HttpClient -@inject NavigationManager Navigation -@inject ToastService ToastService - - - - Create user - - Create a new user - - - - - - - - Back - - - - Form.SubmitAsync()"> - - Continue - - - - - - - - - - - - - - Email - - - - - Username - - - - - - - - -@code -{ - private CreateUserDto Request = new(); - - private FormHandler Form; - - private async Task OnSubmitAsync() - { - await HttpClient.PostAsJsonAsync( - "/api/users", - Request, - Constants.SerializerOptions - ); - - await ToastService.SuccessAsync( - "User creation", - $"Successfully created user {Request.Username}" - ); - - Navigation.NavigateTo("/users"); - } -} \ No newline at end of file diff --git a/Moonlight.Frontend/UI/Admin/Views/Users/Edit.razor b/Moonlight.Frontend/UI/Admin/Views/Users/Edit.razor deleted file mode 100644 index cd285370..00000000 --- a/Moonlight.Frontend/UI/Admin/Views/Users/Edit.razor +++ /dev/null @@ -1,105 +0,0 @@ -@page "/users/{Id:int}" - -@using LucideBlazor -@using ShadcnBlazor.Buttons -@using ShadcnBlazor.Labels -@using ShadcnBlazor.Cards -@using ShadcnBlazor.Extras.Common -@using ShadcnBlazor.Extras.FormHandlers -@using ShadcnBlazor.Extras.Toasts -@using ShadcnBlazor.Inputs -@using Moonlight.Frontend.Mappers -@using Moonlight.Shared.Http.Requests.Users -@using Moonlight.Shared.Http.Responses.Users - -@inject HttpClient HttpClient -@inject NavigationManager Navigation -@inject ToastService ToastService - - - - Update user - - Update an existing user - - - - - - - - Back - - - - Form.SubmitAsync()"> - - Continue - - - - - - - - - - - - - - - Email - - - - - Username - - - - - - - - - -@code -{ - [Parameter] public int Id { get; set; } - - private FormHandler Form; - private UpdateUserDto Request; - private UserDto User; - - private async Task LoadAsync(LazyLoader _) - { - var user = await HttpClient.GetFromJsonAsync($"api/users/{Id}", Constants.SerializerOptions); - User = user!; - - Request = UserMapper.ToUpdate(User); - } - - private async Task OnSubmitAsync() - { - await HttpClient.PatchAsJsonAsync( - $"/api/users/{User.Id}", - Request - ); - - await ToastService.SuccessAsync( - "User creation", - $"Successfully updated user {Request.Username}" - ); - - Navigation.NavigateTo("/users"); - } -} \ No newline at end of file diff --git a/Moonlight.Frontend/UI/Admin/Views/Users/Index.razor b/Moonlight.Frontend/UI/Admin/Views/Users/Index.razor index 0a628dc8..40d171bc 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Users/Index.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Users/Index.razor @@ -1,112 +1,36 @@ -@page "/users" - +@page "/admin/users" @using LucideBlazor -@using ShadcnBlazor.Buttons -@using ShadcnBlazor.DataGrids -@using ShadcnBlazor.Dropdowns -@using ShadcnBlazor.Extras.AlertDialogs -@using ShadcnBlazor.Extras.Toasts -@using ShadcnBlazor.Tabels -@using Moonlight.Shared.Http.Requests -@using Moonlight.Shared.Http.Responses -@using Moonlight.Shared.Http.Responses.Users +@using ShadcnBlazor.Tab -@inject HttpClient HttpClient -@inject AlertDialogService AlertDialogService -@inject ToastService ToastService @inject NavigationManager Navigation - - - Users - - Manage users registered in your application - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - Edit - - - - - - Delete - - - - - - - - - - - - + + + + + Users + + + + Roles + + + + + + + + + @code { - private DataGrid Grid; + [SupplyParameterFromQuery(Name = "tab")] + [Parameter] + public string? Tab { get; set; } - private async Task> LoadAsync(DataGridRequest request) + private void OnTabChanged(string name) { - var query = $"?startIndex={request.StartIndex}&length={request.Length}"; - var filterOptions = request.Filters.Count > 0 ? new FilterOptions(request.Filters) : null; - - var response = await HttpClient.GetFromJsonAsync>( - $"api/users{query}&filterOptions={filterOptions}", - Constants.SerializerOptions - ); - - return new DataGridResponse(response!.Data, response.TotalLength); + Navigation.NavigateTo($"/admin/users?tab={name}"); } - - private void Edit(UserDto dto) => Navigation.NavigateTo($"/users/{dto.Id}"); - - private async Task DeleteAsync(UserDto user) - { - await AlertDialogService.ConfirmDangerAsync( - $"Deletion of user {user.Username}", - "Do you really want to delete this user? This action cannot be undone", - async () => - { - await HttpClient.DeleteAsync($"api/users/{user.Id}"); - await ToastService.SuccessAsync("User deletion", $"Successfully deleted user {user.Username}"); - - await Grid.RefreshAsync(); - } - ); - } -} \ No newline at end of file +} diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Roles.razor b/Moonlight.Frontend/UI/Admin/Views/Users/Roles.razor similarity index 95% rename from Moonlight.Frontend/UI/Admin/Views/Sys/Roles.razor rename to Moonlight.Frontend/UI/Admin/Views/Users/Roles.razor index 34dd51fd..adeaf542 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Roles.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Users/Roles.razor @@ -17,7 +17,13 @@ @inject ToastService ToastService @inject AlertDialogService AlertDialogService - + + + Roles + + Manage roles, their members and permissions + + diff --git a/Moonlight.Frontend/UI/Admin/Views/Users/Users.razor b/Moonlight.Frontend/UI/Admin/Views/Users/Users.razor new file mode 100644 index 00000000..72bfe1c9 --- /dev/null +++ b/Moonlight.Frontend/UI/Admin/Views/Users/Users.razor @@ -0,0 +1,151 @@ +@using LucideBlazor +@using Moonlight.Frontend.UI.Admin.Modals +@using ShadcnBlazor.Buttons +@using ShadcnBlazor.DataGrids +@using ShadcnBlazor.Dropdowns +@using ShadcnBlazor.Extras.AlertDialogs +@using ShadcnBlazor.Extras.Toasts +@using ShadcnBlazor.Tabels +@using Moonlight.Shared.Http.Requests +@using Moonlight.Shared.Http.Requests.Users +@using Moonlight.Shared.Http.Responses +@using Moonlight.Shared.Http.Responses.Users +@using ShadcnBlazor.Extras.Dialogs + +@inject HttpClient HttpClient +@inject AlertDialogService AlertDialogService +@inject DialogService DialogService +@inject ToastService ToastService + + + + Users + + Manage users registered in your instance + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + Edit + + + + + + Delete + + + + + + + + + + + + + +@code +{ + private DataGrid Grid; + + private async Task> LoadAsync(DataGridRequest request) + { + var query = $"?startIndex={request.StartIndex}&length={request.Length}"; + var filterOptions = request.Filters.Count > 0 ? new FilterOptions(request.Filters) : null; + + var response = await HttpClient.GetFromJsonAsync>( + $"api/users{query}&filterOptions={filterOptions}", + Constants.SerializerOptions + ); + + return new DataGridResponse(response!.Data, response.TotalLength); + } + + private async Task CreateAsync() + { + await DialogService.LaunchAsync(parameters => + { + parameters[nameof(CreateUserDialog.OnSubmit)] = async (CreateUserDto dto) => + { + await HttpClient.PostAsJsonAsync( + "/api/users", + dto, + Constants.SerializerOptions + ); + + await ToastService.SuccessAsync( + "User creation", + $"Successfully created user {dto.Username}" + ); + + await Grid.RefreshAsync(); + }; + }); + } + + private async Task EditAsync(UserDto user) + { + await DialogService.LaunchAsync(parameters => + { + parameters[nameof(UpdateUserDialog.User)] = user; + parameters[nameof(CreateUserDialog.OnSubmit)] = async (UpdateUserDto dto) => + { + await HttpClient.PatchAsJsonAsync( + $"/api/users/{user.Id}", + dto + ); + + await ToastService.SuccessAsync( + "User update", + $"Successfully updated user {dto.Username}" + ); + + await Grid.RefreshAsync(); + }; + }); + } + + private async Task DeleteAsync(UserDto user) + { + await AlertDialogService.ConfirmDangerAsync( + $"Deletion of user {user.Username}", + "Do you really want to delete this user? This action cannot be undone", + async () => + { + await HttpClient.DeleteAsync($"api/users/{user.Id}"); + await ToastService.SuccessAsync("User deletion", $"Successfully deleted user {user.Username}"); + + await Grid.RefreshAsync(); + } + ); + } +} \ No newline at end of file