From d833cb7b4f775c5e3410c9e35a8cffce1918f750 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sat, 4 May 2024 13:37:39 +0100 Subject: [PATCH] Draw all statistics pie charts. --- Aaru.Server.New/Aaru.Server.New.csproj | 1 + Aaru.Server.New/Components/App.razor | 3 +- Aaru.Server.New/Components/Pages/Stats.razor | 16 + .../Components/Pages/Stats.razor.cs | 552 +++++++++++++++++- 4 files changed, 555 insertions(+), 17 deletions(-) diff --git a/Aaru.Server.New/Aaru.Server.New.csproj b/Aaru.Server.New/Aaru.Server.New.csproj index 3661c069..d0db30f1 100644 --- a/Aaru.Server.New/Aaru.Server.New.csproj +++ b/Aaru.Server.New/Aaru.Server.New.csproj @@ -9,6 +9,7 @@ + diff --git a/Aaru.Server.New/Components/App.razor b/Aaru.Server.New/Components/App.razor index 375d3112..6255d65a 100644 --- a/Aaru.Server.New/Components/App.razor +++ b/Aaru.Server.New/Components/App.razor @@ -22,7 +22,8 @@ - + + diff --git a/Aaru.Server.New/Components/Pages/Stats.razor b/Aaru.Server.New/Components/Pages/Stats.razor index 46cffa79..7f7f49ae 100644 --- a/Aaru.Server.New/Components/Pages/Stats.razor +++ b/Aaru.Server.New/Components/Pages/Stats.razor @@ -2,7 +2,9 @@ @using Aaru.CommonTypes.Metadata @using Aaru.Server.Database @using Aaru.Server.Database.Models +@using Blazorise.Charts @using Blazorise.DataGrid +@rendermode InteractiveServer @inject Microsoft.EntityFrameworkCore.IDbContextFactory DbContextFactory @@ -17,6 +19,10 @@

All operating systems Aaru has run on...

+ + + + @@ -27,6 +33,7 @@

All Aaru versions...

+ @@ -37,6 +44,7 @@

All Aaru commands...

+ @@ -47,6 +55,7 @@

All filters found...

+ @@ -57,6 +66,7 @@

All media image formats found...

+ @@ -67,6 +77,7 @@

All partitioning schemes found...

+ @@ -77,6 +88,7 @@

All filesystems found...

+ @@ -87,6 +99,7 @@

All media types found in images...

+ @@ -98,6 +111,7 @@

All media types found in devices...

+ @@ -109,6 +123,8 @@

All devices found...

+ + diff --git a/Aaru.Server.New/Components/Pages/Stats.razor.cs b/Aaru.Server.New/Components/Pages/Stats.razor.cs index 670a668f..2b044741 100644 --- a/Aaru.Server.New/Components/Pages/Stats.razor.cs +++ b/Aaru.Server.New/Components/Pages/Stats.razor.cs @@ -1,6 +1,7 @@ using Aaru.CommonTypes.Interop; using Aaru.CommonTypes.Metadata; using Aaru.Server.Database.Models; +using Blazorise.Charts; using Microsoft.EntityFrameworkCore; using DbContext = Aaru.Server.Database.DbContext; using PlatformID = Aaru.CommonTypes.Interop.PlatformID; @@ -9,22 +10,69 @@ namespace Aaru.Server.New.Components.Pages; public partial class Stats { - List OperatingSystems { get; set; } = []; - - List Versions { get; set; } = []; - - List Commands { get; set; } = []; - - List Filters { get; set; } = []; - - List MediaImages { get; set; } = []; - - List Partitions { get; set; } = []; - - List Filesystems { get; set; } = []; - List RealMedia { get; set; } = []; - List VirtualMedia { get; set; } = []; - List Devices { get; set; } = []; + readonly List _backgroundColors = + [ + ChartColor.FromHtmlColorCode("#006412"), ChartColor.FromHtmlColorCode("#0000D3"), + ChartColor.FromHtmlColorCode("#FF6403"), ChartColor.FromHtmlColorCode("#562C05"), + ChartColor.FromHtmlColorCode("#DD0907"), ChartColor.FromHtmlColorCode("#F20884"), + ChartColor.FromHtmlColorCode("#4700A5"), ChartColor.FromHtmlColorCode("#90713A"), + ChartColor.FromHtmlColorCode("#1FB714"), ChartColor.FromHtmlColorCode("#02ABEA"), + ChartColor.FromHtmlColorCode("#FBF305") + ]; + readonly List _borderColors = [ChartColor.FromHtmlColorCode("#8b0000")]; + PieChart? _commandsChart; + List _commandsCounts = []; + string[] _commandsLabels = []; + PieChart? _devicesByBusChart; + List _devicesByBusCounts = []; + string[] _devicesByBusLabels = []; + PieChart? _devicesByManufacturerChart; + List _devicesByManufacturerCounts = []; + string[] _devicesByManufacturerLabels = []; + PieChart? _filesystemsChart; + List _filesystemsCounts = []; + string[] _filesystemsLabels = []; + PieChart? _filtersChart; + List _filtersCounts = []; + string[] _filtersLabels = []; + PieChart? _formatsChart; + List _formatsCounts = []; + string[] _formatsLabels = []; + bool _isAlreadyInitialised; + PieChart? _linuxChart; + List _linuxCounts = []; + string[] _linuxLabels = []; + PieChart? _macosChart; + List _macosCounts = []; + string[] _macosLabels = []; + List _operatingSystemCounts = []; + string[] _operatingSystemLabels = []; + PieChart? _operatingSystemsChart; + PieChart? _partitionsChart; + List _partitionsCounts = []; + string[] _partitionsLabels = []; + PieChart? _realMediaChart; + List _realMediaCounts = []; + string[] _realMediaLabels = []; + PieChart? _versionsChart; + List _versionsCounts = []; + string[] _versionsLabels = []; + PieChart? _virtualMediaChart; + List _virtualMediaCounts = []; + string[] _virtualMediaLabels = []; + PieChart? _windowsChart; + List _windowsCounts = []; + string[] _windowsLabels = []; + List OperatingSystems { get; set; } = []; + List Versions { get; set; } = []; + List Commands { get; set; } = []; + List Filters { get; set; } = []; + List MediaImages { get; set; } = []; + List Partitions { get; set; } = []; + List Filesystems { get; set; } = []; + List RealMedia { get; set; } = []; + List VirtualMedia { get; set; } = []; + List Devices { get; set; } = []; /// protected override async Task OnInitializedAsync() @@ -45,6 +93,98 @@ public partial class Stats .ToListAsync()).OrderBy(static os => os.name) .ToList(); + var osQuery = _ctx.OperatingSystems.GroupBy(static x => new + { + x.Name + }, + static x => x.Count) + .Select(static g => new + { + g.Key.Name, + Count = g.Sum() + }); + + _operatingSystemLabels = await osQuery.Select(static x => x.Name).ToArrayAsync(); + _operatingSystemCounts = await osQuery.Select(static x => x.Count).ToListAsync(); + + for(var i = 0; i < _operatingSystemLabels.Length; i++) + { + _operatingSystemLabels[i] = + DetectOS.GetPlatformName((PlatformID)Enum.Parse(typeof(PlatformID), _operatingSystemLabels[i])); + } + + _linuxLabels = await _ctx.OperatingSystems.Where(static o => o.Name == PlatformID.Linux.ToString()) + .OrderByDescending(static o => o.Count) + .Take(10) + .Select(static x => + $"{DetectOS.GetPlatformName(PlatformID.Linux, x.Version)}{(string.IsNullOrEmpty(x.Version) ? "" : " ")}{x.Version}") + .ToArrayAsync(); + + _linuxCounts = await _ctx.OperatingSystems.Where(static o => o.Name == PlatformID.Linux.ToString()) + .OrderByDescending(static o => o.Count) + .Take(10) + .Select(static x => x.Count) + .ToListAsync(); + + + if(_linuxLabels.Length >= 10) + { + _linuxLabels[9] = "Other"; + + _linuxCounts[9] = + _ctx.OperatingSystems.Where(static o => o.Name == PlatformID.Linux.ToString()) + .Sum(static o => o.Count) - + _linuxCounts.Take(9).Sum(); + } + + _macosLabels = await _ctx.OperatingSystems.Where(static o => o.Name == PlatformID.MacOSX.ToString()) + .OrderByDescending(static o => o.Count) + .Take(10) + .Select(static x => + $"{DetectOS.GetPlatformName(PlatformID.MacOSX, x.Version)}{(string.IsNullOrEmpty(x.Version) ? "" : " ")}{x.Version}") + .ToArrayAsync(); + + _macosCounts = await _ctx.OperatingSystems.Where(static o => o.Name == PlatformID.MacOSX.ToString()) + .OrderByDescending(static o => o.Count) + .Take(10) + .Select(static x => x.Count) + .ToListAsync(); + + + if(_macosLabels.Length >= 10) + { + _macosLabels[9] = "Other"; + + _macosCounts[9] = + _ctx.OperatingSystems.Where(static o => o.Name == PlatformID.MacOSX.ToString()) + .Sum(static o => o.Count) - + _macosCounts.Take(9).Sum(); + } + + _windowsLabels = await _ctx.OperatingSystems.Where(static o => o.Name == PlatformID.Win32NT.ToString()) + .OrderByDescending(static o => o.Count) + .Take(10) + .Select(static x => + $"{DetectOS.GetPlatformName(PlatformID.Win32NT, x.Version)}{(string.IsNullOrEmpty(x.Version) ? "" : " ")}{x.Version}") + .ToArrayAsync(); + + _windowsCounts = await _ctx.OperatingSystems.Where(static o => o.Name == PlatformID.Win32NT.ToString()) + .OrderByDescending(static o => o.Count) + .Take(10) + .Select(static x => x.Count) + .ToListAsync(); + + + if(_windowsLabels.Length >= 10) + { + _windowsLabels[9] = "Other"; + + _windowsCounts[9] = + _ctx.OperatingSystems.Where(static o => o.Name == PlatformID.Win32NT.ToString()) + .Sum(static o => o.Count) - + _windowsCounts.Take(9).Sum(); + } + Versions = (await _ctx.Versions.Select(static nvs => new NameValueStats { name = nvs.Name == "previous" ? "Previous than 3.4.99.0" : nvs.Name, @@ -53,16 +193,118 @@ public partial class Stats .ToListAsync()).OrderBy(static version => version.name) .ToList(); + _versionsLabels = await _ctx.Versions.OrderByDescending(static o => o.Count) + .Take(10) + .Select(static v => v.Name == "previous" ? "Previous than 3.4.99.0" : v.Name) + .ToArrayAsync(); + + _versionsCounts = await _ctx.Versions.OrderByDescending(static o => o.Count) + .Take(10) + .Select(static x => x.Count) + .ToListAsync(); + + if(_versionsLabels.Length >= 10) + { + _versionsLabels[9] = "Other"; + + _versionsCounts[9] = _ctx.Versions.Sum(static o => o.Count) - _versionsCounts.Take(9).Sum(); + } + Commands = await _ctx.Commands.OrderBy(static c => c.Name).ToListAsync(); + _commandsLabels = await _ctx.Commands.OrderByDescending(static o => o.Count) + .Take(10) + .Select(static v => v.Name) + .ToArrayAsync(); + + _commandsCounts = await _ctx.Commands.OrderByDescending(static o => o.Count) + .Take(10) + .Select(static x => x.Count) + .ToListAsync(); + + if(_commandsLabels.Length >= 10) + { + _commandsLabels[9] = "Other"; + + _commandsCounts[9] = _ctx.Commands.Sum(static o => o.Count) - _commandsCounts.Take(9).Sum(); + } + Filters = await _ctx.Filters.OrderBy(static filter => filter.Name).ToListAsync(); + _filtersLabels = await _ctx.Filters.OrderByDescending(static o => o.Count) + .Take(10) + .Select(static v => v.Name) + .ToArrayAsync(); + + _filtersCounts = await _ctx.Filters.OrderByDescending(static o => o.Count) + .Take(10) + .Select(static x => x.Count) + .ToListAsync(); + + if(_filtersLabels.Length >= 10) + { + _filtersLabels[9] = "Other"; + + _filtersCounts[9] = _ctx.Filters.Sum(static o => o.Count) - _filtersCounts.Take(9).Sum(); + } + MediaImages = await _ctx.MediaFormats.OrderBy(static format => format.Name).ToListAsync(); + _formatsLabels = await _ctx.MediaFormats.OrderByDescending(static o => o.Count) + .Take(10) + .Select(static v => v.Name) + .ToArrayAsync(); + + _formatsCounts = await _ctx.MediaFormats.OrderByDescending(static o => o.Count) + .Take(10) + .Select(static x => x.Count) + .ToListAsync(); + + if(_formatsLabels.Length >= 10) + { + _formatsLabels[9] = "Other"; + + _formatsCounts[9] = _ctx.MediaFormats.Sum(static o => o.Count) - _formatsCounts.Take(9).Sum(); + } + Partitions = await _ctx.Partitions.OrderBy(static partition => partition.Name).ToListAsync(); + _partitionsLabels = await _ctx.Partitions.OrderByDescending(static o => o.Count) + .Take(10) + .Select(static v => v.Name) + .ToArrayAsync(); + + _partitionsCounts = await _ctx.Partitions.OrderByDescending(static o => o.Count) + .Take(10) + .Select(static x => x.Count) + .ToListAsync(); + + if(_partitionsLabels.Length >= 10) + { + _partitionsLabels[9] = "Other"; + + _partitionsCounts[9] = _ctx.Partitions.Sum(static o => o.Count) - _partitionsCounts.Take(9).Sum(); + } + Filesystems = await _ctx.Filesystems.OrderBy(static filesystem => filesystem.Name).ToListAsync(); + _filesystemsLabels = await _ctx.Filesystems.OrderByDescending(static o => o.Count) + .Take(10) + .Select(static v => v.Name) + .ToArrayAsync(); + + _filesystemsCounts = await _ctx.Filesystems.OrderByDescending(static o => o.Count) + .Take(10) + .Select(static x => x.Count) + .ToListAsync(); + + if(_filesystemsLabels.Length >= 10) + { + _filesystemsLabels[9] = "Other"; + + _filesystemsCounts[9] = _ctx.Filesystems.Sum(static o => o.Count) - _filesystemsCounts.Take(9).Sum(); + } + RealMedia = []; VirtualMedia = []; @@ -119,6 +361,69 @@ 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(); + Media[] virtualMedias = await _ctx.Medias.Where(static o => !o.Real) + .OrderByDescending(static o => o.Count) + .Take(10) + .ToArrayAsync(); + + foreach(Media media in virtualMedias) + { + try + { + (string type, string subType) mediaType = + MediaType.MediaTypeToString((CommonTypes.MediaType)Enum.Parse(typeof(CommonTypes.MediaType), + media.Type)); + + media.Type = $"{mediaType.type} ({mediaType.subType})"; + } + catch + { + // Could not get media type/subtype pair from type, so just leave it as is + } + } + + _virtualMediaLabels = virtualMedias.Select(static v => v.Type).ToArray(); + _virtualMediaCounts = virtualMedias.Select(static x => x.Count).ToList(); + + if(_virtualMediaLabels.Length >= 10) + { + _virtualMediaLabels[9] = "Other"; + + _virtualMediaCounts[9] = _ctx.Medias.Where(static o => !o.Real).Sum(static o => o.Count) - + _virtualMediaCounts.Take(9).Sum(); + } + + Media[] realMedias = await _ctx.Medias.Where(static o => o.Real) + .OrderByDescending(static o => o.Count) + .Take(10) + .ToArrayAsync(); + + foreach(Media media in realMedias) + { + try + { + (string type, string subType) mediaType = + MediaType.MediaTypeToString((CommonTypes.MediaType)Enum.Parse(typeof(CommonTypes.MediaType), + media.Type)); + + media.Type = $"{mediaType.type} ({mediaType.subType})"; + } + catch + { + // Could not get media type/subtype pair from type, so just leave it as is + } + } + + _realMediaLabels = realMedias.Select(static v => v.Type).ToArray(); + _realMediaCounts = realMedias.Select(static x => x.Count).ToList(); + + if(_realMediaLabels.Length >= 10) + { + _realMediaLabels[9] = "Other"; + + _realMediaCounts[9] = _ctx.Medias.Where(static o => o.Real).Sum(static o => o.Count) - + _realMediaCounts.Take(9).Sum(); + } Devices = await _ctx.DeviceStats.Include(static deviceStat => deviceStat.Report) .Select(static device => new DeviceItem @@ -136,8 +441,223 @@ public partial class Stats .ThenBy(static device => device.Revision) .ThenBy(static device => device.Bus) .ToList(); + + var data = await _ctx.DeviceStats.Select(static d => d.Bus) + .Distinct() + .Select(deviceBus => new + { + deviceBus, + deviceBusCount = _ctx.DeviceStats.LongCount(d => d.Bus == deviceBus) + }) + .Select(static t => new + { + Name = t.deviceBus, + Count = t.deviceBusCount + }) + .ToListAsync(); + + _devicesByBusLabels = data.OrderByDescending(static o => o.Count).Take(10).Select(static v => v.Name).ToArray(); + _devicesByBusCounts = data.OrderByDescending(static o => o.Count).Take(10).Select(static x => x.Count).ToList(); + + if(_devicesByBusLabels.Length >= 10) + { + _devicesByBusLabels[9] = "Other"; + + _devicesByBusCounts[9] = data.Sum(static o => o.Count) - _devicesByBusCounts.Take(9).Sum(); + } + + List devices = await _ctx.DeviceStats + .Where(static d => d.Manufacturer != null && d.Manufacturer != "") + .ToListAsync(); + + data = devices.Select(static d => d.Manufacturer!.ToLowerInvariant()) + .Distinct() + .Select(manufacturer => new + { + manufacturer, + manufacturerCount = + devices.LongCount(d => d.Manufacturer?.ToLowerInvariant() == manufacturer) + }) + .Select(static t => new + { + Name = t.manufacturer, + Count = t.manufacturerCount + }) + .ToList(); + + _devicesByManufacturerLabels = + data.OrderByDescending(static o => o.Count).Take(10).Select(static v => v.Name).ToArray(); + + _devicesByManufacturerCounts = + data.OrderByDescending(static o => o.Count).Take(10).Select(static x => x.Count).ToList(); + + if(_devicesByManufacturerLabels.Length < 10) return; + + _devicesByManufacturerLabels[9] = "Other"; + _devicesByManufacturerCounts[9] = data.Sum(static o => o.Count) - _devicesByManufacturerCounts.Take(9).Sum(); } +#pragma warning disable CS8604 // Possible null reference argument. + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if(_isAlreadyInitialised) return; + _isAlreadyInitialised = true; + + await + Task.WhenAll(HandleRedraw(_operatingSystemsChart, _operatingSystemLabels, GetOperatingSystemsChartDataset), + HandleRedraw(_linuxChart, _linuxLabels, GetLinuxChartDataset), + HandleRedraw(_macosChart, _macosLabels, GetMacosChartDataset), + HandleRedraw(_windowsChart, _windowsLabels, GetWindowsChartDataset), + HandleRedraw(_versionsChart, _versionsLabels, GetVersionsChartDataset), + HandleRedraw(_commandsChart, _commandsLabels, GetCommandsChartDataset), + HandleRedraw(_filtersChart, _filtersLabels, GetFiltersChartDataset), + HandleRedraw(_formatsChart, _formatsLabels, GetFormatsChartDataset), + HandleRedraw(_partitionsChart, _partitionsLabels, GetPartitionsChartDataset), + HandleRedraw(_filesystemsChart, _filesystemsLabels, GetFilesystemsChartDataset), + HandleRedraw(_virtualMediaChart, _virtualMediaLabels, GetVirtualMediaChartDataset), + HandleRedraw(_realMediaChart, _realMediaLabels, GetRealMediaChartDataset), + HandleRedraw(_devicesByBusChart, _devicesByBusLabels, GetDevicesByBusChartDataset), + HandleRedraw(_devicesByManufacturerChart, + _devicesByManufacturerLabels, + GetDevicesByManufacturerChartDataset)); + } +#pragma warning restore CS8604 // Possible null reference argument. + + static async Task HandleRedraw( + BaseChart chart, string[] labels, Func getDataSet) + where TDataSet : ChartDataset where TOptions : ChartOptions where TModel : ChartModel + { + await chart.Clear(); + + await chart.AddLabelsDatasetsAndUpdate(labels, getDataSet()); + } + + PieChartDataset GetOperatingSystemsChartDataset() => new() + { + Label = "Operating systems", + Data = _operatingSystemCounts, + BackgroundColor = _backgroundColors, + BorderColor = _borderColors, + BorderWidth = 1 + }; + + PieChartDataset GetLinuxChartDataset() => new() + { + Label = $"Top {_linuxLabels.Length} Linux versions", + Data = _linuxCounts, + BackgroundColor = _backgroundColors, + BorderColor = _borderColors, + BorderWidth = 1 + }; + + PieChartDataset GetMacosChartDataset() => new() + { + Label = $"Top {_macosLabels.Length} macOS versions", + Data = _macosCounts, + BackgroundColor = _backgroundColors, + BorderColor = _borderColors, + BorderWidth = 1 + }; + + PieChartDataset GetWindowsChartDataset() => new() + { + Label = $"Top {_windowsLabels.Length} Windows versions", + Data = _windowsCounts, + BackgroundColor = _backgroundColors, + BorderColor = _borderColors, + BorderWidth = 1 + }; + + PieChartDataset GetVersionsChartDataset() => new() + { + Label = $"Top {_versionsLabels.Length} Aaru versions", + Data = _versionsCounts, + BackgroundColor = _backgroundColors, + BorderColor = _borderColors, + BorderWidth = 1 + }; + + PieChartDataset GetCommandsChartDataset() => new() + { + Label = $"Top {_commandsLabels.Length} used commands", + Data = _commandsCounts, + BackgroundColor = _backgroundColors, + BorderColor = _borderColors, + BorderWidth = 1 + }; + + PieChartDataset GetFiltersChartDataset() => new() + { + Label = $"Top {_filtersLabels.Length} filters found", + Data = _filtersCounts, + BackgroundColor = _backgroundColors, + BorderColor = _borderColors, + BorderWidth = 1 + }; + + PieChartDataset GetFormatsChartDataset() => new() + { + Label = $"Top {_formatsLabels.Length} media image formats found", + Data = _formatsCounts, + BackgroundColor = _backgroundColors, + BorderColor = _borderColors, + BorderWidth = 1 + }; + + PieChartDataset GetPartitionsChartDataset() => new() + { + Label = $"Top {_partitionsLabels.Length} partitioning schemes found", + Data = _partitionsCounts, + BackgroundColor = _backgroundColors, + BorderColor = _borderColors, + BorderWidth = 1 + }; + + PieChartDataset GetFilesystemsChartDataset() => new() + { + Label = $"Top {_filesystemsLabels.Length} filesystems found", + Data = _filesystemsCounts, + BackgroundColor = _backgroundColors, + BorderColor = _borderColors, + BorderWidth = 1 + }; + + PieChartDataset GetVirtualMediaChartDataset() => new() + { + Label = $"Top {_virtualMediaLabels.Length} media types found in images", + Data = _virtualMediaCounts, + BackgroundColor = _backgroundColors, + BorderColor = _borderColors, + BorderWidth = 1 + }; + + PieChartDataset GetRealMediaChartDataset() => new() + { + Label = $"Top {_realMediaLabels.Length} media types found in devices", + Data = _realMediaCounts, + BackgroundColor = _backgroundColors, + BorderColor = _borderColors, + BorderWidth = 1 + }; + + PieChartDataset GetDevicesByBusChartDataset() => new() + { + Label = $"Top {_devicesByBusLabels.Length} devices by bus", + Data = _devicesByBusCounts, + BackgroundColor = _backgroundColors, + BorderColor = _borderColors, + BorderWidth = 1 + }; + + PieChartDataset GetDevicesByManufacturerChartDataset() => new() + { + Label = $"Top {_devicesByManufacturerLabels.Length} devices by manufacturers", + Data = _devicesByManufacturerCounts, + BackgroundColor = _backgroundColors, + BorderColor = _borderColors, + BorderWidth = 1 + }; + static string GetPlatformName(string name, string version) => DetectOS.GetPlatformName((PlatformID)Enum.Parse(typeof(PlatformID), name), version); } \ No newline at end of file