diff --git a/MP.Stats/Components/ChartUserLog.razor b/MP.Stats/Components/ChartUserLog.razor
new file mode 100644
index 00000000..40f2a97c
--- /dev/null
+++ b/MP.Stats/Components/ChartUserLog.razor
@@ -0,0 +1,32 @@
+
+ @if (RawData == null || RawData.Count == 0)
+ {
+
+ }
+ else
+ {
+
+
+ @foreach (var item in @ParetoData)
+ {
+ -
+ @item.label
+ @item.value
+
+ }
+
+
+
+ }
+
\ No newline at end of file
diff --git a/MP.Stats/Components/ChartUserLog.razor.cs b/MP.Stats/Components/ChartUserLog.razor.cs
new file mode 100644
index 00000000..61bc0c51
--- /dev/null
+++ b/MP.Stats/Components/ChartUserLog.razor.cs
@@ -0,0 +1,253 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Blazorise.Charts;
+using Microsoft.AspNetCore.Components;
+using MP.Stats.Data;
+
+namespace MP.Stats.Components
+{
+ public partial class ChartUserLog
+ {
+ #region Protected Fields
+
+ protected const string EsitoKO = "Esito: Non Passato";
+
+ protected const string EsitoOK = "Esito: OK";
+
+ protected object lineChartOptions = new
+ {
+ Scales = new
+ {
+ XAxes = new object[]
+ {
+ new {
+ Display = true
+ }
+ },
+ YAxes = new object[]
+ {
+ new {
+ Display = true,
+ ticks= new {
+ suggestedMin = 0
+ }
+ }
+ }
+ },
+ Tooltips = new
+ {
+ Mode = "nearest",
+ Intersect = false
+ },
+ Hover = new
+ {
+ Mode = "nearest",
+ Intersect = false
+ },
+ Animation = false,
+ AspectRatio = 4.9
+ };
+
+ protected object pieChartOptions = new
+ {
+ Scales = new
+ {
+ XAxes = new object[]
+ {
+ new {
+ Display = false
+ }
+ },
+ YAxes = new object[]
+ {
+ new {
+ Display = false
+ }
+ }
+ },
+ Legend = new
+ {
+ Display = false
+ },
+ Tooltips = new
+ {
+ Mode = "nearest",
+ Intersect = false
+ },
+ Hover = new
+ {
+ Mode = "nearest",
+ Intersect = false
+ },
+ Animation = false,
+ AspectRatio = 1
+ };
+
+ protected PieChart PieVC;
+ protected LineChart TimeSerieVC;
+
+ #endregion Protected Fields
+
+ #region Protected Properties
+
+ protected SelectData _currFilter { get; set; } = new SelectData();
+
+ protected List _rawData { get; set; } = new List();
+
+ [Inject]
+ protected MessageService MessageService { get; set; }
+
+ protected List ParetoData { get; set; } = new List();
+
+ [Inject]
+ protected MpStatsService StatService { get; set; }
+
+ protected List TSData { get; set; } = new List();
+
+ #endregion Protected Properties
+
+ #region Public Properties
+
+ [Parameter]
+ public List RawData
+ {
+ get => _rawData;
+ set
+ {
+ // salvo valori
+ _rawData = value;
+ if (value != null)
+ {
+ // ricalcolo charting data
+ recalcData();
+ var dataReload = Task.Run(async () =>
+ {
+ await HandleRedraw();
+ });
+ }
+ }
+ }
+
+ #endregion Public Properties
+
+ #region Private Methods
+
+ private PieChartDataset GetBarChartDataset()
+ {
+ var answ = new PieChartDataset
+ {
+ Label = "Numero Controlli",
+ Data = ParetoData.Select(x => x.value).ToList(),
+ BackgroundColor = getPieColors(0.4f),
+ BorderColor = getPieColors(1f),
+ HoverBorderWidth = 3
+ };
+ return answ;
+ }
+
+ private List GetBarChartLabels()
+ {
+ var answ = ParetoData.Select(x => x.label).ToList();
+ return answ;
+ }
+
+ ///
+ /// Elenco 2 linee x controli KO /KO
+ ///
+ ///
+ private LineChartDataset GetLineChartDataset()
+ {
+ var answ = new LineChartDataset
+ {
+ Label = "Numero controlli",
+ Data = TSData.Select(x => x.Value).ToList(),
+ BorderColor = getLineColors(1f),
+ Fill = true,
+ PointRadius = 2,
+ LineTension = 0,
+ BorderDash = new List { }
+ };
+ return answ;
+ }
+
+ private List GetLineChartLabels()
+ {
+ var answ = TSData.Select(x => x.TLabel.ToString("ddd dd.MM")).ToList();
+ return answ;
+ }
+
+ private void recalcData()
+ {
+ if (RawData != null)
+ {
+ ParetoData = RawData
+ .GroupBy(p => p.EsitoOk)
+ .Select(y => new ChartKV() { label = y.First().EsitoOk ? EsitoOK : EsitoKO, value = y.Count() })
+ .OrderByDescending(x => x.value)
+ .ToList();
+
+ TSData = RawData
+ .GroupBy(x => x.DataOra.Date)
+ .Select(y => new ChartTS() { TLabel = y.First().DataOra.Date, Value = y.Count() })
+ .OrderBy(x => x.TLabel)
+ .ToList();
+ }
+ }
+
+ #endregion Private Methods
+
+ #region Protected Methods
+
+ ///
+ /// Genera colori sfondo 33% rosso / arancione / giallo
+ ///
+ ///
+ ///
+ protected List getLineColors(float alpha)
+ {
+ List answ = new List();
+ answ.Add(ChartColor.FromRgba(54, 82, 254, alpha));
+ return answ;
+ }
+
+ ///
+ /// Genera colori sfondo 33% rosso / arancione / giallo
+ ///
+ ///
+ ///
+ protected List getPieColors(float alpha)
+ {
+ List answ = new List();
+ foreach (var item in ParetoData)
+ {
+ if (item.label == EsitoOK)
+ {
+ answ.Add(ChartColor.FromRgba(54, 254, 82, alpha));
+ }
+ else
+ {
+ answ.Add(ChartColor.FromRgba(254, 82, 65, alpha));
+ }
+ }
+ return answ;
+ }
+
+ protected async Task HandleRedraw()
+ {
+ if (PieVC != null)
+ {
+ await PieVC.Clear();
+ await PieVC.AddLabelsDatasetsAndUpdate(GetBarChartLabels(), GetBarChartDataset());
+ }
+ if (TimeSerieVC != null)
+ {
+ await TimeSerieVC.Clear();
+ await TimeSerieVC.AddLabelsDatasetsAndUpdate(GetLineChartLabels(), GetLineChartDataset());
+ }
+ }
+
+ #endregion Protected Methods
+ }
+}
\ No newline at end of file