General Cleanup (and async/awaiting rules enforcing)

This commit is contained in:
Samuele Lorefice
2025-09-09 19:32:19 +02:00
parent 16f53cb931
commit b183521af8
16 changed files with 144 additions and 54 deletions

View File

@@ -21,6 +21,7 @@
<body>
<Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" />
<script src="lib/js/bootstrap.bundle.min.js"></script>
@* ReSharper disable once Html.PathError *@
<script src="_framework/blazor.web.js"></script>
</body>

View File

@@ -6,7 +6,7 @@
<div class="card mb-3">
<div class="card-body align-items-center">
<div class="d-flex flex-row flex-grow-1 align-items-center">
<i class="bi bi-folder2 ms-3 mx-1"></i><p class="mx-1 mb-0 @Display">@(Folder.BasePath ?? "Unknown Folder")</p>
<i class="bi bi-folder2 ms-3 mx-1"></i><p class="mx-1 mb-0 @Display">@Folder.BasePath</p>
<input class="form-control form-control-sm mx-1 @Edit" type="text" @bind="Folder.BasePath"/>
<button class="btn btn-sm btn-success @Edit" @onclick="OnConfirmEdit"><i class="bi bi-check"></i></button>
<div class="ms-auto form-switch">
@@ -19,7 +19,7 @@
</div>
@code {
bool editing = false;
bool editing;
string Display => editing ? "d-none" : "";
string Edit => editing ? "" : "d-none";

View File

@@ -16,7 +16,7 @@
</div>
<div class="card-body">
<div class="progress mb-2" role="progressbar">
<div class="@BGColor" style="width: @(Job.Progress*100)%">@(Job.Progress*100)%</div>
<div class="@BgColor" style="width: @(Job.Progress*100)%">@(Job.Progress*100)%</div>
</div>
<p class="card-text"><i class="me-2 bi bi-stopwatch"></i>
@switch (Job.Status) {
@@ -56,7 +56,7 @@
@code {
[Parameter] public JobStatusDto Job { get; set; }
[Parameter] public required JobStatusDto Job { get; set; }
string BorderColor => Job.Status switch {
EJobStatus.Queued => "border-secondary",
EJobStatus.Running => "border-primary",
@@ -73,7 +73,7 @@
EJobStatus.Failed => "text-bg-danger",
_ => "text-bg-dark",
};
string BGColor => Job.Status switch {
string BgColor => Job.Status switch {
EJobStatus.Queued => "progress-bar text-bg-secondary",
EJobStatus.Running => "progress-bar text-bg-primary",
EJobStatus.Waiting => "progress-bar text-bg-info",

View File

@@ -1,12 +1,11 @@
@page "/"
@using Butter.Dtos;
@using MilkStream.Components.Layout
@using MilkStream.Services
@inject NavigationManager navigationManager
@inject LoginService loginService
@inject ProtectedSessionStorage sessionStorage
@inject ProtectedLocalStorage localStorage
@inject NavigationManager NavigationManager
@inject LoginService LoginService
@inject ProtectedSessionStorage SessionStorage
@inject ProtectedLocalStorage LocalStorage
<PageTitle>Home</PageTitle>
@@ -17,7 +16,7 @@
@if (mediaList.Count == 0) {
<div class="border-warning border-5 border-opacity-100 rounded-3 p-3 m-5 bg-warning-subtle text-center">
<h2 class="text-warning">No media available</h2>
@if (loginService.IsLoggedIn) {
@if (LoginService.IsLoggedIn) {
<p class="text-warning-emphasis">You are logged in, but there is no media available at the moment.</p>
} else {
<p class="text-warning-emphasis">Please <a href="/login" class="link-warning">log-in</a> to be able to browse any media.</p>
@@ -41,7 +40,7 @@
protected async override Task OnAfterRenderAsync(bool firstRender) {
if (firstRender) {
loginService.LoggedUserChanged += (sender, dto) => StateHasChanged();
LoginService.LoggedUserChanged += (_, _) => StateHasChanged();
//do nothing for now
await Task.Delay(1);
isLoading = false;

View File

@@ -20,13 +20,13 @@
@code {
PeriodicTimer timer = new PeriodicTimer(TimeSpan.FromSeconds(1));
List<JobStatusDto> jobs = new();
readonly PeriodicTimer timer = new PeriodicTimer(TimeSpan.FromSeconds(1));
List<JobStatusDto> jobs = [];
protected async override Task OnInitializedAsync() {
LoginService.LoggedUserChanged += async (_, _) => {
jobs = await JobsService.GetJobs();
RefreshJobs();
await RefreshJobs();
StateHasChanged();
};
if (LoginService.IsLoggedIn) {
@@ -43,12 +43,12 @@
}
}
void LaunchScan() => JobsService.StartJob(EJobType.FileSystemScan);
Task LaunchScan() => JobsService.StartJob(EJobType.FileSystemScan);
void LaunchThumb() => JobsService.StartJob(EJobType.ThumbnailGeneration);
Task LaunchThumb() => JobsService.StartJob(EJobType.ThumbnailGeneration);
void LaunchIntegrityCheck() => JobsService.StartJob(EJobType.IntegrityCheck);
Task LaunchIntegrityCheck() => JobsService.StartJob(EJobType.IntegrityCheck);
void LaunchMeta() => JobsService.StartJob(EJobType.MetadataExtraction);
Task LaunchMeta() => JobsService.StartJob(EJobType.MetadataExtraction);
}

View File

@@ -37,10 +37,10 @@
<div class="">DATETIME NOT IMPLEMENTED Value: @option.Value</div>
break;
case DisplayType.TimePicker:
<SettingRange Setting="option" minValue="Convert.ToInt32(option.Options?[0])" maxValue="Convert.ToInt32(option.Options?[1])" Step="Convert.ToInt32(option.Options?[2])"/>
<SettingRange Setting="option" MinValue="Convert.ToInt32(option.Options?[0])" MaxValue="Convert.ToInt32(option.Options?[1])" Step="Convert.ToInt32(option.Options?[2])"/>
break;
case DisplayType.Po2W:
<SettingRange Setting="option" IsPowerOfTwo="true" minValue="Convert.ToInt32(option.Options?[0])" maxValue="Convert.ToInt32(option.Options?[1])" Step="Convert.ToInt32(option.Options?[2])"/>
<SettingRange Setting="option" IsPowerOfTwo="true" MinValue="Convert.ToInt32(option.Options?[0])" MaxValue="Convert.ToInt32(option.Options?[1])" Step="Convert.ToInt32(option.Options?[2])"/>
break;
}
}

View File

@@ -0,0 +1,86 @@
@page "/Settings1"
@using Butter.Dtos.Folder
@using Butter.Dtos.Settings
@using Butter.Settings
@using Butter.Types
@using MilkStream.Components.SettingBoxes
@using MilkStream.Services
@using System.Linq
@inject NavigationManager NavigationManager
@inject LoginService LoginService
@inject SettingsService SettingsService
@inject FoldersService FoldersService
<h3>Settings</h3>
@if (areSettingsLoading || settings is {Count: 0}) {
<LoadSpinner/>
} else {
<div class="row row-cols-2">
<div class="col">
<!--Folder Scan Enabled-->
<SettingSwitch Setting="settings!.FirstOrDefault(s => s.Name == Butter.Settings.Settings.FolderScanEnabled.AsString())"/>
</div>
<div class="col">
<!--Folder Scan Interval-->
<SettingRange Setting="settings!.FirstOrDefault(s => s.Name == Butter.Settings.Settings.FolderScanInterval.AsString())" MinValue="5" MaxValue="360" Step="5"/>
</div>
<div class="col">
<!--File Upload Enabled-->
<SettingSwitch Setting="settings!.FirstOrDefault(s => s.Name == Butter.Settings.Settings.FileUploadEnabled.AsString())"/>
</div>
<div class="col">
<!--File Upload Max Size-->
<SettingRange Setting="settings!.FirstOrDefault(s => s.Name == Butter.Settings.Settings.FileUploadMaxSize.AsString())" MinValue="1024" MaxValue="1000000" Step="1000"/>
</div>
<div class="col">
<!--Thumbnail Path-->
<SettingString Setting="settings!.FirstOrDefault(s => s.Name == Butter.Settings.Settings.ThumbnailPath.AsString())"/>
</div>
<div class="col">
<!--Thumbnail Size-->
<SettingRange Setting="settings!.FirstOrDefault(s => s.Name == Butter.Settings.Settings.ThumbnailSize.AsString())" IsPowerOfTwo="true" MinValue="8" MaxValue="12" Step="1"/>
</div>
<div class="col">
<!--Previews Path-->
<SettingString Setting="settings!.FirstOrDefault(s => s.Name == Butter.Settings.Settings.PreviewPath.AsString())"/>
</div>
<div class="col">
<!--Previews Size-->
<SettingRange Setting="settings!.FirstOrDefault(s => s.Name == Butter.Settings.Settings.PreviewSize.AsString())" IsPowerOfTwo="true" MinValue="8" MaxValue="14" Step="1"/>
</div>
<div class="col">
<!--Max concurrent jobs -->
<SettingRange Setting="settings!.FirstOrDefault(s => s.Name == Butter.Settings.Settings.MaxConcurrentJobs.AsString())" MinValue="1" MaxValue="32" Step="1"/>
</div>
<div class="col">
<!-- User registration enabled -->
<SettingSwitch Setting="settings!.FirstOrDefault(s => s.Name == Butter.Settings.Settings.UserRegistrationEnabled.AsString())"/>
</div>
</div>
}
<h3>Folders</h3>
@code {
bool areSettingsLoading = true;
List<SettingDto>? settings = new();
protected async override Task OnInitializedAsync() {
if (LoginService.IsLoggedIn) {
await LoadSettings();
} else {
LoginService.AuthInfoChanged += async (_, _) => {
await LoadSettings();
};
}
}
async Task LoadSettings() {
settings = await SettingsService.GetAllSettings();
if(settings != null) areSettingsLoading = false;
StateHasChanged();
}
}

View File

@@ -9,7 +9,7 @@
<div class="row">
@if (isSelf || adminAccess) {
@if (isSelf || AdminAccess) {
<div class="col-2"><i class="bi bi-envelope-at"></i> EMail:</div>
<div class="col-2">@user?.Email</div>
}
@@ -31,7 +31,7 @@
<div class="col-2">@(user is {IsBanned: true} ? $"Yes ({user.BannedAt.ToString()})" : "No")</div>
</div>
<div class="row">
@if (adminAccess) {
@if (AdminAccess) {
<div class="col-2"><i class="bi bi-trash3"></i>Deleted:</div>
<div class="col-2">@(user is not {DeletedAt: null} ? user!.DeletedAt.ToString() : "No")</div>
}
@@ -44,13 +44,13 @@
public Guid UserId { get; set; }
bool isSelf;
bool adminAccess => LoginService.LoggedUser?.AccessLevel == EAccessLevel.Admin;
bool AdminAccess => LoginService.LoggedUser?.AccessLevel == EAccessLevel.Admin;
UserInfoDto? user;
protected async override Task OnInitializedAsync() {
await base.OnInitializedAsync();
if (LoginService.IsLoggedIn) await LoadUser();
LoginService.AuthInfoChanged += (sender, info) => LoadUser();
LoginService.AuthInfoChanged += async (_, _) => await LoadUser();
}
async Task LoadUser() {

View File

@@ -5,13 +5,13 @@
@code {
[Parameter]
public required SettingDto Setting { get; set; }
public required SettingDto? Setting { get; set; }
protected virtual SettingDto GetSetting() {
protected virtual SettingDto? GetSetting() {
return Setting;
}
protected override void OnInitialized() {
SettingsService.BeginSave += (sender, args) => SettingsService.UpdateSetting(GetSetting());
SettingsService.BeginSave += (_, _) => SettingsService.UpdateSetting(GetSetting());
}
}

View File

@@ -19,15 +19,16 @@
private float currentValue;
protected override void OnInitialized() {
SettingsService.BeginSave += (sender, args) => SettingsService.UpdateSetting(GetSetting());
if (float.TryParse(Setting.Value, out float value)) {
SettingsService.BeginSave += (_, _) => SettingsService.UpdateSetting(GetSetting());
if (float.TryParse(Setting?.Value, out float value)) {
currentValue = value;
} else {
currentValue = 0; // Default value if parsing fails
}
}
protected override SettingDto GetSetting() {
protected override SettingDto? GetSetting() {
if (Setting == null) return null;
Setting.Value = currentValue.ToString(CultureInfo.InvariantCulture);
return Setting;
}

View File

@@ -1,6 +1,5 @@
@using Butter.Dtos.Settings
@using MilkStream.Services
@using System.Globalization
@inherits SettingBox
@inject SettingsService SettingsService
@@ -10,30 +9,29 @@
<p class="card-text">@(Setting?.Description ?? "No description provided")</p>
<div class="d-flex">
<div class="mx-2">@(IsPowerOfTwo ? Math.Pow(2, currentValue) : currentValue)</div>
<input type="range" id="@Setting?.Name" class="form-range" @bind="@currentValue" min="@minValue" max="@maxValue"/>
<input type="range" id="@Setting?.Name" class="form-range" @bind="@currentValue" min="@MinValue" max="@MaxValue"/>
</div>
</div>
</div>
@code {
[Parameter]
public int minValue {get; set;} = 0;
public int MinValue {get; set;}
[Parameter]
public int maxValue {get; set;} = 100;
public int MaxValue {get; set;} = 100;
[Parameter]
public bool IsPowerOfTwo {get; set;} = false;
public bool IsPowerOfTwo {get; set;}
[Parameter]
public int Step {get; set;} = 1;
private int currentValue;
protected override void OnInitialized() {
SettingsService.BeginSave += (sender, args) => SettingsService.UpdateSetting(GetSetting());
if (int.TryParse(Setting.Value, out int value)) { currentValue = value; } else {
currentValue = 0; // Default value if parsing fails
}
SettingsService.BeginSave += (_, _) => SettingsService.UpdateSetting(GetSetting());
currentValue = int.TryParse(Setting?.Value, out int value) ? value : 0; // Default value if parsing fails
}
protected override SettingDto GetSetting() {
protected override SettingDto? GetSetting() {
if (Setting == null) return null;
Setting.Value = IsPowerOfTwo ? ((int)Math.Pow(2, currentValue)).ToString() : currentValue.ToString();
return Setting;
}

View File

@@ -14,15 +14,16 @@
</div>
@code {
private string currentValue;
private string currentValue = string.Empty;
protected override void OnInitialized() {
base.OnInitialized();
SettingsService.BeginSave += (sender, args) => SettingsService.UpdateSetting(GetSetting());
SettingsService.BeginSave += (_, _) => SettingsService.UpdateSetting(GetSetting());
currentValue = Setting?.Value ?? string.Empty;
}
protected override SettingDto GetSetting() {
protected override SettingDto? GetSetting() {
if (Setting == null) return null;
Setting.Value = currentValue;
return Setting;
}

View File

@@ -1,5 +1,4 @@
@using Butter.Dtos.Settings
@using Butter.Settings
@using MilkStream.Services
@inherits SettingBox
@inject SettingsService SettingsService
@@ -18,13 +17,14 @@
private bool isChecked;
protected override void OnInitialized() {
SettingsService.BeginSave += (sender, args) => SettingsService.UpdateSetting(GetSetting());
if (bool.TryParse(Setting.Value, out var parsedValue)) {
SettingsService.BeginSave += (_, _) => SettingsService.UpdateSetting(GetSetting());
if (bool.TryParse(Setting?.Value, out var parsedValue)) {
isChecked = parsedValue;
}
}
protected override SettingDto GetSetting() {
protected override SettingDto? GetSetting() {
if (Setting == null) return null;
Setting.Value = isChecked.ToString();
return Setting;
}

View File

@@ -1,5 +1,7 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/WebPathMapping/IgnoredPaths/=BLAZOR_002EWEB_002EJS/@EntryIndexedValue">blazor.web.js</s:String>
<s:String x:Key="/Default/CodeInspection/WebPathMapping/IgnoredPaths/=WWWROOT_005CMILKSTREAM_002ESTYLES_002ECSS/@EntryIndexedValue">wwwroot\MilkStream.styles.css</s:String>
<s:String x:Key="/Default/CodeInspection/WebPathMapping/MappedPaths/=WWWROOT_005C_005FFRAMEWORK/@EntryIndexedValue"></s:String>
<s:String x:Key="/Default/CodeInspection/WebPathMapping/PathsInCorrectCasing/=BLAZOR_002EWEB_002EJS/@EntryIndexedValue">blazor.web.js</s:String>
<s:String x:Key="/Default/CodeInspection/WebPathMapping/PathsInCorrectCasing/=WWWROOT_005CMILKSTREAM_002ESTYLES_002ECSS/@EntryIndexedValue">wwwroot\MilkStream.styles.css</s:String>
<s:String x:Key="/Default/CodeInspection/WebPathMapping/PathsInCorrectCasing/=WWWROOT_005C_005FFRAMEWORK/@EntryIndexedValue">wwwroot\_framework</s:String></wpf:ResourceDictionary>

View File

@@ -20,13 +20,15 @@ public sealed class SettingsService : AuthServiceBase {
public async Task<List<SettingDto>?> GetAllSettings() {
var response = await Client.GetAsync("api/settings");
if (response.IsSuccessStatusCode) return await response.Content.ReadFromJsonAsync<List<SettingDto>>();
return null;
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<List<SettingDto>>();
}
public void UpdateSetting(SettingDto setting) {
public void UpdateSetting(SettingDto? setting) {
if (setting == null) {
Logger.Log(LogLevel.Warning, "Setting is null, cannot update.");
return;
}
Logger.Log(LogLevel.Information, $"Updating setting {setting.Name} to {setting.Value}");
var response = Client.PostAsJsonAsync("api/settings", setting).Result;

View File

@@ -77,7 +77,7 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AUtf8JsonWriterCache_002Ecs_002Fl_003AC_0021_003FUsers_003FREDCODE_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003F96d87fca98b4167c66ffae61c9ee88dc182d6e7dbc7eb8dbf41297e660eb_003FUtf8JsonWriterCache_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AValueTask_002Ecs_002Fl_003AC_0021_003FUsers_003FREDCODE_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003F9ec7c6b688aa4b89a1477dc1b679f62bf856b50196f4b8d19cd77f86df0abc_003FValueTask_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AWriteStackFrame_002Ecs_002Fl_003AC_0021_003FUsers_003FREDCODE_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fcfb06811acbbb25f4c1f3ae4eee74f65da5b2e9bd1bdc01ad979ac9b6745e9_003FWriteStackFrame_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/SweaWarningsMode/@EntryValue">DoNotShowAndRun</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/SweaWarningsMode/@EntryValue">ShowAndRun</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/ACCESSOR_OWNER_BODY/@EntryValue">ExpressionBody</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/ThisQualifier/INSTANCE_MEMBERS_QUALIFY_DECLARED_IN/@EntryValue">0</s:String>
<s:Boolean x:Key="/Default/Dpa/IsEnabledInDebug/@EntryValue">True</s:Boolean>