private static void GroupUnparentedBugsAsAnEpic() { var unparentedBugs = timeNodeByWorkItemId.Values.Where(x => x.ParentId == null && x.WorkItemType == "Bug").ToList(); var newParents = new Dictionary <string, TrackedTimeNode>(); var artificialWorkItemId = 0; foreach (var bug in unparentedBugs) { var parentName = "Unparented bugs for " + bug.Project; if (!newParents.ContainsKey(parentName)) { artificialWorkItemId--; newParents[parentName] = new TrackedTimeNode { WorkItem = new WorkItem(artificialWorkItemId) { WorkItemType = "Epic", TeamProject = bug.Project, Title = parentName, } }; timeNodeByWorkItemId[artificialWorkItemId] = newParents[parentName]; } newParents[parentName].Childs.Add(bug); bug.ForceParentId(newParents[parentName].WorkItem.Id); } }
private static GroupedTimeRecords GroupItemsAndLoadParents(IEnumerable <ExportItemViewModelApi> rows) { // Populate timeNodeByWorkItemId Program.WriteLogLine("Grouping by parents..."); foreach (var row in rows) { if (row.TFSID == null) { Program.WriteLogLine($"*** WARN : No WorkItemId for TimetrackerRowId={row.RowID} of {row.DurationInSeconds / 60} min on {row.RecordDate} ."); continue; } var workItemId = row.TFSID.Value; if (!timeNodeByWorkItemId.ContainsKey(workItemId)) { timeNodeByWorkItemId[workItemId] = new TrackedTimeNode { FirstTrackedTimeRow = row }; } timeNodeByWorkItemId[workItemId].DirectTrackedTimeRows.Add(row); } LoadMissingParents(); DefineHierarchyLinks(); GroupUnparentedBugsAsAnEpic(); var groupedByWI = timeNodeByWorkItemId.Values.Where(x => x.ParentId == null) .OrderBy(x => x.Project + " " + x.WorkItemType).ThenBy(x => x.ParentId) .ToList(); Program.WriteLogLine("Grouping by members..."); var members = rows.Select(x => x.TeamMember).Distinct().OrderBy(x => x).ToList(); var groupedByTeamMember = new List <TeamMemberRecords>(); foreach (var member in members) { var tmr = new TeamMemberRecords() { TeamMember = member, GroupedByWorkItem = GetCloneTimeNodesFilteredByMember(member, groupedByWI).ToList() }; groupedByTeamMember.Add(tmr); } var result = new GroupedTimeRecords() { GroupedByWorkItem = groupedByWI, GroupedByTeamMember = groupedByTeamMember }; return(result); }
private static IEnumerable <TrackedTimeNode> GetCloneTimeNodesFilteredByMember(string member, List <TrackedTimeNode> timeNodes) { foreach (var timeNode in timeNodes.Where(x => x.ContainsMember(member))) { var cloneTimeNode = new TrackedTimeNode() { WorkItem = timeNode.WorkItem ?? new WorkItem(timeNode.FirstTrackedTimeRow), }; cloneTimeNode.DirectTrackedTimeRows.AddRange(timeNode.DirectTrackedTimeRows.Where(x => x.TeamMember == member)); cloneTimeNode.FirstTrackedTimeRow = cloneTimeNode.DirectTrackedTimeRows.FirstOrDefault(); if (timeNode.Childs.Any(x => x.ContainsMember(member))) { cloneTimeNode.Childs.AddRange(GetCloneTimeNodesFilteredByMember(member, timeNode.Childs)); } yield return(cloneTimeNode); } }
private IXLCell AddValues(int level, TrackedTimeNode row, IXLCell currentCell, string teamMember, double?wiTotalDurationInMin, double?wiDirectDurationInMin, DateTime?recordDate) { var firstCell = currentCell; currentCell.Value = row.WorkItemId; currentCell = currentCell.CellRight().SetValue(row.Project); currentCell = currentCell.CellRight().SetValue(row.WorkItemType); currentCell = currentCell.CellRight().SetValue(level >= 2 ? row.ParentId : null); currentCell = currentCell.CellRight().SetValue(level >= 3 ? row.ParentId : null); currentCell = currentCell.CellRight().SetValue(level >= 4 ? row.ParentId : null); currentCell = currentCell.CellRight().SetValue(level > 4 ? row.ParentId : null); string indent = ""; if (level > 1) { indent = string.Concat(Enumerable.Repeat("║ ", Math.Max(0, level - 2))) + "╠ "; // for a "tree" visualization } currentCell = currentCell.CellRight().SetValue(indent + row.Title); currentCell = currentCell.CellRight().SetValue(level == 1 ? wiTotalDurationInMin : null); currentCell = currentCell.CellRight().SetValue(level == 2 ? wiTotalDurationInMin : null); currentCell = currentCell.CellRight().SetValue(level == 3 ? wiTotalDurationInMin : null); currentCell = currentCell.CellRight().SetValue(level >= 4 ? wiTotalDurationInMin : null); currentCell = currentCell.CellRight().SetValue(wiDirectDurationInMin / 60d); currentCell = currentCell.CellRight().SetValue(recordDate); currentCell = currentCell.CellRight().SetValue(teamMember); if (showReportsByMonth) { var currentMonth = FirstMonth; while (currentMonth <= Lastmonth) { currentCell = currentCell.CellRight(); double?durationInMin = null; if (wiDirectDurationInMin == null) { // global WorkItem (not a time tracked record) durationInMin = row.GetTotalDurationWithChildrenInMinForMonth(currentMonth); } else if (recordDate.HasValue && recordDate.Value.Year == currentMonth.Year && recordDate.Value.Month == currentMonth.Month) { // time tracked record which is in the current month durationInMin = wiDirectDurationInMin; } if (durationInMin != null && durationInMin.Value > 0) { currentCell.SetValue(durationInMin / 60d); } currentMonth = currentMonth.AddMonths(1); } } var range = worksheet.Range(firstCell, currentCell); if (level == 1 && wiDirectDurationInMin == null) // 1stl level WorkItem (not a time tracked record) { range.Style.Fill.BackgroundColor = XLColor.FromArgb(216, 228, 188); } else if (level > 1 && wiDirectDurationInMin == null) // next level WorkItem (not a time tracked record) { range.Style.Fill.BackgroundColor = XLColor.FromArgb(235, 241, 222); } else { // wiDirectDurationInMin != null (time tracked record) range.Style.Fill.BackgroundColor = XLColor.White; } return(currentCell); }