Updated all forms to use the EnhancedEditForm and blazors native validation. Fixed smaller issues after upgrading to ShadcnBlazor 1.0.11

This commit is contained in:
2026-01-29 08:58:12 +01:00
parent 9b11360a0e
commit 136620f1e6
15 changed files with 362 additions and 395 deletions

View File

@@ -1,10 +1,9 @@
@using Moonlight.Frontend.UI.Admin.Components
@using Moonlight.Shared.Http.Requests.ApiKeys
@using ShadcnBlazor.Dialogs
@using ShadcnBlazor.Extras.Common
@using ShadcnBlazor.Extras.FormHandlers
@using ShadcnBlazor.Extras.Forms
@using ShadcnBlazor.Fields
@using ShadcnBlazor.Inputs
@using ShadcnBlazor.Labels
@inherits ShadcnBlazor.Extras.Dialogs.DialogBase
@@ -15,56 +14,57 @@
</DialogDescription>
</DialogHeader>
<FormHandler @ref="FormHandler" Model="Request" OnValidSubmit="SubmitAsync">
<div class="flex flex-col gap-6">
<FormValidationSummary />
<EnhancedEditForm Model="Request" OnValidSubmit="OnSubmitAsync">
<div class="grid gap-2">
<Label for="keyName">Name</Label>
<TextInputField @bind-Value="Request.Name" id="keyName" placeholder="My API key" />
</div>
<div class="grid gap-2">
<Label for="keyDescription">Description</Label>
<textarea
@bind="Request.Description"
id="keyDescription"
maxlength="100"
class="border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm"
placeholder="What this key is for">
</textarea>
</div>
<div class="grid gap-2">
<Label>Permissions</Label>
<PermissionSelector Permissions="Permissions" />
</div>
</div>
</FormHandler>
<DialogFooter ClassName="justify-end gap-x-1">
<WButtom OnClick="() => FormHandler.SubmitAsync()">Save changes</WButtom>
</DialogFooter>
<FieldGroup>
<DataAnnotationsValidator/>
<FormValidationSummary/>
<FieldSet>
<Field>
<FieldLabel for="keyName">Name</FieldLabel>
<TextInputField @bind-Value="Request.Name" id="keyName" placeholder="My API key"/>
</Field>
<Field>
<FieldLabel for="keyDescription">Description</FieldLabel>
<TextareaInputField @bind-Value="Request.Description" id="keyDescription" placeholder="What this key is for"/>
</Field>
<Field>
<FieldLabel>Permissions</FieldLabel>
<FieldContent>
<PermissionSelector Permissions="Permissions"/>
</FieldContent>
</Field>
</FieldSet>
<Field Orientation="FieldOrientation.Horizontal" ClassName="justify-end">
<SubmitButton>Save changes</SubmitButton>
</Field>
</FieldGroup>
</EnhancedEditForm>
@code
{
[Parameter] public Func<CreateApiKeyDto, Task> OnSubmit { get; set; }
private CreateApiKeyDto Request;
private FormHandler FormHandler;
private List<string> Permissions = new();
private List<string> Permissions = new();
protected override void OnInitialized()
{
Request = new();
Request = new()
{
Permissions = []
};
}
private async Task SubmitAsync()
private async Task<bool> OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore)
{
Request.Permissions = Permissions.ToArray();
await OnSubmit.Invoke(Request);
await CloseAsync();
return true;
}
}

View File

@@ -1,11 +1,9 @@
@using Moonlight.Frontend.UI.Admin.Components
@using Moonlight.Shared.Http.Requests.Roles
@using ShadcnBlazor.Buttons
@using ShadcnBlazor.Dialogs
@using ShadcnBlazor.Extras.Common
@using ShadcnBlazor.Extras.FormHandlers
@using ShadcnBlazor.Extras.Forms
@using ShadcnBlazor.Fields
@using ShadcnBlazor.Inputs
@using ShadcnBlazor.Labels
@inherits ShadcnBlazor.Extras.Dialogs.DialogBase
@@ -18,41 +16,36 @@
</DialogDescription>
</DialogHeader>
<FormHandler @ref="FormHandler" Model="Request" OnValidSubmit="OnSubmitAsync">
<div class="flex flex-col gap-6">
<EnhancedEditForm Model="Request" OnValidSubmit="OnSubmitAsync">
<FieldGroup>
<FormValidationSummary/>
<DataAnnotationsValidator/>
<div class="grid gap-2">
<Label for="roleName">Name</Label>
<TextInputField
@bind-Value="Request.Name"
id="roleName"
placeholder="My fancy role"/>
</div>
<div class="grid gap-2">
<Label for="roleDescription">Description</Label>
<textarea
@bind="Request.Description"
id="roleDescription"
maxlength="100"
class="border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm"
placeholder="Describe what the role should be used for">
</textarea>
</div>
<div class="grid gap-2">
<Label>Permissions</Label>
<PermissionSelector Permissions="Permissions" />
</div>
</div>
</FormHandler>
<DialogFooter ClassName="justify-end gap-x-1">
<WButtom OnClick="SubmitAsync">Save changes</WButtom>
</DialogFooter>
<FieldSet>
<Field>
<FieldLabel for="roleName">Name</FieldLabel>
<TextInputField
@bind-Value="Request.Name"
id="roleName"
placeholder="My fancy role"/>
</Field>
<Field>
<FieldLabel for="keyDescription">Description</FieldLabel>
<TextareaInputField @bind-Value="Request.Description" id="keyDescription"
placeholder="Describe what the role should be used for"/>
</Field>
<Field>
<FieldLabel>Permissions</FieldLabel>
<FieldContent>
<PermissionSelector Permissions="Permissions"/>
</FieldContent>
</Field>
</FieldSet>
<Field Orientation="FieldOrientation.Horizontal" ClassName="justify-end">
<SubmitButton>Save changes</SubmitButton>
</Field>
</FieldGroup>
</EnhancedEditForm>
@code
{
@@ -60,7 +53,6 @@
private CreateRoleDto Request;
private List<string> Permissions;
private FormHandler FormHandler;
protected override void OnInitialized()
{
@@ -68,19 +60,17 @@
{
Permissions = []
};
Permissions = new();
}
private async Task SubmitAsync()
private async Task<bool> OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore)
{
Request.Permissions = Permissions.ToArray();
await FormHandler.SubmitAsync();
}
private async Task OnSubmitAsync()
{
await OnSubmit.Invoke(Request);
await CloseAsync();
return true;
}
}

View File

@@ -1,9 +1,8 @@
@using Moonlight.Shared.Http.Requests.Users
@using ShadcnBlazor.Dialogs
@using ShadcnBlazor.Extras.Common
@using ShadcnBlazor.Extras.FormHandlers
@using ShadcnBlazor.Extras.Forms
@using ShadcnBlazor.Fields
@using ShadcnBlazor.Inputs
@using ShadcnBlazor.Labels
@inherits ShadcnBlazor.Extras.Dialogs.DialogBase
@@ -16,50 +15,50 @@
</DialogDescription>
</DialogHeader>
<FormHandler @ref="FormHandler" Model="Request" OnValidSubmit="SubmitAsync">
<div class="flex flex-col gap-6">
<EnhancedEditForm Model="Request" OnValidSubmit="OnSubmitAsync">
<FieldGroup>
<FormValidationSummary/>
<DataAnnotationsValidator/>
<div class="grid gap-2">
<Label for="username">Username</Label>
<TextInputField
@bind-Value="Request.Username"
id="username"
placeholder="Name of the user"/>
</div>
<div class="grid gap-2">
<Label for="emailAddress">Email Address</Label>
<TextInputField
@bind-Value="Request.Email"
id="emailAddress"
Type="email"
placeholder="email@of.user"/>
</div>
</div>
</FormHandler>
<DialogFooter ClassName="justify-end gap-x-1">
<WButtom OnClick="_ => FormHandler.SubmitAsync()">Save changes</WButtom>
</DialogFooter>
<FieldSet>
<Field>
<FieldLabel for="username">Username</FieldLabel>
<TextInputField
@bind-Value="Request.Username"
id="username"
placeholder="Name of the user"/>
</Field>
<Field>
<FieldLabel for="emailAddress">Email Address</FieldLabel>
<TextInputField
@bind-Value="Request.Email"
id="emailAddress"
placeholder="email@of.user"/>
</Field>
</FieldSet>
<Field Orientation="FieldOrientation.Horizontal" ClassName="justify-end">
<SubmitButton>Save changes</SubmitButton>
</Field>
</FieldGroup>
</EnhancedEditForm>
@code
{
[Parameter] public Func<CreateUserDto, Task> OnSubmit { get; set; }
private CreateUserDto Request;
private FormHandler FormHandler;
protected override void OnInitialized()
{
Request = new();
}
private async Task SubmitAsync()
private async Task<bool> OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore)
{
await OnSubmit.Invoke(Request);
await CloseAsync();
return true;
}
}

View File

@@ -32,9 +32,9 @@
SearchPlaceholder="Search user"
ValueSelector="dto => dto.Username"
Source="LoadUsersAsync"/>
<WButtom OnClick="AddAsync" Variant="ButtonVariant.Outline" Size="ButtonSize.Icon">
<WButton OnClick="AddAsync" Variant="ButtonVariant.Outline" Size="ButtonSize.Icon">
<PlusIcon/>
</WButtom>
</WButton>
</div>
</div>
<div class="mt-3">
@@ -50,9 +50,9 @@
<CellTemplate>
<TableCell>
<div class="flex justify-end me-1.5">
<WButtom OnClick="_ => RemoveAsync(context)" Variant="ButtonVariant.Destructive" Size="ButtonSize.Icon">
<WButton OnClick="_ => RemoveAsync(context)" Variant="ButtonVariant.Destructive" Size="ButtonSize.Icon">
<TrashIcon/>
</WButtom>
</WButton>
</div>
</TableCell>
</CellTemplate>

View File

@@ -3,10 +3,9 @@
@using Moonlight.Shared.Http.Requests.ApiKeys
@using Moonlight.Shared.Http.Responses.ApiKeys
@using ShadcnBlazor.Dialogs
@using ShadcnBlazor.Extras.Common
@using ShadcnBlazor.Extras.FormHandlers
@using ShadcnBlazor.Extras.Forms
@using ShadcnBlazor.Fields
@using ShadcnBlazor.Inputs
@using ShadcnBlazor.Labels
@inherits ShadcnBlazor.Extras.Dialogs.DialogBase
@@ -17,37 +16,32 @@
</DialogDescription>
</DialogHeader>
<FormHandler @ref="FormHandler" Model="Request" OnValidSubmit="SubmitAsync">
<div class="flex flex-col gap-6">
<FormValidationSummary />
<EnhancedEditForm Model="Request" OnValidSubmit="OnSubmitAsync">
<FieldGroup>
<FormValidationSummary/>
<DataAnnotationsValidator/>
<div class="grid gap-2">
<Label for="keyName">Name</Label>
<TextInputField @bind-Value="Request.Name" id="keyName" placeholder="My API key" />
</div>
<div class="grid gap-2">
<Label for="keyDescription">Description</Label>
<textarea
@bind="Request.Description"
id="keyDescription"
maxlength="100"
class="border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm"
placeholder="What this key is for">
</textarea>
</div>
<div class="grid gap-2">
<Label>Permissions</Label>
<PermissionSelector Permissions="Permissions" />
</div>
</div>
</FormHandler>
<DialogFooter ClassName="justify-end gap-x-1">
<WButtom OnClick="_ => FormHandler.SubmitAsync()">Save changes</WButtom>
</DialogFooter>
<FieldSet>
<Field>
<FieldLabel for="keyName">Name</FieldLabel>
<TextInputField @bind-Value="Request.Name" id="keyName" placeholder="My API key"/>
</Field>
<Field>
<FieldLabel for="keyDescription">Description</FieldLabel>
<TextareaInputField @bind-Value="Request.Description" id="keyDescription" placeholder="What this key is for"/>
</Field>
<Field>
<FieldLabel>Permissions</FieldLabel>
<FieldContent>
<PermissionSelector Permissions="Permissions"/>
</FieldContent>
</Field>
</FieldSet>
<Field Orientation="FieldOrientation.Horizontal" ClassName="justify-end">
<SubmitButton>Save changes</SubmitButton>
</Field>
</FieldGroup>
</EnhancedEditForm>
@code
{
@@ -55,7 +49,6 @@
[Parameter] public ApiKeyDto Key { get; set; }
private UpdateApiKeyDto Request;
private FormHandler FormHandler;
private List<string> Permissions = new();
protected override void OnInitialized()
@@ -64,10 +57,12 @@
Permissions = Key.Permissions.ToList();
}
private async Task SubmitAsync()
private async Task<bool> OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore)
{
Request.Permissions = Permissions.ToArray();
await OnSubmit.Invoke(Request);
await CloseAsync();
return true;
}
}

View File

@@ -2,12 +2,10 @@
@using Moonlight.Frontend.UI.Admin.Components
@using Moonlight.Shared.Http.Requests.Roles
@using Moonlight.Shared.Http.Responses.Admin
@using ShadcnBlazor.Buttons
@using ShadcnBlazor.Dialogs
@using ShadcnBlazor.Extras.Common
@using ShadcnBlazor.Extras.FormHandlers
@using ShadcnBlazor.Extras.Forms
@using ShadcnBlazor.Fields
@using ShadcnBlazor.Inputs
@using ShadcnBlazor.Labels
@inherits ShadcnBlazor.Extras.Dialogs.DialogBase
@@ -20,50 +18,44 @@
</DialogDescription>
</DialogHeader>
<FormHandler @ref="FormHandler" Model="Request" OnValidSubmit="OnSubmitAsync">
<div class="flex flex-col gap-6">
<EnhancedEditForm Model="Request" OnValidSubmit="OnSubmitAsync">
<FieldGroup>
<FormValidationSummary/>
<DataAnnotationsValidator/>
<div class="grid gap-2">
<Label for="roleName">Name</Label>
<TextInputField
@bind-Value="Request.Name"
id="roleName"
placeholder="My fancy role"/>
</div>
<div class="grid gap-2">
<Label for="roleDescription">Description</Label>
<textarea
@bind="Request.Description"
id="roleDescription"
maxlength="100"
class="border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm"
placeholder="Describe what the role should be used for">
</textarea>
</div>
<div class="grid gap-2">
<Label>Permissions</Label>
<PermissionSelector Permissions="Permissions" />
</div>
</div>
</FormHandler>
<DialogFooter ClassName="justify-end gap-x-1">
<WButtom OnClick="SubmitAsync">Save changes</WButtom>
</DialogFooter>
<FieldSet>
<Field>
<FieldLabel for="roleName">Name</FieldLabel>
<TextInputField
@bind-Value="Request.Name"
id="roleName"
placeholder="My fancy role"/>
</Field>
<Field>
<FieldLabel for="keyDescription">Description</FieldLabel>
<TextareaInputField @bind-Value="Request.Description" id="keyDescription"
placeholder="Describe what the role should be used for"/>
</Field>
<Field>
<FieldLabel>Permissions</FieldLabel>
<FieldContent>
<PermissionSelector Permissions="Permissions"/>
</FieldContent>
</Field>
</FieldSet>
<Field Orientation="FieldOrientation.Horizontal" ClassName="justify-end">
<SubmitButton>Save changes</SubmitButton>
</Field>
</FieldGroup>
</EnhancedEditForm>
@code
{
[Parameter] public Func<UpdateRoleDto, Task> OnSubmit { get; set; }
[Parameter] public RoleDto Role { get; set; }
private UpdateRoleDto Request;
private List<string> Permissions;
private FormHandler FormHandler;
protected override void OnInitialized()
{
@@ -71,15 +63,12 @@
Permissions = Role.Permissions.ToList();
}
private async Task SubmitAsync()
private async Task<bool> OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore)
{
Request.Permissions = Permissions.ToArray();
await FormHandler.SubmitAsync();
}
private async Task OnSubmitAsync()
{
await OnSubmit.Invoke(Request);
await CloseAsync();
return true;
}
}

View File

@@ -2,10 +2,9 @@
@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.Extras.Forms
@using ShadcnBlazor.Fields
@using ShadcnBlazor.Inputs
@using ShadcnBlazor.Labels
@inherits ShadcnBlazor.Extras.Dialogs.DialogBase
@@ -18,51 +17,50 @@
</DialogDescription>
</DialogHeader>
<FormHandler @ref="FormHandler" Model="Request" OnValidSubmit="SubmitAsync">
<div class="flex flex-col gap-6">
<EnhancedEditForm Model="Request" OnValidSubmit="OnSubmitAsync">
<FieldGroup>
<FormValidationSummary/>
<DataAnnotationsValidator/>
<div class="grid gap-2">
<Label for="username">Username</Label>
<TextInputField
@bind-Value="Request.Username"
id="username"
placeholder="Name of the user"/>
</div>
<div class="grid gap-2">
<Label for="emailAddress">Email Address</Label>
<TextInputField
@bind-Value="Request.Email"
id="emailAddress"
Type="email"
placeholder="email@of.user"/>
</div>
</div>
</FormHandler>
<DialogFooter ClassName="justify-end gap-x-1">
<WButtom OnClick="_ => FormHandler.SubmitAsync()">Save changes</WButtom>
</DialogFooter>
<FieldSet>
<Field>
<FieldLabel for="username">Username</FieldLabel>
<TextInputField
@bind-Value="Request.Username"
id="username"
placeholder="Name of the user"/>
</Field>
<Field>
<FieldLabel for="emailAddress">Email Address</FieldLabel>
<TextInputField
@bind-Value="Request.Email"
id="emailAddress"
placeholder="email@of.user"/>
</Field>
</FieldSet>
<Field Orientation="FieldOrientation.Horizontal" ClassName="justify-end">
<SubmitButton>Save changes</SubmitButton>
</Field>
</FieldGroup>
</EnhancedEditForm>
@code
{
[Parameter] public Func<UpdateUserDto, Task> 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()
private async Task<bool> OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore)
{
await OnSubmit.Invoke(Request);
await CloseAsync();
return true;
}
}