mirror of
https://github.com/aaru-dps/Aaru.Server.git
synced 2025-12-16 19:24:27 +00:00
Render all statistics tables.
This commit is contained in:
@@ -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"/>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user