Starting updating mooncore dependency usage
This commit is contained in:
@@ -4,27 +4,6 @@
|
||||
|
||||
@inject ApplicationAssemblyService ApplicationAssemblyService
|
||||
|
||||
<ErrorLogger>
|
||||
<OAuth2AuthenticationHandler>
|
||||
<Router AppAssembly="@typeof(App).Assembly" AdditionalAssemblies="ApplicationAssemblyService.NavigationAssemblies">
|
||||
<Found Context="routeData">
|
||||
<CascadingValue Name="TargetPageType" Value="routeData.PageType">
|
||||
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
|
||||
</CascadingValue>
|
||||
</Found>
|
||||
<NotFound>
|
||||
<PageTitle>Not found</PageTitle>
|
||||
<LayoutView Layout="@typeof(MainLayout)">
|
||||
<div class="flex flex-col justify-center text-center">
|
||||
<img class="h-48 mt-5 mb-3" src="/svg/notfound.svg" alt="Not found illustration"/>
|
||||
|
||||
<h3 class="mt-2 font-semibold text-white text-lg">Page not found</h3>
|
||||
<p class="mt-1 text-gray-300">
|
||||
The page you requested does not exist
|
||||
</p>
|
||||
</div>
|
||||
</LayoutView>
|
||||
</NotFound>
|
||||
</Router>
|
||||
</OAuth2AuthenticationHandler>
|
||||
</ErrorLogger>
|
||||
<ApplicationRouter DefaultLayout="@typeof(MainLayout)"
|
||||
AppAssembly="@typeof(App).Assembly"
|
||||
AdditionalAssemblies="ApplicationAssemblyService.NavigationAssemblies" />
|
||||
@@ -1,3 +0,0 @@
|
||||
@inherits BaseFormComponent<DateTime>
|
||||
|
||||
<input @bind="Binder.Value" type="date" autocomplete="off" class="form-input w-full">
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
@inject IdentityService IdentityService
|
||||
@inject IServiceProvider ServiceProvider
|
||||
@inject ILogger<MainLayout> Logger
|
||||
@inject IAppLoader[] AppLoaders
|
||||
@@ -40,13 +39,9 @@ else
|
||||
|
||||
<main class="py-10">
|
||||
<div class="px-4 sm:px-6 lg:px-8">
|
||||
<ErrorHandler>
|
||||
<PermissionHandler CheckFunction="CheckPermission">
|
||||
<CascadingValue Value="this" IsFixed="true">
|
||||
@Body
|
||||
</CascadingValue>
|
||||
</PermissionHandler>
|
||||
</ErrorHandler>
|
||||
<CascadingValue Value="this" IsFixed="true">
|
||||
@Body
|
||||
</CascadingValue>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -142,6 +137,4 @@ else
|
||||
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private bool CheckPermission(string permission) => IdentityService.HasPermission(permission);
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
@using Moonlight.Client.Services
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using MoonCore.Blazor.Tailwind.Auth
|
||||
@using Moonlight.Client.UI.Layouts
|
||||
|
||||
@inject IdentityService IdentityService
|
||||
@inject ToastService ToastService
|
||||
@inject NavigationManager Navigation
|
||||
@inject AuthenticationStateManager AuthStateManager
|
||||
|
||||
<div class="sticky top-0 z-40 flex h-16 shrink-0 items-center gap-x-4 bg-gray-800/60 backdrop-blur px-4 shadow-sm sm:gap-x-6 sm:px-6 lg:px-8">
|
||||
@if (Layout.ShowMobileNavigation)
|
||||
@@ -26,45 +27,23 @@
|
||||
<div class="flex justify-between gap-x-4 lg:gap-x-6 w-full">
|
||||
<div></div>
|
||||
<div class="flex items-center gap-x-4 lg:gap-x-6">
|
||||
@*
|
||||
<button type="button" class="-m-2.5 p-2.5 text-gray-200 hover:text-gray-100">
|
||||
<span class="sr-only">View notifications</span>
|
||||
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0"/>
|
||||
</svg>
|
||||
</button>
|
||||
*@
|
||||
|
||||
<!-- Separator -->
|
||||
<div class="hidden lg:block lg:h-6 lg:w-px lg:bg-gray-900/10" aria-hidden="true"></div>
|
||||
|
||||
<!-- Profile dropdown -->
|
||||
<div class="relative">
|
||||
<button @onclick="ToggleProfileNav" @onfocusout="ProfileNav_OnFocusOut" type="button" class="-m-1.5 flex items-center p-1.5" id="user-menu-button" aria-expanded="false" aria-haspopup="true">
|
||||
<span class="sr-only">Open user menu</span>
|
||||
<img class="h-8 w-8 rounded-full" src="https://masuowo.xyz/assets/images/avatar.png" alt="">
|
||||
<span class="hidden lg:flex lg:items-center">
|
||||
<span class="ml-4 text-sm font-semibold leading-6 text-gray-100" aria-hidden="true">
|
||||
@("@" + IdentityService.Username)
|
||||
@("@" + Username)
|
||||
</span>
|
||||
<svg class="ml-2 h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<!--
|
||||
Dropdown menu, show/hide based on menu state.
|
||||
|
||||
Entering: ""
|
||||
From: "transform scale-95"
|
||||
To: "transform opacity-100 scale-100"
|
||||
Leaving: "transition ease-in duration-75"
|
||||
From: "transform opacity-100 scale-100"
|
||||
To: "transform opacity-0 scale-95"
|
||||
-->
|
||||
|
||||
<div class="@(ShowProfileNav ? "opacity-100" : "opacity-0 hidden") transition ease-out duration-100 absolute right-0 z-10 mt-2.5 w-44 origin-top-right rounded-md bg-gray-750 py-2 shadow-lg ring-1 ring-gray-100/5 focus:outline-none" role="menu" aria-orientation="vertical" aria-labelledby="user-menu-button" tabindex="-1">
|
||||
<!-- Active: "bg-gray-50", Not Active: "" -->
|
||||
<a href="/admin" class="block px-3 py-1 text-sm leading-6 text-gray-100 hover:text-primary-500" role="menuitem" tabindex="-1" id="user-menu-item-0">Your profile</a>
|
||||
<a @onclick="Logout" @onclick:preventDefault href="#" class="block px-3 py-1 text-sm leading-6 text-gray-100 hover:text-primary-500" role="menuitem" tabindex="-1" id="user-menu-item-1">Sign out</a>
|
||||
</div>
|
||||
@@ -76,8 +55,17 @@
|
||||
@code
|
||||
{
|
||||
[Parameter] public MainLayout Layout { get; set; }
|
||||
[CascadingParameter] public Task<AuthenticationState> AuthState { get; set; }
|
||||
|
||||
private bool ShowProfileNav = false;
|
||||
private string Username;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var identity = await AuthState;
|
||||
var usernameClaim = identity.User.Claims.ToArray().First(x => x.Type == "username");
|
||||
Username = usernameClaim.Value;
|
||||
}
|
||||
|
||||
protected override Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
@@ -109,11 +97,5 @@
|
||||
}
|
||||
|
||||
private async Task Logout()
|
||||
{
|
||||
await IdentityService.Logout();
|
||||
await ToastService.Info("Successfully logged out");
|
||||
|
||||
//await Layout.Load();
|
||||
Navigation.NavigateTo(Navigation.Uri, true);
|
||||
}
|
||||
=> await AuthStateManager.Logout();
|
||||
}
|
||||
|
||||
@@ -4,40 +4,19 @@
|
||||
@using Moonlight.Client.UI.Layouts
|
||||
|
||||
@inject NavigationManager Navigation
|
||||
@inject IdentityService IdentityService
|
||||
@inject ISidebarItemProvider[] SidebarItemProviders
|
||||
|
||||
@{
|
||||
var url = new Uri(Navigation.Uri);
|
||||
}
|
||||
|
||||
<div class="relative z-40 lg:hidden transition-opacity @(Layout.ShowMobileNavigation ? "opacity-100" : "opacity-0 hidden")" role="dialog" aria-modal="true">
|
||||
<div
|
||||
class="relative z-40 lg:hidden transition-opacity @(Layout.ShowMobileNavigation ? "opacity-100" : "opacity-0 hidden")"
|
||||
role="dialog" aria-modal="true">
|
||||
<div class="fixed inset-0 bg-gray-800/80"></div>
|
||||
|
||||
<div class="fixed inset-0 flex justify-center bg-gray-900">
|
||||
<!--
|
||||
Off-canvas menu, show/hide based on off-canvas menu state.
|
||||
|
||||
Entering: "transition ease-in-out duration-300 transform"
|
||||
From: "-translate-x-full"
|
||||
To: "translate-x-0"
|
||||
Leaving: "transition ease-in-out duration-300 transform"
|
||||
From: "translate-x-0"
|
||||
To: "-translate-x-full"
|
||||
-->
|
||||
<div class="relative flex w-full max-w-xs flex-1">
|
||||
<!--
|
||||
Close button, show/hide based on off-canvas menu state.
|
||||
|
||||
Entering: "ease-in-out duration-300"
|
||||
From: "opacity-0"
|
||||
To: "opacity-100"
|
||||
Leaving: "ease-in-out duration-300"
|
||||
From: "opacity-100"
|
||||
To: "opacity-0"
|
||||
-->
|
||||
|
||||
<!-- Sidebar component, swap this element with another sidebar if you like -->
|
||||
<div class="flex grow flex-col gap-y-5 overflow-y-auto bg-gray-900 px-6 pb-4">
|
||||
<div class="flex h-16 shrink-0 items-center">a
|
||||
<img class="h-8 w-auto" src="/logo.svg" alt="Moonlight">
|
||||
@@ -46,40 +25,42 @@
|
||||
<ul role="list" class="flex flex-1 flex-col gap-y-7">
|
||||
@foreach (var group in Items)
|
||||
{
|
||||
<li>
|
||||
@if (!string.IsNullOrEmpty(group.Key))
|
||||
{
|
||||
<div class="text-xs font-semibold leading-6 text-gray-400">
|
||||
@group.Key
|
||||
</div>
|
||||
}
|
||||
|
||||
<ul role="list" class="-mx-2 space-y-1">
|
||||
@foreach (var item in group.Value)
|
||||
<li>
|
||||
@if (!string.IsNullOrEmpty(group.Key))
|
||||
{
|
||||
var isMatch = item.RequiresExactMatch
|
||||
? url.LocalPath == item.Path
|
||||
: url.LocalPath.StartsWith(item.Path);
|
||||
|
||||
<li>
|
||||
@if (isMatch)
|
||||
{
|
||||
<a href="@item.Path" class="bg-gray-800 text-white group flex gap-x-3 rounded-md p-2 text-sm leading-6 items-center">
|
||||
<i class="ms-1 text-lg shrink-0 @item.Icon"></i>
|
||||
@item.Name
|
||||
</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a href="@item.Path" class="text-gray-300 hover:text-white hover:bg-gray-800 group flex gap-x-3 rounded-md p-2 text-sm leading-6 items-center">
|
||||
<i class="ms-1 text-lg shrink-0 @item.Icon"></i>
|
||||
@item.Name
|
||||
</a>
|
||||
}
|
||||
</li>
|
||||
<div class="text-xs font-semibold leading-6 text-gray-400">
|
||||
@group.Key
|
||||
</div>
|
||||
}
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<ul role="list" class="-mx-2 space-y-1">
|
||||
@foreach (var item in group.Value)
|
||||
{
|
||||
var isMatch = item.RequiresExactMatch
|
||||
? url.LocalPath == item.Path
|
||||
: url.LocalPath.StartsWith(item.Path);
|
||||
|
||||
<li>
|
||||
@if (isMatch)
|
||||
{
|
||||
<a href="@item.Path"
|
||||
class="bg-gray-800 text-white group flex gap-x-3 rounded-md p-2 text-sm leading-6 items-center">
|
||||
<i class="ms-1 text-lg shrink-0 @item.Icon"></i>
|
||||
@item.Name
|
||||
</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a href="@item.Path"
|
||||
class="text-gray-300 hover:text-white hover:bg-gray-800 group flex gap-x-3 rounded-md p-2 text-sm leading-6 items-center">
|
||||
<i class="ms-1 text-lg shrink-0 @item.Icon"></i>
|
||||
@item.Name
|
||||
</a>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</nav>
|
||||
@@ -88,12 +69,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Static sidebar for desktop -->
|
||||
<div class="hidden lg:fixed lg:inset-y-0 lg:z-50 lg:flex lg:w-72 lg:flex-col">
|
||||
<!-- Sidebar component, swap this element with another sidebar if you like -->
|
||||
<div class="flex grow flex-col gap-y-5 overflow-y-auto bg-gray-800/60 px-6 pb-4">
|
||||
<div class="flex h-16 shrink-0 items-center">
|
||||
<img class="h-8 w-auto" src="https://gamecp.masuowo.xyz/api/core/asset/Core/svg/logo.svg" alt="Your Company">
|
||||
<img class="h-8 w-auto" src="https://gamecp.masuowo.xyz/api/core/asset/Core/svg/logo.svg"
|
||||
alt="Your Company">
|
||||
</div>
|
||||
<nav class="flex flex-1 flex-col">
|
||||
<ul role="list" class="flex flex-1 flex-col gap-y-7">
|
||||
@@ -117,14 +97,16 @@
|
||||
<li>
|
||||
@if (isMatch)
|
||||
{
|
||||
<a href="@item.Path" class="bg-gray-800 text-white group flex gap-x-3 rounded-md p-2 text-sm leading-6 items-center">
|
||||
<a href="@item.Path"
|
||||
class="bg-gray-800 text-white group flex gap-x-3 rounded-md p-2 text-sm leading-6 items-center">
|
||||
<i class="ms-1 text-lg shrink-0 @item.Icon"></i>
|
||||
@item.Name
|
||||
</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a href="@item.Path" class="text-gray-300 hover:text-white hover:bg-gray-800 group flex gap-x-3 rounded-md p-2 text-sm leading-6 items-center">
|
||||
<a href="@item.Path"
|
||||
class="text-gray-300 hover:text-white hover:bg-gray-800 group flex gap-x-3 rounded-md p-2 text-sm leading-6 items-center">
|
||||
<i class="ms-1 text-lg shrink-0 @item.Icon"></i>
|
||||
@item.Name
|
||||
</a>
|
||||
@@ -149,7 +131,7 @@
|
||||
{
|
||||
Items = SidebarItemProviders
|
||||
.SelectMany(x => x.Get())
|
||||
.Where(x => x.Permission == null || (x.Permission != null && IdentityService.HasPermission(x.Permission)))
|
||||
//.Where(x => x.Permission == null || (x.Permission != null && IdentityService.HasPermission(x.Permission)))
|
||||
.GroupBy(x => x.Group ?? "")
|
||||
.OrderByDescending(x => string.IsNullOrEmpty(x.Key))
|
||||
.ToDictionary(x => x.Key, x => x.OrderBy(y => y.Priority).ToArray());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@page "/admin/api"
|
||||
|
||||
@*
|
||||
@using MoonCore.Attributes
|
||||
@using MoonCore.Helpers
|
||||
@using MoonCore.Models
|
||||
@@ -108,4 +108,4 @@
|
||||
configuration.WithField(x => x.ExpiresAt);
|
||||
};
|
||||
}
|
||||
}
|
||||
}*@
|
||||
69
Moonlight.Client/UI/Views/Admin/Users/Create.razor
Normal file
69
Moonlight.Client/UI/Views/Admin/Users/Create.razor
Normal file
@@ -0,0 +1,69 @@
|
||||
@page "/admin/users/create"
|
||||
|
||||
@using MoonCore.Helpers
|
||||
@using Moonlight.Shared.Http.Requests.Admin.Users
|
||||
|
||||
@inject HttpApiClient ApiClient
|
||||
@inject NavigationManager Navigation
|
||||
@inject ToastService ToastService
|
||||
|
||||
<PageHeader Title="Create User">
|
||||
<a href="/admin/users" class="btn btn-secondary">
|
||||
<i class="icon-chevron-left mr-1"></i>
|
||||
Back
|
||||
</a>
|
||||
<WButton OnClick="_ => Form.Submit()" CssClasses="btn btn-primary">
|
||||
<i class="icon-check mr-1"></i>
|
||||
Create
|
||||
</WButton>
|
||||
</PageHeader>
|
||||
|
||||
<div class="mt-5">
|
||||
<HandleForm @ref="Form" Model="Request" OnValidSubmit="OnSubmit">
|
||||
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
|
||||
<div class="sm:col-span-2">
|
||||
<label class="block text-sm font-medium leading-6 text-white">Name</label>
|
||||
<div class="mt-2">
|
||||
<input @bind="Request.Username" type="text" autocomplete="off" class="form-input w-full">
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<label class="block text-sm font-medium leading-6 text-white">Version</label>
|
||||
<div class="mt-2">
|
||||
<input @bind="Request.Email" type="email" autocomplete="off" class="form-input w-full">
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<label class="block text-sm font-medium leading-6 text-white">Author</label>
|
||||
<div class="mt-2">
|
||||
<input @bind="Request.Password" type="password" autocomplete="off" class="form-input w-full">
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<label class="block text-sm font-medium leading-6 text-white">Donate Url</label>
|
||||
<div class="mt-2">
|
||||
<input @bind="Request.PermissionsJson" type="text" autocomplete="off" class="form-input w-full">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</HandleForm>
|
||||
</div>
|
||||
|
||||
@code
|
||||
{
|
||||
private HandleForm Form;
|
||||
private CreateUserRequest Request;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Request = new();
|
||||
}
|
||||
|
||||
private async Task OnSubmit()
|
||||
{
|
||||
await ApiClient.Post("api/users", Request);
|
||||
|
||||
await ToastService.Success("Successfully created User");
|
||||
Navigation.NavigateTo("/admin/users");
|
||||
}
|
||||
}
|
||||
@@ -1,71 +1,55 @@
|
||||
@page "/admin/users"
|
||||
@page "/admin/users"
|
||||
|
||||
@using MoonCore.Attributes
|
||||
@using MoonCore.Blazor.Tailwind.Forms.Components
|
||||
@using MoonCore.Helpers
|
||||
@using MoonCore.Models
|
||||
@using Moonlight.Shared.Http.Requests.Admin.Users
|
||||
@using MoonCore.Blazor.Tailwind.Dt
|
||||
@using Moonlight.Shared.Http.Responses.Admin.Users
|
||||
|
||||
@attribute [RequirePermission("admin.users.read")]
|
||||
@inject HttpApiClient ApiClient
|
||||
@inject AlertService AlertService
|
||||
@inject ToastService ToastService
|
||||
|
||||
@inject HttpApiClient HttpApiClient
|
||||
<PageHeader Title="Users" />
|
||||
|
||||
<Crud TItem="UserDetailResponse"
|
||||
TCreateForm="CreateUserRequest"
|
||||
TUpdateForm="UpdateUserRequest"
|
||||
OnConfigure="OnConfigure">
|
||||
<View>
|
||||
<Column TItem="UserDetailResponse" Field="@(x => x.Id)" Title="Id" />
|
||||
<Column TItem="UserDetailResponse" Field="@(x => x.Username)" Title="Username" />
|
||||
<Column TItem="UserDetailResponse" Field="@(x => x.Email)" Title="Email" />
|
||||
</View>
|
||||
</Crud>
|
||||
<DataTable @ref="Table" TItem="UserDetailResponse" PageSize="15" LoadItemsPaginatedAsync="LoadData">
|
||||
<DataTableColumn TItem="UserDetailResponse" Field="@(x => x.Id)" Name="Id" />
|
||||
<DataTableColumn TItem="UserDetailResponse" Field="@(x => x.Username)" Name="Username" />
|
||||
<DataTableColumn TItem="UserDetailResponse" Field="@(x => x.Email)" Name="Email" />
|
||||
<DataTableColumn TItem="UserDetailResponse">
|
||||
<ColumnTemplate>
|
||||
<div class="flex justify-end">
|
||||
<a href="/admin/users/update/@(context.Id)" class="text-primary-500 mr-2 sm:mr-3">
|
||||
<i class="icon-pencil text-base"></i>
|
||||
</a>
|
||||
|
||||
<a href="#" @onclick="() => Delete(context)" @onclick:preventDefault
|
||||
class="text-danger-500">
|
||||
<i class="icon-trash text-base"></i>
|
||||
</a>
|
||||
</div>
|
||||
</ColumnTemplate>
|
||||
</DataTableColumn>
|
||||
</DataTable>
|
||||
|
||||
@code
|
||||
{
|
||||
private void OnConfigure(CrudOptions<UserDetailResponse, CreateUserRequest, UpdateUserRequest> crudOptions)
|
||||
private DataTable<UserDetailResponse> Table;
|
||||
|
||||
private async Task<IPagedData<UserDetailResponse>> LoadData(PaginationOptions options)
|
||||
=> await ApiClient.GetJson<PagedData<UserDetailResponse>>($"api/admin/users?page={options.Page}&pageSize={options.PerPage}");
|
||||
|
||||
private async Task Delete(UserDetailResponse detailResponse)
|
||||
{
|
||||
crudOptions.ItemName = "User";
|
||||
|
||||
crudOptions.ItemLoader = async (page, pageSize)
|
||||
=> await HttpApiClient.GetJson<PagedData<UserDetailResponse>>($"api/admin/users?page={page}&pageSize={pageSize}");
|
||||
await AlertService.ConfirmDanger(
|
||||
"User deletion",
|
||||
$"Do you really want to delete the user '{detailResponse.Username}'",
|
||||
async () =>
|
||||
{
|
||||
await ApiClient.Delete($"api/admin/users/{detailResponse.Id}");
|
||||
await ToastService.Success("Successfully deleted user");
|
||||
|
||||
crudOptions.SingleItemLoader = async id
|
||||
=> await HttpApiClient.GetJson<UserDetailResponse>($"api/admin/users/{id}");
|
||||
|
||||
crudOptions.QueryIdentifier = response => response.Id.ToString();
|
||||
|
||||
crudOptions.OnCreate = async request
|
||||
=> await HttpApiClient.Post("api/admin/users", request);
|
||||
|
||||
crudOptions.OnUpdate = async (item, request)
|
||||
=> await HttpApiClient.Patch($"api/admin/users/{item.Id}", request);
|
||||
|
||||
crudOptions.OnDelete = async item
|
||||
=> await HttpApiClient.Delete($"api/admin/users/{item.Id}");
|
||||
|
||||
crudOptions.OnConfigureCreate = configuration =>
|
||||
{
|
||||
configuration.WithField(x => x.Username);
|
||||
configuration.WithField(x => x.Email);
|
||||
configuration.WithField(x => x.Password)
|
||||
.WithComponent<StringComponent>(component => component.Type = "password");
|
||||
|
||||
configuration.WithField(x => x.PermissionsJson)
|
||||
.WithComponent<TagComponent>();
|
||||
};
|
||||
|
||||
crudOptions.OnConfigureUpdate = (_, configuration) =>
|
||||
{
|
||||
configuration.WithField(x => x.Username);
|
||||
configuration.WithField(x => x.Email);
|
||||
|
||||
configuration.WithField(x => x.Password, fieldConfiguration =>
|
||||
{
|
||||
fieldConfiguration.Description = "Optional. Specify if you want to change this accounts password";
|
||||
})
|
||||
.WithComponent<StringComponent>(component => component.Type = "password");
|
||||
};
|
||||
await Table.Refresh();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
69
Moonlight.Client/UI/Views/Admin/Users/Update.razor
Normal file
69
Moonlight.Client/UI/Views/Admin/Users/Update.razor
Normal file
@@ -0,0 +1,69 @@
|
||||
@page "/users/update/{Id:int}"
|
||||
|
||||
@using MoonCore.Helpers
|
||||
@using Moonlight.Shared.Http.Requests.Admin.Users
|
||||
@using Moonlight.Shared.Http.Responses.Admin.Users
|
||||
|
||||
@inject HttpApiClient ApiClient
|
||||
@inject NavigationManager Navigation
|
||||
@inject ToastService ToastService
|
||||
|
||||
<LazyLoader Load="Load">
|
||||
<PageHeader Title="Update User">
|
||||
<a href="/admin/users" class="btn btn-secondary">
|
||||
<i class="icon-chevron-left mr-1"></i>
|
||||
Back
|
||||
</a>
|
||||
<WButton OnClick="_ => Form.Submit()" CssClasses="btn btn-primary">
|
||||
<i class="icon-check mr-1"></i>
|
||||
Update
|
||||
</WButton>
|
||||
</PageHeader>
|
||||
|
||||
<div class="mt-5">
|
||||
<HandleForm @ref="Form" Model="Request" OnValidSubmit="OnSubmit">
|
||||
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
|
||||
<div class="sm:col-span-2">
|
||||
<label class="block text-sm font-medium leading-6 text-white">Name</label>
|
||||
<div class="mt-2">
|
||||
<input @bind="Request.Username" type="text" autocomplete="off" class="form-input w-full">
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<label class="block text-sm font-medium leading-6 text-white">Version</label>
|
||||
<div class="mt-2">
|
||||
<input @bind="Request.Email" type="email" autocomplete="off" class="form-input w-full">
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<label class="block text-sm font-medium leading-6 text-white">Author</label>
|
||||
<div class="mt-2">
|
||||
<input @bind="Request.Password" type="password" autocomplete="off" class="form-input w-full">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</HandleForm>
|
||||
</div>
|
||||
</LazyLoader>
|
||||
|
||||
@code
|
||||
{
|
||||
[Parameter] public int Id { get; set; }
|
||||
|
||||
private HandleForm Form;
|
||||
private UpdateUserRequest Request;
|
||||
|
||||
private async Task Load(LazyLoader _)
|
||||
{
|
||||
var detail = await ApiClient.GetJson<UserDetailResponse>($"api/users/{Id}");
|
||||
Request = Mapper.Map<UpdateUserRequest>(detail);
|
||||
}
|
||||
|
||||
private async Task OnSubmit()
|
||||
{
|
||||
await ApiClient.Patch($"api/admin/users/{Id}", Request);
|
||||
|
||||
await ToastService.Success("Successfully updated User");
|
||||
Navigation.NavigateTo("/admin/users");
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,26 @@
|
||||
@page "/"
|
||||
|
||||
@using Moonlight.Client.Services
|
||||
|
||||
@inject IdentityService IdentityService
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
|
||||
<div class="font-medium leading-[1.1] tracking-tight">
|
||||
<div class="animate-shimmer bg-gradient-to-r from-violet-400 via-sky-400 to-purple-400 bg-clip-text font-semibold text-transparent text-3xl" style="animation-duration: 5s; background-size: 200% 100%">
|
||||
Welcome, @(IdentityService.Username)
|
||||
Welcome, @(Username)
|
||||
</div>
|
||||
<div class="text-gray-200 text-2xl">What do you want to do today?</div>
|
||||
</div>
|
||||
|
||||
<div class="text-primary-500/10"></div>
|
||||
<div class="text-primary-500/10"></div>
|
||||
|
||||
@code
|
||||
{
|
||||
[CascadingParameter] public Task<AuthenticationState> AuthState { get; set; }
|
||||
|
||||
private string Username;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var identity = await AuthState;
|
||||
var usernameClaim = identity.User.Claims.ToArray().First(x => x.Type == "username");
|
||||
Username = usernameClaim.Value;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user