예제 #1
0
        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);
            }
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
            }
        }
예제 #4
0
        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);
        }