Recreated solution with web app template. Improved theme. Switched to ShadcnBlazor library

This commit is contained in:
2025-12-25 19:16:53 +01:00
parent 0cc35300f1
commit a2d4edc0e5
272 changed files with 2441 additions and 14449 deletions

View File

@@ -1,15 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Moonlight.Shared.Http.Requests.Admin.ApiKeys;
public class CreateApiKeyRequest
{
[Required(ErrorMessage = "You need to specify a description")]
public string Description { get; set; }
[Required(ErrorMessage = "You need to specify permissions for the api key")]
public string[] Permissions { get; set; } = [];
[Required(ErrorMessage = "You need to specify an expire date")]
public DateTime ExpiresAt { get; set; } = DateTime.UtcNow.AddDays(30);
}

View File

@@ -1,9 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Moonlight.Shared.Http.Requests.Admin.ApiKeys;
public class UpdateApiKeyRequest
{
[Required(ErrorMessage = "You need to specify a description")]
public string Description { get; set; }
}

View File

@@ -1,12 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Moonlight.Shared.Http.Requests.Admin.Sys.Files;
public class CombineRequest
{
[Required(ErrorMessage = "Destination is required")]
public string Destination { get; set; }
[Required(ErrorMessage = "Files are required")]
public string[] Files { get; set; }
}

View File

@@ -1,18 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Moonlight.Shared.Http.Requests.Admin.Sys.Files;
public class CompressRequest
{
[Required(ErrorMessage = "Format is required")]
public string Format { get; set; }
[Required(ErrorMessage = "Destination is required")]
public string Destination { get; set; }
[Required(ErrorMessage = "Root is required")]
public string Root { get; set; }
[Required(ErrorMessage = "Items are required")]
public string[] Items { get; set; }
}

View File

@@ -1,15 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Moonlight.Shared.Http.Requests.Admin.Sys.Files;
public class DecompressRequest
{
[Required(ErrorMessage = "You need to provide a format")]
public string Format { get; set; }
[Required(ErrorMessage = "You need to provide a path")]
public string Path { get; set; }
[Required(ErrorMessage = "You need to provide a destination")]
public string Destination { get; set; }
}

View File

@@ -1,9 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Moonlight.Shared.Http.Requests.Admin.Sys;
public class GenerateDiagnoseRequest
{
[Required(ErrorMessage = "You need to define providers")]
public string[] Providers { get; set; } = [];
}

View File

@@ -1,21 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Moonlight.Shared.Misc;
namespace Moonlight.Shared.Http.Requests.Admin.Sys.Theme;
public class CreateThemeRequest
{
[Required(ErrorMessage = "You need to provide a name")]
public string Name { get; set; }
[Required(ErrorMessage = "You need to provide an author")]
public string Author { get; set; }
[Required(ErrorMessage = "You need to provide a version")]
public string Version { get; set; }
public string? UpdateUrl { get; set; }
public string? DonateUrl { get; set; }
public ApplicationTheme Content { get; set; } = new();
}

View File

@@ -1,23 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Moonlight.Shared.Misc;
namespace Moonlight.Shared.Http.Requests.Admin.Sys.Theme;
public class UpdateThemeRequest
{
public bool IsEnabled { get; set; }
[Required(ErrorMessage = "You need to provide a name")]
public string Name { get; set; }
[Required(ErrorMessage = "You need to provide an author")]
public string Author { get; set; }
[Required(ErrorMessage = "You need to provide a version")]
public string Version { get; set; }
public string? UpdateUrl { get; set; }
public string? DonateUrl { get; set; }
public ApplicationTheme Content { get; set; }
}

View File

@@ -1,22 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Moonlight.Shared.Http.Requests.Admin.Users;
public class CreateUserRequest
{
[Required(ErrorMessage = "You need to provide an email address")]
[EmailAddress(ErrorMessage = "You need to provide a valid email address")]
public string Email { get; set; }
[Required(ErrorMessage = "You need to provide a username")]
[RegularExpression("^[a-z][a-z0-9]*$", ErrorMessage = "Usernames can only contain lowercase characters and numbers and should not start with a number")]
public string Username { get; set; }
[Required(ErrorMessage = "You need to provide a password")]
[MinLength(8, ErrorMessage = "Your password needs to be at least 8 characters long")]
[MaxLength(256, ErrorMessage = "Your password should not exceed the length of 256 characters")]
public string Password { get; set; }
[Required(ErrorMessage = "You need to provide permissions")]
public string[] Permissions { get; set; } = [];
}

View File

@@ -1,19 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Moonlight.Shared.Http.Requests.Admin.Users;
public class UpdateUserRequest
{
[Required(ErrorMessage = "You need to provide an email address")]
[EmailAddress(ErrorMessage = "You need to provide a valid email address")]
public string Email { get; set; }
[Required(ErrorMessage = "You need to provide a username")]
[RegularExpression("^[a-z][a-z0-9]*$", ErrorMessage = "Usernames can only contain lowercase characters and numbers and should not start with a number")]
public string Username { get; set; }
public string? Password { get; set; }
[Required(ErrorMessage = "You need to provide permissions")]
public string[] Permissions { get; set; } = [];
}

View File

@@ -0,0 +1,62 @@
using System.Diagnostics.CodeAnalysis;
namespace Moonlight.Shared.Http.Requests;
public class FilterOptions : IParsable<FilterOptions>
{
public Dictionary<string, string> Filters { get; set; }
public FilterOptions()
{
Filters = new();
}
public FilterOptions(Dictionary<string, string> filters)
{
Filters = filters;
}
public static FilterOptions Parse(string s, IFormatProvider? provider)
{
if (!TryParse(s, provider, out var result))
throw new AggregateException("Unable to parse filter options");
return result;
}
public static bool TryParse(
[NotNullWhen(true)] string? input,
IFormatProvider? provider,
[MaybeNullWhen(false)] out FilterOptions result
)
{
result = new();
if (string.IsNullOrEmpty(input))
return true;
var filters = input.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
foreach (var part in filters)
{
var filterParts = part.Split('$', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (filterParts.Length != 2)
continue;
result.Filters.Add(filterParts[0], filterParts[1]);
}
return true;
}
public override string ToString()
{
var result = "";
foreach (var filter in Filters)
result += $"{filter.Key}${filter.Value};";
return result;
}
}

View File

@@ -0,0 +1,13 @@
using System.ComponentModel.DataAnnotations;
namespace Moonlight.Shared.Http.Requests.Users;
public class CreateUserRequest
{
[Required]
[MinLength(3)]
[MaxLength(32)]
public string Username { get; set; }
[Required] [EmailAddress] public string Email { get; set; }
}

View File

@@ -0,0 +1,13 @@
using System.ComponentModel.DataAnnotations;
namespace Moonlight.Shared.Http.Requests.Users;
public class UpdateUserRequest
{
[Required]
[MinLength(3)]
[MaxLength(32)]
public string Username { get; set; }
[Required] [EmailAddress] public string Email { get; set; }
}

View File

@@ -1,10 +0,0 @@
namespace Moonlight.Shared.Http.Responses.Admin.ApiKeys;
public class ApiKeyResponse
{
public int Id { get; set; }
public string Description { get; set; }
public string[] Permissions { get; set; } = [];
public DateTimeOffset ExpiresAt { get; set; }
public DateTimeOffset CreatedAt { get; set; }
}

View File

@@ -1,10 +0,0 @@
namespace Moonlight.Shared.Http.Responses.Admin.ApiKeys;
public class CreateApiKeyResponse
{
public int Id { get; set; }
public string Secret { get; set; }
public string Description { get; set; }
public string[] Permissions { get; set; } = [];
public DateTimeOffset ExpiresAt { get; set; }
}

View File

@@ -1,16 +0,0 @@
namespace Moonlight.Shared.Http.Responses.Admin.Hangfire;
public class HangfireStatsResponse
{
public long Servers { get; set; }
public long Recurring { get; set; }
public long Enqueued { get; set; }
public long Queues { get; set; }
public long Scheduled { get; set; }
public long Processing { get; set; }
public long Succeeded { get; set; }
public long Failed { get; set; }
public long Deleted { get; set; }
public long? Retries { get; set; }
public long? Awaiting { get; set; }
}

View File

@@ -1,7 +0,0 @@
namespace Moonlight.Shared.Http.Responses.Admin.Sys;
public class DiagnoseProvideResponse
{
public string Name { get; set; }
public string Type { get; set; }
}

View File

@@ -1,6 +0,0 @@
namespace Moonlight.Shared.Http.Responses.Admin.Sys;
public class DownloadUrlResponse
{
public string Url { get; set; }
}

View File

@@ -1,11 +0,0 @@
namespace Moonlight.Shared.Http.Responses.Admin.Sys;
public class FileSystemEntryResponse
{
public string Name { get; set; }
public bool IsFolder { get; set; }
public long Size { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}

View File

@@ -1,9 +0,0 @@
namespace Moonlight.Shared.Http.Responses.Admin.Sys;
public class SystemOverviewResponse
{
public int CpuUsage { get; set; }
public long MemoryUsage { get; set; }
public string OperatingSystem { get; set; }
public TimeSpan Uptime { get; set; }
}

View File

@@ -1,19 +0,0 @@
using Moonlight.Shared.Misc;
namespace Moonlight.Shared.Http.Responses.Admin;
public class ThemeResponse
{
public int Id { get; set; }
public bool IsEnabled { get; set; }
public string Name { get; set; }
public string Author { get; set; }
public string Version { get; set; }
public string? UpdateUrl { get; set; }
public string? DonateUrl { get; set; }
public ApplicationTheme Content { get; set; }
}

View File

@@ -1,9 +0,0 @@
namespace Moonlight.Shared.Http.Responses.Admin.Users;
public class UserResponse
{
public int Id { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string[] Permissions { get; set; }
}

View File

@@ -1,20 +0,0 @@
namespace Moonlight.Shared.Http.Responses.Auth;
public class AuthClaimResponse
{
// ReSharper disable once UnusedMember.Global
// Its used by the json serializer ^^
public AuthClaimResponse()
{
}
public AuthClaimResponse(string type, string value)
{
Type = type;
Value = value;
}
public string Type { get; set; }
public string Value { get; set; }
}

View File

@@ -1,7 +0,0 @@
namespace Moonlight.Shared.Http.Responses.Auth;
public class AuthSchemeResponse
{
public string DisplayName { get; set; }
public string Identifier { get; set; }
}

View File

@@ -0,0 +1,3 @@
namespace Moonlight.Shared.Http.Responses.Auth;
public record ClaimResponse(string Type, string Value);

View File

@@ -0,0 +1,3 @@
namespace Moonlight.Shared.Http.Responses.Auth;
public record SchemeResponse(string Name, string DisplayName);

View File

@@ -0,0 +1,3 @@
namespace Moonlight.Shared.Http.Responses;
public record PagedData<T>(T[] Data, int TotalLength);

View File

@@ -0,0 +1,3 @@
namespace Moonlight.Shared.Http.Responses.Users;
public record UserResponse(int Id, string Username, string Email);

View File

@@ -0,0 +1,17 @@
using System.Text.Json.Serialization;
using Moonlight.Shared.Http.Requests.Users;
using Moonlight.Shared.Http.Responses;
using Moonlight.Shared.Http.Responses.Auth;
using Moonlight.Shared.Http.Responses.Users;
namespace Moonlight.Shared.Http;
[JsonSerializable(typeof(CreateUserRequest))]
[JsonSerializable(typeof(UpdateUserRequest))]
[JsonSerializable(typeof(ClaimResponse[]))]
[JsonSerializable(typeof(SchemeResponse[]))]
[JsonSerializable(typeof(UserResponse))]
[JsonSerializable(typeof(PagedData<UserResponse>))]
public partial class SerializationContext : JsonSerializerContext
{
}

View File

@@ -1,45 +0,0 @@
namespace Moonlight.Shared.Misc;
public class ApplicationTheme
{
public string ColorBase100 { get; set; }
public string ColorBase200 { get; set; }
public string ColorBase300 { get; set; }
public string ColorBaseContent { get; set; }
public string ColorPrimary { get; set; }
public string ColorPrimaryContent { get; set; }
public string ColorSecondary { get; set; }
public string ColorSecondaryContent { get; set; }
public string ColorAccent { get; set; }
public string ColorAccentContent { get; set; }
public string ColorNeutral { get; set; }
public string ColorNeutralContent { get; set; }
public string ColorInfo { get; set; }
public string ColorInfoContent { get; set; }
public string ColorSuccess { get; set; }
public string ColorSuccessContent { get; set; }
public string ColorWarning { get; set; }
public string ColorWarningContent { get; set; }
public string ColorError { get; set; }
public string ColorErrorContent { get; set; }
public float RadiusSelector { get; set; }
public float RadiusField { get; set; }
public float RadiusBox { get; set; }
public float SizeSelector { get; set; }
public float SizeField { get; set; }
public float Border { get; set; }
public int Depth { get; set; }
public int Noise { get; set; }
}

View File

@@ -1,7 +0,0 @@
namespace Moonlight.Shared.Misc;
public class FrontendConfiguration
{
public string ApiUrl { get; set; }
public string HostEnvironment { get; set; }
}

View File

@@ -1,19 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<Title>Moonlight.Shared</Title>
<PackageTags>shared</PackageTags>
<PackageId>Moonlight.Shared</PackageId>
<Version>2.1.15</Version>
<Authors>Moonlight Panel</Authors>
<Description>A build of the shared classes for moonlight development</Description>
<PackageProjectUrl>https://github.com/Moonlight-Panel/Moonlight</PackageProjectUrl>
<DevelopmentDependency>true</DevelopmentDependency>
<IsPackable>true</IsPackable>
</PropertyGroup>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>