Render all statistics tables.

This commit is contained in:
2024-05-04 03:57:15 +01:00
parent c2ce0d8b3e
commit 1d9bce3f49
6 changed files with 235 additions and 49 deletions

View File

@@ -8,6 +8,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Blazorise.Bootstrap" Version="1.5.2"/>
<PackageReference Include="Blazorise.DataGrid" Version="1.5.2"/>
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="1.5.2"/>
<PackageReference Include="Markdig" Version="0.37.0"/>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="8.0.4"/>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.4"/>

View File

@@ -1,11 +1,15 @@
<!DOCTYPE html>
@using Blazorise
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<base href="/"/>
<link href="bootstrap/bootstrap.min.css" rel="stylesheet"/>
<link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" rel="stylesheet">
<link href="_content/Blazorise.Icons.FontAwesome/v6/css/all.min.css" rel="stylesheet">
<link href="_content/Blazorise/blazorise.css" rel="stylesheet"/>
<link href="_content/Blazorise.Bootstrap/blazorise.bootstrap.css" rel="stylesheet"/>
<link href="css/prism.css" rel="stylesheet"/>
<link href="app.css" rel="stylesheet"/>
<link href="Aaru.Server.New.styles.css" rel="stylesheet"/>
@@ -14,9 +18,22 @@
</head>
<body>
<Routes/>
<Blazorise.ThemeProvider Theme="@theme">
<Routes/>
</Blazorise.ThemeProvider>
<script src="_framework/blazor.web.js"></script>
<script src="scripts/prism.js"></script>
</body>
</html>
</html>
@code{
private readonly Theme theme = new()
{
ColorOptions = new ThemeColorOptions
{
Dark = ThemeColors.Gray.Shades["100"].Value,
Light = ThemeColors.Gray.Shades["800"].Value
}
};
}

View File

@@ -1,6 +1,134 @@
@page "/Stats"
@using Aaru.CommonTypes.Metadata
@using Aaru.Server.Database
@using Aaru.Server.Database.Models
@using Blazorise.DataGrid
@inject Microsoft.EntityFrameworkCore.IDbContextFactory<DbContext> DbContextFactory
<PageTitle>Aaru: Statistics</PageTitle>
<PageTitle>Aaru: Statistics</PageTitle>
@*
TODO: Group by datagrid
TODO: Sortable datagrid
*@
<div class="stats-section">
<h1>
<p class="text-center" style="color: deeppink;">All operating systems Aaru has run on...</p>
</h1>
<DataGrid Data="@OperatingSystems" FixedHeader FixedHeaderDataGridMaxHeight="300px" PageSize="int.MaxValue" TItem="NameValueStats">
<DataGridColumn Caption="Name" Field="@nameof(NameValueStats.name)"/>
<DataGridNumericColumn Caption="Times" Field="@nameof(NameValueStats.Value)"/>
</DataGrid>
</div>
<div class="stats-section">
<h1>
<p class="text-center" style="color: deeppink;">All Aaru versions...</p>
</h1>
<DataGrid Data="@Versions" FixedHeader FixedHeaderDataGridMaxHeight="300px" PageSize="int.MaxValue" TItem="NameValueStats">
<DataGridColumn Caption="Version" Field="@nameof(NameValueStats.name)"/>
<DataGridNumericColumn Caption="Times run" Field="@nameof(NameValueStats.Value)"/>
</DataGrid>
</div>
<div class="stats-section">
<h1>
<p class="text-center" style="color: deeppink;">All Aaru commands...</p>
</h1>
<DataGrid Data="@Commands" FixedHeader FixedHeaderDataGridMaxHeight="300px" PageSize="int.MaxValue" TItem="Command">
<DataGridColumn Caption="Command" Field="@nameof(Command.Name)"/>
<DataGridNumericColumn Caption="Times run" Field="@nameof(Command.Count)"/>
</DataGrid>
</div>
<div class="stats-section">
<h1>
<p class="text-center" style="color: deeppink;">All filters found...</p>
</h1>
<DataGrid Data="@Filters" FixedHeader FixedHeaderDataGridMaxHeight="300px" PageSize="int.MaxValue" TItem="Filter">
<DataGridColumn Caption="Filter" Field="@nameof(Filter.Name)"/>
<DataGridNumericColumn Caption="Times found" Field="@nameof(Filter.Count)"/>
</DataGrid>
</div>
<div class="stats-section">
<h1>
<p class="text-center" style="color: deeppink;">All media image formats found...</p>
</h1>
<DataGrid Data="@MediaImages" FixedHeader FixedHeaderDataGridMaxHeight="300px" PageSize="int.MaxValue" TItem="MediaFormat">
<DataGridColumn Caption="Media image format" Field="@nameof(MediaFormat.Name)"/>
<DataGridNumericColumn Caption="Times found" Field="@nameof(MediaFormat.Count)"/>
</DataGrid>
</div>
<div class="stats-section">
<h1>
<p class="text-center" style="color: deeppink;">All partitioning schemes found...</p>
</h1>
<DataGrid Data="@Partitions" FixedHeader FixedHeaderDataGridMaxHeight="300px" PageSize="int.MaxValue" TItem="Partition">
<DataGridColumn Caption="Partitioning scheme" Field="@nameof(Partition.Name)"/>
<DataGridNumericColumn Caption="Times found" Field="@nameof(Partition.Count)"/>
</DataGrid>
</div>
<div class="stats-section">
<h1>
<p class="text-center" style="color: deeppink;">All filesystems found...</p>
</h1>
<DataGrid Data="@Filesystems" FixedHeader FixedHeaderDataGridMaxHeight="300px" PageSize="int.MaxValue" TItem="Filesystem">
<DataGridColumn Caption="Filesystem name" Field="@nameof(Filesystem.Name)"/>
<DataGridNumericColumn Caption="Times found" Field="@nameof(Filesystem.Count)"/>
</DataGrid>
</div>
<div class="stats-section">
<h1>
<p class="text-center" style="color: deeppink;">All media types found in images...</p>
</h1>
<DataGrid Data="@VirtualMedia" FixedHeader FixedHeaderDataGridMaxHeight="300px" PageSize="int.MaxValue" TItem="MediaItem">
<DataGridColumn Caption="Physical type" Field="@nameof(MediaItem.Type)"/>
<DataGridColumn Caption="Logical type" Field="@nameof(MediaItem.SubType)"/>
<DataGridNumericColumn Caption="Times found" Field="@nameof(MediaItem.Count)"/>
</DataGrid>
</div>
<div class="stats-section">
<h1>
<p class="text-center" style="color: deeppink;">All media types found in devices...</p>
</h1>
<DataGrid Data="@RealMedia" FixedHeader FixedHeaderDataGridMaxHeight="300px" PageSize="int.MaxValue" TItem="MediaItem">
<DataGridColumn Caption="Physical type" Field="@nameof(MediaItem.Type)"/>
<DataGridColumn Caption="Logical type" Field="@nameof(MediaItem.SubType)"/>
<DataGridNumericColumn Caption="Times found" Field="@nameof(MediaItem.Count)"/>
</DataGrid>
</div>
<div class="stats-section">
<h1>
<p class="text-center" style="color: deeppink;">All devices found...</p>
</h1>
<DataGrid Data="@Devices" FixedHeader FixedHeaderDataGridMaxHeight="300px" PageSize="int.MaxValue" TItem="DeviceItem">
<DataGridColumn Caption="Manufacturer" Field="@nameof(DeviceItem.Manufacturer)"/>
<DataGridColumn Caption="Model" Field="@nameof(DeviceItem.Model)"/>
<DataGridColumn Caption="Revision" Field="@nameof(DeviceItem.Revision)"/>
<DataGridColumn Caption="Bus" Field="@nameof(DeviceItem.Bus)"/>
<DataGridColumn Caption="Report" Field="@nameof(DeviceItem.ReportId)">
<DisplayTemplate>
@{
int? reportId = context?.ReportId;
if(reportId > 0)
{
<a href="/report/@reportId.Value" target="_blank">Yes</a>
}
else
{
<span>No</span>
}
}
</DisplayTemplate>
</DataGridColumn>
</DataGrid>
</div>

View File

@@ -9,6 +9,23 @@ namespace Aaru.Server.New.Components.Pages;
public partial class Stats
{
List<NameValueStats> OperatingSystems { get; set; } = [];
List<NameValueStats> Versions { get; set; } = [];
List<Command> Commands { get; set; } = [];
List<Filter> Filters { get; set; } = [];
List<MediaFormat> MediaImages { get; set; } = [];
List<Partition> Partitions { get; set; } = [];
List<Filesystem> Filesystems { get; set; } = [];
List<MediaItem> RealMedia { get; set; } = [];
List<MediaItem> VirtualMedia { get; set; } = [];
List<DeviceItem> Devices { get; set; } = [];
/// <inheritdoc />
protected override async Task OnInitializedAsync()
{
@@ -17,38 +34,37 @@ public partial class Stats
// 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();
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();
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<Command> commands = await _ctx.Commands.OrderBy(static c => c.Name).ToListAsync();
Commands = await _ctx.Commands.OrderBy(static c => c.Name).ToListAsync();
List<Filter> filters = await _ctx.Filters.OrderBy(static filter => filter.Name).ToListAsync();
Filters = await _ctx.Filters.OrderBy(static filter => filter.Name).ToListAsync();
List<MediaFormat> mediaImages = await _ctx.MediaFormats.OrderBy(static format => format.Name).ToListAsync();
MediaImages = await _ctx.MediaFormats.OrderBy(static format => format.Name).ToListAsync();
List<Partition> partitions = await _ctx.Partitions.OrderBy(static partition => partition.Name).ToListAsync();
Partitions = await _ctx.Partitions.OrderBy(static partition => partition.Name).ToListAsync();
List<Filesystem> filesystems =
await _ctx.Filesystems.OrderBy(static filesystem => filesystem.Name).ToListAsync();
Filesystems = await _ctx.Filesystems.OrderBy(static filesystem => filesystem.Name).ToListAsync();
List<MediaItem> realMedia = [];
List<MediaItem> virtualMedia = [];
RealMedia = [];
VirtualMedia = [];
await foreach(Media nvs in _ctx.Medias.AsAsyncEnumerable())
{
@@ -60,7 +76,7 @@ public partial class Stats
if(nvs.Real)
{
realMedia.Add(new MediaItem
RealMedia.Add(new MediaItem
{
Type = mediaType.type,
SubType = mediaType.subType,
@@ -69,7 +85,7 @@ public partial class Stats
}
else
{
virtualMedia.Add(new MediaItem
VirtualMedia.Add(new MediaItem
{
Type = mediaType.type,
SubType = mediaType.subType,
@@ -81,7 +97,7 @@ public partial class Stats
{
if(nvs.Real)
{
realMedia.Add(new MediaItem
RealMedia.Add(new MediaItem
{
Type = nvs.Type,
SubType = null,
@@ -90,7 +106,7 @@ public partial class Stats
}
else
{
virtualMedia.Add(new MediaItem
VirtualMedia.Add(new MediaItem
{
Type = nvs.Type,
SubType = null,
@@ -100,24 +116,22 @@ public partial class Stats
}
}
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();
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<DeviceItem> 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 = 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)
Devices = Devices.OrderBy(static device => device.Manufacturer)
.ThenBy(static device => device.Model)
.ThenBy(static device => device.Revision)
.ThenBy(static device => device.Bus)

View File

@@ -1,5 +1,8 @@
using Aaru.Server.New.Components;
using Aaru.Server.New.Components.Account;
using Blazorise;
using Blazorise.Bootstrap;
using Blazorise.Icons.FontAwesome;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
@@ -43,6 +46,8 @@ builder.Services.AddIdentityCore<IdentityUser>(options =>
builder.Services.AddSingleton<IEmailSender<IdentityUser>, IdentityNoOpEmailSender>();
builder.Services.AddBlazorise(options => { options.Immediate = true; }).AddBootstrapProviders().AddFontAwesomeIcons();
WebApplication app = builder.Build();
// Configure the HTTP request pipeline.

View File

@@ -697,3 +697,22 @@ kbd {
padding: 3px 5px;
vertical-align: middle;
}
.table {
color: #DEDEDE;
}
.stats-section {
margin: 0 auto;
max-width: 800px;
padding: 30px 15px 40px !important;
position: relative;
}
.table-fixed-header .table thead:not(.table-thead-theme) th {
background-color: #333333;
}
.table-fixed-header {
scrollbar-color: #888888 #333333;
}