This commit is contained in:
REDCODE
2025-08-30 18:56:39 +02:00
parent a279025647
commit d46ec912bb
7 changed files with 78 additions and 13 deletions

View File

@@ -9,7 +9,7 @@ FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR "/src"
COPY ["./Lactose.csproj", "Lactose/"]
COPY ["Lactose/Lactose.csproj", "Lactose/"]
RUN dotnet restore "Lactose/Lactose.csproj"
WORKDIR "/src/Lactose"

View File

@@ -5,6 +5,8 @@
@using Butter.Settings
@using MilkStream.Services
@using System.Diagnostics
@using System.Globalization
@using System.Runtime.InteropServices
@using System.Linq;
@inject NavigationManager NavigationManager
@@ -14,6 +16,42 @@
<PageTitle>Settings</PageTitle>
@code {
// Typed shadow copy that every input binds to
private readonly Dictionary<string, object> _typedValues = new();
protected override void OnInitialized() {
foreach (var opt in settings) {
_typedValues[opt.Name] = opt.DisplayType switch {
DisplayType.IntNumber => int.Parse(opt.Value),
DisplayType.FloatNumber => double.Parse(opt.Value),
DisplayType.Checkbox or DisplayType.Switch => bool.Parse(opt.Value),
DisplayType.TimePicker => double.Parse(opt.Value), // slider 0-23.9
_ => opt.Value // string
};
}
}
// Two-way binder helper
private void BindValue<T>(string key, T value) {
_typedValues[key] = value!;
settings.First(o => o.Name == key).Value = value switch {
bool b => b.ToString(),
double d => d.ToString(CultureInfo.InvariantCulture),
int i => i.ToString(CultureInfo.InvariantCulture),
_ => value!.ToString()
};
}
private BindConverter<T> GetBindTarget<T>(string key) => value => {
BindValue(key, value);
return true;
};
}
<div>
<h3>Settings</h3>
@if (settings.Any()) {
@@ -24,33 +62,43 @@
<p class="align-self-start mb-0" style="font-style: italic">@option.Description</p>
@switch (option.DisplayType) {
case DisplayType.Text:
<input type="text" class="form-control ms-auto" value="@option.Value"/>
<input type="text" id="@option.Name" class="form-control ms-auto" @bind="@option.Value"/>
break;
case DisplayType.Password:
<input type="password" class="form-control ms-auto" value="@option.Value"/>
<input type="password" id="@option.Name" class="form-control ms-auto"
@bind="@option.Value"/>
break;
case DisplayType.IntNumber:
case DisplayType.FloatNumber:
<div class="ms-auto">
<input type="number" class="form-control ms-auto" value="@option.Value"/>
<input type="number" id="@option.Name" class="form-control ms-auto"
@bind="@option.Value"/>
</div>
break;
case DisplayType.Checkbox:
<input type="checkbox" class="form-check-input ms-auto" role="switch" value="@option.Value"/>
<input type="checkbox" id="@option.Name" class="form-check-input ms-auto"
@bind="@option.Value"/>
break;
case DisplayType.Switch:
<input type="checkbox" class="form-check-input ms-auto m-1" role="switch" value="@option.Value"/>
<div class="form-switch d-flex ms-auto">
<input type="checkbox" id="@option.Name" class="form-check-input m-1"
@bind="@option.Value"/>
</div>
break;
case DisplayType.DateTimePicker:
<div class="ms-auto">DATETIME NOT IMPLEMENTED Value: @option.Value</div>
break;
case DisplayType.TimePicker:
<div class="ms-auto"><input type="range" class="form-range" role="range" value="@option.Value"/></div>
<div class="ms-auto">
<div class="mx-1">@option.Value</div>
<input type="range" id="@option.Name" class="form-range" @bind="@option.Value"/>
</div>
break;
}
</div>
</div>
}
<button class="btn btn-primary my-2" @onclick="OnSaveChanges"><i class="bi bi-floppy2"></i>Save Changes</button>
} else {
<div class="alert alert-danger my-2 my-sm-5 mx-auto" style="max-width: fit-content" role="alert">
@@ -69,9 +117,9 @@
<div class="card-body d-flex justify-content-between align-items-center">
<div class="d-flex flex-row flex-grow-1 form-switch">
<div><strong>Path:</strong> @folder.BasePath</div>
<div class="ms-auto"><input class="form-check-input m-1" type="checkbox" role="switch"
<div class="ms-auto"><input class="form-check-input m-1" type="checkbox"
id="@folder.Id"
checked="@folder.Active"/><strong> @(folder.Active ? "Active" : "Disabled")</strong>
checked="@folder.Active"/>
</div>
</div>
</div>
@@ -91,6 +139,7 @@
@code {
List<SettingDto> settings = new();
List<FolderFullDto> folders = new();
protected async override Task OnAfterRenderAsync(bool firstRender) {
if (firstRender) {
if (!LoginService.IsLoggedIn) NavigationManager.NavigateTo("/");

View File

@@ -20,4 +20,5 @@ RUN dotnet publish "./MilkStream.csproj" -c $BUILD_CONFIGURATION -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
VOLUME ["/home/app/.aspnet/DataProtection-Keys"]
ENTRYPOINT ["dotnet", "MilkStream.dll"]

View File

@@ -27,6 +27,13 @@ builder.Services.AddScoped<JwtTokenRefresher>();
builder.Services.AddLogging();
builder.WebHost.UseStaticWebAssets();
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options => {
options.IdleTimeout = TimeSpan.FromMinutes(30);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
var app = builder.Build();
// Configure the HTTP request pipeline.

View File

@@ -0,0 +1,5 @@
namespace MilkStream;
public class StringExtensions {
}

View File

@@ -1,8 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Default": "Debug",
"Microsoft.AspNetCore": "Warning"
}
}
},
"DetailedErrors": true,
"BaseUrl": "http://localhost:5162/"
}

View File

@@ -3,8 +3,9 @@
image: lactose
container_name: lactose
build:
context: ./Lactose
dockerfile: Dockerfile
#context: ./Lactose
context: .
dockerfile: Lactose/Dockerfile
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports: