diff --git a/Aaru.Server.New/Aaru.Server.New.csproj b/Aaru.Server.New/Aaru.Server.New.csproj index 9ce7942d..7a2232df 100644 --- a/Aaru.Server.New/Aaru.Server.New.csproj +++ b/Aaru.Server.New/Aaru.Server.New.csproj @@ -23,4 +23,8 @@ + + + + diff --git a/Aaru.Server.New/Components/Layout/NavMenu.razor b/Aaru.Server.New/Components/Layout/NavMenu.razor index 7f973e97..7cc131de 100644 --- a/Aaru.Server.New/Components/Layout/NavMenu.razor +++ b/Aaru.Server.New/Components/Layout/NavMenu.razor @@ -20,6 +20,12 @@ + + diff --git a/Aaru.Server.New/Components/Layout/NavMenu.razor.css b/Aaru.Server.New/Components/Layout/NavMenu.razor.css index b9e7935d..203d235d 100644 --- a/Aaru.Server.New/Components/Layout/NavMenu.razor.css +++ b/Aaru.Server.New/Components/Layout/NavMenu.razor.css @@ -66,6 +66,10 @@ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-arrow-bar-left' viewBox='0 0 16 16'%3E%3Cpath d='M12.5 15a.5.5 0 0 1-.5-.5v-13a.5.5 0 0 1 1 0v13a.5.5 0 0 1-.5.5ZM10 8a.5.5 0 0 1-.5.5H3.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L3.707 7.5H9.5a.5.5 0 0 1 .5.5Z'/%3E%3C/svg%3E"); } +.bi-graph-up-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-graph-up' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M0 0h1v15h15v1H0zm14.817 3.113a.5.5 0 0 1 .07.704l-4.5 5.5a.5.5 0 0 1-.74.037L7.06 6.767l-3.656 5.027a.5.5 0 0 1-.808-.588l4-5.5a.5.5 0 0 1 .758-.06l2.609 2.61 4.15-5.073a.5.5 0 0 1 .704-.07'/%3E%3C/svg%3E"); +} + .nav-item { font-size: 0.9rem; padding-bottom: 0.5rem; diff --git a/Aaru.Server.New/Components/Pages/Stats.razor b/Aaru.Server.New/Components/Pages/Stats.razor new file mode 100644 index 00000000..23f9c674 --- /dev/null +++ b/Aaru.Server.New/Components/Pages/Stats.razor @@ -0,0 +1,6 @@ +@page "/Stats" +@using Aaru.Server.Database + +@inject Microsoft.EntityFrameworkCore.IDbContextFactory DbContextFactory + +Aaru: Statistics \ No newline at end of file diff --git a/Aaru.Server.New/Components/Pages/Stats.razor.cs b/Aaru.Server.New/Components/Pages/Stats.razor.cs new file mode 100644 index 00000000..8f6f3e0c --- /dev/null +++ b/Aaru.Server.New/Components/Pages/Stats.razor.cs @@ -0,0 +1,129 @@ +using Aaru.CommonTypes.Interop; +using Aaru.CommonTypes.Metadata; +using Aaru.Server.Database.Models; +using Microsoft.EntityFrameworkCore; +using DbContext = Aaru.Server.Database.DbContext; +using PlatformID = Aaru.CommonTypes.Interop.PlatformID; + +namespace Aaru.Server.New.Components.Pages; + +public partial class Stats +{ + /// + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + + // TOOD: Cache real OS name in database, lookups would be much faster + await using DbContext _ctx = await DbContextFactory.CreateDbContextAsync(); + + var operatingSystems = (await _ctx.OperatingSystems.OrderBy(static os => os.Name) + .ThenBy(static os => os.Version) + .Select(static nvs => new NameValueStats + { + name = + $"{GetPlatformName(nvs.Name, nvs.Version)}{(string.IsNullOrEmpty(nvs.Version) ? "" : " ")}{nvs.Version}", + Value = nvs.Count + }) + .ToListAsync()).OrderBy(static os => os.name) + .ToList(); + + var versions = (await _ctx.Versions.Select(static nvs => new NameValueStats + { + name = nvs.Name == "previous" ? "Previous than 3.4.99.0" : nvs.Name, + Value = nvs.Count + }) + .ToListAsync()).OrderBy(static version => version.name) + .ToList(); + + List commands = await _ctx.Commands.OrderBy(static c => c.Name).ToListAsync(); + + List filters = await _ctx.Filters.OrderBy(static filter => filter.Name).ToListAsync(); + + List mediaImages = await _ctx.MediaFormats.OrderBy(static format => format.Name).ToListAsync(); + + List partitions = await _ctx.Partitions.OrderBy(static partition => partition.Name).ToListAsync(); + + List filesystems = + await _ctx.Filesystems.OrderBy(static filesystem => filesystem.Name).ToListAsync(); + + List realMedia = []; + List virtualMedia = []; + + await foreach(Media nvs in _ctx.Medias.AsAsyncEnumerable()) + { + try + { + (string type, string subType) mediaType = + MediaType.MediaTypeToString((CommonTypes.MediaType)Enum.Parse(typeof(CommonTypes.MediaType), + nvs.Type)); + + if(nvs.Real) + { + realMedia.Add(new MediaItem + { + Type = mediaType.type, + SubType = mediaType.subType, + Count = nvs.Count + }); + } + else + { + virtualMedia.Add(new MediaItem + { + Type = mediaType.type, + SubType = mediaType.subType, + Count = nvs.Count + }); + } + } + catch + { + if(nvs.Real) + { + realMedia.Add(new MediaItem + { + Type = nvs.Type, + SubType = null, + Count = nvs.Count + }); + } + else + { + virtualMedia.Add(new MediaItem + { + Type = nvs.Type, + SubType = null, + Count = nvs.Count + }); + } + } + } + + realMedia = realMedia.OrderBy(static media => media.Type).ThenBy(static media => media.SubType).ToList(); + virtualMedia = virtualMedia.OrderBy(static media => media.Type).ThenBy(static media => media.SubType).ToList(); + + + List devices = await _ctx.DeviceStats.Include(static deviceStat => deviceStat.Report) + .Select(static device => new DeviceItem + { + Manufacturer = device.Manufacturer, + Model = device.Model, + Revision = device.Revision, + Bus = device.Bus, + ReportId = device.Report != null && device.Report.Id != 0 + ? device.Report.Id + : 0 + }) + .ToListAsync(); + + devices = devices.OrderBy(static device => device.Manufacturer) + .ThenBy(static device => device.Model) + .ThenBy(static device => device.Revision) + .ThenBy(static device => device.Bus) + .ToList(); + } + + static string GetPlatformName(string name, string version) => + DetectOS.GetPlatformName((PlatformID)Enum.Parse(typeof(PlatformID), name), version); +} \ No newline at end of file diff --git a/Aaru.Server.New/Program.cs b/Aaru.Server.New/Program.cs index c869a6cc..ac3daace 100644 --- a/Aaru.Server.New/Program.cs +++ b/Aaru.Server.New/Program.cs @@ -3,6 +3,7 @@ using Aaru.Server.New.Components.Account; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; +using DbContext = Aaru.Server.Database.DbContext; WebApplicationBuilder builder = WebApplication.CreateBuilder(args); @@ -24,10 +25,10 @@ builder.Services.AddAuthentication(options => string connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); -builder.Services.AddDbContext(options => options - .UseMySql(connectionString, - new MariaDbServerVersion(new Version(10, 4, 0))) - .UseLazyLoadingProxies()); +builder.Services.AddDbContextFactory(options => options + .UseMySql(connectionString, + new MariaDbServerVersion(new Version(10, 4, 0))) + .UseLazyLoadingProxies()); builder.Services.AddDatabaseDeveloperPageExceptionFilter();