public async Task <IActionResult> RunReport(TfsStatesViewModel viewModel) { if (viewModel.ConnectionId == Guid.Empty) { ModelState.AddModelError(nameof(viewModel.ConnectionId), "Connection is required"); } if (string.IsNullOrEmpty(viewModel.Project) || viewModel.Project == NoProjectSelected) { ModelState.AddModelError(nameof(viewModel.Project), "Project is required"); } if (string.IsNullOrEmpty(viewModel.Iteration) || viewModel.Iteration == NoIterationSelected) { ModelState.AddModelError( nameof(viewModel.Iteration), "Iteration Under is required (you can select a parent iteration container)"); } await LoadLookups(viewModel); if (!ModelState.IsValid) { return(View(ViewName, viewModel)); } var sw = Stopwatch.StartNew(); await FileUtility.Cleanup(); TfsQueryResult queryResult = null; var knownConn = await this.settingsService.GetConnection(viewModel.ConnectionId); try { SendProgress($"Querying project {viewModel.Project}, iteration under {viewModel.Iteration}..."); queryResult = await this.tfsQueryService.Query(knownConn, viewModel); } catch (Exception ex) { Trace.WriteLine(ex); var settingsUrl = Url.Action("Index", "Settings"); viewModel.RunReadyState.NotReady( $"Error querying TFS. Verify <a href='{settingsUrl}'>TFS settings</a> " + $"and your connectivity and try again."); return(View(ViewName, viewModel)); } if (queryResult.TfsItems.Count > 0) { var fName = $"TfsStates_{DateTime.Now.Ticks}.xlsx"; var filename = await FileUtility.GetFilename(fName); SendProgress($"Writing {filename}..."); var projectUrl = $"{knownConn.Url}/{viewModel.Project}"; this.excelWriterService.Write(filename, queryResult.TfsItems, projectUrl); SendProgress($"Launching {filename}..."); System.Threading.Thread.Sleep(1000); viewModel.ResultFilename = fName; await Electron.Shell.OpenExternalAsync(filename); } // eat file in use exception try { await this.reportHistoryService.Record(knownConn.Id, viewModel.Project, viewModel.Iteration); } catch (IOException ioEx) { } if (queryResult.TfsItems.Count > 0) { var chart = chartService.CreateBarChart(queryResult); ViewData["chart"] = chart; } sw.Stop(); var items = queryResult.TfsItems; var totalTransitions = items.Sum(x => x.TransitionCount); var avgTransitions = items.Count > 0 ? Math.Round(items.Average(x => x.TransitionCount), 0) : 0; viewModel.FinalProgress = new ReportProgress { WorkItemsProcessed = queryResult.TotalWorkItems, Message = $"Processed {"work item".ToQuantity(queryResult.TotalWorkItems, "###,##0")} and " + $"{"revision".ToQuantity(queryResult.TotalRevisions, "###,##0")} in {sw.Elapsed.Humanize()}. " + $"{"transition".ToQuantity(totalTransitions, "###,##0")}. " + $"Average work item transitions: {avgTransitions}" }; return(View(ViewName, viewModel)); }