diff options
Diffstat (limited to 'Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics')
30 files changed, 3245 insertions, 432 deletions
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/App.config b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/App.config index ed4582d5b..75b63289d 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/App.config +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/App.config @@ -22,7 +22,7 @@ </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" /> @@ -30,27 +30,27 @@ </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" /> + <bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.Security.Cryptography.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.Console" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.Diagnostics.StackTrace" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.Reactive.Core" publicKeyToken="94bc3704cddfc263" culture="neutral" /> @@ -74,7 +74,7 @@ </dependentAssembly> <dependentAssembly> <assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-3.19.8.16603" newVersion="3.19.8.16603" /> + <bindingRedirect oldVersion="0.0.0.0-5.0.5.0" newVersion="5.0.5.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" /> @@ -92,6 +92,10 @@ <assemblyIdentity name="System.Text.Encoding.CodePages" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" /> </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Z.EntityFramework.Extensions" publicKeyToken="59b66d028979105b" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.50.0" newVersion="4.0.50.0" /> + </dependentAssembly> </assemblyBinding> </runtime> </configuration>
\ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/CollectionConverter .cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/CollectionConverter .cs new file mode 100644 index 000000000..2d9a3cfd9 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/CollectionConverter .cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace Tango.MachineStudio.Statistics.Converters +{ + public class CollectionConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if(value != null && value is System.Collections.IEnumerable) + { + var colection = value as System.Collections.IEnumerable; + var text = new StringBuilder(); + foreach(var val in colection) + { + string visibleText = val.ToString(); + if(val is bool && parameter is string) + { + string[] tokens = (parameter as string).Split(','); + if(tokens.Count() > 1) + { + visibleText = (bool)val == true ? tokens[1] : tokens[0]; + } + } + text.Append(visibleText); + text.Append("/"); + } + string str_text = text.ToString(); + if(str_text.Length > 1) + { + str_text = str_text.Remove(str_text.Length - 1); + } + return str_text; + } + return ""; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/DateTimeToStringFormatConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/DateTimeToStringFormatConverter.cs new file mode 100644 index 000000000..6b5154ce3 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/DateTimeToStringFormatConverter.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace Tango.MachineStudio.Statistics.Converters +{ + public class DateTimeToStringFormatConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value != null) + { + return ((TimeSpan)value).ToString(@"hh\:mm\:ss"); + } + else + { + return TimeSpan.FromSeconds(0).ToString(@"hh\:mm\:ss"); + } + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/JobLengthConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/JobLengthConverter.cs new file mode 100644 index 000000000..cd928d9c9 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/JobLengthConverter.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace Tango.MachineStudio.Statistics.Converters +{ + public class JobLengthConverter : IMultiValueConverter + { + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + try + { + if (values != null && values.Count() == 3) + { + double length = (double)values[0]; + double endPoint = (double)values[1]; + double width = (double)values[2]; + var v = Math.Round((endPoint / length) * width, MidpointRounding.AwayFromZero); + + if (double.IsInfinity(v)) + { + return 0d; + } + return v; + } + } + catch { } + + return 0d; + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/LiquidQuantityToFormatStringConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/LiquidQuantityToFormatStringConverter.cs new file mode 100644 index 000000000..3ab013ab3 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/LiquidQuantityToFormatStringConverter.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + + +namespace Tango.MachineStudio.Statistics.Converters +{ + public class LiquidQuantityToFormatStringConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + try + { + string format = ""; + if (parameter is string) + { + format = (string)parameter; + } + + var longValue = System.Convert.ToUInt64(value.ToString()); + double liters_val = (longValue / 1000000000d); + double cc_val = (longValue / 1000000d); + double dispensers_val = (longValue / 130000000d); + string tooltip = String.Format($"Nanoliters: {longValue.ToString(format)}\nCubic Centimeters: {cc_val}\nLiters: {liters_val}\nDispensers: {dispensers_val}"); + return tooltip; + } + catch { } + + return ""; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/LiquidTypeToColorConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/LiquidTypeToColorConverter.cs new file mode 100644 index 000000000..b36bf608e --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/LiquidTypeToColorConverter.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using System.Windows.Media; +using Tango.BL; +using Tango.BL.Enumerations; + +namespace Tango.MachineStudio.Statistics.Converters +{ + public class LiquidTypeToColorConverter : IValueConverter + { + private static Dictionary<LiquidTypes,Color> liquidTypes; + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (liquidTypes == null) + { + liquidTypes = new Dictionary<LiquidTypes, Color>(); + + foreach (var type in ObservablesStaticCollections.Instance.LiquidTypes.ToList()) + { + liquidTypes.Add(type.Type, type.LiquidTypeColor); + } + } + + if (value != null) + { + return liquidTypes[(LiquidTypes)value]; + } + + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/MidTankLevelToElementHeightConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/MidTankLevelToElementHeightConverter.cs new file mode 100644 index 000000000..de002046e --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/MidTankLevelToElementHeightConverter.cs @@ -0,0 +1,41 @@ +using System; +using System.Globalization; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace Tango.MachineStudio.Statistics.Converters +{ + public class MidTankLevelToElementHeightConverter : IMultiValueConverter + { + public const double MAX_QUANTITY = 130000000; + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + try + { + double parentActualHeight; + Double.TryParse(values[0].ToString(), out parentActualHeight); + double quantity; + Double.TryParse(values[1].ToString(), out quantity); + + double midTankLevel = (double)Math.Min(quantity, MAX_QUANTITY); + double delta = ((midTankLevel / MAX_QUANTITY) * parentActualHeight); + if (quantity > 0 && midTankLevel < (MAX_QUANTITY/10))// if quantity < 10|% set 2 pixel + delta = 2.0; + var test = delta; + return parentActualHeight - delta; + } + catch + { + return 0d; + } + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/NanoLiterToLiterFormatConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/NanoLiterToLiterFormatConverter.cs new file mode 100644 index 000000000..97f4ec066 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/NanoLiterToLiterFormatConverter.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace Tango.MachineStudio.Statistics.Converters +{ + public class NanoLiterToLiterFormatConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + try + { + var longValue = System.Convert.ToUInt64(value.ToString()); + double val = (longValue / 1000000000d); + if (parameter is string) + { + string format= (string)parameter; + return val.ToString(format); + } + return val.ToString(); + } + catch { } + + return ""; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/StringToBoolYesNoNullConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/StringToBoolYesNoNullConverter.cs new file mode 100644 index 000000000..f7633a7d0 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/StringToBoolYesNoNullConverter.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; +using System.Windows.Data; + +namespace Tango.MachineStudio.Statistics.Converters +{ + public class StringToBoolYesNoNullConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if(value is bool) + { + return (bool)value ? "Yes" : "No"; + } + return "Null"; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + //throw new NotImplementedException(); + if (value is ComboBoxItem) + { + string str_val = ((ComboBoxItem)value).Content.ToString(); + if (str_val.ToUpper() == "NO") + return false; + if (str_val.ToUpper() == "YES") + return true; + } + return null; + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/StringToFirstLetterConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/StringToFirstLetterConverter.cs new file mode 100644 index 000000000..a1c9561b9 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/StringToFirstLetterConverter.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace Tango.MachineStudio.Statistics.Converters +{ + public class StringToFirstLetterConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value != null && value.ToString().Length > 1) + { + return value.ToString().First().ToString(); + } + else + { + return value; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +}
\ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/TooltipLiquidQuantityFormatConverter.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/TooltipLiquidQuantityFormatConverter.cs new file mode 100644 index 000000000..6c4d1347f --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Converters/TooltipLiquidQuantityFormatConverter.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +namespace Tango.MachineStudio.Statistics.Converters +{ + class TooltipLiquidQuantityFormatConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + try + { + string format = ""; + if (parameter is string) + { + format = (string)parameter; + } + var longValue = System.Convert.ToUInt64(value.ToString()); + decimal liters_val = (decimal)(longValue / 1000000000d); + decimal cc_val = (decimal)(longValue / 1000000d); + decimal dispensers_val = (decimal)(longValue / 130000000d); + string tooltip = String.Format($"Nanoliters: {longValue.ToString(format)}\nCubic Centimeters: {cc_val}\nLiters: {liters_val}\nDispensers: {dispensers_val}"); + return tooltip; + } + catch { } + + return ""; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/ExcelModel.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/ExcelModel.cs new file mode 100644 index 000000000..f06b9fe60 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/ExcelModel.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.MachineStudio.Statistics.Models +{ + public class ExcelModel + { + public String ID { get; set; } + public String Machine { get; set; } + public String User { get; set; } + public String JobName { get; set; } + public String Thread { get; set; } + public String Length { get; set; } + public String Source { get; set; } + public String UploadDuration { get; set; } + public String HeatingDuration { get; set; } + public String StartTime { get; set; } + public String IsGradient { get; set; } + public String GR { get; set; } + public String Status { get; set; } + public String EndTime { get; set; } + public String EndPosition { get; set; } + public String Cyan { get; set; } + public String Magenta { get; set; } + public String Yellow { get; set; } + public String Black { get; set; } + public String Transparent { get; set; } + public String Lubricant { get; set; } + public String Cleaner { get; set; } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/JobRunModel.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/JobRunModel.cs new file mode 100644 index 000000000..83897ca16 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/JobRunModel.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; + +namespace Tango.MachineStudio.Statistics.Models +{ + public class JobRunModel + { + public JobRun JobRun { get; set; } + + public Machine Machine { get; set; } + + public User User { get; set; } + + public TimeSpan? UploadDuration { get; set; } + + public TimeSpan? HeatingDuration { get; set; } + + public RmlModel Rml { get; set; } + + public void Init() + { + if (JobRun.HeatingStartDate != null) + { + UploadDuration = JobRun.HeatingStartDate - JobRun.StartDate; + } + + if (JobRun.ActualStartDate != null && JobRun.HeatingStartDate != null) + { + HeatingDuration = JobRun.ActualStartDate - JobRun.HeatingStartDate; + } + + + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/JobRunStatisticsModel.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/JobRunStatisticsModel.cs new file mode 100644 index 000000000..98b719cae --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/JobRunStatisticsModel.cs @@ -0,0 +1,45 @@ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL; +using Tango.BL.Entities; +using Tango.Core.ExtensionMethods; + +namespace Tango.MachineStudio.Statistics.Models +{ + public class JobRunStatisticsModel : JobRun + { + private static Dictionary<String, Machine> _machines = new Dictionary<string, Machine>(); + + public JobRunStatisticsModel() + { + + } + + public JobRunStatisticsModel(JobRun run) + { + run.MapPropertiesTo(this, MappingFlags.NoReferenceTypes); + } + + public Task LoadMachine(ObservablesContext context) + { + return Task.Factory.StartNew(() => + { + if (!_machines.ContainsKey(MachineGuid)) + { + Machine = context.Machines.SingleOrDefault(x => x.Guid == MachineGuid); + _machines.Add(MachineGuid, Machine); + } + else + { + Machine = _machines[MachineGuid]; + } + }); + } + + public Machine Machine { get; set; } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/RmlModel.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/RmlModel.cs new file mode 100644 index 000000000..789779e42 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/RmlModel.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.MachineStudio.Statistics.Models +{ + public class RmlModel + { + public string Guid { get; set; } + + public string Name { get; set; } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/StatisticsValueCollection.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/StatisticsValueCollection.cs new file mode 100644 index 000000000..b5615e4d1 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/StatisticsValueCollection.cs @@ -0,0 +1,319 @@ +using LiveCharts; +using LiveCharts.Wpf; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using System.Windows.Media; +using Tango.BL.Enumerations; +using Tango.BL.ValueObjects; +using Tango.Core; +using System.Windows.Media; +using System.Windows; + +namespace Tango.MachineStudio.Statistics.Models +{ + public class StatisticsValue + { + public string Name { get; set; } + + public object Value { get; set; } + + public string Unit { get; set; } + } + public class MoreValue + { + public string Text { get; set; } + } + + public class StatisticsValueCollection : ExtendedObject + { + private List<Color> _pieColors; + + #region Properties + + private ObservableCollection<StatisticsValue> _statisticsCollection; + + /// <summary> + /// Gets or sets the statistics collection of StatisticsValue object. + /// </summary> + public ObservableCollection<StatisticsValue> StatisticsCollection + { + get { return _statisticsCollection; } + set + { + _statisticsCollection = value; + RaisePropertyChangedAuto(); + } + } + + private List<StatisticsValue> _threadConsumptionPerThread; + /// <summary> + /// Gets or sets the thread consumption per thread list. + /// </summary> + public List<StatisticsValue> ThreadConsumptionPerThread + { + get { return _threadConsumptionPerThread; } + set { _threadConsumptionPerThread = value; RaisePropertyChangedAuto(); } + } + + /// <summary> + /// Gets or sets the thread consumption per thread collection. + /// </summary> + public CompositeCollection ThreadConsumptionPerThreadCollection { get; set; } + + private LabeledSeriesCollection _pieJobSource; + + /// <summary> + /// Gets or sets the pie job source. + /// </summary> + public LabeledSeriesCollection PieJobSource + { + get { return _pieJobSource; } + set { _pieJobSource = value; RaisePropertyChangedAuto(); } + } + + private LabeledSeriesCollection _pieJobRunStatus; + + /// <summary> + /// Gets or sets the pie job run status. + /// </summary> + public LabeledSeriesCollection PieJobRunStatus + { + get { return _pieJobRunStatus; } + set { _pieJobRunStatus = value; RaisePropertyChangedAuto(); } + } + + private LabeledSeriesCollection _pieGradientSolid; + + /// <summary> + /// Gets or sets the pie gradient solid. + /// </summary> + public LabeledSeriesCollection PieGradientSolid + { + get { return _pieGradientSolid; } + set { _pieGradientSolid = value; RaisePropertyChangedAuto(); } + } + + private List<TotalLiquidQuantityModel> _liquidQuantities; + + /// <summary> + /// Gets or sets the liquid quantities. + /// </summary> + public List<TotalLiquidQuantityModel> LiquidQuantities + { + get + { + if (_liquidQuantities == null) + { + _liquidQuantities = new List<TotalLiquidQuantityModel>(); + } + return _liquidQuantities; + } + set + { _liquidQuantities = value; RaisePropertyChangedAuto(); } + } + + private ulong _totalLiquidQuantities; + + /// <summary> + /// Gets or sets the total liquid quantities. + /// </summary> + public ulong TotalLiquidQuantities + { + get { return _totalLiquidQuantities; } + set { _totalLiquidQuantities = value; RaisePropertyChangedAuto(); } + } + + #endregion + + public StatisticsValueCollection() + { + StatisticsCollection = new ObservableCollection<StatisticsValue>(); + ThreadConsumptionPerThread = new List<StatisticsValue>(); + ThreadConsumptionPerThreadCollection = new CompositeCollection(); + + _pieColors = new List<Color>(); + _pieColors.Add(((SolidColorBrush)Application.Current.Resources["RedBrush500"]).Color); + _pieColors.Add(((SolidColorBrush)Application.Current.Resources["OrangeBrush"]).Color); + _pieColors.Add(((SolidColorBrush)Application.Current.Resources["GreenBrush"]).Color); + _pieColors.Add(((SolidColorBrush)Application.Current.Resources["BlueBrush100"]).Color); + _pieColors.Add(Color.FromRgb(255, 216, 76)); + + + PieJobSource = new LabeledSeriesCollection() + { + Title = "PPC/MS", + SeriesColors = _pieColors, + }; + PieJobRunStatus = new LabeledSeriesCollection() + { + Title = "Failed/Aborted/Completed", + SeriesColors = _pieColors, + }; + PieGradientSolid = new LabeledSeriesCollection() + { + Title = "Gradient/Solid", + SeriesColors = _pieColors, + }; + } + + /// <summary> + /// Cleans all values. + /// </summary> + public void Clean() + { + StatisticsCollection.Clear(); + ThreadConsumptionPerThreadCollection.Clear(); + ThreadConsumptionPerThread.Clear(); + PieJobSource.SeriesCollection.Clear(); + PieJobRunStatus.SeriesCollection.Clear(); + PieGradientSolid.SeriesCollection.Clear(); + } + + /// <summary> + /// Adds the statistics value. + /// </summary> + public void AddStatisticsValue(string name, object value, string unit) + { + StatisticsCollection.Add(new StatisticsValue() { Name = name, Value = value, Unit = unit }); + RaisePropertyChanged("StatisticsCollection"); + } + + /// <summary> + /// Creates the thread consumption per thread. + /// </summary> + public void CreateThreadConsumptionPerThread(List<StatisticsValue> threads) + { + ThreadConsumptionPerThreadCollection.Add(new CollectionContainer() { Collection = threads.Take(threads.Count() > 2 ? 2 : threads.Count()) }); + if (threads.Count() > 2) + { + ThreadConsumptionPerThreadCollection.Add(new CollectionContainer() { Collection = new List<MoreValue>() { new MoreValue() { Text = "More threads ..." } } }); + ThreadConsumptionPerThread = threads.Skip(2).ToList(); + } + + RaisePropertyChanged("ThreadConsumptionPerThreadCollection"); + } + + #region GeneratePieChart + Func<ChartPoint, string> labelPoint = chartPoint => + string.Format("{0} ({1:P})", chartPoint.Y, chartPoint.Participation); + + public void GeneratePieJobSource(int PPCCount, int MSCount) + { + var series = new PieSeries() + { + Title = "PPC", + Values = new ChartValues<int>() { PPCCount }, + Fill = new SolidColorBrush(_pieColors[4]), + DataLabels = true, + ToolTip = "", + LabelPoint = labelPoint + + }; + + PieJobSource.SeriesCollection.Add(series); + + series = new PieSeries() + { + Title = "MS", + Values = new ChartValues<int>() { MSCount }, + Fill = new SolidColorBrush(_pieColors[3]), + DataLabels = true, + ToolTip = "", + LabelPoint = labelPoint + }; + PieJobSource.SeriesCollection.Add(series); + RaisePropertyChanged("PieJobSource"); + } + + public void GeneratePieJobRunStatus(int failedCount, int abortedCount, int completedCount) + { + var series = new PieSeries() + { + Title = "Failed", + Values = new ChartValues<int>() { failedCount }, + Fill = new SolidColorBrush(_pieColors[0]), + DataLabels = true, + ToolTip = "", + LabelPoint = labelPoint + }; + + PieJobRunStatus.SeriesCollection.Add(series); + + series = new PieSeries() + { + Title = "Aborted", + Values = new ChartValues<int>() { abortedCount }, + Fill = new SolidColorBrush(_pieColors[1]), + DataLabels = true, + ToolTip = "", + LabelPoint = labelPoint, + + }; + PieJobRunStatus.SeriesCollection.Add(series); + + series = new PieSeries() + { + Title = "Completed", + Values = new ChartValues<int>() { completedCount }, + Fill = new SolidColorBrush(_pieColors[2]), + DataLabels = true, + ToolTip = "", + LabelPoint = labelPoint + }; + PieJobRunStatus.SeriesCollection.Add(series); + + RaisePropertyChanged("PieJobRunStatus"); + } + + public void GeneratePieGradientSolid(int gradientCount, int solidCount) + { + var series = new PieSeries() + { + Title = "Solid", + Values = new ChartValues<int>() { solidCount }, + Fill = new SolidColorBrush(_pieColors[4]), + DataLabels = true, + ToolTip = "", + LabelPoint = labelPoint + }; + PieGradientSolid.SeriesCollection.Add(series); + + series = new PieSeries() + { + Title = "Gradient", + Values = new ChartValues<int>() { gradientCount }, + Fill = new SolidColorBrush(_pieColors[3]), + DataLabels = true, + ToolTip = "", + LabelPoint = labelPoint + + }; + + PieGradientSolid.SeriesCollection.Add(series); + + + RaisePropertyChanged("PieGradientSolid"); + } + #endregion + + /// <summary> + /// Generates the statistics liquid quantity and TotalLiquidQuantities. + /// </summary> + public void GenerateStatisticsLiquidQuantity(List<TotalLiquidQuantityModel> liquidQuantities) + { + LiquidQuantities = liquidQuantities; + TotalLiquidQuantities = 0; + + foreach (var item in liquidQuantities) + { + TotalLiquidQuantities += (ulong)item.Quantity; + } + } + + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/TotalLiquidQuantityModel.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/TotalLiquidQuantityModel.cs new file mode 100644 index 000000000..b5e2e9fb7 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Models/TotalLiquidQuantityModel.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Enumerations; + +namespace Tango.MachineStudio.Statistics.Models +{ + public class TotalLiquidQuantityModel + { + public LiquidTypes LiquidType { get; set; } + public ulong Quantity { get; set; } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Tango.MachineStudio.Statistics.csproj b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Tango.MachineStudio.Statistics.csproj index 243663c5a..4ce0ea87d 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Tango.MachineStudio.Statistics.csproj +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Tango.MachineStudio.Statistics.csproj @@ -38,6 +38,9 @@ <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"> <HintPath>..\..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll</HintPath> </Reference> + <Reference Include="Google.Protobuf, Version=3.4.1.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\Google.Protobuf.3.4.1\lib\net45\Google.Protobuf.dll</HintPath> + </Reference> <Reference Include="LiveCharts, Version=0.9.7.0, Culture=neutral, PublicKeyToken=0bc1f845d1ebb8df, processorArchitecture=MSIL"> <HintPath>..\..\..\packages\LiveCharts.0.9.7\lib\net45\LiveCharts.dll</HintPath> </Reference> @@ -73,13 +76,38 @@ <Reference Include="PresentationFramework" /> </ItemGroup> <ItemGroup> + <Compile Include="Converters\CollectionConverter .cs" /> + <Compile Include="Converters\DateTimeToStringFormatConverter.cs" /> + <Compile Include="Converters\JobLengthConverter.cs" /> + <Compile Include="Converters\LiquidQuantityToFormatStringConverter.cs" /> + <Compile Include="Converters\LiquidTypeToColorConverter.cs" /> + <Compile Include="Converters\MidTankLevelToElementHeightConverter.cs" /> + <Compile Include="Converters\NanoLiterToLiterFormatConverter.cs" /> + <Compile Include="Converters\StringToBoolYesNoNullConverter.cs" /> + <Compile Include="Converters\StringToFirstLetterConverter.cs" /> + <Compile Include="Converters\TooltipLiquidQuantityFormatConverter.cs" /> + <Compile Include="Models\ExcelModel.cs" /> + <Compile Include="Models\TotalLiquidQuantityModel.cs" /> + <Compile Include="Models\JobRunModel.cs" /> + <Compile Include="Models\JobRunStatisticsModel.cs" /> <Compile Include="Models\LabeledSeriesCollection.cs" /> + <Compile Include="Models\RmlModel.cs" /> + <Compile Include="Models\StatisticsValueCollection.cs" /> <Compile Include="Tooltips\PieChartTooltipControl.xaml.cs"> <DependentUpon>PieChartTooltipControl.xaml</DependentUpon> </Compile> <Compile Include="StatisticsModule.cs" /> + <Compile Include="ValidationRules\DateExpiredRule.cs" /> <Compile Include="ViewModelLocator.cs" /> + <Compile Include="ViewModels\ChartsViewVM.cs" /> + <Compile Include="ViewModels\JobRunsViewVM.cs" /> <Compile Include="ViewModels\MainViewVM.cs" /> + <Compile Include="Views\ChartsView.xaml.cs"> + <DependentUpon>ChartsView.xaml</DependentUpon> + </Compile> + <Compile Include="Views\JobRunsView.xaml.cs"> + <DependentUpon>JobRunsView.xaml</DependentUpon> + </Compile> <Compile Include="Views\MainView.xaml.cs"> <DependentUpon>MainView.xaml</DependentUpon> </Compile> @@ -94,6 +122,14 @@ <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </Page> + <Page Include="Views\ChartsView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Views\JobRunsView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> <Page Include="Views\MainView.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> @@ -128,6 +164,10 @@ <Resource Include="Images\statistics.png" /> </ItemGroup> <ItemGroup> + <ProjectReference Include="..\..\..\SideChains\Tango.AutoComplete\Tango.AutoComplete.csproj"> + <Project>{bb2abb74-ba58-4812-83aa-ec8171f42df4}</Project> + <Name>Tango.AutoComplete</Name> + </ProjectReference> <ProjectReference Include="..\..\..\Tango.BL\Tango.BL.csproj"> <Project>{f441feee-322a-4943-b566-110e12fd3b72}</Project> <Name>Tango.BL</Name> @@ -136,10 +176,18 @@ <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project> <Name>Tango.Core</Name> </ProjectReference> + <ProjectReference Include="..\..\..\Tango.CSV\Tango.CSV.csproj"> + <Project>{58e8825f-0c96-449c-b320-1e82b0aa876b}</Project> + <Name>Tango.CSV</Name> + </ProjectReference> <ProjectReference Include="..\..\..\Tango.Logging\Tango.Logging.csproj"> <Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project> <Name>Tango.Logging</Name> </ProjectReference> + <ProjectReference Include="..\..\..\Tango.PMR\Tango.PMR.csproj"> + <Project>{e4927038-348d-4295-aaf4-861c58cb3943}</Project> + <Name>Tango.PMR</Name> + </ProjectReference> <ProjectReference Include="..\..\..\Tango.Serialization\Tango.Serialization.csproj"> <Project>{22f87980-e990-4686-be81-be63d562c4d5}</Project> <Name>Tango.Serialization</Name> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Tooltips/PieChartTooltipControl.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Tooltips/PieChartTooltipControl.xaml index 07f1308ec..b03f02249 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Tooltips/PieChartTooltipControl.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Tooltips/PieChartTooltipControl.xaml @@ -7,7 +7,7 @@ mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <Grid> - <Border Padding="10" Background="White" CornerRadius="5" BorderThickness="1" BorderBrush="Silver" MaxWidth="400"> + <Border Padding="10" Background="{StaticResource TransparentBackgroundBrush450}" CornerRadius="5" BorderThickness="1" BorderBrush="{StaticResource borderBrush}" MaxWidth="400"> <TextBlock Text="{Binding Title}" TextWrapping="Wrap"></TextBlock> </Border> </Grid> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ValidationRules/DateExpiredRule.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ValidationRules/DateExpiredRule.cs new file mode 100644 index 000000000..98b90f855 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ValidationRules/DateExpiredRule.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; + + +namespace Tango.MachineStudio.Statistics.ValidationRules +{ + public class DateExpiredRule : ValidationRule + { + public override ValidationResult Validate(object value, CultureInfo cultureInfo) + { + DateTime orderDate = (DateTime)value; + + return new ValidationResult(orderDate < DateTime.Now, "Please enter a date until today."); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/ChartsViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/ChartsViewVM.cs new file mode 100644 index 000000000..a98257086 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/ChartsViewVM.cs @@ -0,0 +1,364 @@ +using LiveCharts; +using LiveCharts.Wpf; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Media; +using Tango.BL.Enumerations; +using Tango.MachineStudio.Common; +using Tango.MachineStudio.Statistics.Models; +using Tango.BL.Entities; +using Tango.SharedUI; +using Tango.BL; +using Tango.MachineStudio.Common.Notifications; +using System.Threading.Tasks; +using Tango.Core.Commands; + +namespace Tango.MachineStudio.Statistics.ViewModels +{ + public class ChartsViewVM : ViewModel + { + private INotificationProvider _notification; + //private ObservablesContext _context; + private List<JobRunStatisticsModel> _job_runs; + private bool _loaded; + + #region Properties + private LabeledSeriesCollection _timelineJobStatusSeries; + public LabeledSeriesCollection TimelineJobStatusSeries + { + get { return _timelineJobStatusSeries; } + set { _timelineJobStatusSeries = value; RaisePropertyChangedAuto(); } + } + + private LabeledSeriesCollection _pieJobFailedReasons; + public LabeledSeriesCollection PieJobFailedReasons + { + get { return _pieJobFailedReasons; } + set { _pieJobFailedReasons = value; RaisePropertyChangedAuto(); } + } + + private LabeledSeriesCollection _printPerWeekSeries; + public LabeledSeriesCollection PrintPerWeekSeries + { + get { return _printPerWeekSeries; } + set { _printPerWeekSeries = value; RaisePropertyChangedAuto(); } + } + + private DateTime _startDate; + public DateTime StartDate + { + get { return _startDate; } + set { _startDate = value; RaisePropertyChangedAuto(); RaisePropertyChanged("EndDate"); } + } + + private DateTime _endDate; + public DateTime EndDate + { + get { return _endDate; } + set { _endDate = value; RaisePropertyChangedAuto(); RaisePropertyChanged("StartDate"); } + } + + public RelayCommand LoadJobRunsCommand { get; set; } + #endregion + + public ChartsViewVM(INotificationProvider notificationProvider) + { + _notification = notificationProvider; + StartDate = DateTime.Now.AddMonths(-1); + EndDate = DateTime.Now; + LoadJobRunsCommand = new RelayCommand(async () => await LoadJobRuns(), () => IsFree); + } + + #region Generate Charts + + private async Task LoadJobRuns() + { + using (_notification.PushTaskItem("Loading statistics...")) + { + try + { + IsFree = false; + + await Task.Factory.StartNew(() => + { + using (var db = ObservablesContext.CreateDefault()) + { + DateTime startUtc = new DateTime(StartDate.Year, StartDate.Month, StartDate.Day, 0, 0, 0).ToUniversalTime(); + TimeSpan offsetTime = (EndDate.Date == DateTime.Now.Date) ? DateTime.Now.TimeOfDay : new TimeSpan(23, 59, 59); + DateTime endUtc = EndDate.ToUniversalTime() + offsetTime; + + _job_runs = db.JobRuns.Where(x => (x.StartDate <= endUtc && x.StartDate >= startUtc)).OrderBy(x => x.StartDate).ToList().Select(x => new JobRunStatisticsModel(x)).ToList(); + + foreach (var run in _job_runs) + { + run.LoadMachine(db).GetAwaiter().GetResult(); + } + } + }); + + InvokeUIOnIdle(() => + { + if (_loaded) + { + OnDateRangeChanged(); + } + }); + + _loaded = true; + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading statistics."); + } + finally + { + IsFree = true; + } + } + } + + + private List<JobRunStatisticsModel> GetJobRunsByDateRange(DateTime startDate, DateTime endTime, JobRunStatus? status = null) + { + return _job_runs.Where(x => x.StartDate.ToLocalTime() >= startDate && x.StartDate.ToLocalTime() <= endTime && (status == null || x.JobRunStatus == status)).ToList(); + } + + private List<JobRunStatisticsModel> GetJobRunsByDate(DateTime date, JobRunStatus? status = null) + { + return _job_runs.Where(x => x.StartDate.ToLocalTime().Date == date.Date && (status == null || x.JobRunStatus == status)).ToList(); + } + + private IEnumerable<DateTime> CreateDates(DateTime start, DateTime end) + { + for (DateTime date = start.Date; date.Date <= end.Date; date = date.AddDays(1)) + { + yield return date; + } + } + + private void GenerateTimelineJobStatusChart() + { + TimelineJobStatusSeries = new LabeledSeriesCollection() + { + Title = "Job Runs Status", + ChartTitle = "Number Of Runs", + LabelsTitle = "Date", + SeriesColors = new List<Color>() + { + Colors.Green, + Colors.Orange, + Colors.Red, + }, + }; + + Series completed_job_runs = new ColumnSeries() + { + Title = "Completed", + Values = new ChartValues<int>(), + Fill = Brushes.Green, + MinWidth = 1, + + }; + Series aborted_job_runs = new ColumnSeries() + { + Title = "Aborted", + Values = new ChartValues<int>(), + Fill = Brushes.Orange, + MinWidth = 1, + }; + Series failed_job_runs = new ColumnSeries() + { + Title = "Failed", + Values = new ChartValues<int>(), + Fill = Brushes.Red, + MinWidth = 1, + }; + + if (EndDate - StartDate > TimeSpan.FromDays(40)) + { + completed_job_runs = new LineSeries() + { + Title = "Completed", + Values = new ChartValues<int>(), + Fill = new SolidColorBrush(Colors.Green) { Opacity = 0.5 }, + MinWidth = 1, + PointGeometry = null, + StrokeThickness = 0, + + }; + aborted_job_runs = new LineSeries() + { + Title = "Aborted", + Values = new ChartValues<int>(), + Fill = new SolidColorBrush(Colors.Orange) { Opacity = 0.5 }, + MinWidth = 1, + PointGeometry = null, + StrokeThickness = 0, + }; + failed_job_runs = new LineSeries() + { + Title = "Failed", + Values = new ChartValues<int>(), + Fill = new SolidColorBrush(Colors.Red) { Opacity = 0.5 }, + MinWidth = 1, + PointGeometry = null, + StrokeThickness = 0, + }; + } + + foreach (var date in CreateDates(StartDate, EndDate)) + { + completed_job_runs.Values.Add(GetJobRunsByDate(date, JobRunStatus.Completed).Count()); + aborted_job_runs.Values.Add(GetJobRunsByDate(date, JobRunStatus.Aborted).Count()); + failed_job_runs.Values.Add(GetJobRunsByDate(date, JobRunStatus.Failed).Count()); + + TimelineJobStatusSeries.Labels.Add(date.ToShortDateString()); + } + + + + TimelineJobStatusSeries.SeriesCollection.Add(failed_job_runs); + TimelineJobStatusSeries.SeriesCollection.Add(aborted_job_runs); + TimelineJobStatusSeries.SeriesCollection.Add(completed_job_runs); + } + + private void GeneratePieFailedReasonsChart() + { + var groups = GetJobRunsByDateRange(StartDate, EndDate, JobRunStatus.Failed).GroupBy(x => x.FailedMessage).OrderBy(x => x.Count()); + + List<Color> colors = new List<Color>(); + + int max = groups.Count() > 0 ? groups.Max(x => x.Count()) : 0; + + for (int i = 0; i < groups.Count(); i++) + { + int count = groups.ElementAt(i).Count(); + double alpha = Math.Max(((double)(count) / max * 200), 20); + colors.Add(Color.FromArgb((byte)alpha, 200, 0, 0)); + } + + PieJobFailedReasons = new LabeledSeriesCollection() + { + Title = "Job Failure Reasons", + SeriesColors = colors, + }; + + int index = 0; + + foreach (var group in groups) + { + int count = group.Count(); + + var series = new PieSeries() + { + Title = group.First().FailedMessage, + Values = new ChartValues<int>() { count }, + Fill = new SolidColorBrush(colors[index++]), + DataLabels = true, + ToolTip = group.First().FailedMessage, + }; + + PieJobFailedReasons.SeriesCollection.Add(series); + } + } + + private void GeneratePrintPerWeekChart() + { + List<JobRunStatisticsModel> range_job_runs = GetJobRunsByDateRange(StartDate, EndDate); + + Dictionary<Machine, List<double>> weeks_print_avg = new Dictionary<Machine, List<double>>(); + + //Init machines weeks averages dictionary. + foreach (var machine in range_job_runs.Select(x => x.Machine).OrderBy(x => x.Name).DistinctBy(x => x.Guid)) + { + weeks_print_avg[machine] = new List<double>(); + } + + //Create all available dates + List<DateTime> all_dates = range_job_runs.Select(x => x.StartDate).ToList(); + + //get first Sunday. + DateTime current_sunday = all_dates.FirstOrDefault(x => x.DayOfWeek == DayOfWeek.Sunday); + + if (current_sunday != null && all_dates.Count > 0) + { + //Iterate over each week starting from the earliest Sunday. + while (current_sunday <= all_dates.Last()) + { + var week_job_runs = range_job_runs.Where(x => x.EndPosition > 10 && x.StartDate >= current_sunday && x.StartDate <= current_sunday.AddDays(7)).ToList(); + + foreach (var machine_job_runs in week_job_runs.GroupBy(x => x.Machine)) + { + weeks_print_avg[machine_job_runs.Key].Add(machine_job_runs.Select(x => x.EndPosition).Average()); + } + + current_sunday = current_sunday.AddDays(8); + } + } + + Dictionary<Machine, double> week_print_avg = new Dictionary<Machine, double>(); + + //Init machines week average dictionary. + foreach (var machine in weeks_print_avg) + { + if (machine.Value.Count > 0) + { + week_print_avg[machine.Key] = machine.Value.Average(); + } + } + + //Init chart series + PrintPerWeekSeries = new LabeledSeriesCollection() + { + Title = "Average Printed Thread Per Week (m)", + ChartTitle = "Average Print Per Week (m)", + LabelsTitle = "Date", + SeriesColors = new List<Color>() + { + + }, + }; + + //Init series colors intensity by number of prints. + double max = week_print_avg.Count > 0 ? week_print_avg.Max(x => x.Value) : 0; + foreach (var machine in week_print_avg) + { + double a = (machine.Value / max); + PrintPerWeekSeries.SeriesColors.Add(Color.FromArgb((byte)(255d * (machine.Value / max)), 0, 200, 0)); + } + + //Init columns. + int index = 0; + + foreach (var machine in week_print_avg) + { + var series = new ColumnSeries() + { + Title = machine.Key.Name, + Values = new ChartValues<int>() { (int)machine.Value }, + Fill = new SolidColorBrush(PrintPerWeekSeries.SeriesColors[index++]), + DataLabels = true, + ToolTip = machine.Key.SerialNumber, + }; + + PrintPerWeekSeries.SeriesCollection.Add(series); + } + } + + #endregion + + #region Filter by Date + public void OnDateRangeChanged() + { + if (_job_runs != null)// && _job_runs.Count > 0)// && _loaded) + { + GenerateTimelineJobStatusChart(); + GeneratePieFailedReasonsChart(); + GeneratePrintPerWeekChart(); + } + } + #endregion + + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/JobRunsViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/JobRunsViewVM.cs new file mode 100644 index 000000000..ae1592d8d --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/JobRunsViewVM.cs @@ -0,0 +1,729 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Data.Entity; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL; +using Tango.BL.Builders; +using Tango.BL.Entities; +using Tango.BL.Enumerations; +using Tango.Core.Commands; +using Tango.MachineStudio.Common; +using Tango.MachineStudio.Common.Notifications; +using Tango.MachineStudio.Statistics.Models; +using Tango.SharedUI; +using Tango.SharedUI.Components; +using Tango.AutoComplete.Editors; +using System.Windows.Media; +using LiveCharts.Wpf; +using LiveCharts; +using Tango.BL.ValueObjects; +using System.Diagnostics; +using Microsoft.Win32; +using Tango.CSV; +using System.ComponentModel; + +namespace Tango.MachineStudio.Statistics.ViewModels +{ + public enum HeadCleaningSelectionEnum + { + [Description("Exclude")] + Exclude = 0, + [Description("Include")] + Include = 1, + [Description("Only")] + Only = 2 + }; + + + public class JobRunsViewVM : ViewModel + { + private INotificationProvider _notification; + private List<Machine> _allMachines; + private List<User> _allUsers; + private List<RmlModel> _rmlsModels; + + + + #region Properties + + private ObservableCollection<JobRunModel> _jobRuns; + /// <summary> + /// Gets or sets the job runs. Contains filtered data of JobRunModel. + /// </summary> + public ObservableCollection<JobRunModel> JobRuns + { + get { return _jobRuns; } + set + { + _jobRuns = value; + RaisePropertyChangedAuto(); + } + } + + private JobRunModel _selectedJobRun = null; + /// <summary> + /// Gets or sets the JobRunModel. Binding to selected item of grid items. + /// </summary> + public JobRunModel SelectedJobRun + { + get { return _selectedJobRun; } + set + { + _selectedJobRun = value; + RaisePropertyChangedAuto(); + } + } + + private SelectedObjectCollection<Machine> _selectedMachines; + /// <summary> + /// Gets or sets the selected machines. Contains all available machines and selected machines. Binding to ComboBox Machines. + /// </summary> + public SelectedObjectCollection<Machine> SelectedMachines + { + get { return _selectedMachines; } + set + { + _selectedMachines = value; + RaisePropertyChangedAuto(); + } + } + + private DateTime _startSelectedDate; + /// <summary> + /// Gets or sets the start selected date. + /// </summary> + public DateTime StartSelectedDate + { + get { return _startSelectedDate; } + set { _startSelectedDate = value; + RaisePropertyChangedAuto(); + } + } + + private DateTime _endSelectedDate; + /// <summary> + /// Gets or sets the end selected date. + /// </summary> + public DateTime EndSelectedDate + { + get { return _endSelectedDate; } + set { _endSelectedDate = value; RaisePropertyChangedAuto(); } + } + + protected Double _lengthLowerValue; + /// <summary> + /// Gets or sets the length lower value of Range Slider + /// </summary> + public Double LengthLowerValue + { + get { return _lengthLowerValue; } + set + { + _lengthLowerValue = value; + RaisePropertyChangedAuto(); + } + } + + protected Double _lengthUpperValue; + /// <summary> + /// Gets or sets the length upper value of Range Slider. + /// </summary> + public Double LengthUpperValue + { + get { return _lengthUpperValue; } + set + { + _lengthUpperValue = value; + RaisePropertyChangedAuto(); + } + } + + private SelectedObjectCollection<JobSource> _jobRunSelectedSources; + /// <summary> + /// Gets or sets the job run selected sources. Binding to ComboBox "Source". + /// </summary> + public SelectedObjectCollection<JobSource> JobRunSelectedSources + { + get { return _jobRunSelectedSources; } + set { _jobRunSelectedSources = value; RaisePropertyChangedAuto(); } + } + + private SelectedObjectCollection<JobRunStatus> _jobRunSelectedStatuses; + /// <summary> + /// Gets or sets the job run selected statuses. Binding to ComboBox "Status". + /// </summary> + public SelectedObjectCollection<JobRunStatus> JobRunSelectedStatuses + { + get { return _jobRunSelectedStatuses; } + set { _jobRunSelectedStatuses = value; RaisePropertyChangedAuto(); } + } + + public SelectedObjectCollection<bool> _isGradientSelection; + /// <summary> + /// Gets or sets the is gradient selection. Binding to ComboBox "IsGradient". + /// </summary> + public SelectedObjectCollection<bool> IsGradientSelection + { + get { return _isGradientSelection; } + set + { + _isGradientSelection = value; + RaisePropertyChangedAuto(); + } + } + + private SelectedObjectCollection<RmlModel> _selectedThreads; + /// <summary> + /// Gets or sets the selected threads. Contains all available threads and selected threads. Binding to ComboBox "Thread". + /// </summary> + public SelectedObjectCollection<RmlModel> SelectedThreads + { + get { return _selectedThreads; } + set + { + _selectedThreads = value; + RaisePropertyChangedAuto(); + } + } + + private HeadCleaningSelectionEnum _headCleaningSelected; + + public HeadCleaningSelectionEnum HeadCleaningSelected + { + get { return _headCleaningSelected; } + set + { + _headCleaningSelected = value; + RaisePropertyChangedAuto(); + } + } + + + /// <summary> + /// Gets or sets the JobRuns providers. + /// </summary> + public ISuggestionProvider JobsProvider { get; set; } + + private Job _selectedJob; + /// <summary> + /// Gets or sets the job. + /// </summary> + public Job SelectedJob + { + get { return _selectedJob; } + set + { + _selectedJob = value; + RaisePropertyChangedAuto(); + } + } + + /// <summary> + /// Gets or sets the statistics value collection. Class - container included calculated statistic values. + /// </summary> + public StatisticsValueCollection StatisticsValueCollection { get; set; } + + #endregion + + public RelayCommand LoadJobRunsCommand { get; set; } + + public RelayCommand ExportToExcelCommand { get; set; } + + public JobRunsViewVM(INotificationProvider notificationProvider) + { + _notification = notificationProvider; + JobRuns = new ObservableCollection<JobRunModel>(); + LoadJobRunsCommand = new RelayCommand(async () => await LoadJobRuns(), () => IsFree); + ExportToExcelCommand = new RelayCommand(ExportToExcel, () => IsFree); + LengthUpperValue = 10000.0; + LengthLowerValue = 0.0; + DateTime now = DateTime.Now; + StartSelectedDate = now.AddMonths(-1); + EndSelectedDate = now; + + JobRunSelectedSources = new SelectedObjectCollection<JobSource>(new ObservableCollection<JobSource>() + { + JobSource.Local, + JobSource.Remote + }, new ObservableCollection<JobSource>() + { + JobSource.Local, + JobSource.Remote + }); + JobRunSelectedSources.SelectionChanged -= (x, y) => RaisePropertyChanged(nameof(JobRunSelectedSources)); + JobRunSelectedSources.SelectionChanged += (x, y) => RaisePropertyChanged(nameof(JobRunSelectedSources)); + + JobRunSelectedStatuses = new SelectedObjectCollection<JobRunStatus>(new ObservableCollection<JobRunStatus>() + { + JobRunStatus.Aborted, + JobRunStatus.Completed, + JobRunStatus.Failed, + + }, new ObservableCollection<JobRunStatus>() + { + JobRunStatus.Aborted, + JobRunStatus.Completed, + JobRunStatus.Failed, + + }); + JobRunSelectedStatuses.SelectionChanged -= (x, y) => RaisePropertyChanged(nameof(JobRunSelectedStatuses)); + JobRunSelectedStatuses.SelectionChanged += (x, y) => RaisePropertyChanged(nameof(JobRunSelectedStatuses)); + + IsGradientSelection = new SelectedObjectCollection<bool>(new ObservableCollection<bool> + { + true, + false + }, new ObservableCollection<bool> + { + true, + false + }); + IsGradientSelection.SelectionChanged -= (x, y) => RaisePropertyChanged(nameof(IsGradientSelection)); + IsGradientSelection.SelectionChanged += (x, y) => RaisePropertyChanged(nameof(IsGradientSelection)); + + HeadCleaningSelected = HeadCleaningSelectionEnum.Exclude; + + JobsProvider = new SuggestionProvider((filter) => + { + try + { + if (filter != null) + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + return db.Jobs.Where(x => x.Name != null && x.Name.ToLower().Contains(filter.ToLower())).ToList(); + } + } + else + { + return new List<Job>(); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading jobs."); + return null; + } + }); + + StatisticsValueCollection = new StatisticsValueCollection(); + } + + /// <summary> + /// Initializes this instance. Called form main view VM in OnApplicationReady + /// </summary> + public async void Init() + { + using (_notification.PushTaskItem("Loading job runs...")) + { + try + { + IsFree = false; + + using (var db = ObservablesContext.CreateDefault()) + { + _allMachines = await db.Machines.ToListAsync(); + _allUsers = await db.Users.Include(x => x.Contact).ToListAsync(); + _rmlsModels = await db.Rmls.Select(x => new RmlModel() { Name = x.Name, Guid = x.Guid }).ToListAsync(); + SelectedMachines = new SelectedObjectCollection<Machine>(_allMachines.ToObservableCollection(), new ObservableCollection<Machine>()); + SelectedThreads = new SelectedObjectCollection<RmlModel>(_rmlsModels.ToObservableCollection(), new ObservableCollection<RmlModel>()); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading job runs."); + } + finally + { + IsFree = true; + } + } + + } + + /// <summary> + /// Loads the job runs by filters. + /// </summary> + private async Task LoadJobRuns() + { + using (_notification.PushTaskItem("Loading job runs...")) + { + try + { + IsFree = false; + + using (var db = ObservablesContext.CreateDefault()) + { + DateTime startUtc = new DateTime(StartSelectedDate.Year, StartSelectedDate.Month, StartSelectedDate.Day, 0, 0, 0).ToUniversalTime(); + TimeSpan offsetTime = (EndSelectedDate.Date == DateTime.Now.Date) ? DateTime.Now.TimeOfDay : new TimeSpan(23, 59, 59); + DateTime endUtc = EndSelectedDate.ToUniversalTime() + offsetTime; + + string jobName = SelectedJob == null ? "" : SelectedJob.Name; + + var db_JobRuns = db.JobRuns.Where(x => (x.StartDate <= endUtc && x.StartDate >= startUtc)) + .Select(x => new + { + x.ID, + x.ActualStartDate, + x.EndDate, + x.EndPosition, + x.GradientResolutionCm, + x.Guid, + x.HeatingStartDate, + x.IsGradient, + x.JobGuid, + x.JobLength, + x.JobName, + x.JobSource, + x.MachineGuid, + x.RmlGuid, + x.StartDate, + x.Status, + x.UploadingStartDate, + x.UserGuid, + x.CyanQuantity, + x.MagentaQuantity, + x.YellowQuantity, + x.BlackQuantity, + x.TransparentQuantity, + x.LubricantQuantity, + x.CleanerQuantity, + x.IsHeadCleaning + }); + var machineIDs = new HashSet<string>(SelectedMachines.SynchedSource.ToList().Select(p => p.Guid)); + if (machineIDs.Count > 0) + { + db_JobRuns = db_JobRuns.Where(x => machineIDs.Contains(x.MachineGuid)); + } + int[] jobRunSourceArr = JobRunSelectedSources.SynchedSource.Select(x => (int)x).ToArray(); + if (jobRunSourceArr.Length > 0) + { + db_JobRuns = db_JobRuns.Where(x => jobRunSourceArr.Contains(x.JobSource)); + } + int[] jobRunStatusArr = JobRunSelectedStatuses.SynchedSource.Select(x => (int)x).ToArray(); + if (jobRunStatusArr.Length > 0) + { + db_JobRuns = db_JobRuns.Where(x => jobRunStatusArr.Contains(x.Status)); + } + bool[] isGradientArr = IsGradientSelection.SynchedSource.Select(x => (bool)x).ToArray(); + if (isGradientArr.Length > 0) + { + db_JobRuns = db_JobRuns.Where(x => isGradientArr.Contains(x.IsGradient)); + } + + if(HeadCleaningSelected != HeadCleaningSelectionEnum.Include) + { + bool isHeadCleaning = HeadCleaningSelected == HeadCleaningSelectionEnum.Only; + db_JobRuns = db_JobRuns.Where(x => isHeadCleaning == x.IsHeadCleaning); + } + + List<String> rmlGuids = SelectedThreads.SynchedSource.Select(y => y.Guid).ToList(); + if (rmlGuids != null && rmlGuids.Count > 0) + { + db_JobRuns = db_JobRuns.Where(x => rmlGuids.Contains(x.RmlGuid)); + } + if (!String.IsNullOrEmpty(jobName)) + { + db_JobRuns = db_JobRuns.Where(x => x.JobName.ToLower().StartsWith(jobName.ToLower())); + } + + var runs_db = await db_JobRuns.ToListAsync(); //Execute actual query. + + + List<JobRun> runs = runs_db.Where(x => (x.JobLength < LengthUpperValue && x.JobLength >= LengthLowerValue)) + .Select(x => new JobRun() + { + ID = x.ID, + ActualStartDate = x.ActualStartDate, + EndDate = x.EndDate, + EndPosition = x.EndPosition, + GradientResolutionCm = x.GradientResolutionCm, + Guid = x.Guid, + HeatingStartDate = x.HeatingStartDate, + IsGradient = x.IsGradient, + JobGuid = x.JobGuid, + JobLength = x.JobLength, + JobName = x.JobName, + JobSource = x.JobSource, + MachineGuid = x.MachineGuid, + RmlGuid = x.RmlGuid, + StartDate = x.StartDate, + Status = x.Status, + UploadingStartDate = x.UploadingStartDate, + UserGuid = x.UserGuid, + CyanQuantity = x.CyanQuantity, + MagentaQuantity = x.MagentaQuantity, + YellowQuantity = x.YellowQuantity, + BlackQuantity = x.BlackQuantity, + TransparentQuantity = x.TransparentQuantity, + LubricantQuantity = x.LubricantQuantity, + CleanerQuantity = x.CleanerQuantity, + IsHeadCleaning = x.IsHeadCleaning + }).ToList(); + + var modelList = runs.Select(x => new JobRunModel() + { + JobRun = x, + Machine = _allMachines.FirstOrDefault(y => y.Guid == x.MachineGuid), + User = _allUsers.SingleOrDefault(y => y.Guid == x.UserGuid), + Rml = _rmlsModels.SingleOrDefault(y => y.Guid == x.RmlGuid), + }).OrderByDescending(x => x.JobRun.StartDate).ToList(); + + modelList.ForEach(x => x.Init()); + JobRuns = modelList.ToObservableCollection(); + GenerateStatistics(); + } + + + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading job runs."); + } + finally + { + IsFree = true; + } + } + } + + private void ExportToExcel() + { + SaveFileDialog dlg = new SaveFileDialog(); + dlg.Title = "Job Runs Statistic Report"; + dlg.Filter = "CSV Files|*.csv"; + dlg.FileName = $"Statistics_Job_runs"; + dlg.DefaultExt = ".csv"; + if (dlg.ShowDialog().Value) + { + try + { + CsvFile<ExcelModel> csvFile = new CsvFile<ExcelModel>(new CsvDestination(dlg.FileName), new CsvDefinition() + { + Columns = new List<String>() + { + "ID", + "Machine", + "User", + "Job Name", + "Thread", + "Length", + "Source", + "Upload Duration", + "Heating Duration", + "Start Time", + "IsGradient", + "Gradient Resolution", + "Status", + "End Date", + "End Position", + "Cyan", + "Magenta", + "Yellow", + "Black", + "Transparent", + "Lubricant", + "Cleaner" + }, + }); + var selection = JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.JobRun.EndDate != null && z.JobRun.ActualStartDate != null); + foreach (var jobRunModel in selection) + { + ExcelModel excel_model = new ExcelModel(); + excel_model.ID = jobRunModel.JobRun.ID.ToString(); + excel_model.Machine = jobRunModel.Machine != null ? jobRunModel.Machine.SerialNumber : ""; + excel_model.User = jobRunModel.User != null ? jobRunModel.User.Contact.FullName: ""; + excel_model.JobName = jobRunModel.JobRun.JobName; + excel_model.Thread = jobRunModel.Rml != null ? jobRunModel.Rml.Name : ""; + excel_model.Length = String.Format("{0:0.##}", jobRunModel.JobRun.JobLength); + excel_model.Source = jobRunModel.JobRun.Source.ToString(); + excel_model.UploadDuration = jobRunModel.UploadDuration != null ? ((TimeSpan)(jobRunModel.UploadDuration)).ToString(@"hh\:mm\:ss") : TimeSpan.FromSeconds(0).ToString(@"hh\:mm\:ss"); + excel_model.HeatingDuration = jobRunModel.HeatingDuration != null ? ((TimeSpan)(jobRunModel.HeatingDuration)).ToString(@"hh\:mm\:ss") : TimeSpan.FromSeconds(0).ToString(@"hh\:mm\:ss"); + excel_model.StartTime = jobRunModel.JobRun.ActualStartDate != null ? ((DateTime)jobRunModel.JobRun.ActualStartDate).ToLocalTime().ToString("MM/dd/yy HH:mm"): ""; + excel_model.IsGradient = jobRunModel.JobRun.IsGradient ? "Yes" : "No"; + excel_model.GR = jobRunModel.JobRun.GradientResolutionCm.ToString(); + excel_model.Status = jobRunModel.JobRun.JobRunStatus.ToString(); + excel_model.EndTime = jobRunModel.JobRun.EndDate != null ? ((DateTime)jobRunModel.JobRun.EndDate).ToLocalTime().ToString("MM/dd/yy HH:mm"): ""; + excel_model.EndPosition = String.Format("{0:0.##}", jobRunModel.JobRun.EndPosition); + excel_model.Cyan = jobRunModel.JobRun.CyanQuantity < 0 ? "" :jobRunModel.JobRun.CyanQuantity.ToString(); + excel_model.Magenta = jobRunModel.JobRun.MagentaQuantity < 0 ? "" : jobRunModel.JobRun.MagentaQuantity.ToString(); + excel_model.Yellow = jobRunModel.JobRun.YellowQuantity < 0 ? "" : jobRunModel.JobRun.YellowQuantity.ToString(); + excel_model.Black = jobRunModel.JobRun.BlackQuantity < 0 ? "" : jobRunModel.JobRun.BlackQuantity.ToString(); + excel_model.Transparent = jobRunModel.JobRun.TransparentQuantity < 0 ? "" : jobRunModel.JobRun.TransparentQuantity.ToString(); + excel_model.Lubricant = jobRunModel.JobRun.LubricantQuantity < 0 ? "" : jobRunModel.JobRun.LubricantQuantity.ToString(); + excel_model.Cleaner = jobRunModel.JobRun.CleanerQuantity < 0 ? "" : jobRunModel.JobRun.CleanerQuantity.ToString(); + csvFile.Append(excel_model); + + } + + csvFile.Dispose(); + _notification.ShowInfo("Report generated successfully."); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error generating Statistics Job Runs report."); + _notification.ShowError($"Error generating Statistics Job Runs report..\n{ex.Message}"); + } + } + } + #region GenerateS_StatisticsValueCollection + + /// <summary> + /// Generates the statistics. + /// </summary> + protected void GenerateStatistics() + { + StatisticsValueCollection.Clean(); + if (JobRuns.Count() == 0) + return; + GenerateTotalRunsCount(); + GenerateTotalRunsLength(); + GenerateTotalThreadConsumption(); + GenerateRunsDuration(); + GenerateAverageUploadDuration(); + GenerateAverageHeatingDuration(); + + GeneratePieCharts(); + CreateThreadConsumptionPerThread(); + GenerateAllLiquidQuantities(); + } + + protected void GenerateTotalRunsCount() + {//Total Runs: + int val = JobRuns.Count(); + StatisticsValueCollection.AddStatisticsValue("Total Runs ", val, " "); + } + + /// <summary> + /// Generates the total length of the job runs. + /// </summary> + protected void GenerateTotalRunsLength() + { + double val = JobRuns.Where(z => z.JobRun.EndPosition > 0).Sum(x => x.JobRun.JobLength); + StatisticsValueCollection.AddStatisticsValue("Total Runs Length", val, " m"); + } + + /// <summary> + /// Generates the duration and average of the job runs. + /// </summary> + protected void GenerateRunsDuration() + { + var selection = JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.JobRun.EndDate != null && z.JobRun.ActualStartDate != null); + double val = 0d; + double average = 0d; + if (selection != null && selection.Count<JobRunModel>() > 0) + { + val = selection.Sum(x => (x.JobRun.EndDate - x.JobRun.ActualStartDate).Value.TotalHours); + average = selection.Average(x => (x.JobRun.EndDate - x.JobRun.ActualStartDate).Value.TotalMilliseconds); + } + StatisticsValueCollection.AddStatisticsValue("Total Dyeing Time", val, " hours"); + StatisticsValueCollection.AddStatisticsValue("Average Dyeing Time", Math.Max(TimeSpan.FromMilliseconds(average).TotalHours, 0), " hours"); + } + + /// <summary> + /// Generates the average upload duration of the job runs. + /// </summary> + protected void GenerateAverageUploadDuration() + { + var average = (long)JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.UploadDuration != null).Average(x => x.UploadDuration.Value.TotalMilliseconds); + StatisticsValueCollection.AddStatisticsValue("Average Upload Duration", Math.Max(TimeSpan.FromMilliseconds(average).TotalMinutes, 0), " minutes"); + } + + /// <summary> + /// Generates the average duration heating of the job runs. + /// </summary> + protected void GenerateAverageHeatingDuration() + { + var average = JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.HeatingDuration != null && z.HeatingDuration.Value.Ticks > 0).Average(x => x.HeatingDuration.Value.TotalMilliseconds); + StatisticsValueCollection.AddStatisticsValue("Average Heating Duration", Math.Max(TimeSpan.FromMilliseconds(average).TotalMinutes, 0), " minutes"); + } + + /// <summary> + /// Generates the total thread consumption by EndPosition. + /// </summary> + protected void GenerateTotalThreadConsumption() + { + double val = JobRuns.Where(z => z.JobRun.EndPosition > 0).Sum(x => x.JobRun.EndPosition); + StatisticsValueCollection.AddStatisticsValue("Total Dyeing Length", val, " m"); + } + + /// <summary> + /// Generates the pie charts in percentage: JobSource, JobRunStatus, Gradient. + /// </summary> + protected void GeneratePieCharts() + { + int PPCCount = JobRuns.Count(x => x.JobRun.Source == JobSource.Local); + int MSCount = JobRuns.Count(x => x.JobRun.Source == JobSource.Remote); + StatisticsValueCollection.GeneratePieJobSource(PPCCount, MSCount); + + int failedCount = JobRuns.Count(x => x.JobRun.JobRunStatus == JobRunStatus.Failed); + int abortedCount = JobRuns.Count(x => x.JobRun.JobRunStatus == JobRunStatus.Aborted); + int completedCount = JobRuns.Count(x => x.JobRun.JobRunStatus == JobRunStatus.Completed); + StatisticsValueCollection.GeneratePieJobRunStatus(failedCount, abortedCount, completedCount); + + int gradientCount = JobRuns.Count(x => x.JobRun.IsGradient == true); + int solidCount = JobRuns.Count(x => x.JobRun.IsGradient == false); + StatisticsValueCollection.GeneratePieGradientSolid(gradientCount, solidCount); + + } + + /// <summary> + /// Creates the thread consumption per thread. + /// </summary> + protected void CreateThreadConsumptionPerThread() + { + var temp = JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.Rml != null).GroupBy(x => x.Rml.Name); + List<StatisticsValue> result = JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.Rml != null && !String.IsNullOrEmpty(z.Rml.Name)).GroupBy(x => x.Rml.Name).Select(y => new StatisticsValue { Name = y.Key, Value = y.Sum(x => x.JobRun.EndPosition), Unit = "m" }).ToList(); + StatisticsValueCollection.CreateThreadConsumptionPerThread(result); + } + + /// <summary> + /// Generates all liquid quantities. + /// </summary> + protected void GenerateAllLiquidQuantities() + { + var runs = JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.JobRun.LiquidQuantitiesFast.Count > 0).ToList(); + + Dictionary<LiquidTypes, ulong> total_quantities = new Dictionary<LiquidTypes, ulong>(); + + foreach (LiquidTypes ltype in (LiquidTypes[])Enum.GetValues(typeof(LiquidTypes))) + { + total_quantities[ltype] = 0; + } + + foreach (var run in runs) + { + foreach (var lq in run.JobRun.LiquidQuantitiesFast) + { + if (lq.Quantity < 0) + { + Debug.WriteLine($"Warning: JobRun '{run.JobRun.ID}' contains an invalid value '{lq.Quantity}' for {lq.LiquidType} quantity."); + } + + total_quantities[lq.LiquidType] += Convert.ToUInt64(Math.Max(lq.Quantity, 0)); + } + } + + List<TotalLiquidQuantityModel> allLiquidQuantities = total_quantities.Select(x => new TotalLiquidQuantityModel() + { + LiquidType = x.Key, + Quantity = x.Value + }).ToList(); + + + //foreach (LiquidTypes ltype in (LiquidTypes[])Enum.GetValues(typeof(LiquidTypes))) + //{ + // var liquidQuantityByTypeList = db_liquidQuantities.Select(x => x.FirstOrDefault(y => y.LiquidType == ltype)).Where(x => x != null); + // var count = liquidQuantityByTypeList != null ? liquidQuantityByTypeList.Sum(x => x.Quantity) : 0; + // JobRunLiquidQuantity lq = new JobRunLiquidQuantity() { LiquidType = ltype, Quantity = count }; + // allLiquidQuantities.Add(lq); + //} + StatisticsValueCollection.GenerateStatisticsLiquidQuantity(allLiquidQuantities); + } + #endregion + + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/MainViewVM.cs index ef9561d0b..e7e2013c5 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/ViewModels/MainViewVM.cs @@ -7,360 +7,49 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Media; using Tango.BL; -using Tango.BL.Entities; using Tango.BL.Enumerations; using Tango.Core.Helpers; using Tango.MachineStudio.Common; using Tango.MachineStudio.Statistics.Models; using System.Data.Entity; using Tango.MachineStudio.Common.Notifications; +using Tango.BL.Entities; namespace Tango.MachineStudio.Statistics.ViewModels { public class MainViewVM : StudioViewModel { - private ObservablesContext _context; - private List<JobRun> _job_runs; - private bool rendered; private INotificationProvider _notification; - private bool _loaded; - - private LabeledSeriesCollection _timelineJobStatusSeries; - public LabeledSeriesCollection TimelineJobStatusSeries - { - get { return _timelineJobStatusSeries; } - set { _timelineJobStatusSeries = value; RaisePropertyChangedAuto(); } - } - - private LabeledSeriesCollection _pieJobFailedReasons; - public LabeledSeriesCollection PieJobFailedReasons - { - get { return _pieJobFailedReasons; } - set { _pieJobFailedReasons = value; RaisePropertyChangedAuto(); } - } - - private LabeledSeriesCollection _printPerWeekSeries; - public LabeledSeriesCollection PrintPerWeekSeries - { - get { return _printPerWeekSeries; } - set { _printPerWeekSeries = value; RaisePropertyChangedAuto(); } - } - private DateTime _startDate; - public DateTime StartDate + private ChartsViewVM _chartsViewVM; + public ChartsViewVM ChartsViewVM { - get { return _startDate; } - set { _startDate = value; RaisePropertyChangedAuto(); OnDateRangeChanged(); } + get { return _chartsViewVM; } + set { _chartsViewVM = value; RaisePropertyChangedAuto(); } } - private DateTime _endDate; - public DateTime EndDate + private JobRunsViewVM _jobRunsViewVM; + public JobRunsViewVM JobRunsViewVM { - get { return _endDate; } - set { _endDate = value; RaisePropertyChangedAuto(); OnDateRangeChanged(); } + get { return _jobRunsViewVM; } + set { _jobRunsViewVM = value; RaisePropertyChangedAuto(); } } - - private DateTime _minDate; - public DateTime MinDate - { - get { return _minDate; } - set { _minDate = value; RaisePropertyChangedAuto(); } - } - - private DateTime _maxDate; - public DateTime MaxDate - { - get { return _maxDate; } - set { _maxDate = value; RaisePropertyChangedAuto(); } - } - - + public MainViewVM(INotificationProvider notificationProvider) { _notification = notificationProvider; - - StartDate = DateTime.Now.AddMonths(-1); - EndDate = DateTime.Now; + ChartsViewVM = new ChartsViewVM(_notification); + JobRunsViewVM = new JobRunsViewVM(_notification); } public override void OnApplicationReady() { - + JobRunsViewVM.Init(); } - private List<JobRun> GetJobRunsByDateRange(DateTime startDate, DateTime endTime, JobRunStatus? status = null) - { - return _job_runs.Where(x => x.StartDate.ToLocalTime() >= startDate && x.StartDate.ToLocalTime() <= endTime && (status == null || x.JobRunStatus == status)).ToList(); - } - - private List<JobRun> GetJobRunsByDate(DateTime date, JobRunStatus? status = null) - { - return _job_runs.Where(x => x.StartDate.ToLocalTime().Date == date.Date && (status == null || x.JobRunStatus == status)).ToList(); - } - - private IEnumerable<DateTime> CreateDates(DateTime start, DateTime end) - { - for (DateTime date = start.Date; date.Date <= end.Date; date = date.AddDays(1)) - { - yield return date; - } - } - - - - public override async void OnNavigatedTo() + public override void OnNavigatedTo() { base.OnNavigatedTo(); - - if (rendered) return; - - rendered = true; - - - using (_notification.PushTaskItem("Loading statistics...")) - { - IsFree = false; - - await Task.Factory.StartNew(() => - { - _context = ObservablesContext.CreateDefault(); - _job_runs = _context.JobRuns.Include(x => x.Job).Include(x => x.Job.Machine).OrderBy(x => x.StartDate).ToList(); - }); - - if (_job_runs.Count > 0) - { - MinDate = _job_runs.Min(x => x.StartDate); - MaxDate = _job_runs.Max(x => x.StartDate); - } - - InvokeUIOnIdle(() => - { - OnDateRangeChanged(); - }); - - _loaded = true; - - IsFree = true; - } - } - - private void OnDateRangeChanged() - { - if (_job_runs != null && _job_runs.Count > 0 && _loaded) - { - GenerateTimelineJobStatusChart(); - GeneratePieFailedReasonsChart(); - GeneratePrintPerWeekChart(); - } - } - - private void GenerateTimelineJobStatusChart() - { - TimelineJobStatusSeries = new LabeledSeriesCollection() - { - Title = "Job Runs Status", - ChartTitle = "Number Of Runs", - LabelsTitle = "Date", - SeriesColors = new List<Color>() - { - Colors.Green, - Colors.Orange, - Colors.Red, - }, - }; - - Series completed_job_runs = new ColumnSeries() - { - Title = "Completed", - Values = new ChartValues<int>(), - Fill = Brushes.Green, - MinWidth = 1, - - }; - Series aborted_job_runs = new ColumnSeries() - { - Title = "Aborted", - Values = new ChartValues<int>(), - Fill = Brushes.Orange, - MinWidth = 1, - }; - Series failed_job_runs = new ColumnSeries() - { - Title = "Failed", - Values = new ChartValues<int>(), - Fill = Brushes.Red, - MinWidth = 1, - }; - - if (EndDate - StartDate > TimeSpan.FromDays(40)) - { - completed_job_runs = new LineSeries() - { - Title = "Completed", - Values = new ChartValues<int>(), - Fill = new SolidColorBrush(Colors.Green) { Opacity = 0.5 }, - MinWidth = 1, - PointGeometry = null, - StrokeThickness = 0, - - }; - aborted_job_runs = new LineSeries() - { - Title = "Aborted", - Values = new ChartValues<int>(), - Fill = new SolidColorBrush(Colors.Orange) { Opacity = 0.5 }, - MinWidth = 1, - PointGeometry = null, - StrokeThickness = 0, - }; - failed_job_runs = new LineSeries() - { - Title = "Failed", - Values = new ChartValues<int>(), - Fill = new SolidColorBrush(Colors.Red) { Opacity = 0.5 }, - MinWidth = 1, - PointGeometry = null, - StrokeThickness = 0, - }; - } - - foreach (var date in CreateDates(StartDate, EndDate)) - { - completed_job_runs.Values.Add(GetJobRunsByDate(date, JobRunStatus.Completed).Count()); - aborted_job_runs.Values.Add(GetJobRunsByDate(date, JobRunStatus.Aborted).Count()); - failed_job_runs.Values.Add(GetJobRunsByDate(date, JobRunStatus.Failed).Count()); - - TimelineJobStatusSeries.Labels.Add(date.ToShortDateString()); - } - - - - TimelineJobStatusSeries.SeriesCollection.Add(failed_job_runs); - TimelineJobStatusSeries.SeriesCollection.Add(aborted_job_runs); - TimelineJobStatusSeries.SeriesCollection.Add(completed_job_runs); - } - - private void GeneratePieFailedReasonsChart() - { - var groups = GetJobRunsByDateRange(StartDate, EndDate, JobRunStatus.Failed).GroupBy(x => x.FailedMessage).OrderBy(x => x.Count()); - - List<Color> colors = new List<Color>(); - - int max = groups.Count() > 0 ? groups.Max(x => x.Count()) : 0; - - for (int i = 0; i < groups.Count(); i++) - { - int count = groups.ElementAt(i).Count(); - double alpha = Math.Max(((double)(count) / max * 200), 20); - colors.Add(Color.FromArgb((byte)alpha, 200, 0, 0)); - } - - PieJobFailedReasons = new LabeledSeriesCollection() - { - Title = "Job Failure Reasons", - SeriesColors = colors, - }; - - int index = 0; - - foreach (var group in groups) - { - int count = group.Count(); - - var series = new PieSeries() - { - Title = group.First().FailedMessage, - Values = new ChartValues<int>() { count }, - Fill = new SolidColorBrush(colors[index++]), - DataLabels = true, - ToolTip = group.First().FailedMessage, - }; - - PieJobFailedReasons.SeriesCollection.Add(series); - } - } - - private void GeneratePrintPerWeekChart() - { - List<JobRun> range_job_runs = GetJobRunsByDateRange(StartDate, EndDate); - - Dictionary<Machine, List<double>> weeks_print_avg = new Dictionary<Machine, List<double>>(); - - //Init machines weeks averages dictionary. - foreach (var machine in range_job_runs.Select(x => x.Job.Machine).OrderBy(x => x.Name).DistinctBy(x => x.Guid)) - { - weeks_print_avg[machine] = new List<double>(); - } - - //Create all available dates - List<DateTime> all_dates = range_job_runs.Select(x => x.StartDate).ToList(); - - //get first Sunday. - DateTime current_sunday = all_dates.FirstOrDefault(x => x.DayOfWeek == DayOfWeek.Sunday); - - if (current_sunday != null && all_dates.Count > 0) - { - //Iterate over each week starting from the earliest Sunday. - while (current_sunday <= all_dates.Last()) - { - var week_job_runs = range_job_runs.Where(x => x.EndPosition > 10 && x.StartDate >= current_sunday && x.StartDate <= current_sunday.AddDays(7)).ToList(); - - foreach (var machine_job_runs in week_job_runs.GroupBy(x => x.Job.Machine)) - { - weeks_print_avg[machine_job_runs.Key].Add(machine_job_runs.Select(x => x.EndPosition).Average()); - } - - current_sunday = current_sunday.AddDays(8); - } - } - - Dictionary<Machine, double> week_print_avg = new Dictionary<Machine, double>(); - - //Init machines week average dictionary. - foreach (var machine in weeks_print_avg) - { - if (machine.Value.Count > 0) - { - week_print_avg[machine.Key] = machine.Value.Average(); - } - } - - //Init chart series - PrintPerWeekSeries = new LabeledSeriesCollection() - { - Title = "Average Printed Thread Per Week (m)", - ChartTitle = "Average Print Per Week (m)", - LabelsTitle = "Date", - SeriesColors = new List<Color>() - { - - }, - }; - - //Init series colors intensity by number of prints. - double max = week_print_avg.Count > 0 ? week_print_avg.Max(x => x.Value) : 0; - foreach (var machine in week_print_avg) - { - double a = (machine.Value / max); - PrintPerWeekSeries.SeriesColors.Add(Color.FromArgb((byte)(255d * (machine.Value / max)), 0, 200, 0)); - } - - //Init columns. - int index = 0; - - foreach (var machine in week_print_avg) - { - var series = new ColumnSeries() - { - Title = machine.Key.Name, - Values = new ChartValues<int>() { (int)machine.Value }, - Fill = new SolidColorBrush(PrintPerWeekSeries.SeriesColors[index++]), - DataLabels = true, - ToolTip = machine.Key.SerialNumber, - }; - - PrintPerWeekSeries.SeriesCollection.Add(series); - } } } } diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/ChartsView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/ChartsView.xaml new file mode 100644 index 000000000..b76154941 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/ChartsView.xaml @@ -0,0 +1,145 @@ +<UserControl x:Class="Tango.MachineStudio.Statistics.Views.ChartsView" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:vm="clr-namespace:Tango.MachineStudio.Statistics.ViewModels" + xmlns:global="clr-namespace:Tango.MachineStudio.Statistics" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:localrule="clr-namespace:Tango.MachineStudio.Statistics.ValidationRules" + xmlns:local="clr-namespace:Tango.MachineStudio.Statistics.Views" + xmlns:tooltips="clr-namespace:Tango.MachineStudio.Statistics.Tooltips" + xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf" + mc:Ignorable="d" + d:DesignHeight="450" d:DesignWidth="800"> + <Grid IsEnabled="{Binding IsFree}"> + <Grid.RowDefinitions> + <RowDefinition Height="80"/> + <RowDefinition Height="337*"/> + </Grid.RowDefinitions> + + + <StackPanel Margin="60 20 0 0" VerticalAlignment="Center" HorizontalAlignment="Left" Orientation="Horizontal" DockPanel.Dock="Left"> + <StackPanel> + <TextBlock FontSize="10">Start Date:</TextBlock> + <DatePicker x:Name="startdatePicker" SelectedDateChanged="StartDatePicker_SelectedDateChanged" materialDesign:HintAssist.Hint="Pick start date" Width="200" VerticalAlignment="Bottom" FontSize="16"> + <DatePicker.SelectedDate> + <Binding Path="StartDate" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True"> + <Binding.ValidationRules> + <localrule:DateExpiredRule x:Name="StartDateExpiredRule"/> + </Binding.ValidationRules> + </Binding> + </DatePicker.SelectedDate> + </DatePicker> + </StackPanel> + + <StackPanel Margin="40 0 0 0"> + <TextBlock FontSize="10">End Date:</TextBlock> + <DatePicker x:Name="endDatePicker" materialDesign:HintAssist.Hint="Pick end date" Width="200" VerticalAlignment="Bottom" FontSize="16" SelectedDateChanged="EndDatePicker_SelectedDateChanged"> + <DatePicker.SelectedDate> + <Binding Path="EndDate" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True"> + <Binding.ValidationRules> + <localrule:DateExpiredRule x:Name="EndDateExpiredRule"/> + </Binding.ValidationRules> + </Binding> + </DatePicker.SelectedDate> + </DatePicker> + </StackPanel> + <Button Width="100" Margin="60 0 0 0" Command="{Binding LoadJobRunsCommand}" VerticalAlignment="Bottom" HorizontalAlignment="Right" Content="LOAD"> + <Button.Style> + <Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}"> + <Setter Property="IsEnabled" Value="False"/> + <Style.Triggers> + <MultiDataTrigger> + <MultiDataTrigger.Conditions> + <Condition Binding="{Binding Path=(Validation.HasError), Source={x:Reference startdatePicker}}" Value="False"/> + <Condition Binding="{Binding Path=(Validation.HasError), Source={x:Reference endDatePicker}}" Value="False"/> + </MultiDataTrigger.Conditions> + <Setter Property="IsEnabled" Value="True"/> + </MultiDataTrigger> + </Style.Triggers> + </Style> + </Button.Style> + </Button> + </StackPanel> + + + <UniformGrid Columns="3" Margin="50 20 50 50" Rows="2" Grid.Row="1"> + <Border BorderBrush="{StaticResource Statistics.BorderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> + <DockPanel> + <TextBlock DockPanel.Dock="Top" FontSize="16" FontWeight="Bold" HorizontalAlignment="Center" Padding="10" Text="{Binding TimelineJobStatusSeries.Title}"></TextBlock> + <lvc:CartesianChart Series="{Binding TimelineJobStatusSeries.SeriesCollection}" LegendLocation="Bottom"> + <lvc:CartesianChart.DataTooltip> + <lvc:DefaultTooltip BulletSize="20" Background="{StaticResource TransparentBackgroundBrush450}" Foreground="{StaticResource Dialog.Foreground}"/> + </lvc:CartesianChart.DataTooltip> + <lvc:CartesianChart.AxisX> + <lvc:Axis Title="{Binding TimelineJobStatusSeries.LabelsTitle}" Labels="{Binding TimelineJobStatusSeries.Labels}" Foreground="{StaticResource DarkGrayBrush200}"> + <lvc:Axis.Separator> + <lvc:Separator Stroke="#A5A5A5" /> + </lvc:Axis.Separator> + </lvc:Axis> + </lvc:CartesianChart.AxisX> + <lvc:CartesianChart.AxisY> + <lvc:Axis Title="{Binding TimelineJobStatusSeries.ChartTitle}" MinValue="0" Foreground="{StaticResource DarkGrayBrush200}" > + <lvc:Axis.Separator> + <lvc:Separator Stroke="#B0B0B0" /> + </lvc:Axis.Separator> + </lvc:Axis> + </lvc:CartesianChart.AxisY> + </lvc:CartesianChart> + </DockPanel> + </Border> + + <Border BorderBrush="{StaticResource Statistics.BorderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> + <DockPanel> + <TextBlock DockPanel.Dock="Top" FontSize="16" FontWeight="Bold" HorizontalAlignment="Center" Padding="10" Text="{Binding PieJobFailedReasons.Title}"></TextBlock> + <UniformGrid Columns="2"> + <lvc:PieChart DataHover="PieChart_DataHover" Series="{Binding PieJobFailedReasons.SeriesCollection}" LegendLocation="None" Background="Transparent"> + <lvc:PieChart.Resources> + <Style TargetType="lvc:PieSeries"> + <Setter Property="Stroke" Value="#99F9F9F9"></Setter> + <Setter Property="StrokeThickness" Value="2"/> + </Style> + </lvc:PieChart.Resources> + <lvc:PieChart.DataTooltip> + <tooltips:PieChartTooltipControl Visibility="Hidden" /> + </lvc:PieChart.DataTooltip> + </lvc:PieChart> + + <TextBlock x:Name="txtPieTitle" TextWrapping="Wrap"></TextBlock> + </UniformGrid> + </DockPanel> + </Border> + + <Border BorderBrush="{StaticResource Statistics.BorderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> + <DockPanel> + <TextBlock DockPanel.Dock="Top" FontSize="16" FontWeight="Bold" HorizontalAlignment="Center" Padding="10" Text="{Binding PrintPerWeekSeries.Title}"></TextBlock> + <lvc:CartesianChart Series="{Binding PrintPerWeekSeries.SeriesCollection}" LegendLocation="Bottom" > + <lvc:CartesianChart.Resources> + <Style TargetType="lvc:ColumnSeries"> + <Setter Property="Foreground" Value="{StaticResource DarkGrayBrush200}"></Setter> + </Style> + </lvc:CartesianChart.Resources> + <lvc:CartesianChart.AxisX> + <lvc:Axis Title="{Binding PrintPerWeekSeries.LabelsTitle}" Labels="{Binding PrintPerWeekSeries.Labels}" Foreground="{StaticResource DarkGrayBrush200}"> + <lvc:Axis.Separator> + <lvc:Separator Stroke="#A5A5A5" /> + </lvc:Axis.Separator> + </lvc:Axis> + </lvc:CartesianChart.AxisX> + <lvc:CartesianChart.AxisY> + <lvc:Axis Title="{Binding PrintPerWeekSeries.ChartTitle}" MinValue="0" Foreground="{StaticResource DarkGrayBrush200}" > + <lvc:Axis.Separator> + <lvc:Separator Stroke="#6F6F6F" /> + </lvc:Axis.Separator> + </lvc:Axis> + </lvc:CartesianChart.AxisY> + <lvc:CartesianChart.DataTooltip> + <lvc:DefaultTooltip BulletSize="20" Background="{StaticResource TransparentBackgroundBrush450}" Foreground="{StaticResource Dialog.Foreground}"/> + </lvc:CartesianChart.DataTooltip> + </lvc:CartesianChart> + </DockPanel> + </Border> + </UniformGrid> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/ChartsView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/ChartsView.xaml.cs new file mode 100644 index 000000000..bd97ed2bc --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/ChartsView.xaml.cs @@ -0,0 +1,74 @@ +using LiveCharts; +using LiveCharts.Wpf; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.MachineStudio.Statistics.Views +{ + /// <summary> + /// Interaction logic for ChartsView.xaml + /// </summary> + public partial class ChartsView : UserControl + { + public ChartsView() + { + InitializeComponent(); + } + private void PieChart_DataHover(object sender, ChartPoint chartPoint) + { + var tooltip = ((chartPoint.ChartView as PieChart).DataTooltip as Tooltips.PieChartTooltipControl).Title; + txtPieTitle.Text = tooltip; + } + private void StartDatePicker_SelectedDateChanged(object sender, SelectionChangedEventArgs e) + { + DatePicker datePickerObj = sender as DatePicker; + if (datePickerObj != null && datePickerObj.SelectedDate != null && endDatePicker.SelectedDate != null) + { + if (datePickerObj.SelectedDate > endDatePicker.SelectedDate) + { + BindingExpression start_be = datePickerObj.GetBindingExpression(DatePicker.SelectedDateProperty); + ValidationError validationError = new ValidationError(StartDateExpiredRule, start_be); + validationError.ErrorContent = "The start time must be less than or equal to end time."; + Validation.MarkInvalid(start_be, validationError); + } + else if (Validation.GetHasError(endDatePicker)) + { + BindingExpression end_be = endDatePicker.GetBindingExpression(DatePicker.SelectedDateProperty); + Validation.ClearInvalid(end_be); + } + } + } + + private void EndDatePicker_SelectedDateChanged(object sender, SelectionChangedEventArgs e) + { + DatePicker datePickerObj = sender as DatePicker; + if (datePickerObj.SelectedDate != null && startdatePicker.SelectedDate != null) + { + if (datePickerObj != null && datePickerObj.SelectedDate < startdatePicker.SelectedDate) + { + BindingExpression end_be = datePickerObj.GetBindingExpression(DatePicker.SelectedDateProperty); + ValidationError validationError = new ValidationError(EndDateExpiredRule, end_be); + validationError.ErrorContent = "The end time must be greater than or equal to the start time."; + Validation.MarkInvalid(end_be, validationError); + } + else if (Validation.GetHasError(startdatePicker)) + { + BindingExpression start_be = startdatePicker.GetBindingExpression(DatePicker.SelectedDateProperty); + Validation.ClearInvalid(start_be); + } + } + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/JobRunsView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/JobRunsView.xaml new file mode 100644 index 000000000..bc99c1bfa --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/JobRunsView.xaml @@ -0,0 +1,787 @@ +<UserControl x:Class="Tango.MachineStudio.Statistics.Views.JobRunsView" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:sharedConverters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:localConverters="clr-namespace:Tango.MachineStudio.Statistics.Converters" + xmlns:localrule="clr-namespace:Tango.MachineStudio.Statistics.ValidationRules" + xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:autoComplete="clr-namespace:Tango.AutoComplete.Editors;assembly=Tango.AutoComplete" + xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf" + xmlns:tooltips="clr-namespace:Tango.MachineStudio.Statistics.Tooltips" + xmlns:sys="clr-namespace:System;assembly=mscorlib" + xmlns:enumerations="clr-namespace:Tango.BL.Enumerations;assembly=Tango.BL" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + xmlns:local="clr-namespace:Tango.MachineStudio.Statistics.Views" + xmlns:model="clr-namespace:Tango.MachineStudio.Statistics.Models" + xmlns:vs="clr-namespace:Tango.MachineStudio.Statistics.ViewModels" + xmlns:wellknowntypes="clr-namespace:Google.Protobuf.WellKnownTypes;assembly=Google.Protobuf" + mc:Ignorable="d" + d:DesignHeight="450" d:DesignWidth="1800" Foreground="{StaticResource JobFieldForeground}"> + <UserControl.Resources> + <sharedConverters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> + <sharedConverters:BooleanToYesNoConverter x:Key="BooleanToYesNoConverter"/> + <sharedConverters:EnumToDescriptionConverter x:Key="EnumToDescriptionConverter" /> + <localConverters:DateTimeToStringFormatConverter x:Key="DateTimeToStringFormatConverter" /> + <sharedConverters:DateTimeUTCToShortDateTimeConverter x:Key="DateTimeUTCToShortDateTimeConverter"/> + <localConverters:StringToBoolYesNoNullConverter x:Key="StringToBoolYesNoNullConverter"/> + <localConverters:LiquidTypeToColorConverter x:Key="LiquidTypeToColorConverter"/> + <localConverters:CollectionConverter x:Key="CollectionConverter"/> + <localConverters:StringToFirstLetterConverter x:Key="StringToFirstLetterConverter"/> + <localConverters:MidTankLevelToElementHeightConverter x:Key="MidTankLevelToElementHeightConverter"/> + <localConverters:JobLengthConverter x:Key="JobLengthConverter"/> + <localConverters:NanoLiterToLiterFormatConverter x:Key="NanoLiterToLiterFormatConverter"/> + <localConverters:LiquidQuantityToFormatStringConverter x:Key="LiquidQuantityToFormatStringConverter"/> + <localConverters:TooltipLiquidQuantityFormatConverter x:Key="TooltipLiquidQuantityFormatConverter"/> + + <ResourceDictionary x:Key="SelectAllTextBoxResource"> + <Style TargetType="TextBox"> + <EventSetter Event="GotFocus" Handler="TextBox_GotFocus"></EventSetter> + <EventSetter Event="MouseDown" Handler="TextBox_PreviewMouseUp"></EventSetter> + </Style> + </ResourceDictionary> + + <ObjectDataProvider x:Key="HeadCleaning" MethodName="GetValues" ObjectType="{x:Type sys:Enum}"> + <ObjectDataProvider.MethodParameters> + <x:Type TypeName="vs:HeadCleaningSelectionEnum"/> + </ObjectDataProvider.MethodParameters> + </ObjectDataProvider> + + <Style TargetType="{x:Type TextBlock}" x:Key="WrapText"> + <Setter Property="TextWrapping" Value="Wrap"/> + </Style> + + <Style TargetType="lvc:PieSeries"> + <Setter Property="Stroke" Value="#99F9F9F9"></Setter> + <Setter Property="StrokeThickness" Value="2"/> + <Setter Property="Foreground" Value="#FF1C1C1F" /> + </Style> + <Style TargetType="lvc:PieChart"> + <Setter Property="Background" Value="Transparent"/> + <Setter Property="LegendLocation" Value="None"/> + </Style> + + <DataTemplate x:Key="PopUpDataTemplate"> + <CheckBox VerticalAlignment="Center" FontSize="11" DockPanel.Dock="Left" IsChecked="{Binding IsSelected}" Click="CheckBox_StayChecked" Tag="{Binding Path=ItemsSource, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}},Mode=OneWay}"> + <CheckBox.Content> + <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" Text="{Binding Data}"></TextBlock> + </CheckBox.Content> + </CheckBox> + </DataTemplate> + + <DataTemplate x:Key="PopupBoolDataTemplate"> + <CheckBox VerticalAlignment="Center" FontSize="11" DockPanel.Dock="Left" IsChecked="{Binding IsSelected}" Click="CheckBox_StayChecked" Tag="{Binding Path=ItemsSource, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}},Mode=OneWay}"> + <CheckBox.Content> + <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" Text="{Binding Data, Converter={StaticResource BooleanToYesNoConverter}}"/> + </CheckBox.Content> + </CheckBox> + </DataTemplate> + + + <Style x:Key="{x:Type ToolTip}" TargetType="{x:Type ToolTip}" BasedOn="{StaticResource MaterialDesignToolTip}"> + <Setter Property="Background" Value="{StaticResource Logging.Background}" /> + <Setter Property="Foreground" Value="{StaticResource MainWindow.Foreground}" /> + </Style> + + </UserControl.Resources> + + <Grid IsEnabled="{Binding IsFree}" > + <Grid.ColumnDefinitions> + <ColumnDefinition Width="3*"/> + <ColumnDefinition Width="1*"/> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition Height="Auto"/> + <RowDefinition Height="*"/> + <RowDefinition Height="Auto"/> + </Grid.RowDefinitions> + <Grid Grid.Row="0" Background="{StaticResource WhiteBackgroundBrush}" Width="Auto" Margin="20 0 0 1" > + <Border Padding="14 14 12 14" BorderBrush="DimGray" BorderThickness="0" Background="{StaticResource Logging.Background}" HorizontalAlignment="Stretch" CornerRadius="2" > + <Border.Effect> + <DropShadowEffect ShadowDepth="4" BlurRadius="10" Opacity="0.5"/> + </Border.Effect> + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*"/> + <ColumnDefinition Width="Auto"/> + </Grid.ColumnDefinitions> + + <Grid > + <Grid.RowDefinitions> + <RowDefinition Height="1*"/> + <RowDefinition Height="1*"/> + </Grid.RowDefinitions> + <StackPanel Orientation="Horizontal" Grid.Row="0"> + <StackPanel Margin="10 5 0 0" Orientation="Vertical" HorizontalAlignment="Center"> + <TextBlock Text="Machine:" VerticalAlignment="Center" FontSize="11"></TextBlock> + <ToggleButton Width="140" Margin="0 10 0 0" x:Name="selectMachineButton" HorizontalAlignment="Left" FontSize="16" VerticalAlignment="Center"> + <ToggleButton.Template> + <ControlTemplate> + <Grid> + <Border CornerRadius="3" BorderBrush="{StaticResource borderBrush}" BorderThickness="1" TextElement.Foreground="Black" Height="24"> + <DockPanel> + <Button x:Name="selectMachineButton" Width="18" Padding="0" Height="16" DockPanel.Dock="Right" BorderBrush="{x:Null}" HorizontalAlignment="Left" Click="Button_Click" Style="{StaticResource MaterialDesignFlatButton}" Foreground="{StaticResource MainWindow.Foreground}"> + <materialDesign:PackIcon Width="16" Height="16" Kind="ChevronDown" VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" HorizontalAlignment="Right"/> + </Button> + <TextBlock VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" FontSize="11" Margin="5"> + <TextBlock.Style> + <Style TargetType="{x:Type TextBlock}"> + <Setter Property="Text" Value="{Binding SelectedMachines.SynchedSource.Count, StringFormat={}Selected Machines({0})}"> + </Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding SelectedMachines.SynchedSource.Count}" Value="0"> + <Setter Property="Text" Value="All machines"/> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBlock.Style> + </TextBlock> + </DockPanel> + </Border> + <Popup AllowsTransparency="True" StaysOpen="False" IsOpen="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=IsChecked }"> + <Border Padding="3" CornerRadius="0 0 3 3" MinWidth="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=Width}" Margin="5" BorderBrush="{StaticResource AutoCompleteTextBox.Popup.BorderBrush}" > + <Border.Effect> + <DropShadowEffect Opacity="0.2" /> + </Border.Effect> + <controls:AllSelectedCheckboxList Style="{StaticResource AllSelectedCheckBoxListStyle}" MaxHeight="600" ItemsSource="{Binding SelectedMachines}" Background="{StaticResource ComboBox.Floating.Background}" Foreground="{StaticResource MainWindow.Foreground}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SelectionMode="Multiple" AllSelected="True" FontSize="11" FontFamily="{StaticResource FontName}"> + <controls:AllSelectedCheckboxList.ItemTemplate> + <DataTemplate > + <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" Text="{Binding Data.SerialNumber}" ToolTip="{Binding Data.SerialNumber}" FontFamily="{StaticResource FontName}" Background="{DynamicResource TransparentBackgroundBrush}" FontSize="11"></TextBlock> + + </DataTemplate> + </controls:AllSelectedCheckboxList.ItemTemplate> + </controls:AllSelectedCheckboxList> + </Border> + </Popup> + </Grid> + </ControlTemplate> + </ToggleButton.Template> + </ToggleButton> + </StackPanel> + + <StackPanel Margin="30 10 0 0" HorizontalAlignment="Center"> + <TextBlock FontSize="11">Start Date:</TextBlock> + <DatePicker x:Name="startdatePicker" SelectedDateChanged="StartDatePicker_SelectedDateChanged" Margin="0 5 0 0" materialDesign:HintAssist.Hint="Pick start date" Width="130" VerticalAlignment="Center" FontSize="11" > + <DatePicker.SelectedDate> + <Binding Path="StartSelectedDate" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True"> + <Binding.ValidationRules> + <localrule:DateExpiredRule x:Name="StartDateExpiredRule"/> + </Binding.ValidationRules> + </Binding> + </DatePicker.SelectedDate> + </DatePicker> + </StackPanel> + <StackPanel Margin="30 10 0 0" HorizontalAlignment="Center"> + <TextBlock FontSize="11">End Date:</TextBlock> + <DatePicker x:Name="endDatePicker" Margin="0 5 0 0" materialDesign:HintAssist.Hint="Pick end date" Width="130" VerticalAlignment="Center" FontSize="11" SelectedDateChanged="EndDatePicker_SelectedDateChanged"> + <DatePicker.SelectedDate> + <Binding Path="EndSelectedDate" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True"> + <Binding.ValidationRules> + <localrule:DateExpiredRule x:Name="EndDateExpiredRule"/> + </Binding.ValidationRules> + </Binding> + </DatePicker.SelectedDate> + + </DatePicker> + </StackPanel> + </StackPanel> + + <StackPanel Orientation="Horizontal" Grid.Row="1"> + <StackPanel Margin="10 10 0 0" Orientation="Vertical" HorizontalAlignment="Center"> + <TextBlock Text="Job Name:" VerticalAlignment="Center" FontSize="11"></TextBlock> + <autoComplete:AutoCompleteTextBox Margin="0 10 0 0" Provider="{Binding JobsProvider}" Width="140" FontSize="11" LoadingContent="Loading..." SelectedItem="{Binding SelectedJob,Mode=TwoWay}" materialDesign:HintAssist.Hint="All" DisplayMember="Name" materialDesign:HintAssist.IsFloating="False"> + <autoComplete:AutoCompleteTextBox.ItemTemplate> + <DataTemplate> + <StackPanel> + <TextBlock Text="{Binding Name}" FontWeight="Bold" FontStyle="Italic"></TextBlock> + </StackPanel> + </DataTemplate> + </autoComplete:AutoCompleteTextBox.ItemTemplate> + </autoComplete:AutoCompleteTextBox> + </StackPanel> + <StackPanel Margin="30 10 0 0" Orientation="Vertical" HorizontalAlignment="Center"> + <TextBlock Text="Source:" VerticalAlignment="Center" FontSize="11"></TextBlock> + <ToggleButton Width="130" Height="24" Margin="0 10 0 0" x:Name="selectJobRunSources" HorizontalAlignment="Left" FontSize="16" VerticalAlignment="Center"> + <ToggleButton.Template> + <ControlTemplate> + <Grid> + <Border CornerRadius="3" BorderBrush="{StaticResource borderBrush}" BorderThickness="1" TextElement.Foreground="Black" > + <DockPanel> + <Button x:Name="jobRunSourcesButton" Width="18" Padding="0" Height="16" DockPanel.Dock="Right" BorderBrush="{x:Null}" HorizontalAlignment="Left" Click="JobRunSourcesButton_Click" Style="{StaticResource MaterialDesignFlatButton}" Foreground="{StaticResource MainWindow.Foreground}"> + <materialDesign:PackIcon Width="16" Height="16" Kind="ChevronDown" VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" HorizontalAlignment="Right"/> + </Button> + <TextBlock VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" FontSize="11" Margin="5" Text="{Binding JobRunSelectedSources.SynchedSource, Converter={StaticResource CollectionConverter}}"/> + </DockPanel> + </Border> + <Popup AllowsTransparency="True" StaysOpen="False" IsOpen="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=IsChecked }"> + <Border Padding="3" CornerRadius="0 0 3 3" MinWidth="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=Width}" Margin="5" Background="{StaticResource TransparentBackgroundBrush200}" BorderBrush="{StaticResource AutoCompleteTextBox.Popup.BorderBrush}" > + <Border.Effect> + <DropShadowEffect Opacity="0.2" /> + </Border.Effect> + <ItemsControl ItemsSource="{Binding JobRunSelectedSources}" Foreground="{StaticResource MainWindow.Foreground}" ItemTemplate="{StaticResource PopUpDataTemplate}"/> + + </Border> + </Popup> + </Grid> + </ControlTemplate> + </ToggleButton.Template> + </ToggleButton> + </StackPanel> + <StackPanel Margin="30 10 0 0" Orientation="Vertical" HorizontalAlignment="Center"> + <TextBlock Text="Gradient:" VerticalAlignment="Center" FontSize="11"></TextBlock> + <ToggleButton Height="24" Width="130" Margin="0 10 0 0" x:Name="selectIsGradient" HorizontalAlignment="Left" FontSize="16" VerticalAlignment="Center"> + <ToggleButton.Template> + <ControlTemplate> + <Grid> + <Border CornerRadius="3" BorderBrush="{StaticResource borderBrush}" BorderThickness="1" TextElement.Foreground="Black" > + <DockPanel> + <Button x:Name="isGradientButton" Width="18" Padding="0" Height="16" DockPanel.Dock="Right" BorderBrush="{x:Null}" HorizontalAlignment="Left" Click="IsGradientButton_Click" Style="{StaticResource MaterialDesignFlatButton}" Foreground="{StaticResource MainWindow.Foreground}"> + <materialDesign:PackIcon Width="16" Height="16" Kind="ChevronDown" VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" HorizontalAlignment="Right"/> + </Button> + <TextBlock VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" FontSize="11" Margin="5 0 2 0"> + <Run Text="{Binding IsGradientSelection.SynchedSource, Converter={StaticResource CollectionConverter}, ConverterParameter='No, Yes'}"></Run> + </TextBlock> + </DockPanel> + </Border> + <Popup AllowsTransparency="True" StaysOpen="False" IsOpen="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=IsChecked }"> + <Border Padding="3" CornerRadius="0 0 3 3" MinWidth="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=Width}" Margin="5" Background="{StaticResource TransparentBackgroundBrush200}" BorderBrush="{StaticResource AutoCompleteTextBox.Popup.BorderBrush}"> + <Border.Effect> + <DropShadowEffect Opacity="0.2" /> + </Border.Effect> + <ItemsControl ItemsSource="{Binding IsGradientSelection}" Foreground="{StaticResource MainWindow.Foreground}" ItemTemplate="{StaticResource PopupBoolDataTemplate}"/> + + </Border> + </Popup> + </Grid> + </ControlTemplate> + </ToggleButton.Template> + </ToggleButton> + </StackPanel> + <StackPanel Margin="30 10 0 0" Orientation="Vertical" HorizontalAlignment="Center"> + <TextBlock Text="Length:" VerticalAlignment="Center" FontSize="11"></TextBlock> + <Border BorderThickness="1" CornerRadius="3" BorderBrush="{StaticResource borderBrush}" Margin="0 10 0 0" Height="24" Padding="10 0"> + <StackPanel Orientation="Horizontal"> + <TextBlock Text="{Binding LengthLowerValue, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" FontSize="11" Width="30"></TextBlock> + <mahapps:RangeSlider Focusable="True" Height="40" Margin="5 5 5 5" Minimum="0" Maximum="10000" Width="140" ExtendedMode="True" + LowerValue="{Binding LengthLowerValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" + UpperValue="{Binding LengthUpperValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" + VerticalAlignment="Center" IsSnapToTickEnabled="True" FontSize="8"/> + <TextBlock Text="{Binding LengthUpperValue}" VerticalAlignment="Center" FontSize="11" Width="30"></TextBlock> + </StackPanel> + </Border> + </StackPanel> + <StackPanel Margin="30 10 0 0" Orientation="Vertical" HorizontalAlignment="Center"> + <TextBlock Text="Status:" VerticalAlignment="Center" FontSize="11"></TextBlock> + <ToggleButton Height="24" Width="170" Margin="0 10 0 0" x:Name="selectJobRunStatus" HorizontalAlignment="Left" FontSize="16" VerticalAlignment="Center"> + <ToggleButton.Template> + <ControlTemplate> + <Grid> + <Border CornerRadius="3" BorderBrush="{StaticResource borderBrush}" BorderThickness="1" TextElement.Foreground="Black" > + <DockPanel> + <Button x:Name="jobRunStatusButton" Width="18" Padding="0" Height="16" DockPanel.Dock="Right" BorderBrush="{x:Null}" HorizontalAlignment="Left" Click="JobRunStatusButton_Click" Style="{StaticResource MaterialDesignFlatButton}" Foreground="{StaticResource MainWindow.Foreground}"> + <materialDesign:PackIcon Width="16" Height="16" Kind="ChevronDown" VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" HorizontalAlignment="Right"/> + </Button> + <TextBlock VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" FontSize="11" Margin="5" Text="{Binding JobRunSelectedStatuses.SynchedSource, Converter={StaticResource CollectionConverter}}"/> + </DockPanel> + </Border> + <Popup AllowsTransparency="True" StaysOpen="False" IsOpen="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=IsChecked }"> + <Border Padding="3" CornerRadius="0 0 3 3" MinWidth="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=Width}" Margin="5" Background="{StaticResource TransparentBackgroundBrush200}" BorderBrush="{StaticResource AutoCompleteTextBox.Popup.BorderBrush}" > + <Border.Effect> + <DropShadowEffect Opacity="0.2" /> + </Border.Effect> + <ItemsControl ItemsSource="{Binding JobRunSelectedStatuses}" Foreground="{StaticResource MainWindow.Foreground}" ItemTemplate="{StaticResource PopUpDataTemplate}"/> + </Border> + </Popup> + </Grid> + </ControlTemplate> + </ToggleButton.Template> + </ToggleButton> + </StackPanel> + <StackPanel Margin="30 10 0 0" Orientation="Vertical" HorizontalAlignment="Center"> + <TextBlock Text="Threads:" VerticalAlignment="Center" FontSize="11"></TextBlock> + <ToggleButton Width="100" Margin="0 10 0 0" x:Name="selectThreadsButton" HorizontalAlignment="Left" FontSize="16" VerticalAlignment="Center"> + <ToggleButton.Template> + <ControlTemplate> + <Grid> + <Border CornerRadius="3" BorderBrush="{StaticResource borderBrush}" BorderThickness="1" TextElement.Foreground="Black" Height="24"> + <DockPanel> + <Button x:Name="selectThreadButton" Width="18" Padding="0" Height="16" DockPanel.Dock="Right" BorderBrush="{x:Null}" HorizontalAlignment="Left" Click="SelectMachineButton_Click" Style="{StaticResource MaterialDesignFlatButton}" Foreground="{StaticResource MainWindow.Foreground}"> + <materialDesign:PackIcon Width="16" Height="16" Kind="ChevronDown" VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" HorizontalAlignment="Right"/> + </Button> + <TextBlock VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" FontSize="11" Margin="5" > + <TextBlock.Style> + <Style TargetType="{x:Type TextBlock}"> + <Setter Property="Text" Value="{Binding SelectedThreads.SynchedSource.Count, StringFormat={}Selected Threads({0})}"> + </Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding SelectedThreads.SynchedSource.Count}" Value="0"> + <Setter Property="Text" Value="All threads"/> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBlock.Style> + </TextBlock> + </DockPanel> + </Border> + <Popup AllowsTransparency="True" StaysOpen="False" IsOpen="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=IsChecked }"> + <Border Padding="3" CornerRadius="0 0 3 3" MinWidth="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=Width}" Margin="5" BorderBrush="{StaticResource AutoCompleteTextBox.Popup.BorderBrush}" > + <Border.Effect> + <DropShadowEffect Opacity="0.2" /> + </Border.Effect> + <controls:AllSelectedCheckboxList Style="{StaticResource AllSelectedCheckBoxListStyle}" MaxHeight="600" ItemsSource="{Binding SelectedThreads}" Background="{StaticResource ComboBox.Floating.Background}" Foreground="{StaticResource MainWindow.Foreground}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SelectionMode="Multiple" AllSelected="True" FontSize="11" FontFamily="{StaticResource FontName}"> + <controls:AllSelectedCheckboxList.ItemTemplate> + <DataTemplate > + <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" Text="{Binding Data.Name}" ToolTip="{Binding Data.Name}" FontFamily="{StaticResource FontName}"></TextBlock> + </DataTemplate> + </controls:AllSelectedCheckboxList.ItemTemplate> + </controls:AllSelectedCheckboxList> + </Border> + </Popup> + </Grid> + </ControlTemplate> + </ToggleButton.Template> + </ToggleButton> + </StackPanel> + <StackPanel Margin="30 10 0 0" Orientation="Vertical" HorizontalAlignment="Center"> + <TextBlock Text="HeadCleaning:" VerticalAlignment="Center" FontSize="11"></TextBlock> + <ToggleButton Height="24" Width="120" Margin="0 10 0 0" x:Name="isHeadCleaningToggleButton" HorizontalAlignment="Left" FontSize="16" VerticalAlignment="Center"> + <ToggleButton.Template> + <ControlTemplate> + <Grid> + <Border CornerRadius="3" BorderBrush="{StaticResource borderBrush}" BorderThickness="1" TextElement.Foreground="Black" > + <DockPanel> + <Button x:Name="IsHeadCleaningButton" Width="18" Padding="0" Height="16" DockPanel.Dock="Right" BorderBrush="{x:Null}" HorizontalAlignment="Left" Click="IsHeadCleaningButton_Click" Style="{StaticResource MaterialDesignFlatButton}" Foreground="{StaticResource MainWindow.Foreground}"> + <materialDesign:PackIcon Width="16" Height="16" Kind="ChevronDown" VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" HorizontalAlignment="Right"/> + </Button> + <TextBlock VerticalAlignment="Center" Foreground="{StaticResource MainWindow.Foreground}" FontSize="11" Margin="5 0 2 0" Text="{Binding HeadCleaningSelected, Converter={StaticResource EnumToDescriptionConverter}}"> + + </TextBlock> + </DockPanel> + </Border> + <Popup AllowsTransparency="True" StaysOpen="False" IsOpen="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=IsChecked }"> + <Border Padding="3" CornerRadius="0 0 3 3" MinWidth="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton},Path=Width}" Margin="5" Background="{StaticResource TransparentBackgroundBrush200}" BorderBrush="{StaticResource AutoCompleteTextBox.Popup.BorderBrush}"> + <Border.Effect> + <DropShadowEffect Opacity="0.2" /> + </Border.Effect> + <ListBox x:Name="HeadCleaningListBoxItem" ItemsSource="{Binding Source={StaticResource HeadCleaning}}" Foreground="{StaticResource MainWindow.Foreground}" SelectedItem="{Binding HeadCleaningSelected, Mode=TwoWay}" SelectionMode="Single" > + <ListBox.ItemTemplate> + <DataTemplate> + <CheckBox x:Name="HeadCleaningCheckBox" Selector.IsSelected="True" VerticalAlignment="Center" FontSize="11" DockPanel.Dock="Left" IsChecked="{Binding IsSelected, Mode=TwoWay, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, UpdateSourceTrigger=PropertyChanged}" Click="CheckBox_PreventUndoCheck"> + <CheckBox.Content> + <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" Text="{Binding Converter={StaticResource EnumToDescriptionConverter}}"/> + </CheckBox.Content> + </CheckBox> + </DataTemplate> + </ListBox.ItemTemplate> + </ListBox> + </Border> + </Popup> + </Grid> + </ControlTemplate> + </ToggleButton.Template> + </ToggleButton> + </StackPanel> + </StackPanel> + </Grid> + <Button Grid.Column="1" HorizontalAlignment="Right" Command="{Binding LoadJobRunsCommand}" Margin="0 0 10 0" Padding="30 15" Height="Auto" VerticalAlignment="Center" Content="ANALYZE"> + <Button.Style> + <Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}"> + <Setter Property="IsEnabled" Value="False"/> + <Style.Triggers> + <MultiDataTrigger> + <MultiDataTrigger.Conditions> + <Condition Binding="{Binding Path=(Validation.HasError), Source={x:Reference startdatePicker}}" Value="False"/> + <Condition Binding="{Binding Path=(Validation.HasError), Source={x:Reference endDatePicker}}" Value="False"/> + </MultiDataTrigger.Conditions> + <Setter Property="IsEnabled" Value="True"/> + </MultiDataTrigger> + </Style.Triggers> + </Style> + </Button.Style> + </Button> + </Grid> + </Border> + </Grid> + + <DataGrid x:Name="ItemsGrid" GridLinesVisibility="None" Grid.Row="1" Margin="20 0 0 10" SelectionMode="Single" SelectionUnit="FullRow" BorderBrush="{StaticResource borderBrush}" IsReadOnly="True" BorderThickness="1" RowHeight="80" + Background="{StaticResource TransparentBackgroundBrush}" AlternatingRowBackground="{StaticResource Transparent200}" AutoGenerateColumns="False" CanUserReorderColumns="False" + CanUserAddRows="False" CanUserDeleteRows="False" ItemsSource="{Binding JobRuns}" HorizontalScrollBarVisibility="Disabled" CanUserResizeColumns="False" CanUserResizeRows="False" + SelectedItem="{Binding SelectedJobRun}" CanUserSortColumns="True" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" FontSize="11"> + + <DataGrid.Resources> + <Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}"> + <Setter Property="HorizontalAlignment" Value="Left"></Setter> + <Setter Property="HorizontalContentAlignment" Value="Left"></Setter> + <Setter Property="Padding" Value="0 8 0 8"></Setter> + <Setter Property="Margin" Value="0 0 0 0"></Setter> + <Setter Property="FontWeight" Value="SemiBold"/> + </Style> + </DataGrid.Resources> + + <DataGrid.CellStyle> + <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}"> + <Setter Property="BorderThickness" Value="0"/> + <Setter Property="FocusVisualStyle" Value="{x:Null}"/> + <Setter Property="VerticalContentAlignment" Value="Center"></Setter> + <Setter Property="VerticalAlignment" Value="Center"/> + <Setter Property="HorizontalAlignment" Value="Left"/> + <Setter Property="Margin" Value="0 0 10 0"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type DataGridCell}"> + <ContentPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> + </ControlTemplate> + </Setter.Value> + </Setter> + <Style.Triggers> + <Trigger Property="IsSelected" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + <Setter Property="Foreground" Value="{StaticResource AccentColorBrush}" /> + </Trigger> + </Style.Triggers> + </Style> + </DataGrid.CellStyle> + <DataGrid.RowStyle> + <Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}"> + <Setter Property="BorderThickness" Value="0 0 0 1"/> + <Setter Property="BorderBrush" Value="LightGray"/> + <Style.Triggers> + <Trigger Property="IsMouseOver" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + <Setter Property="Foreground" Value="{StaticResource AccentColorBrush}" /> + <Setter Property="Cursor" Value="Hand"></Setter> + </Trigger> + <Trigger Property="IsSelected" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + </Trigger> + <Trigger Property="IsFocused" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + </Trigger> + </Style.Triggers> + </Style> + </DataGrid.RowStyle> + + <DataGrid.Columns> + <DataGridTemplateColumn Header="" Width="50"> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <materialDesign:PackIcon Width="24" Height="24" Margin="8 -5 0 0"> + <materialDesign:PackIcon.Style> + <Style TargetType="materialDesign:PackIcon"> + <Setter Property="Kind" Value="Check"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding JobRun.JobRunStatus}" Value="Completed"> + <Setter Property="Kind" Value="Check"></Setter> + <Setter Property="Foreground" Value="{StaticResource GreenOpenFileBrush}"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding JobRun.JobRunStatus}" Value="Aborted"> + <Setter Property="Kind" Value="Alert"></Setter> + <Setter Property="Foreground" Value="{StaticResource OrangeBrush}"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding JobRun.JobRunStatus}" Value="Failed"> + <Setter Property="Kind" Value="AlertOctagon"></Setter> + <Setter Property="Foreground" Value="{StaticResource RedBrush100}"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </materialDesign:PackIcon.Style> + </materialDesign:PackIcon> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + <DataGridTextColumn Header="ID" Binding="{Binding JobRun.ID}" Width="50" ElementStyle="{StaticResource WrapText}"/> + <DataGridTextColumn Header="Machine" Binding="{Binding Machine.SerialNumber}" Width="100" ></DataGridTextColumn> + <DataGridTextColumn Header="User" Binding="{Binding User.Contact.FullName,TargetNullValue='PPC',FallbackValue='PPC'}" Width="100" ElementStyle="{StaticResource WrapText}" /> + <DataGridTextColumn Header="Job Name" Binding="{Binding JobRun.JobName}" Width="100" ElementStyle="{StaticResource WrapText}"/> + <DataGridTextColumn Header="Thread" Binding="{Binding Rml.Name}" Width="80" ElementStyle="{StaticResource WrapText}"/> + <DataGridTextColumn Header="Length" Binding="{Binding JobRun.JobLength, StringFormat={}{0:0.00}}" Width="60" /> + <DataGridTextColumn Header="Source" Binding="{Binding JobRun.Source, Converter={StaticResource EnumToDescriptionConverter}}" Width="60" /> + <DataGridTextColumn Header="Upload Duration" Binding="{Binding UploadDuration, Converter={StaticResource DateTimeToStringFormatConverter}, FallbackValue='N/A',TargetNullValue='N/A'}" Width="80"/> + <DataGridTextColumn Header="Heating Duration" Binding="{Binding HeatingDuration, Converter={StaticResource DateTimeToStringFormatConverter}, FallbackValue='N/A',TargetNullValue='N/A'}" Width="80" /> + <DataGridTextColumn Header="Start Time" Binding="{Binding JobRun.ActualStartDate, Converter={StaticResource DateTimeUTCToShortDateTimeConverter}}" Width="95" /> + <DataGridTextColumn Header="IsGradient" Binding="{Binding JobRun.IsGradient}" Width="70" /> + <DataGridTextColumn Header="GR" Binding="{Binding JobRun.GradientResolutionCm}" Width="30" /> + <DataGridTextColumn Header="Status" Binding="{Binding JobRun.JobRunStatus, Converter={StaticResource EnumToDescriptionConverter}}" Width="70"/> + <DataGridTextColumn Header="End Time" Binding="{Binding JobRun.EndDate, Converter={StaticResource DateTimeUTCToShortDateTimeConverter}}" Width="95" /> + <DataGridTextColumn Header="End Position" Binding="{Binding JobRun.EndPosition, StringFormat={}{0:0.00}}" Width="70" /> + <DataGridTemplateColumn Header="Liquid Quantities" Width="1*"> + <DataGridTemplateColumn.CellStyle> + <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}"> + <Setter Property="BorderThickness" Value="0"/> + <Setter Property="FocusVisualStyle" Value="{x:Null}"/> + <Setter Property="VerticalContentAlignment" Value="Center"></Setter> + <Setter Property="VerticalAlignment" Value="Center"/> + <Setter Property="HorizontalAlignment" Value="Stretch"/> + <Setter Property="Margin" Value="0 0 10 0"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type DataGridCell}"> + <ContentPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> + </ControlTemplate> + </Setter.Value> + </Setter> + <Style.Triggers> + <Trigger Property="IsSelected" Value="True"> + <Setter Property="Background" Value="Transparent"></Setter> + <Setter Property="Foreground" Value="{StaticResource AccentColorBrush}" /> + </Trigger> + </Style.Triggers> + </Style> + </DataGridTemplateColumn.CellStyle> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> + <Grid.RowDefinitions> + <RowDefinition Height="1*"/> + <RowDefinition Height="20"/> + </Grid.RowDefinitions> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="1*" MaxWidth="200"/> + </Grid.ColumnDefinitions> + <ItemsControl ItemsSource="{Binding JobRun.LiquidQuantitiesFast,Mode=OneWay}" Margin="0 0 0 0" Height="70"> + <ItemsControl.ItemContainerStyle> + <Style TargetType="ContentPresenter"> + <Setter Property="Visibility" Value="Visible"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding Quantity}" Value="0"> + <Setter Property="Visibility" Value="Collapsed"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </ItemsControl.ItemContainerStyle> + <ItemsControl.ItemsPanel> + <ItemsPanelTemplate> + <StackPanel Orientation="Horizontal" IsItemsHost="True"></StackPanel> + </ItemsPanelTemplate> + </ItemsControl.ItemsPanel> + <ItemsControl.ItemTemplate> + <DataTemplate> + <DockPanel ToolTip="{Binding Quantity, Converter={StaticResource TooltipLiquidQuantityFormatConverter}, ConverterParameter='#,#\\'}" ToolTipService.Placement="Center" ToolTipService.VerticalOffset="10"> + <Grid DockPanel.Dock="Top" Height="40" Margin="0 5 8 0" Width="16" > + <Border x:Name="LiquidTypeBorder" BorderThickness="1" BorderBrush="{StaticResource borderBrush}" CornerRadius="2" > + <Canvas x:Name="LiquidCanvas" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="0" ClipToBounds="True" ToolTip="{Binding Quantity}" ToolTipService.Placement="Left" ToolTipService.VerticalOffset="10"> + <Border Height="{Binding RelativeSource={RelativeSource AncestorType=Canvas}, Path=ActualHeight }" Width="{Binding RelativeSource={RelativeSource AncestorType=Canvas}, Path=ActualWidth }" > + <Border.Background> + <SolidColorBrush Color="{Binding LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" /> + </Border.Background> + <Border.Style> + <Style> + <Setter Property="Canvas.Top" > + <Setter.Value> + <MultiBinding Converter="{StaticResource MidTankLevelToElementHeightConverter}"> + <Binding RelativeSource="{RelativeSource Self}" Path="ActualHeight" /> + <Binding Path="Quantity" /> + </MultiBinding> + </Setter.Value> + </Setter> + </Style> + </Border.Style> + </Border> + <Border Background="Transparent" ToolTip="{Binding Quantity, Converter={StaticResource TooltipLiquidQuantityFormatConverter}, ConverterParameter='#,#\\'}" Height="{Binding RelativeSource={RelativeSource AncestorType=Canvas}, Path=ActualHeight }" Width="{Binding RelativeSource={RelativeSource AncestorType=Canvas}, Path=ActualWidth }"></Border> + </Canvas> + </Border> + </Grid> + <TextBlock DockPanel.Dock="Bottom" FontSize="9" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0 0 10 0" Text="{Binding LiquidType,Converter={StaticResource StringToFirstLetterConverter}}" Foreground="Gray"/> + </DockPanel> + + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + <Border Grid.Row="1" Grid.Column="0" Background="Transparent" HorizontalAlignment="Stretch" Height="8" BorderThickness="1" BorderBrush="{StaticResource borderBrush}"> + <Rectangle Margin="0 0 -1 0" Fill="{StaticResource AccentColorBrush}" HorizontalAlignment="Left" VerticalAlignment="Stretch" ToolTip="{Binding JobRun.EndPosition}"> + <Rectangle.Width> + <MultiBinding Converter="{StaticResource JobLengthConverter}"> + <Binding Path="JobRun.JobLength" /> + <Binding Path="JobRun.EndPosition"/> + <Binding Path="ActualWidth" RelativeSource="{RelativeSource AncestorType=Border}"/> + </MultiBinding> + </Rectangle.Width> + </Rectangle> + </Border> + </Grid> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + </DataGrid.Columns> + </DataGrid> + <Border Grid.Row="1" Grid.Column="1" Grid.RowSpan="2" Margin="20, 0, 20, 20" BorderBrush="{StaticResource borderBrush}" Background="{StaticResource TransparentBackgroundBrush}" BorderThickness="1"> + + <StackPanel> + <TextBlock Margin="10" Text="{Binding SelectedJobName}"></TextBlock> + </StackPanel> + </Border> + <Border Grid.Row="2" Margin="20, 0, 0, 20" Height="200" BorderBrush="{StaticResource borderBrush}" Background="{StaticResource TransparentBackgroundBrush}" BorderThickness="1"> + <Grid > + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*"/> + <ColumnDefinition Width="2"/> + <ColumnDefinition Width="*"/> + <ColumnDefinition Width="2"/> + <ColumnDefinition Width="*"/> + </Grid.ColumnDefinitions> + <Border Grid.Column="0" BorderBrush="{StaticResource borderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> + <StackPanel Orientation="Vertical" Margin="5"> + <ItemsControl ItemsSource="{Binding StatisticsValueCollection.StatisticsCollection}"> + <ItemsControl.ItemTemplate> + <DataTemplate> + <StackPanel Orientation="Horizontal" Margin="0 3"> + <TextBlock Text="{Binding Name}" FontWeight="SemiBold"/> + <TextBlock Text=": "/> + <TextBlock Text="{Binding Value, StringFormat={}{0:N2}}"/> + <TextBlock Text="{Binding Unit}"/> + </StackPanel> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + <TextBlock Visibility="Collapsed" Margin="0 10 0 0" Text="Total Thread Consumption per thread:" FontWeight="SemiBold"> + <TextBlock.Style> + <Style TargetType="TextBlock"> + <Setter Property="Visibility" Value="Visible" /> + <Style.Triggers> + <DataTrigger Binding="{Binding StatisticsValueCollection.ThreadConsumptionPerThreadCollection.Count}" Value="0"> + <Setter Property="Visibility" Value="Collapsed" /> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBlock.Style> + </TextBlock> + <ItemsControl Visibility="Collapsed" ItemsSource="{Binding StatisticsValueCollection.ThreadConsumptionPerThreadCollection}"> + <ItemsControl.ItemsPanel> + <ItemsPanelTemplate> + <UniformGrid Rows="3" /> + </ItemsPanelTemplate> + </ItemsControl.ItemsPanel> + <ItemsControl.Resources> + <DataTemplate DataType="{x:Type model:StatisticsValue}"> + <StackPanel Orientation="Horizontal"> + <TextBlock Text="{Binding Name}" FontWeight="SemiBold"/> + <TextBlock Text=": "/> + <TextBlock Text="{Binding Value, StringFormat={}{0:0.0}}"/> + <TextBlock Text="{Binding Unit}"/> + </StackPanel> + </DataTemplate> + <DataTemplate DataType="{x:Type model:MoreValue}"> + <Border BorderThickness="0"> + <TextBlock Text="{Binding Text}" Tag="{Binding Path=DataContext.StatisticsValueCollection.ThreadConsumptionPerThread, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}}" HorizontalAlignment="Left" VerticalAlignment="Center" > + <TextBlock.ToolTip > + <ToolTip DataContext="{Binding RelativeSource={RelativeSource Self},Path=PlacementTarget.Tag}" Placement="Right" Background="{StaticResource Logging.Background}"> + <Border CornerRadius="5"> + <ItemsControl ItemsSource="{Binding }"> + <ItemsControl.ItemTemplate> + <DataTemplate> + <StackPanel Orientation="Horizontal" Margin="2"> + <TextBlock Margin="5 0 0 0" Text="{Binding Name}" FontWeight="SemiBold"/> + <TextBlock Text=": "/> + <TextBlock Text="{Binding Value, StringFormat={}{0:N0}}"/> + <TextBlock Text="{Binding Unit}"/> + </StackPanel> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + </Border> + </ToolTip> + </TextBlock.ToolTip> + </TextBlock> + </Border> + </DataTemplate> + </ItemsControl.Resources> + </ItemsControl> + </StackPanel> + </Border> + <Border Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Stretch" Width="2" Background="{StaticResource borderBrush}" Margin="0 4" Visibility="Visible"></Border> + <Border Grid.Column="2" BorderBrush="{StaticResource borderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> + <DockPanel> + <UniformGrid Columns="3"> + <DockPanel> + <TextBlock DockPanel.Dock="Top" FontSize="12" FontWeight="Bold" HorizontalAlignment="Center" Padding="2" Text="PPC/MS"></TextBlock> + <lvc:PieChart Series="{Binding StatisticsValueCollection.PieJobSource.SeriesCollection}" > + <lvc:PieChart.DataTooltip> + <tooltips:PieChartTooltipControl Visibility="Visible" /> + </lvc:PieChart.DataTooltip> + </lvc:PieChart> + </DockPanel> + <DockPanel> + <TextBlock DockPanel.Dock="Top" FontSize="12" FontWeight="Bold" HorizontalAlignment="Center" Padding="2" Text="Failed/Aborted/Completed"></TextBlock> + <lvc:PieChart Series="{Binding StatisticsValueCollection.PieJobRunStatus.SeriesCollection}"> + <lvc:PieChart.DataTooltip> + <tooltips:PieChartTooltipControl Visibility="Visible" /> + </lvc:PieChart.DataTooltip> + </lvc:PieChart> + </DockPanel> + <DockPanel> + <TextBlock DockPanel.Dock="Top" FontSize="12" FontWeight="Bold" HorizontalAlignment="Center" Padding="2" Text="Gradient/Solid"></TextBlock> + <lvc:PieChart Series="{Binding StatisticsValueCollection.PieGradientSolid.SeriesCollection}" > + <lvc:PieChart.DataTooltip> + <tooltips:PieChartTooltipControl Visibility="Visible" /> + </lvc:PieChart.DataTooltip> + </lvc:PieChart> + </DockPanel> + </UniformGrid> + </DockPanel> + </Border> + + <Border Grid.Column="3" HorizontalAlignment="Center" VerticalAlignment="Stretch" Width="2" Background="{StaticResource borderBrush}" Margin="0 6" CornerRadius="1"/> + + <Border Grid.Column="4" BorderBrush="{StaticResource borderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> + <DockPanel> + <ItemsControl DockPanel.Dock="Top" ItemsSource="{Binding StatisticsValueCollection.LiquidQuantities}"> + <ItemsControl.ItemsPanel> + <ItemsPanelTemplate> + <UniformGrid Columns="3"/> + </ItemsPanelTemplate> + </ItemsControl.ItemsPanel> + <ItemsControl.ItemTemplate> + <DataTemplate> + <Border Background="Transparent" ToolTip="{Binding Quantity, Converter={StaticResource TooltipLiquidQuantityFormatConverter}, ConverterParameter='#,#\\'}"> + <StackPanel Orientation="Horizontal" Margin="4"> + <Ellipse Width="30" Height="30"> + <Ellipse.Fill> + <SolidColorBrush Color="{Binding LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" /> + </Ellipse.Fill> + </Ellipse> + <StackPanel Orientation="Vertical" Margin="4"> + <TextBlock Text="{Binding LiquidType,Converter={StaticResource EnumToDescriptionConverter}}" FontWeight="SemiBold"></TextBlock> + <TextBlock > + <Run Text="{Binding Quantity, Converter={StaticResource NanoLiterToLiterFormatConverter}, ConverterParameter='0.00'}"></Run> + <Run Text=" liters"></Run> + </TextBlock> + </StackPanel> + </StackPanel> + </Border> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + <Border Background="Transparent" ToolTip="{Binding StatisticsValueCollection.TotalLiquidQuantities, Converter={StaticResource TooltipLiquidQuantityFormatConverter}, ConverterParameter='#,#\\'}"> + <TextBlock DockPanel.Dock="Bottom" Margin="4 10 0 0 "> + <Run Text="Total liquid quantities for all: " FontWeight="SemiBold"/> + <Run Text="{Binding StatisticsValueCollection.TotalLiquidQuantities, Converter={StaticResource NanoLiterToLiterFormatConverter}, ConverterParameter='0.00'}"></Run> + <Run Text=" liters"></Run> + <TextBlock.Style> + <Style TargetType="TextBlock"> + <Setter Property="Visibility" Value="Visible" /> + <Style.Triggers> + <DataTrigger Binding="{Binding StatisticsValueCollection.LiquidQuantities.Count}" Value="0"> + <Setter Property="Visibility" Value="Collapsed" /> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBlock.Style> + </TextBlock> + </Border> + </DockPanel> + </Border> + </Grid> + </Border> + <Grid Grid.Row="0" Grid.Column="1" Margin="20 0 20 0"> + <Border Padding="14 14 12 14" BorderBrush="DimGray" BorderThickness="0" Background="{StaticResource Logging.Background}" HorizontalAlignment="Stretch" CornerRadius="2" > + <Border.Effect> + <DropShadowEffect ShadowDepth="4" BlurRadius="10" Opacity="0.5"/> + </Border.Effect> + + <Button Grid.Column="1" HorizontalAlignment="Right" Command="{Binding ExportToExcelCommand}" Margin="0 0 10 0" Padding="10 15" Height="Auto" VerticalAlignment="Center" Width="Auto">EXPORT TO EXCEL</Button> + </Border> + </Grid> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/JobRunsView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/JobRunsView.xaml.cs new file mode 100644 index 000000000..961d7f691 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/JobRunsView.xaml.cs @@ -0,0 +1,175 @@ +using LiveCharts; +using LiveCharts.Wpf; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Tango.SharedUI.Components; + +namespace Tango.MachineStudio.Statistics.Views +{ + /// <summary> + /// Interaction logic for JobRunsView.xaml + /// </summary> + public partial class JobRunsView : UserControl + { + private int _lastSelectedGridItemIndex; + public JobRunsView() + { + InitializeComponent(); + _lastSelectedGridItemIndex = -1; + } + + + private void Button_Click(object sender, RoutedEventArgs e) + { + selectMachineButton.IsChecked = true; + e.Handled = true; + } + + private void JobRunSourcesButton_Click(object sender, RoutedEventArgs e) + { + selectJobRunSources.IsChecked = true; + e.Handled = true; + } + private void IsGradientButton_Click(object sender, RoutedEventArgs e) + { + selectIsGradient.IsChecked = true; + e.Handled = true; + } + private void JobRunStatusButton_Click(object sender, RoutedEventArgs e) + { + selectJobRunStatus.IsChecked = true; + e.Handled = true; + } + + private async void TextBox_GotFocus(object sender, RoutedEventArgs e) + { + await Task.Delay(200); + TextBox txtBox = sender as TextBox; + txtBox.SelectAll(); + } + + private void TextBox_PreviewMouseUp(object sender, MouseButtonEventArgs e) + { + e.Handled = true; + } + + private void SelectMachineButton_Click(object sender, RoutedEventArgs e) + { + selectThreadsButton.IsChecked = true; + e.Handled = true; + } + + private void IsHeadCleaningButton_Click(object sender, RoutedEventArgs e) + { + isHeadCleaningToggleButton.IsChecked = true; + e.Handled = true; + } + + private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + DataGrid dataGrid = sender as DataGrid; + _lastSelectedGridItemIndex = -1; + if (e.AddedItems != null && e.AddedItems.Count > 0) + { + DataGridRow row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromItem(e.AddedItems[0]); + if (row != null) + { + _lastSelectedGridItemIndex = row.GetIndex(); + } + } + } + + private void StartDatePicker_SelectedDateChanged(object sender, SelectionChangedEventArgs e) + { + DatePicker datePickerObj = sender as DatePicker; + if(datePickerObj != null && datePickerObj.SelectedDate != null && endDatePicker.SelectedDate != null) + { + if(datePickerObj.SelectedDate> endDatePicker.SelectedDate) + { + BindingExpression start_be = datePickerObj.GetBindingExpression(DatePicker.SelectedDateProperty); + ValidationError validationError = new ValidationError(StartDateExpiredRule, start_be); + validationError.ErrorContent = "The start time must be less than or equal to end time."; + Validation.MarkInvalid(start_be, validationError); + } + else if (Validation.GetHasError(endDatePicker)) + { + BindingExpression end_be = endDatePicker.GetBindingExpression(DatePicker.SelectedDateProperty); + Validation.ClearInvalid(end_be); + } + } + } + + private void EndDatePicker_SelectedDateChanged(object sender, SelectionChangedEventArgs e) + { + DatePicker datePickerObj = sender as DatePicker; + if (datePickerObj.SelectedDate != null && startdatePicker.SelectedDate != null ) + { + if(datePickerObj != null && datePickerObj.SelectedDate < startdatePicker.SelectedDate) + { + BindingExpression end_be = datePickerObj.GetBindingExpression(DatePicker.SelectedDateProperty); + ValidationError validationError = new ValidationError(EndDateExpiredRule, end_be); + validationError.ErrorContent = "The end time must be greater than or equal to the start time."; + Validation.MarkInvalid(end_be, validationError); + } + else if (Validation.GetHasError(startdatePicker)) + { + BindingExpression start_be = startdatePicker.GetBindingExpression(DatePicker.SelectedDateProperty); + Validation.ClearInvalid(start_be); + } + } + } + + private void CheckBox_PreventUndoCheck(object sender, RoutedEventArgs e) + { + if( sender is CheckBox) + { + CheckBox cb = sender as CheckBox; + if (cb.IsChecked == false) + { + cb.IsChecked = true; + e.Handled = true; + return; + } + } + e.Handled = false; + } + private void CheckBox_StayChecked(object sender, RoutedEventArgs e) + { + if (sender is CheckBox) + { + CheckBox cb = sender as CheckBox; + if (cb.IsChecked == false) + { + var col = cb.Tag; + Type type = col.GetType(); + if (col != null && col.GetType().GetGenericTypeDefinition() == typeof(SelectedObjectCollection<>)) + { + dynamic dSynchedSource = type.GetProperty("SynchedSource").GetValue(col); + if(dSynchedSource != null && dSynchedSource.GetType().GetGenericTypeDefinition() == typeof(ObservableCollection<>) && dSynchedSource.Count == 0) + { + cb.IsChecked = true; + e.Handled = true; + return; + } + } + } + } + e.Handled = false; + } + + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/MainView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/MainView.xaml index 55804c7b3..21c099db9 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/MainView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/MainView.xaml @@ -11,100 +11,28 @@ xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf" mc:Ignorable="d" d:DesignHeight="1080" d:DesignWidth="1920" Background="Transparent" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> - <Grid IsEnabled="{Binding IsFree}"> + <Grid> <Grid.RowDefinitions> - <RowDefinition Height="80"/> - <RowDefinition Height="337*"/> + <RowDefinition Height="1*"/> + <RowDefinition Height="20"/> </Grid.RowDefinitions> - - <StackPanel Margin="60 20 0 0" VerticalAlignment="Center" HorizontalAlignment="Left" Orientation="Horizontal"> - <StackPanel> - <TextBlock FontSize="10">Start Date:</TextBlock> - <DatePicker DisplayDateStart="{Binding MinDate}" DisplayDateEnd="{Binding MaxDate}" SelectedDate="{Binding StartDate}" materialDesign:HintAssist.Hint="Pick start date" Width="200" VerticalAlignment="Bottom" FontSize="16"></DatePicker> - </StackPanel> - - <StackPanel Margin="40 0 0 0"> - <TextBlock FontSize="10">End Date:</TextBlock> - <DatePicker DisplayDateStart="{Binding MinDate}" DisplayDateEnd="{Binding MaxDate}" SelectedDate="{Binding EndDate}" materialDesign:HintAssist.Hint="Pick end date" Width="200" VerticalAlignment="Bottom" FontSize="16"></DatePicker> - </StackPanel> - </StackPanel> - - <UniformGrid Columns="3" Margin="50 20 50 50" Rows="2" Grid.Row="1"> - <Border BorderBrush="{StaticResource Statistics.BorderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> - <DockPanel> - <TextBlock DockPanel.Dock="Top" FontSize="16" FontWeight="Bold" HorizontalAlignment="Center" Padding="10" Text="{Binding TimelineJobStatusSeries.Title}"></TextBlock> - <lvc:CartesianChart Series="{Binding TimelineJobStatusSeries.SeriesCollection}" LegendLocation="Bottom" SeriesColors="{Binding TimelineJobStatusSeries.SeriesColors}"> - <lvc:CartesianChart.DataTooltip> - <lvc:DefaultTooltip BulletSize="20" Background="{StaticResource TransparentBackgroundBrush450}" Foreground="{StaticResource Dialog.Foreground}"/> - </lvc:CartesianChart.DataTooltip> - <lvc:CartesianChart.AxisX> - <lvc:Axis Title="{Binding TimelineJobStatusSeries.LabelsTitle}" Labels="{Binding TimelineJobStatusSeries.Labels}" Foreground="{StaticResource DarkGrayBrush200}"> - <lvc:Axis.Separator> - <lvc:Separator Stroke="#A5A5A5" /> - </lvc:Axis.Separator> - </lvc:Axis> - </lvc:CartesianChart.AxisX> - <lvc:CartesianChart.AxisY> - <lvc:Axis Title="{Binding TimelineJobStatusSeries.ChartTitle}" MinValue="0" Foreground="{StaticResource DarkGrayBrush200}" > - <lvc:Axis.Separator> - <lvc:Separator Stroke="#B0B0B0" /> - </lvc:Axis.Separator> - </lvc:Axis> - </lvc:CartesianChart.AxisY> - </lvc:CartesianChart> - </DockPanel> - </Border> - - <Border BorderBrush="{StaticResource Statistics.BorderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> - <DockPanel> - <TextBlock DockPanel.Dock="Top" FontSize="16" FontWeight="Bold" HorizontalAlignment="Center" Padding="10" Text="{Binding PieJobFailedReasons.Title}"></TextBlock> - <UniformGrid Columns="2"> - <lvc:PieChart DataHover="PieChart_DataHover" Series="{Binding PieJobFailedReasons.SeriesCollection}" LegendLocation="None" SeriesColors="{Binding PieJobFailedReasons.SeriesColors}" Background="Transparent"> - <lvc:PieChart.Resources> - <Style TargetType="lvc:PieSeries"> - <Setter Property="Stroke" Value="#99F9F9F9"></Setter> - <Setter Property="StrokeThickness" Value="2"/> - </Style> - </lvc:PieChart.Resources> - <lvc:PieChart.DataTooltip> - <tooltips:PieChartTooltipControl Visibility="Hidden" /> - </lvc:PieChart.DataTooltip> - </lvc:PieChart> - - <TextBlock x:Name="txtPieTitle" TextWrapping="Wrap"></TextBlock> - </UniformGrid> - </DockPanel> - </Border> - - <Border BorderBrush="{StaticResource Statistics.BorderBrush}" Padding="5" BorderThickness="1" CornerRadius="5" Margin="10"> - <DockPanel> - <TextBlock DockPanel.Dock="Top" FontSize="16" FontWeight="Bold" HorizontalAlignment="Center" Padding="10" Text="{Binding PrintPerWeekSeries.Title}"></TextBlock> - <lvc:CartesianChart Series="{Binding PrintPerWeekSeries.SeriesCollection}" LegendLocation="Bottom" SeriesColors="{Binding PrintPerWeekSeries.SeriesColors}" > - <lvc:CartesianChart.Resources> - <Style TargetType="lvc:ColumnSeries"> - <Setter Property="Foreground" Value="{StaticResource DarkGrayBrush200}"></Setter> - </Style> - </lvc:CartesianChart.Resources> - <lvc:CartesianChart.AxisX> - <lvc:Axis Title="{Binding PrintPerWeekSeries.LabelsTitle}" Labels="{Binding PrintPerWeekSeries.Labels}" Foreground="{StaticResource DarkGrayBrush200}"> - <lvc:Axis.Separator> - <lvc:Separator Stroke="#A5A5A5" /> - </lvc:Axis.Separator> - </lvc:Axis> - </lvc:CartesianChart.AxisX> - <lvc:CartesianChart.AxisY> - <lvc:Axis Title="{Binding PrintPerWeekSeries.ChartTitle}" MinValue="0" Foreground="{StaticResource DarkGrayBrush200}" > - <lvc:Axis.Separator> - <lvc:Separator Stroke="#6F6F6F" /> - </lvc:Axis.Separator> - </lvc:Axis> - </lvc:CartesianChart.AxisY> - <lvc:CartesianChart.DataTooltip> - <lvc:DefaultTooltip BulletSize="20" Background="{StaticResource TransparentBackgroundBrush450}" Foreground="{StaticResource Dialog.Foreground}"/> - </lvc:CartesianChart.DataTooltip> - </lvc:CartesianChart> - </DockPanel> - </Border> - </UniformGrid> + <Grid Grid.Row="0" IsEnabled="{Binding IsFree}"> + <TabControl Background="Transparent" Margin="0,40,0,0" x:Name="chartsTabControl" Padding="0 25 0 0"> + <TabControl.Resources> + <Style TargetType="TabPanel"> + <Setter Property="HorizontalAlignment" Value="Center"/> + </Style> + <Style TargetType="TabItem" BasedOn="{StaticResource {x:Type TabItem}}"> + <Setter Property="Padding" Value="20,2"></Setter> + </Style> + </TabControl.Resources> + <TabItem Header="JOB RUNS" Margin="-100 0 0 0 "> + <local:JobRunsView x:Name="jobRunsView" DataContext="{Binding JobRunsViewVM}"/> + </TabItem> + <TabItem Header="STATS" Margin="-100 0 0 0 "> + <local:ChartsView x:Name="processParametersView" DataContext="{Binding ChartsViewVM}"/> + </TabItem> + </TabControl> + </Grid> </Grid> </UserControl> diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/MainView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/MainView.xaml.cs index 3948c4e5a..f0d1c39a7 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/MainView.xaml.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/Views/MainView.xaml.cs @@ -28,10 +28,6 @@ namespace Tango.MachineStudio.Statistics.Views InitializeComponent(); } - private void PieChart_DataHover(object sender, ChartPoint chartPoint) - { - var tooltip = ((chartPoint.ChartView as PieChart).DataTooltip as Tooltips.PieChartTooltipControl).Title; - txtPieTitle.Text = tooltip; - } + } } diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/packages.config b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/packages.config index 31c5f029f..6938c8a4b 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/packages.config +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Statistics/packages.config @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <packages> <package id="EntityFramework" version="6.2.0" targetFramework="net461" /> + <package id="Google.Protobuf" version="3.4.1" targetFramework="net461" /> <package id="LiveCharts" version="0.9.7" targetFramework="net461" /> <package id="LiveCharts.Wpf" version="0.9.7" targetFramework="net461" /> <package id="MahApps.Metro" version="1.5.0" targetFramework="net461" /> |
