diff options
| author | Roy <Roy.mail.net@gmail.com> | 2022-11-13 03:46:12 +0200 |
|---|---|---|
| committer | Roy <Roy.mail.net@gmail.com> | 2022-11-13 03:46:12 +0200 |
| commit | d38bf750367c6d6cdda3a6a3efbdf3552aa85358 (patch) | |
| tree | 000818a2a1e49d1e3decc630a94cf183bbaf2128 /Software/Visual_Studio/FSE | |
| parent | 8431040bf909ba65d5ce242b5fd2cc91005ba679 (diff) | |
| download | Tango-d38bf750367c6d6cdda3a6a3efbdf3552aa85358.tar.gz Tango-d38bf750367c6d6cdda3a6a3efbdf3552aa85358.zip | |
FSE Stats Module.
Extended job run structure.
CSV export.
Diffstat (limited to 'Software/Visual_Studio/FSE')
21 files changed, 1678 insertions, 25 deletions
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Images/cmyk.png b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Images/cmyk.png Binary files differnew file mode 100644 index 000000000..f179008e4 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Images/cmyk.png diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/CsvModel.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/CsvModel.cs new file mode 100644 index 000000000..99ef6be53 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/CsvModel.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Statistics.Models +{ + public class CsvModel + { + public String JobIndex { get; set; } + public String JobName { get; set; } + public String Thread { get; set; } + public String Length { get; set; } + public String StartTime { get; set; } + public String Duration { get; set; } + public String EndPosition { get; set; } + public String Status { get; set; } + public String SegmentIndex { get; set; } + public String Offset { get; set; } + public String ColorSpace { get; set; } + public String InputRed { get; set; } + public String InputGreen { get; set; } + public String InputBlue { get; set; } + public String InputL { get; set; } + public String InputA { get; set; } + public String InputB { get; set; } + public String InputCatalog { get; set; } + public String InputCatalogItem { get; set; } + public String InputCyan { get; set; } + public String InputMagenta { get; set; } + public String InputYellow { get; set; } + public String InputBlack { get; set; } + public String OutputCyan { get; set; } + public String OutputMagenta { get; set; } + public String OutputYellow { get; set; } + public String OutputBlack { get; set; } + public String OutputLightCyan { get; set; } + public String OutputLightMagenta { get; set; } + public String OutputLightYellow { get; set; } + public String OutputTransparentInk { get; set; } + public String OutputLubricant { get; set; } + public String FailureReason { get; set; } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/LiquidQuantityModel.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/LiquidQuantityModel.cs new file mode 100644 index 000000000..9ce4768b5 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/LiquidQuantityModel.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Enumerations; + +namespace Tango.FSE.Statistics.Models +{ + public class LiquidQuantityModel + { + public LiquidTypes LiquidType { get; set; } + public double Quantity { get; set; } + + public double Liters + { + get { return Quantity / 1000000000d; } + } + + public String Title + { + get + { + return LiquidType.ToDescription() + $": {Liters.ToString("0.0000")} Liters"; + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/StatsModel.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/StatsModel.cs new file mode 100644 index 000000000..773bea60b --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/StatsModel.cs @@ -0,0 +1,52 @@ +using LiveCharts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Enumerations; +using Tango.Core; + +namespace Tango.FSE.Statistics.Models +{ + public class StatsModel : ExtendedObject + { + public int TotalRuns { get; set; } + public int TotalDyeingLength { get; set; } + public int AverageDyeingLength { get; set; } + public TimeSpan TotalDyeingTime { get; set; } + public TimeSpan AverageDyeingTime { get; set; } + public Func<ChartPoint, string> StatusCounts { get; set; } = (point) => { return point.Y.ToString(); }; + public Func<ChartPoint, string> QuantityCounts { get; set; } = (point) => { return (Convert.ToUInt64(point.Y) / 1000000000d).ToString("0.00"); }; + public double CompletedRuns { get; set; } + public double FailedRuns { get; set; } + public double AbortedRuns { get; set; } + + private List<LiquidQuantityModel> _liquidQuantities; + public List<LiquidQuantityModel> LiquidQuantities + { + get { return _liquidQuantities; } + set { _liquidQuantities = value; RaisePropertyChangedAuto(); } + } + + public StatsModel() + { + LiquidQuantities = new List<LiquidQuantityModel>() + { + new LiquidQuantityModel() { LiquidType = LiquidTypes.Cyan, Quantity = 1 }, + new LiquidQuantityModel() { LiquidType = LiquidTypes.Magenta, Quantity = 1 }, + new LiquidQuantityModel() { LiquidType = LiquidTypes.Yellow, Quantity = 1 }, + new LiquidQuantityModel() { LiquidType = LiquidTypes.Black, Quantity = 1 }, + new LiquidQuantityModel() { LiquidType = LiquidTypes.LightCyan, Quantity = 1 }, + new LiquidQuantityModel() { LiquidType = LiquidTypes.LightMagenta, Quantity = 1 }, + new LiquidQuantityModel() { LiquidType = LiquidTypes.LightYellow, Quantity = 1 }, + new LiquidQuantityModel() { LiquidType = LiquidTypes.TransparentInk, Quantity = 1 }, + new LiquidQuantityModel() { LiquidType = LiquidTypes.Lubricant, Quantity = 1 }, + }; + + FailedRuns = 1; + CompletedRuns = 1; + AbortedRuns = 1; + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/StopModel.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/StopModel.cs new file mode 100644 index 000000000..b4cb29e7e --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Models/StopModel.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media; +using Tango.BL.DTO; +using Tango.BL.Entities; +using Tango.BL.Enumerations; +using Tango.Core.Commands; +using Tango.PPC.Shared.Statistics; + +namespace Tango.FSE.Statistics.Models +{ + public class StopModel : PresentationBrushStop + { + public JobRunDTO JobRun { get; set; } + public PresentationJob Job { get; set; } + public PresentationSegment Segment { get; set; } + public int JobIndex { get; set; } + public int SegmentIndex { get; set; } + public String ThreadName { get; set; } + public RelayCommand<StopModel> ShowFailedMessageCommand { get; set; } + public ProcessParametersTable ProcessParameters { get; set; } + public bool IsAdvancedMode { get; set; } + + public String Input + { + get + { + switch (ColorSpace) + { + case ColorSpaces.RGB: + return $"{Red}, {Green}, {Blue}"; + case ColorSpaces.LAB: + return $"{Math.Round(L, 2)}, {Math.Round(A, 2)}, {Math.Round(B, 2)}"; + case ColorSpaces.Catalog: + return $"{Catalog} => {CatalogItem}"; + case ColorSpaces.Volume: + return $"{Math.Round(Cyan, 2)}, {Math.Round(Magenta, 2)}, {Math.Round(Yellow, 2)}, {Math.Round(Black, 2)}"; + } + + return "Unspecified"; + } + } + + public TimeSpan Duration + { + get + { + return JobRun.EndDate - JobRun.StartDate; + } + } + + public double CyanOutput + { + get { return GetLiquidTypeOfDefault(LiquidTypes.Cyan); } + } + + public double MagentaOutput + { + get { return GetLiquidTypeOfDefault(LiquidTypes.Magenta); } + } + + public double YellowOutput + { + get { return GetLiquidTypeOfDefault(LiquidTypes.Yellow); } + } + + public double BlackOutput + { + get { return GetLiquidTypeOfDefault(LiquidTypes.Black); } + } + + public double LightCyanOutput + { + get { return GetLiquidTypeOfDefault(LiquidTypes.LightCyan); } + } + + public double LightMagentaOutput + { + get { return GetLiquidTypeOfDefault(LiquidTypes.LightMagenta); } + } + + public double LightYellowOutput + { + get { return GetLiquidTypeOfDefault(LiquidTypes.LightYellow); } + } + + public double TransparentInkOutput + { + get { return GetLiquidTypeOfDefault(LiquidTypes.TransparentInk); } + } + + public double LubricantOutput + { + get { return GetLiquidTypeOfDefault(LiquidTypes.Lubricant); } + } + + private double GetLiquidTypeOfDefault(LiquidTypes liquidType) + { + var lt = LiquidVolumes.FirstOrDefault(x => x.LiquidType == liquidType); + + if (lt != null) + { + return Math.Round(lt.Volume, 2); + } + + return 0; + } + + public List<LiquidQuantityModel> LiquidQuantities + { + get + { + return new List<LiquidQuantityModel>() + { + new LiquidQuantityModel(){ LiquidType = LiquidTypes.Cyan, Quantity = JobRun.CyanQuantity }, + new LiquidQuantityModel(){ LiquidType = LiquidTypes.Magenta, Quantity = JobRun.MagentaQuantity }, + new LiquidQuantityModel(){ LiquidType = LiquidTypes.Yellow, Quantity = JobRun.YellowQuantity }, + new LiquidQuantityModel(){ LiquidType = LiquidTypes.Black, Quantity = JobRun.BlackQuantity }, + new LiquidQuantityModel(){ LiquidType = LiquidTypes.LightCyan, Quantity = JobRun.LightCyanQuantity }, + new LiquidQuantityModel(){ LiquidType = LiquidTypes.LightMagenta, Quantity = JobRun.LightMagentaQuantity }, + new LiquidQuantityModel(){ LiquidType = LiquidTypes.LightYellow, Quantity = JobRun.LightYellowQuantity }, + new LiquidQuantityModel(){ LiquidType = LiquidTypes.TransparentInk, Quantity = JobRun.TransparentQuantity }, + new LiquidQuantityModel(){ LiquidType = LiquidTypes.Lubricant, Quantity = JobRun.LubricantQuantity }, + }; + } + } + + public Color BestMatchColor + { + get + { + return BestMatchR == 0 && BestMatchG == 0 && BestMatchB == 0 ? Colors.Transparent : Color.FromRgb((byte)BestMatchR, (byte)BestMatchG, (byte)BestMatchB); + } + } + + public Brush BestMatchBrush + { + get { return new SolidColorBrush(BestMatchColor); } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Tango.FSE.Statistics.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Tango.FSE.Statistics.csproj index 70aba2f5c..f4209111c 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Tango.FSE.Statistics.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Tango.FSE.Statistics.csproj @@ -46,6 +46,12 @@ <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> + <Reference Include="LiveCharts.Wpf, Version=0.9.7.0, Culture=neutral, PublicKeyToken=0bc1f845d1ebb8df, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\LiveCharts.Wpf.0.9.7\lib\net45\LiveCharts.Wpf.dll</HintPath> + </Reference> <Reference Include="MahApps.Metro, Version=1.6.5.1, Culture=neutral, processorArchitecture=MSIL"> <HintPath>..\..\..\packages\MahApps.Metro.1.6.5\lib\net46\MahApps.Metro.dll</HintPath> </Reference> @@ -78,6 +84,10 @@ <Reference Include="PresentationFramework" /> </ItemGroup> <ItemGroup> + <Compile Include="Models\CsvModel.cs" /> + <Compile Include="Models\LiquidQuantityModel.cs" /> + <Compile Include="Models\StatsModel.cs" /> + <Compile Include="Models\StopModel.cs" /> <Compile Include="ViewModelLocator.cs" /> <Compile Include="StatisticsModule.cs" /> <Compile Include="ViewModels\MainViewVM.cs" /> @@ -127,6 +137,10 @@ <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.Integration\Tango.Integration.csproj"> <Project>{4206ac58-3b57-4699-8835-90bf6db01a61}</Project> <Name>Tango.Integration</Name> @@ -165,6 +179,10 @@ <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> </Page> + <Page Include="Themes\Generic.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> <Page Include="Views\MainView.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> @@ -173,6 +191,9 @@ <ItemGroup> <Resource Include="Images\statistics.png" /> </ItemGroup> + <ItemGroup> + <Resource Include="Images\cmyk.png" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets" Condition="Exists('..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets')" /> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Themes/Generic.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Themes/Generic.xaml new file mode 100644 index 000000000..2c6475626 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Themes/Generic.xaml @@ -0,0 +1,9 @@ +<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:local="clr-namespace:Tango.FSE.Statistics.Themes"> + + + <BitmapImage x:Key="jobImage" UriSource="../Images/cmyk.png" /> + +</ResourceDictionary>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/ViewModels/MainViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/ViewModels/MainViewVM.cs index 2a14b7de1..c85a411e3 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/ViewModels/MainViewVM.cs @@ -1,14 +1,24 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Data.Entity; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows.Data; +using Tango.BL; +using Tango.BL.DTO; +using Tango.BL.Entities; using Tango.BL.Enumerations; +using Tango.Core.Commands; +using Tango.CSV; using Tango.FSE.Common; using Tango.FSE.Common.AutoComplete; using Tango.FSE.Common.Navigation; +using Tango.FSE.Common.Notifications; +using Tango.FSE.Common.Statistics; +using Tango.FSE.Statistics.Models; using Tango.PPC.Shared.Statistics; using Tango.SharedUI.Components; using Tango.SharedUI.Helpers; @@ -17,6 +27,48 @@ namespace Tango.FSE.Statistics.ViewModels { public class MainViewVM : FSEViewModel { + private List<ProcessParametersTable> _processTables; + + private DateTime _startSelectedDate; + public DateTime StartSelectedDate + { + get { return _startSelectedDate; } + set + { + _startSelectedDate = value; + RaisePropertyChangedAuto(); + } + } + + private DateTime _endSelectedDate; + public DateTime EndSelectedDate + { + get { return _endSelectedDate; } + set { _endSelectedDate = value; RaisePropertyChangedAuto(); } + } + + protected Double _lengthLowerValue; + public Double LengthLowerValue + { + get { return _lengthLowerValue; } + set + { + _lengthLowerValue = value; + RaisePropertyChangedAuto(); + } + } + + protected Double _lengthUpperValue; + public Double LengthUpperValue + { + get { return _lengthUpperValue; } + set + { + _lengthUpperValue = value; + RaisePropertyChangedAuto(); + } + } + private RequiredFiltersData _filtersData; public RequiredFiltersData FiltersData { @@ -38,10 +90,82 @@ namespace Tango.FSE.Statistics.ViewModels set { _selectedThreads = value; RaisePropertyChangedAuto(); } } + private String _jobName; + public String JobName + { + get { return _jobName; } + set { _jobName = value; RaisePropertyChangedAuto(); } + } + + private bool _includeHeadCleaning; + public bool IncludeHeadCleaning + { + get { return _includeHeadCleaning; } + set { _includeHeadCleaning = value; RaisePropertyChangedAuto(); } + } + + private bool _isSettingsBarOpened; + public bool IsSettingsBarOpened + { + get { return _isSettingsBarOpened; } + set { _isSettingsBarOpened = value; RaisePropertyChangedAuto(); } + } + + private bool _isFiltersAvailable; + public bool IsFiltersAvailable + { + get { return _isFiltersAvailable; } + set { _isFiltersAvailable = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + private List<StopModel> _stops; + public List<StopModel> Stops + { + get { return _stops; } + set { _stops = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(IsResultsAvailable)); InvalidateRelayCommands(); } + } + + private ListCollectionView _stopView; + public ListCollectionView StopsView + { + get { return _stopView; } + set { _stopView = value; RaisePropertyChangedAuto(); } + } + + private bool _jobNameExact; + public bool JobNameExact + { + get { return _jobNameExact; } + set { _jobNameExact = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand GetStatisticsCommand { get; set; } + public AutoCompleteSource<String> JobsAutoCompleteProvider { get; set; } + private StatsModel _stats; + public StatsModel Stats + { + get { return _stats; } + set { _stats = value; RaisePropertyChangedAuto(); } + } + + public bool IsResultsAvailable + { + get { return Stops != null && Stops.Count > 0 && Stops[0].JobIndex != -1000; } + } + + public RelayCommand<StopModel> ShowFailedMessageCommand { get; set; } + + public RelayCommand ExportToCsvCommand { get; set; } + + public MainViewVM() { + IsSettingsBarOpened = true; + + _processTables = new List<ProcessParametersTable>(); + JobRunSelectedStatuses = new SelectedObjectCollection<JobRunStatus>(new ObservableCollection<JobRunStatus>() { JobRunStatus.Aborted, @@ -58,15 +182,31 @@ namespace Tango.FSE.Statistics.ViewModels JobRunSelectedStatuses.SelectionChanged -= (x, y) => RaisePropertyChanged(nameof(JobRunSelectedStatuses)); JobRunSelectedStatuses.SelectionChanged += (x, y) => RaisePropertyChanged(nameof(JobRunSelectedStatuses)); - FiltersData = new RequiredFiltersData(); - JobsAutoCompleteProvider = new AutoCompleteSource<string>(AutoCompleteJobs); + + StartSelectedDate = DateTime.Now.AddYears(-7); + EndSelectedDate = DateTime.Now; + LengthUpperValue = 10000; + + GetStatisticsCommand = new RelayCommand(GetStatistics, () => IsFiltersAvailable); + + //Just for showing the columns :/ + Stops = new List<StopModel>() { new StopModel() { JobRun = new JobRunDTO(), Job = new PresentationJob(), JobIndex = -1000 } }; + var view = new ListCollectionView(Stops); + view.GroupDescriptions.Add(new PropertyGroupDescription("JobIndex")); + view.GroupDescriptions.Add(new PropertyGroupDescription("SegmentIndex")); + StopsView = view; + + Stats = new StatsModel(); + + ShowFailedMessageCommand = new RelayCommand<StopModel>(ShowJobRunFailedMessage); + ExportToCsvCommand = new RelayCommand(ExportToCSV, () => IsResultsAvailable); } private List<String> AutoCompleteJobs(string key) { key = key ?? String.Empty; - return FiltersData.Jobs.Where(x => x.ToLower().Contains(key.ToLower())).ToList(); + return FiltersData.Jobs.Where(x => x != null).Where(x => x.ToLower().Contains(key.ToLower())).ToList(); } public override void OnApplicationStarted() @@ -86,32 +226,338 @@ namespace Tango.FSE.Statistics.ViewModels }); } - public async override void OnNavigatedTo() + public async override void OnApplicationReady() { - base.OnNavigatedTo(); - await LoadFiltersData(); - await LoadStatistics(); + base.OnApplicationReady(); + + MachineProvider.MachineConnected += MachineProvider_MachineConnected; + MachineProvider.MachineDisconnected += MachineProvider_MachineDisconnected; + + try + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + _processTables = await db.ProcessParametersTables.ToListAsync(); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading process parameters tables for statistics."); + } + } + + private void MachineProvider_MachineDisconnected(object sender, Common.Connection.MachineDisconnectedEventArgs e) + { + + } + + private async void MachineProvider_MachineConnected(object sender, Common.Connection.MachineConnectedEventArgs e) + { + if (MachineProvider.IsPPCAvailable && (e.DifferentFromPrevious || !IsFiltersAvailable)) + { + await LoadFiltersData(); + } } private async Task LoadFiltersData() { - FiltersData = await StatisticsProvider.GetRequiredFiltersData(); - SelectedThreads = new SelectedObjectCollection<ThreadFilterData>(FiltersData.Rmls.ToObservableCollection(), new ObservableCollection<ThreadFilterData>()); + try + { + FiltersData = await StatisticsProvider.GetRequiredFiltersData(); + SelectedThreads = new SelectedObjectCollection<ThreadFilterData>(FiltersData.Rmls.ToObservableCollection(), new ObservableCollection<ThreadFilterData>()); + IsFiltersAvailable = true; + } + catch (Exception ex) + { + IsFiltersAvailable = false; + NotificationProvider.PushErrorReportingSnackbar(ex, "Statistics Module Error", "Error loading required statistics filter data."); + } + } + + private async void GetStatistics() + { + StatisticsModel model = null; + try + { + using (var task = NotificationProvider.PushTaskItem("Getting statistics from the remote machine...", false)) + { + await Task.Delay(3000); + + Filters filters = new Filters(); + filters.StartDateUTC = StartSelectedDate; + filters.EndDateUTC = EndSelectedDate; + filters.EndStatuses = JobRunSelectedStatuses.SynchedSource.Cast<int>().ToList(); + filters.IncludeHeadCleaning = IncludeHeadCleaning; + filters.JobName = JobName; + filters.ExactJobName = JobNameExact; + filters.MinLength = (int)LengthLowerValue; + filters.MaxLength = (int)LengthUpperValue; + filters.RmlGuids = SelectedThreads.SynchedSource.Select(x => x.Guid).ToList(); + + model = await StatisticsProvider.GetStatistics(filters); + + List<StopModel> stops = new List<StopModel>(); + + int jobIndex = 0; + + foreach (var job in model.StatisticsResult.JobRuns.OrderByDescending(x => x.JobRun.StartDate)) + { + var rmlName = FiltersData.Rmls.FirstOrDefault(x => x.Guid == job.JobRun.RmlGuid)?.Name; + var processTable = _processTables.FirstOrDefault(x => x.Guid == job.JobRun.ProcessParametersTableGuid); + + jobIndex++; + + foreach (var jobSegment in job.Job.Segments) + { + foreach (var jobStop in jobSegment.Stops) + { + StopModel stop = new StopModel(); + stop.JobIndex = jobIndex; + stop.SegmentIndex = job.Job.Segments.IndexOf(jobSegment) + 1; + stop.ThreadName = rmlName; + stop.ProcessParameters = processTable; + stop.IsAdvancedMode = !BuildProvider.IsTwineStudio && CurrentUser.HasRole(Roles.FSETwineTechnician); + + stop.ColorSpace = jobStop.ColorSpace; + + stop.L = jobStop.L; + stop.A = jobStop.A; + stop.B = jobStop.B; + + stop.Red = jobStop.Red; + stop.Green = jobStop.Green; + stop.Blue = jobStop.Blue; + + stop.Cyan = jobStop.Cyan; + stop.Magenta = jobStop.Magenta; + stop.Yellow = jobStop.Yellow; + stop.Black = jobStop.Black; + + stop.Catalog = jobStop.Catalog; + stop.CatalogItem = jobStop.CatalogItem; + + stop.StartMeters = jobStop.StartMeters; + + stop.Job = job.Job; + stop.JobRun = job.JobRun; + stop.Segment = jobSegment; + + stop.LiquidVolumes = jobStop.LiquidVolumes; + stop.BestMatchR = jobStop.BestMatchR; + stop.BestMatchG = jobStop.BestMatchG; + stop.BestMatchB = jobStop.BestMatchB; + + stop.ShowFailedMessageCommand = ShowFailedMessageCommand; + + stops.Add(stop); + } + } + } + + Stops = stops; + + var view = new ListCollectionView(Stops); + view.GroupDescriptions.Add(new PropertyGroupDescription("JobIndex")); + view.GroupDescriptions.Add(new PropertyGroupDescription("SegmentIndex")); + + StopsView = view; + + var stats = new StatsModel(); + + try + { + stats.TotalRuns = model.StatisticsResult.JobRuns.Count; + stats.CompletedRuns = model.StatisticsResult.JobRuns.Count(x => x.JobRun.Status == (int)JobRunStatus.Completed); + stats.FailedRuns = model.StatisticsResult.JobRuns.Count(x => x.JobRun.Status == (int)JobRunStatus.Failed); + stats.AbortedRuns = model.StatisticsResult.JobRuns.Count(x => x.JobRun.Status == (int)JobRunStatus.Aborted); + stats.TotalDyeingLength = (int)model.StatisticsResult.JobRuns.Where(x => x.JobRun.EndPosition > 0).Select(x => x.JobRun.EndPosition).Sum(); + stats.AverageDyeingLength = (int)model.StatisticsResult.JobRuns.Where(x => x.JobRun.EndPosition > 0).Select(x => x.JobRun.EndPosition).Average(); + + var timeRuns = model.StatisticsResult.JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.JobRun.EndDate != null && z.JobRun.ActualStartDate != null).ToList(); + + stats.TotalDyeingTime = TimeSpan.FromHours(timeRuns.Sum(x => (x.JobRun.EndDate - x.JobRun.ActualStartDate.Value).TotalHours)); + stats.AverageDyeingTime = TimeSpan.FromHours(timeRuns.Average(x => (x.JobRun.EndDate - x.JobRun.ActualStartDate.Value).TotalHours)); + + List<LiquidQuantityModel> liquidQuantities = new List<LiquidQuantityModel>(); + + Dictionary<LiquidTypes, double> quantities = new Dictionary<LiquidTypes, double>(); + quantities.Add(LiquidTypes.Cyan, 0); + quantities.Add(LiquidTypes.Magenta, 0); + quantities.Add(LiquidTypes.Yellow, 0); + quantities.Add(LiquidTypes.Black, 0); + quantities.Add(LiquidTypes.LightCyan, 0); + quantities.Add(LiquidTypes.LightMagenta, 0); + quantities.Add(LiquidTypes.LightYellow, 0); + quantities.Add(LiquidTypes.TransparentInk, 0); + quantities.Add(LiquidTypes.Lubricant, 0); + + foreach (var stop in stops) + { + quantities[LiquidTypes.Cyan] += stop.JobRun.CyanQuantity; + quantities[LiquidTypes.Magenta] += stop.JobRun.MagentaQuantity; + quantities[LiquidTypes.Yellow] += stop.JobRun.YellowQuantity; + quantities[LiquidTypes.Black] += stop.JobRun.BlackQuantity; + quantities[LiquidTypes.LightCyan] += stop.JobRun.LightCyanQuantity; + quantities[LiquidTypes.LightMagenta] += stop.JobRun.LightMagentaQuantity; + quantities[LiquidTypes.LightYellow] += stop.JobRun.LightYellowQuantity; + quantities[LiquidTypes.TransparentInk] += stop.JobRun.TransparentQuantity; + quantities[LiquidTypes.Lubricant] += stop.JobRun.LubricantQuantity; + } + + foreach (var item in quantities) + { + liquidQuantities.Add(new LiquidQuantityModel() { LiquidType = item.Key, Quantity = item.Value }); + } + + stats.LiquidQuantities = liquidQuantities; + } + catch (Exception ex) + { + LogManager.Log(ex, "Error generating statistics summaries."); + } + + Stats = stats; + + if (Stops.Count > 0) + { + await Task.Delay(1000); + + IsSettingsBarOpened = false; + + await Task.Delay(1000); + } + } + } + catch (Exception ex) + { + NotificationProvider.PushErrorReportingSnackbar(ex, "Statistics Module Error", "Error statistics from the remote machine."); + } + } + + private async void ShowJobRunFailedMessage(StopModel stop) + { + await NotificationProvider.ShowError($"Job Failure Message:\n{stop.JobRun.FailedMessage}"); } - private async Task LoadStatistics() + private async void ExportToCSV() { - Filters filters = new Filters(); - filters.StartDateUTC = DateTime.Now.AddYears(-1).ToUniversalTime(); - filters.EndDateUTC = DateTime.Now.ToUniversalTime(); - filters.EndStatuses = JobRunSelectedStatuses.SynchedSource.Cast<int>().ToList(); - filters.IncludeHeadCleaning = false; - filters.JobName = null; - filters.MinLength = 0; - filters.MaxLength = 10000; - filters.RmlGuids = SelectedThreads.SynchedSource.Select(x => x.Guid).ToList(); + var result = await StorageProvider.SaveFile("Export To CSV File", "CSV Files|*.csv", $"{MachineProvider.Machine.SerialNumber}_JobRuns_{DateTime.Now.ToFileName()}.csv", ".csv"); + if (result.Confirmed) + { + using (NotificationProvider.PushTaskItem("Exporting job runs to file...")) + { + await Task.Delay(1000); + + try + { + CsvFile<CsvModel> csvFile = new CsvFile<CsvModel>(new CsvDestination(result.SelectedItem), new CsvDefinition() + { + Columns = new List<String>() + { + "Job Index", + "Job Name", + "Thread", + "Length", + "Start Time", + "Duration", + "End Position", + "Status", + "Segment Index", + "Offset", + "Color Space", + "Input Red", + "Input Green", + "Input Blue", + "Input L", + "Input A", + "Input B", + "Input Catalog", + "Input Catalog Item", + "Input Cyan", + "Input Magenta", + "Input Yellow", + "Input Black", + "Output Cyan", + "Output Magenta", + "Output Yellow", + "Output Black", + "Output Light Cyan", + "Output Light Magenta", + "Output Light Yellow", + "Output Transparent Ink", + "Output Lubricant", + "Failure Reason", + }, + }); + + foreach (var stop in Stops.OrderBy(x => x.JobIndex).ToList()) + { + CsvModel model = new CsvModel(); + model.JobIndex = stop.JobIndex.ToString(); + model.JobName = stop.JobRun.JobName; + model.Thread = stop.ThreadName; + model.Length = ((int)stop.JobRun.JobLength).ToString(); + model.StartTime = stop.JobRun.StartDate.ToLocalTime().ToString(); + model.Duration = stop.Duration.ToStringUnlimitedHours(); + model.EndPosition = stop.JobRun.EndPosition.ToString(); + model.Status = ((JobRunStatus)stop.JobRun.Status).ToString(); + model.SegmentIndex = stop.SegmentIndex.ToString(); + model.Offset = stop.StartMeters.ToString(); + model.ColorSpace = stop.ColorSpace.ToString(); + + switch (stop.ColorSpace) + { + case ColorSpaces.RGB: + model.InputRed = stop.Red.ToString(); + model.InputGreen = stop.Green.ToString(); + model.InputBlue = stop.Blue.ToString(); + break; + case ColorSpaces.LAB: + model.InputL = stop.L.ToString(); + model.InputA = stop.A.ToString(); + model.InputB = stop.B.ToString(); + break; + case ColorSpaces.Catalog: + model.InputCatalog = stop.Catalog; + model.InputCatalogItem = stop.CatalogItem; + break; + case ColorSpaces.Volume: + model.InputCyan = stop.Cyan.ToString(); + model.InputMagenta = stop.Magenta.ToString(); + model.InputYellow = stop.Yellow.ToString(); + model.InputBlack = stop.Black.ToString(); + break; + } + + + model.OutputCyan = stop.CyanOutput.ToString(); + model.OutputMagenta = stop.MagentaOutput.ToString(); + model.OutputYellow = stop.YellowOutput.ToString(); + model.OutputBlack = stop.BlackOutput.ToString(); + model.OutputLightCyan = stop.LightCyanOutput.ToString(); + model.OutputLightMagenta = stop.LightMagentaOutput.ToString(); + model.OutputLightYellow = stop.LightYellowOutput.ToString(); + model.OutputTransparentInk = stop.TransparentInkOutput.ToString(); + model.OutputLubricant = stop.LubricantOutput.ToString(); + model.FailureReason = stop.JobRun.FailedMessage; + + csvFile.Append(model); + } + + csvFile.Dispose(); - var model = await StatisticsProvider.GetStatistics(filters); + NotificationProvider.PushSnackbarItem(MessageType.Success, "Statistics File Export", true, "Export completed successfully.\nTap to open the file.", null, null, async () => + { + await StorageProvider.ShowInExplorer(result.SelectedItem); + }); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error exporting csv file."); + await NotificationProvider.ShowError($"Error exporting the csv file.\n{ex.FlattenMessage()}"); + } + } + } } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Views/MainView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Views/MainView.xaml index 24afcc9c0..099ab57f9 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Views/MainView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/Views/MainView.xaml @@ -5,10 +5,453 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:global="clr-namespace:Tango.FSE.Statistics" xmlns:vm="clr-namespace:Tango.FSE.Statistics.ViewModels" + xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:controls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" + xmlns:autoComplete="clr-namespace:Tango.AutoComplete.Editors;assembly=Tango.AutoComplete" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf" xmlns:local="clr-namespace:Tango.FSE.Statistics.Views" mc:Ignorable="d" - d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> - <Grid> - <TextBlock FontSize="60" HorizontalAlignment="Center" VerticalAlignment="Center">Statistics View</TextBlock> + d:DesignHeight="720" d:DesignWidth="1280" Background="{StaticResource FSE_PrimaryBackgroundBrush}" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + + <UserControl.Resources> + <Style x:Key="EmptyColumnStyle" TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}"> + <Setter Property="Background" Value="{StaticResource FSE_PrimaryBackgroundLightBrush}"></Setter> + <Setter Property="BorderBrush" Value="{StaticResource FSE_PrimaryBackgroundLightBrush}"></Setter> + <Setter Property="BorderThickness" Value="0 0 0 1"></Setter> + <Setter Property="Margin" Value="15 0 0 -1"></Setter> + <Setter Property="Padding" Value="0"></Setter> + <Style.Triggers> + <Trigger Property="IsSelected" Value="True"> + <Setter Property="Background" Value="{StaticResource FSE_PrimaryBackgroundLightBrush}"></Setter> + </Trigger> + </Style.Triggers> + </Style> + + <DataTemplate x:Key="EmptyColumnTemplate"> + <Grid> + <Border Width="30" HorizontalAlignment="Left" Background="{StaticResource FSE_PrimaryBackgroundBrush}" Margin="-28 -10 0 -10" Height="35" /> + <Border Background="{Binding BestMatchBrush,Mode=OneWay}" Width="20" Height="20" HorizontalAlignment="Left" Margin="10 0 0 0"> + <Border.ToolTip> + <TextBlock> + <Run FontWeight="SemiBold">Best Match</Run> + <LineBreak/> + <Run Text="{Binding BestMatchR}"></Run>, + <Run Text="{Binding BestMatchG}"></Run>, + <Run Text="{Binding BestMatchB}"></Run> + </TextBlock> + </Border.ToolTip> + </Border> + </Grid> + </DataTemplate> + + <Style x:Key="EmptyColumnStyle2" TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}"> + <Setter Property="Background" Value="{StaticResource FSE_PrimaryBackgroundLightBrush}"></Setter> + <Setter Property="BorderBrush" Value="{StaticResource FSE_PrimaryBackgroundLightBrush}"></Setter> + <Setter Property="BorderThickness" Value="0 0 0 1"></Setter> + <Setter Property="Margin" Value="0 0 0 -1"></Setter> + <Setter Property="Padding" Value="0"></Setter> + <Style.Triggers> + <Trigger Property="IsSelected" Value="True"> + <Setter Property="Background" Value="{StaticResource FSE_PrimaryBackgroundLightBrush}"></Setter> + </Trigger> + </Style.Triggers> + </Style> + </UserControl.Resources> + + <Grid IsEnabled="{Binding IsFree}"> + + <Border Margin="40 0 0 0"> + <Grid> + <DataGrid Style="{StaticResource FSE_DataGrid}" HeadersVisibility="Column" CellStyle="{StaticResource FSE_DataGrid_Cell}" ItemsSource="{Binding StopsView}" SelectedIndex="-1"> + <DataGrid.GroupStyle> + <GroupStyle> + <GroupStyle.ContainerStyle> + <Style TargetType="{x:Type GroupItem}"> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type GroupItem}"> + <StackPanel> + <Border Background="{StaticResource FSE_PrimaryBackgroundLightBrush}" MinHeight="60" BorderBrush="{StaticResource FSE_BorderBrush}" BorderThickness="1"> + <Grid> + <StackPanel Margin="10 0 0 0" Orientation="Horizontal"> + <material:PackIcon Background="Transparent" Width="24" Height="24" VerticalAlignment="Center" DataContext="{Binding Items[0].Items[0].JobRun}"> + <material:PackIcon.Style> + <Style TargetType="material:PackIcon"> + <Setter Property="Kind" Value="CheckBold"></Setter> + <Setter Property="Foreground" Value="{StaticResource FSE_SuccessBrush}"></Setter> + <Setter Property="ToolTip" Value="Completed"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding Status}" Value="1"> + <Setter Property="Kind" Value="Alert"></Setter> + <Setter Property="Foreground" Value="{StaticResource FSE_WarningBrush}"></Setter> + <Setter Property="ToolTip" Value="Aborted By User"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding Status}" Value="2"> + <Setter Property="Kind" Value="Alert"></Setter> + <Setter Property="Foreground" Value="{StaticResource FSE_ErrorBrush}"></Setter> + <Setter Property="ToolTip" Value="Failed"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </material:PackIcon.Style> + </material:PackIcon> + <TextBlock Margin="10 0 0 0" Width="140" TextWrapping="Wrap" FontWeight="Bold" VerticalAlignment="Center" FontSize="14" Text="{Binding Items[0].Items[0].JobRun.JobName}" /> + <TextBlock Margin="20 0 0 0" Text="{Binding Items[0].Items[0].ThreadName}" VerticalAlignment="Center" Width="100" TextWrapping="Wrap"></TextBlock> + <TextBlock Margin="20 0 0 0" Text="{Binding Items[0].Items[0].JobRun.JobLength}" VerticalAlignment="Center" Width="80"></TextBlock> + <TextBlock Text="{Binding Items[0].Items[0].JobRun.StartDate,Converter={StaticResource DateTimeUTCToShortDateTimeConverter}}" VerticalAlignment="Center" Width="120"></TextBlock> + <TextBlock Text="{Binding Items[0].Items[0].Duration,Mode=OneWay,Converter={StaticResource TotalDyeTimeConverter}}" VerticalAlignment="Center" Width="100"></TextBlock> + <TextBlock Text="{Binding Items[0].Items[0].JobRun.EndPosition,StringFormat=N1}" VerticalAlignment="Center" Width="80"></TextBlock> + </StackPanel> + + <Grid Visibility="{Binding IsAdvancedMode,Converter={StaticResource BooleanToVisibilityConverter}}" DataContext="{Binding Items[0].Items[0]}" Width="250" Margin="0 0 50 5" HorizontalAlignment="Right" VerticalAlignment="Bottom"> + <StackPanel Orientation="Horizontal"> + <TextBlock Width="175" VerticalAlignment="Center" Foreground="{StaticResource FSE_GrayBrush}" FontSize="{StaticResource FSE_SmallerFontSize}" FontStyle="Italic"> + <Run>App:</Run> + <Run Text="{Binding JobRun.ApplicationVersion,TargetNullValue='N/A'}"></Run>, + <Run>Firmware:</Run> + <Run Text="{Binding JobRun.FirmwareVersion,TargetNullValue='N/A'}"></Run>, + <Run>CE:</Run> + <Run Text="{Binding JobRun.CeVersion,TargetNullValue='N/A'}"></Run> + </TextBlock> + + <controls:ToggleIconButton x:Name="toggleProcess" CheckedIcon="ArrowDown" UncheckedIcon="Settings" Width="14" Background="Transparent" Foreground="{StaticResource FSE_GrayBrush}" UncheckedForeground="{StaticResource FSE_GrayBrush}" Height="14" Cursor="Hand" Margin="5 0 0 0" /> + + <Popup AllowsTransparency="True" PlacementTarget="{Binding ElementName=toggleProcess}" StaysOpen="False" Placement="Bottom" IsOpen="{Binding ElementName=toggleProcess,Path=IsChecked,Mode=TwoWay}"> + <Border Background="{StaticResource FSE_PrimaryBackgroundLighterBrush}" Padding="5" CornerRadius="5"> + <Grid> + <StackPanel> + <TextBlock FontWeight="Bold" FontStyle="Italic" TextDecorations="Underline">Process Parameters</TextBlock> + <ItemsControl Margin="0 5 0 0" ItemsSource="{Binding ProcessParameters.Parameters}" FontSize="{StaticResource FSE_SmallerFontSize}"> + <ItemsControl.ItemTemplate> + <DataTemplate> + <TextBlock> + <Run Text="{Binding Name}" FontWeight="SemiBold"></Run>: + <Run Text="{Binding Value}"></Run> + </TextBlock> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + </StackPanel> + </Grid> + </Border> + </Popup> + </StackPanel> + </Grid> + + <controls:IconButton DataContext="{Binding Items[0].Items[0]}" Command="{Binding ShowFailedMessageCommand}" CommandParameter="{Binding}" Width="32" Height="32" ToolTip="Show failure reason" Cursor="Hand" HorizontalAlignment="Right" VerticalAlignment="Center" Icon="MessageAlert" Foreground="{StaticResource FSE_ErrorBrush}" Margin="0 0 10 0"> + <controls:IconButton.Style> + <Style TargetType="controls:IconButton" BasedOn="{StaticResource {x:Type controls:IconButton}}"> + <Setter Property="Visibility" Value="Hidden"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding JobRun.Status}" Value="2"> + <Setter Property="Visibility" Value="Visible"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </controls:IconButton.Style> + </controls:IconButton> + </Grid> + </Border> + <ItemsPresenter /> + </StackPanel> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + </GroupStyle.ContainerStyle> + </GroupStyle> + <GroupStyle> + <GroupStyle.HeaderTemplate> + <DataTemplate> + <StackPanel> + <Border Margin="20 0 0 0" Background="#383838" Padding="0 5" BorderBrush="{StaticResource FSE_PrimaryBackgroundMidBrush}" BorderThickness="0 0 0 1"> + <StackPanel Orientation="Horizontal"> + <TextBlock Margin="10 0 0 0" FontWeight="Bold" VerticalAlignment="Center" Foreground="{StaticResource FSE_GrayBrush}"> + <Run>Segment</Run> + <Run Text="{Binding Name,Mode=OneWay}"></Run> + </TextBlock> + + <TextBlock Margin="233 0 0 0" Text="{Binding Items[0].Segment.Length,StringFormat=N1}" VerticalAlignment="Center" Width="80" Foreground="{StaticResource FSE_GrayBrush}" FontSize="12"></TextBlock> + </StackPanel> + </Border> + </StackPanel> + </DataTemplate> + </GroupStyle.HeaderTemplate> + </GroupStyle> + </DataGrid.GroupStyle> + <DataGrid.Columns> + <DataGridTemplateColumn Header=" NAME" Width="190" CellStyle="{StaticResource EmptyColumnStyle}" CellTemplate="{StaticResource EmptyColumnTemplate}" /> + <DataGridTextColumn Header="THREAD" Width="120" CellStyle="{StaticResource EmptyColumnStyle2}" /> + <DataGridTextColumn Header="LENGTH" Width="80" CellStyle="{StaticResource EmptyColumnStyle2}" /> + <DataGridTextColumn Header="START TIME" Width="120" CellStyle="{StaticResource EmptyColumnStyle2}" /> + <DataGridTextColumn Header="DURATION" Width="100" CellStyle="{StaticResource EmptyColumnStyle2}" /> + <DataGridTextColumn Header="END POSITION" Width="120" CellStyle="{StaticResource EmptyColumnStyle2}" /> + <DataGridTextColumn Header="OFFSET" Width="90" Binding="{Binding StartMeters}" /> + <DataGridTextColumn Header="COLOR SPACE" Width="120" Binding="{Binding ColorSpace}" /> + <DataGridTextColumn Header="INPUT" Width="150" Binding="{Binding Input}" /> + <DataGridTemplateColumn Header="OUTPUT" Width="*"> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <Grid> + <StackPanel Orientation="Horizontal"> + <Grid> + <TextBlock HorizontalAlignment="Center" FontWeight="Bold"> + <Run Foreground="Cyan" Text="{Binding CyanOutput,Mode=OneWay,TargetNullValue=0}"></Run> + , + <Run Foreground="Magenta" Text="{Binding MagentaOutput,Mode=OneWay,TargetNullValue=0}"></Run> + , + <Run Foreground="Yellow" Text="{Binding YellowOutput,Mode=OneWay,TargetNullValue=0}"></Run> + , + <Run Foreground="Black" Text="{Binding BlackOutput,Mode=OneWay,TargetNullValue=0}"></Run> + , + <Run Foreground="#9BFFFF" Text="{Binding LightCyanOutput,Mode=OneWay,TargetNullValue=0}"></Run> + , + <Run Foreground="#FFA5FF" Text="{Binding LightMagentaOutput,Mode=OneWay,TargetNullValue=0}"></Run> + , + <Run Foreground="#FFFF9B" Text="{Binding LightYellowOutput,Mode=OneWay,TargetNullValue=0}"></Run> + , + <Run Foreground="#BBBBBB" Text="{Binding TransparentInkOutput,Mode=OneWay,TargetNullValue=0}"></Run> + </TextBlock> + </Grid> + </StackPanel> + </Grid> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + </DataGrid.Columns> + </DataGrid> + <Border Margin="0 48 0 0" Background="{StaticResource FSE_PrimaryBackgroundBrush}" Visibility="{Binding IsResultsAvailable,Converter={StaticResource BooleanToVisibilityInverseConverter}}"> + <Border Width="400" Padding="50" CornerRadius="25" HorizontalAlignment="Center" VerticalAlignment="Center" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}"> + <TextBlock HorizontalAlignment="Center" Foreground="{StaticResource FSE_GrayBrush}" FontSize="25">NO DATA AVAILABLE</TextBlock> + </Border> + </Border> + </Grid> + </Border> + + <!--Left Panel--> + <Border HorizontalAlignment="Left" Background="{StaticResource FSE_PrimaryBackgroundMidBrush}" BorderThickness="0 0 1 0" BorderBrush="{StaticResource FSE_BorderBrush}"> + <Border.Style> + <Style TargetType="Border"> + <Setter Property="Margin" Value="-300 0 0 0"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding ElementName=chkSettingsBar,Path=IsChecked}" Value="True"> + <DataTrigger.EnterActions> + <BeginStoryboard> + <Storyboard> + <ThicknessAnimation Storyboard.TargetProperty="Margin" To="0 0 0 0" Duration="00:00:0.2" /> + </Storyboard> + </BeginStoryboard> + </DataTrigger.EnterActions> + <DataTrigger.ExitActions> + <BeginStoryboard> + <Storyboard> + <ThicknessAnimation Storyboard.TargetProperty="Margin" To="-300 0 0 0" Duration="00:00:0.2" /> + </Storyboard> + </BeginStoryboard> + </DataTrigger.ExitActions> + </DataTrigger> + </Style.Triggers> + </Style> + </Border.Style> + <Grid Width="300" ClipToBounds="False"> + <DockPanel> + <Menu DockPanel.Dock="Top" Margin="0 0 0 0" Background="{StaticResource FSE_PrimaryBackgroundMidBrush}"> + <MenuItem Header="_File"> + <MenuItem Header="Export To CSV" Command="{Binding ExportToCsvCommand}"> + <MenuItem.Icon> + <material:PackIcon Kind="FileCsv" /> + </MenuItem.Icon> + </MenuItem> + </MenuItem> + </Menu> + + <DockPanel> + <Button DockPanel.Dock="Bottom" Command="{Binding GetStatisticsCommand}" HorizontalAlignment="Center" Width="250" Style="{StaticResource FSE_Button_Polygon}" Height="40" FontSize="14" Margin="0 20 0 30" IsEnabled="{Binding MachineProvider.IsPPCAvailable}">Get Statistics</Button> + + <ScrollViewer IsEnabled="{Binding IsFiltersAvailable}" Margin="0 30 0 0" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"> + <Border Padding="20"> + <StackPanel VerticalAlignment="Top"> + <StackPanel> + <GroupBox Padding="5 0 0 0" Style="{StaticResource FSE_Game_GroupBox}" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}"> + <GroupBox.Header> + <TextBox FontSize="{StaticResource FSE_SmallerFontSize}">Start Date</TextBox> + </GroupBox.Header> + <DatePicker SelectedDate="{Binding StartSelectedDate}" /> + </GroupBox> + + <GroupBox Margin="0 30 0 0" Padding="5 0 0 0" Style="{StaticResource FSE_Game_GroupBox}" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}"> + <GroupBox.Header> + <TextBox FontSize="{StaticResource FSE_SmallerFontSize}">End Date</TextBox> + </GroupBox.Header> + <DatePicker SelectedDate="{Binding EndSelectedDate}" /> + </GroupBox> + + <GroupBox Margin="0 30 0 0" Padding="5 0 0 0" Style="{StaticResource FSE_Game_GroupBox}" Height="49" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}"> + <GroupBox.Header> + <TextBox FontSize="{StaticResource FSE_SmallerFontSize}">Threads</TextBox> + </GroupBox.Header> + <controls:SelectionComboBox Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" Margin="-5 0 0 0" Width="Auto" ItemsSource="{Binding SelectedThreads}" DisplayMemberPath="Name" FontSize="{StaticResource FSE_SmallFontSize}" /> + </GroupBox> + + <GroupBox Margin="0 30 0 0" Padding="5 0 0 0" Style="{StaticResource FSE_Game_GroupBox}" Height="49" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}"> + <GroupBox.Header> + <TextBox FontSize="{StaticResource FSE_SmallerFontSize}">Status</TextBox> + </GroupBox.Header> + <controls:SelectionComboBox Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" Margin="-5 0 0 0" Width="Auto" ItemsSource="{Binding JobRunSelectedStatuses}" FontSize="{StaticResource FSE_SmallFontSize}" /> + </GroupBox> + + <GroupBox Margin="0 30 0 0" Padding="5 0 0 0" Style="{StaticResource FSE_Game_GroupBox}" Height="55" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}"> + <GroupBox.Header> + <TextBox FontSize="{StaticResource FSE_SmallerFontSize}">Job</TextBox> + </GroupBox.Header> + <DockPanel> + <controls:ToggleIconButton DockPanel.Dock="Right" Width="18" Height="18" CheckedIcon="FormatLetterMatches" UncheckedIcon="FormatLetterStartsWith" Margin="10 1 5 0" VerticalAlignment="Center" IsChecked="{Binding JobNameExact,Mode=TwoWay}" CheckedForeground="{StaticResource FSE_OrangeBrush}" ToolTip="Match exact job name or anything that starts with" /> + <autoComplete:AutoCompleteTextBox BorderThickness="0" FontSize="{StaticResource FSE_SmallFontSize}" material:HintAssist.Hint="Job Name" MaxPopupHeight="300" Margin="0 5 0 0" Provider="{Binding JobsAutoCompleteProvider}" Text="{Binding JobName,Mode=TwoWay}" /> + </DockPanel> + </GroupBox> + + <Grid Margin="0 30 0 0"> + <GroupBox Padding="5 0 0 0" Style="{StaticResource FSE_Game_GroupBox}" Height="54" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}"> + <GroupBox.Header> + <TextBox FontSize="{StaticResource FSE_SmallerFontSize}">Length</TextBox> + </GroupBox.Header> + <mahapps:RangeSlider Focusable="True" Height="40" Margin="5 5 5 5" Minimum="0" Maximum="10000" ExtendedMode="True" + LowerValue="{Binding LengthLowerValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" + UpperValue="{Binding LengthUpperValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" + VerticalAlignment="Center" IsSnapToTickEnabled="True" FontSize="8"/> + </GroupBox> + + <Grid HorizontalAlignment="Right" VerticalAlignment="Top" Width="130" TextBlock.Foreground="{StaticResource FSE_GrayBrush}"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="1*" /> + <ColumnDefinition Width="30" /> + <ColumnDefinition Width="1*" /> + </Grid.ColumnDefinitions> + <TextBlock HorizontalAlignment="Left" Text="{Binding LengthLowerValue}" Grid.Column="0"></TextBlock> + <material:PackIcon HorizontalAlignment="Center" Grid.Column="1" Kind="ArrowLeftRight" Margin="0 -2 0 0" VerticalAlignment="Center" Width="20" Height="20"></material:PackIcon> + <TextBlock HorizontalAlignment="Right" Text="{Binding LengthUpperValue}" Grid.Column="2"></TextBlock> + </Grid> + </Grid> + </StackPanel> + </StackPanel> + </Border> + </ScrollViewer> + + </DockPanel> + </DockPanel> + + <Grid HorizontalAlignment="Right" Margin="0 0 -30 0" VerticalAlignment="Center" Width="30" Height="350" ClipToBounds="False"> + <Grid ClipToBounds="True"> + <Polygon Fill="{StaticResource FSE_PrimaryBackgroundMidBrush}" Width="95" Margin="-65 0 0 0" Points="0,0 100,30 100,320 0,350" Stroke="{StaticResource FSE_BorderBrush}" Stretch="Fill"></Polygon> + </Grid> + <controls:ToggleIconButton x:Name="chkSettingsBar" Cursor="Hand" CheckedIcon="ChevronLeftCircle" UncheckedIcon="ChevronRightCircle" Width="32" Height="32" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0 0 -15 0" IsChecked="{Binding IsSettingsBarOpened}" /> + </Grid> + </Grid> + </Border> + + <!--Summaries--> + <Border HorizontalAlignment="Right" VerticalAlignment="Bottom" MinWidth="930" Height="200" Background="#D6282828" Opacity="1" CornerRadius="25 25 0 0" BorderThickness="1 0 1 0" BorderBrush="{StaticResource FSE_BorderBrush}"> + <Border.Style> + <Style TargetType="Border"> + <Setter Property="Margin" Value="0 0 30 -176"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding ElementName=chkSumBar,Path=IsChecked}" Value="True"> + <DataTrigger.EnterActions> + <BeginStoryboard> + <Storyboard> + <ThicknessAnimation Storyboard.TargetProperty="Margin" To="0 0 30 0" Duration="00:00:0.2" /> + </Storyboard> + </BeginStoryboard> + </DataTrigger.EnterActions> + <DataTrigger.ExitActions> + <BeginStoryboard> + <Storyboard> + <ThicknessAnimation Storyboard.TargetProperty="Margin" To="0 0 30 -176" Duration="00:00:0.2" /> + </Storyboard> + </BeginStoryboard> + </DataTrigger.ExitActions> + </DataTrigger> + </Style.Triggers> + </Style> + </Border.Style> + + + <DockPanel> + <Border DockPanel.Dock="Top" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" BorderBrush="{StaticResource FSE_BorderBrush}" BorderThickness="0 1 0 0" CornerRadius="25 25 0 0"> + <DockPanel HorizontalAlignment="Center"> + <controls:ToggleIconButton x:Name="chkSumBar" Cursor="Hand" CheckedIcon="ChevronDown" UncheckedIcon="ChevronUp" Width="24" Height="24" VerticalAlignment="Top" HorizontalAlignment="Center" Margin="0 0 0 0" IsChecked="{Binding IsSummariesBarOpened}" /> + <TextBlock Margin="10 0 0 0" VerticalAlignment="Center">Statistics</TextBlock> + </DockPanel> + </Border> + <Grid> + <DockPanel> + <StackPanel Margin="20 10 10 10" TextElement.FontSize="{StaticResource FSE_SmallFontSize}"> + <TextBlock><Run FontWeight="SemiBold">Total Runs:</Run> <Run Text="{Binding Stats.TotalRuns}"></Run></TextBlock> + <TextBlock Margin="0 8 0 0"><Run FontWeight="SemiBold">Total Dyeing Length:</Run> <Run Text="{Binding Stats.TotalDyeingLength,StringFormat='N'}"></Run></TextBlock> + <TextBlock Margin="0 8 0 0"><Run FontWeight="SemiBold">Average Dyeing Length:</Run> <Run Text="{Binding Stats.AverageDyeingLength,StringFormat='N'}"></Run></TextBlock> + <TextBlock Margin="0 8 0 0"><Run FontWeight="SemiBold">Total Dyeing Time:</Run> <Run Text="{Binding Stats.TotalDyeingTime,Converter={StaticResource TimeSpanHumanizeConverter}}"></Run></TextBlock> + <TextBlock Margin="0 8 0 0"><Run FontWeight="SemiBold">Average Dyeing Time:</Run> <Run Text="{Binding Stats.AverageDyeingTime,Converter={StaticResource TimeSpanHumanizeConverter}}"></Run></TextBlock> + </StackPanel> + + <DockPanel> + <lvc:PieChart Opacity="1" FontSize="{StaticResource FSE_SmallFontSize}" DisableAnimations="True" LegendLocation="Bottom" Hoverable="True" DataTooltip="{x:Null}" HorizontalAlignment="Center" Width="250"> + <lvc:PieChart.Series> + <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_PrimaryBackgroundBrush}" Fill="#5FC139" FontSize="12" Title="Completed" Values="{Binding Stats.CompletedRuns,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="True" + LabelPoint="{Binding Stats.StatusCounts}"/> + <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_PrimaryBackgroundBrush}" Fill="{StaticResource FSE_ErrorBrush}" FontSize="12" Title="Failed" Values="{Binding Stats.FailedRuns,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="True" + LabelPoint="{Binding Stats.StatusCounts}"/> + <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_PrimaryBackgroundBrush}" Fill="#E19200" FontSize="12" Title="Aborted" Values="{Binding Stats.AbortedRuns,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="True" + LabelPoint="{Binding Stats.StatusCounts}"/> + </lvc:PieChart.Series> + </lvc:PieChart> + + <DockPanel> + <TextBlock FontSize="12" DockPanel.Dock="Bottom" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0 0 0 3">Ink Consumption</TextBlock> + <lvc:PieChart Opacity="0.8" FontSize="{StaticResource FSE_SmallFontSize}" DisableAnimations="True" LegendLocation="None" Hoverable="True" DataTooltip="{x:Null}" HorizontalAlignment="Center" Height="155" Width="155" VerticalAlignment="Top" Margin="0 0 0 0"> + <lvc:PieChart.Series> + <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[0].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[0].Title}" Values="{Binding Stats.LiquidQuantities[0].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/> + <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[1].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[1].Title}" Values="{Binding Stats.LiquidQuantities[1].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/> + <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[2].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[2].Title}" Values="{Binding Stats.LiquidQuantities[2].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/> + <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[3].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[3].Title}" Values="{Binding Stats.LiquidQuantities[3].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/> + <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[4].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[4].Title}" Values="{Binding Stats.LiquidQuantities[4].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/> + <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[5].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[5].Title}" Values="{Binding Stats.LiquidQuantities[5].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/> + <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[6].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[6].Title}" Values="{Binding Stats.LiquidQuantities[6].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/> + <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[7].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[7].Title}" Values="{Binding Stats.LiquidQuantities[7].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/> + <lvc:PieSeries Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Stroke="{StaticResource FSE_BorderBrush}" Fill="{Binding Stats.LiquidQuantities[8].LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}" FontSize="12" Title="{Binding Stats.LiquidQuantities[8].Title}" Values="{Binding Stats.LiquidQuantities[8].Quantity,Converter={StaticResource DoubleToChartValuesConverter}}" DataLabels="False" LabelPoint="{Binding Stats.QuantityCounts}"/> + </lvc:PieChart.Series> + </lvc:PieChart> + </DockPanel> + + <ItemsControl Margin="20 10 0 0" Width="460" HorizontalAlignment="Left" ItemsSource="{Binding Stats.LiquidQuantities}" FontSize="{StaticResource FSE_SmallerFontSize}"> + <ItemsControl.ItemsPanel> + <ItemsPanelTemplate> + <UniformGrid Columns="4"/> + </ItemsPanelTemplate> + </ItemsControl.ItemsPanel> + <ItemsControl.ItemTemplate> + <DataTemplate> + <Border Background="Transparent"> + <StackPanel Orientation="Horizontal" Margin="4"> + <Ellipse VerticalAlignment="Top" Margin="0 0 0 0" StrokeThickness="1" Stroke="{StaticResource FSE_BorderBrush}" Width="30" Height="30" Fill="{Binding LiquidType,Converter={StaticResource LiquidTypeToColorConverter}}"> + + </Ellipse> + <StackPanel Orientation="Vertical" Margin="4 2 0 0"> + <TextBlock Text="{Binding LiquidType,Converter={StaticResource EnumToDescriptionConverter}}" FontWeight="SemiBold"></TextBlock> + <TextBlock > + <Run Text="{Binding Liters,Mode=OneWay,StringFormat='0.000'}"></Run> + <Run Text=" liters"></Run> + </TextBlock> + </StackPanel> + </StackPanel> + </Border> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + </DockPanel> + </DockPanel> + </Grid> + </DockPanel> + </Border> </Grid> </UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/app.config b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/app.config index 36bc04f85..73edaaf87 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/app.config +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/app.config @@ -74,6 +74,26 @@ <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" /> </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="SharpDX.Mathematics" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="SharpDX.Direct3D11" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="SharpDX.DXGI" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" /> + </dependentAssembly> </assemblyBinding> </runtime> <entityFramework> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/packages.config b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/packages.config index dd8c723e4..a637c2e6c 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/packages.config +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Statistics/packages.config @@ -3,6 +3,8 @@ <package id="ControlzEx" version="3.0.2.4" targetFramework="net461" /> <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.6.5" targetFramework="net461" /> <package id="MaterialDesignColors" version="1.2.2" targetFramework="net461" /> <package id="MaterialDesignThemes" version="3.0.1" targetFramework="net461" /> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/SelectionComboBox.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/SelectionComboBox.cs new file mode 100644 index 000000000..2ae90ce8f --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/SelectionComboBox.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +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.Core.ExtensionMethods; +using Tango.SharedUI.Components; +using Tango.SharedUI.Controls; + +namespace Tango.FSE.Common.Controls +{ + public class SelectionComboBox : Control + { + private bool _preventAllSelected = false; + private bool _preventSelection = false; + private ICollectionView _filterView; + private TextBox _filterTextBox; + private Popup _popup; + private Button _toggle; + private bool _preventToggle; + + public bool? AllSelected + { + get { return (bool?)GetValue(AllSelectedProperty); } + set { SetValue(AllSelectedProperty, value); } + } + public static readonly DependencyProperty AllSelectedProperty = + DependencyProperty.Register("AllSelected", typeof(bool?), typeof(SelectionComboBox), new PropertyMetadata(null, (d, e) => (d as SelectionComboBox).OnAllSelectedChanged())); + + public ISelectedObjectCollection ItemsSource + { + get { return (ISelectedObjectCollection)GetValue(ItemsSourceProperty); } + set { SetValue(ItemsSourceProperty, value); } + } + public static readonly DependencyProperty ItemsSourceProperty = + DependencyProperty.Register("ItemsSource", typeof(ISelectedObjectCollection), typeof(SelectionComboBox), new PropertyMetadata(null, (d, e) => (d as SelectionComboBox).OnItemsSourceChanged())); + + public String DisplayMemberPath + { + get { return (String)GetValue(DisplayMemberPathProperty); } + set { SetValue(DisplayMemberPathProperty, value); } + } + public static readonly DependencyProperty DisplayMemberPathProperty = + DependencyProperty.Register("DisplayMemberPath", typeof(String), typeof(SelectionComboBox), new PropertyMetadata(null)); + + public String Filter + { + get { return (String)GetValue(FilterProperty); } + set { SetValue(FilterProperty, value); } + } + public static readonly DependencyProperty FilterProperty = + DependencyProperty.Register("Filter", typeof(String), typeof(SelectionComboBox), new PropertyMetadata(null, (d, e) => (d as SelectionComboBox).OnFilterChanged())); + + public bool IsOpened + { + get { return (bool)GetValue(IsOpenedProperty); } + set { SetValue(IsOpenedProperty, value); } + } + public static readonly DependencyProperty IsOpenedProperty = + DependencyProperty.Register("IsOpened", typeof(bool), typeof(SelectionComboBox), new PropertyMetadata(false)); + + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + if (!this.IsInDesignMode()) + { + _filterTextBox = GetTemplateChild("filterTextBox") as TextBox; + _popup = GetTemplateChild("popup") as Popup; + _toggle = GetTemplateChild("toggle") as Button; + _toggle.Click += _toggle_Click; + _popup.Opened += _popup_Opened; + _popup.Closed += _popup_Closed; + } + } + + private void _toggle_Click(object sender, RoutedEventArgs e) + { + if (!_preventToggle) + { + if (!_popup.IsOpen) + { + _popup.IsOpen = true; + } + else + { + _popup.IsOpen = false; + } + } + + _preventToggle = false; + } + + private async void _popup_Closed(object sender, EventArgs e) + { + _preventToggle = true; + await Task.Delay(100); + _preventToggle = false; + } + + private void _popup_Opened(object sender, EventArgs e) + { + _filterTextBox.Focus(); + } + + private void OnItemsSourceChanged() + { + if (ItemsSource != null) + { + _filterView = CollectionViewSource.GetDefaultView(ItemsSource); + _filterView.Filter = ApplyFilter; + ItemsSource.SelectionChanged += ItemsSource_SelectionChanged; + } + } + + private void ItemsSource_SelectionChanged(object sender, EventArgs e) + { + if (!_preventSelection) + { + if (ItemsSource.GetItems().All(x => x.IsSelected)) + { + _preventAllSelected = true; + AllSelected = true; + } + else if (ItemsSource.GetItems().All(x => !x.IsSelected)) + { + _preventAllSelected = true; + AllSelected = false; + } + else + { + _preventAllSelected = true; + AllSelected = null; + } + } + + _preventAllSelected = false; + } + + private void OnAllSelectedChanged() + { + _preventSelection = true; + + if (!_preventAllSelected && AllSelected != null) + { + + foreach (var item in ItemsSource.GetItems()) + { + item.IsSelected = AllSelected.Value; + } + } + + _preventSelection = false; + } + + private void OnFilterChanged() + { + _filterView?.Refresh(); + } + + private bool ApplyFilter(object obj) + { + if (Filter.IsNotNullOrEmpty()) + { + if (obj is SelectedObject selectedObject) + { + try + { + return selectedObject.Data.GetPropertyValueByPath(DisplayMemberPath).ToStringSafe().ToLower().Contains(Filter.ToLower()); + } + catch + { + return true; + } + } + else + { + return false; + } + } + else + { + return true; + } + } + + static SelectionComboBox() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(SelectionComboBox), new FrameworkPropertyMetadata(typeof(SelectionComboBox))); + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/SelectionComboBox.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/SelectionComboBox.xaml new file mode 100644 index 000000000..551693f2f --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/SelectionComboBox.xaml @@ -0,0 +1,94 @@ +<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:local="clr-namespace:Tango.FSE.Common.Controls" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"> + + <Style TargetType="{x:Type local:SelectionComboBox}"> + <Setter Property="Height" Value="26"></Setter> + <Setter Property="Width" Value="200"></Setter> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type local:SelectionComboBox}"> + <Border> + <Grid> + <Border Background="{TemplateBinding Background}" CornerRadius="3" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" TextElement.Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> + <DockPanel> + <Button Style="{StaticResource FSE_FlatButton_OpacityHover}" x:Name="toggle" Width="30" Padding="0" Height="16" DockPanel.Dock="Right" BorderBrush="{x:Null}" HorizontalAlignment="Left" Foreground="Black"> + <Path + Width="8" Height="8" + Margin="0 0 5 0" + Stretch="Uniform" + HorizontalAlignment="Right" + VerticalAlignment="Center" + Data="M7,10L12,15L17,10H7Z" + Fill="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=Foreground}" /> + </Button> + <TextBlock VerticalAlignment="Center" Foreground="{StaticResource FSE_PrimaryForegroundBrush}" Margin="5"> + <TextBlock.Style> + <Style TargetType="{x:Type TextBlock}"> + <Setter Property="Text"> + <Setter.Value> + <MultiBinding StringFormat="{}{0}{1}"> + <Binding RelativeSource="{RelativeSource AncestorType=local:SelectionComboBox}" Path="ItemsSource.SynchedSource.Count"/> + <Binding Source=" Selected" /> + </MultiBinding> + </Setter.Value> + </Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=local:SelectionComboBox},Path=ItemsSource.SynchedSource.Count}" Value="0"> + <Setter Property="Text" Value="All Selected"/> + </DataTrigger> + </Style.Triggers> + </Style> + </TextBlock.Style> + </TextBlock> + </DockPanel> + </Border> + <Popup x:Name="popup" MinWidth="{Binding RelativeSource={RelativeSource AncestorType=local:SelectionComboBox},Path=ActualWidth}" AllowsTransparency="True" StaysOpen="False"> + <Border Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" Padding="3" CornerRadius="0 0 3 3" Margin="0 5 0 0"> + <Border.Effect> + <DropShadowEffect Opacity="0.5" /> + </Border.Effect> + <DockPanel> + <DockPanel Margin="0 2 0 5" DockPanel.Dock="Top"> + <DockPanel> + <materialDesign:PackIcon VerticalAlignment="Center" Kind="Magnify" Foreground="{StaticResource FSE_GrayBrush}" /> + <TextBox x:Name="filterTextBox" Style="{StaticResource FSE_Rounded_Corners_TextBox}" Text="{Binding RelativeSource={RelativeSource AncestorType=local:SelectionComboBox},Path=Filter,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></TextBox> + </DockPanel> + </DockPanel> + <DockPanel Margin="2 0 0 5" DockPanel.Dock="Top"> + <CheckBox IsChecked="{Binding RelativeSource={RelativeSource AncestorType=local:SelectionComboBox},Path=AllSelected}" /> + <TextBlock VerticalAlignment="Center" Margin="5 0 0 0" Text="All"></TextBlock> + </DockPanel> + <ListBox Style="{StaticResource FSE_BlankListBox}" Padding="0" Margin="0" BorderThickness="0" HorizontalAlignment="Stretch" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=local:SelectionComboBox},Path=ItemsSource}" MaxHeight="200" DisplayMemberPath="Data" HorizontalContentAlignment="Stretch"> + <ListBox.ItemTemplate> + <DataTemplate> + <DockPanel Margin="2"> + <CheckBox IsChecked="{Binding IsSelected,Mode=TwoWay}"> + <CheckBox.Content> + <TextBlock VerticalAlignment="Center" Margin="5 0 0 0"> + <TextBlock.Text> + <MultiBinding Converter="{StaticResource DisplayMemberPathToStringConverter}"> + <Binding Path="Data" /> + <Binding RelativeSource="{RelativeSource AncestorType=local:SelectionComboBox}" Path="DisplayMemberPath" /> + </MultiBinding> + </TextBlock.Text> + </TextBlock> + </CheckBox.Content> + </CheckBox> + </DockPanel> + </DataTemplate> + </ListBox.ItemTemplate> + </ListBox> + </DockPanel> + </Border> + </Popup> + </Grid> + </Border> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + +</ResourceDictionary>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/DisplayMemberPathToStringConverter.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/DisplayMemberPathToStringConverter.cs new file mode 100644 index 000000000..99806afc4 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/DisplayMemberPathToStringConverter.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Data; +using Tango.Core.ExtensionMethods; + +namespace Tango.FSE.Common.Converters +{ + public class DisplayMemberPathToStringConverter : IMultiValueConverter + { + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + try + { + if (values[0] != null && values[1].ToStringSafe() != null && values[1] != DependencyProperty.UnsetValue) + { + return values[0].GetPropertyValueByPath(values[1].ToStringSafe()); + } + else + { + return values[0].ToStringSafe(); + } + } + catch + { + return values[0].ToStringSafe(); + } + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/DoubleToChartValuesConverter.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/DoubleToChartValuesConverter.cs index 5d6eba085..d0bab62c6 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/DoubleToChartValuesConverter.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/DoubleToChartValuesConverter.cs @@ -12,7 +12,7 @@ namespace Tango.FSE.Common.Converters { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return new LiveCharts.ChartValues<double>() { (double)value }; + return new LiveCharts.ChartValues<double>() { System.Convert.ToDouble(value) }; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/LiquidTypeToColorConverter.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/LiquidTypeToColorConverter.cs new file mode 100644 index 000000000..672032868 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/LiquidTypeToColorConverter.cs @@ -0,0 +1,51 @@ +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.Enumerations; + +namespace Tango.FSE.Common.Converters +{ + public class LiquidTypeToColorConverter : IValueConverter + { + public static SolidColorBrush LightCyan { get; set; } = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#9BFFFF")); + public static SolidColorBrush LightMagenta { get; set; } = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFA5FF")); + public static SolidColorBrush LightYellow { get; set; } = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFFF9B")); + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + switch ((LiquidTypes)value) + { + case LiquidTypes.Cyan: + return Brushes.Cyan; + case LiquidTypes.Magenta: + return Brushes.Magenta; + case LiquidTypes.Yellow: + return Brushes.Yellow; + case LiquidTypes.Black: + return Brushes.Black; + case LiquidTypes.Lubricant: + return Brushes.Beige; + case LiquidTypes.LightCyan: + return LightCyan; + case LiquidTypes.LightMagenta: + return LightMagenta; + case LiquidTypes.LightYellow: + return LightYellow; + case LiquidTypes.TransparentInk: + return Brushes.Transparent; + } + + return Colors.Transparent; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/NanolitersToLitersConverter.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/NanolitersToLitersConverter.cs new file mode 100644 index 000000000..96faf5519 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Converters/NanolitersToLitersConverter.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.FSE.Common.Converters +{ + public class NanolitersToLitersConverter : 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/FSE/Tango.FSE.Common/Resources/Controls.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Controls.xaml index 7b3fd9048..e2b01843e 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Controls.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Controls.xaml @@ -14,6 +14,7 @@ <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Controls/ProgressRingDouble.xaml" /> <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Controls/FSEGroupBox.xaml" /> <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Controls/FSERoundedCornersComboBox.xaml" /> + <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Controls/SelectionComboBox.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml index 869e886d4..d6bf2376e 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml @@ -55,4 +55,7 @@ <localConverters:TotalDyeTimeConverter x:Key="TotalDyeTimeConverter" /> <localConverters:TotalMetersConverter x:Key="TotalMetersConverter" /> <localConverters:CapitalizationConverter x:Key="CapitalizationConverter" /> + <localConverters:DisplayMemberPathToStringConverter x:Key="DisplayMemberPathToStringConverter" /> + <localConverters:LiquidTypeToColorConverter x:Key="LiquidTypeToColorConverter" /> + <localConverters:NanolitersToLitersConverter x:Key="NanolitersToLitersConverter" /> </ResourceDictionary>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj index f5e8e48dc..6dea217cb 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj @@ -201,17 +201,21 @@ <Compile Include="Controls\RunningJobViewer.xaml.cs"> <DependentUpon>RunningJobViewer.xaml</DependentUpon> </Compile> + <Compile Include="Controls\SelectionComboBox.cs" /> <Compile Include="Controls\TextIconButton.cs" /> <Compile Include="Controls\ToggleIconButton.cs" /> <Compile Include="Converters\CapitalizationConverter.cs" /> <Compile Include="Converters\DateTimeUtcHumanizeConverter.cs" /> + <Compile Include="Converters\DisplayMemberPathToStringConverter.cs" /> <Compile Include="Converters\DoubleToChartValuesConverter.cs" /> <Compile Include="Converters\EventTypeTechnicalDescriptionConverter.cs" /> <Compile Include="Converters\EventTypeDescriptionConverter.cs" /> <Compile Include="Converters\EventTypeTitleConverter.cs" /> <Compile Include="Converters\FilePathToIconConverter.cs" /> <Compile Include="Converters\JobProgressToPositionConverter.cs" /> + <Compile Include="Converters\LiquidTypeToColorConverter.cs" /> <Compile Include="Converters\LiquidTypeToShortNameConverter.cs" /> + <Compile Include="Converters\NanolitersToLitersConverter.cs" /> <Compile Include="Converters\TimeSpanHumanizeConverter.cs" /> <Compile Include="Converters\TotalDyeTimeConverter.cs" /> <Compile Include="Converters\TotalMetersConverter.cs" /> @@ -394,6 +398,10 @@ <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </Page> + <Page Include="Controls\SelectionComboBox.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> <Page Include="Controls\TextIconButton.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Statistics/DefaultStatisticsProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Statistics/DefaultStatisticsProvider.cs index f5b44b25d..56e5907dd 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Statistics/DefaultStatisticsProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Statistics/DefaultStatisticsProvider.cs @@ -22,7 +22,6 @@ namespace Tango.FSE.UI.Statistics try { LogManager.Log("Retrieving remote machine statistics required filters data..."); - var response = await MachineProvider.MachineOperator.SendGenericRequest<GetStatisticsRequiredFiltersRequest, GetStatisticsRequiredFiltersResponse>(new GetStatisticsRequiredFiltersRequest()); return response.FiltersData; } @@ -38,6 +37,13 @@ namespace Tango.FSE.UI.Statistics { LogManager.Log("Retrieving remote machine statistics data..."); + DateTime startUtc = new DateTime(filters.StartDateUTC.Year, filters.StartDateUTC.Month, filters.StartDateUTC.Day, 0, 0, 0).ToUniversalTime(); + TimeSpan offsetTime = (filters.EndDateUTC.Date == DateTime.Now.Date) ? DateTime.Now.TimeOfDay : new TimeSpan(23, 59, 59); + DateTime endUtc = filters.EndDateUTC.ToUniversalTime() + offsetTime; + + filters.StartDateUTC = startUtc; + filters.EndDateUTC = endUtc; + var response = await MachineProvider.MachineOperator.SendGenericRequest<GetStatisticsRequest, GetStatisticsResponse>( new GetStatisticsRequest() { Filters = filters }, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(60) }); |
