internal static int AddLeadTaskRow( DataGridView dgv, ViewFiltersBuilder viewFiltersBuilder, WorkItemInfoFiller workItemInfoFiller, ViewColumnsIndexes viewColumnsIndexes, FreeDaysCalculator freeDaysCalculator, FocusFactorCalculator focusFactorCalculator, WorkItem leadTask, DataContainer data, Dictionary<int, string> planningAssignments) { dgv.Rows.Add(new DataGridViewRow()); var leadTaskRow = dgv.Rows[dgv.Rows.Count - 1]; List<int> blockersIds = data.BlockersDict.ContainsKey(leadTask.Id) ? data.BlockersDict[leadTask.Id] : null; bool shouldCheckEstimate = workItemInfoFiller.FillLeadTaskInfo( viewFiltersBuilder, leadTask, leadTaskRow, data, blockersIds); viewFiltersBuilder.MarkLeadTaskRow(leadTaskRow); if (blockersIds != null) foreach (int blockerId in blockersIds) { AddBlockerRow( dgv, viewFiltersBuilder, workItemInfoFiller, data, planningAssignments, blockerId); } if (leadTask.IsProposed()) return ScheduleFiller.AddDatesProposed( viewColumnsIndexes, freeDaysCalculator, focusFactorCalculator, leadTask, leadTaskRow, viewColumnsIndexes.FirstDateColumnIndex, m_proposedLtMark, m_proposedLtMark, shouldCheckEstimate); return ScheduleFiller.AddDatesActive( viewColumnsIndexes, freeDaysCalculator, focusFactorCalculator, leadTask, leadTaskRow, viewColumnsIndexes.FirstDateColumnIndex, m_activeLtMark, m_activeLtMark); }
internal static Dictionary<int, Tuple<int?, int>> MakeSchedule( DataContainer dataContainer, Dictionary<int, string> planningAssignments, FreeDaysCalculator freeDaysCalculator, FocusFactorCalculator focusFactorCalculator) { var result = new Dictionary<int, Tuple<int?, int>>(); var usersBlockersDict = new Dictionary<string, Dictionary<int, BlockerData>>(); var usersTasksDict = SeparateByUser(dataContainer, planningAssignments); short i = 0; var numbersToUsersMapping = usersTasksDict.ToDictionary(u => ++i, u => u.Key); i = 0; var usersToNumbersMapping = usersTasksDict.Keys.ToDictionary(u => u, u => ++i); var usersToProcess = new List<short>(numbersToUsersMapping.Keys); var processedUsers = new List<short>(2*numbersToUsersMapping.Keys.Count); while (usersToProcess.Count > 0) { string user = numbersToUsersMapping[usersToProcess[0]]; var blockersFromOtherUsers = ScheduleUserTasks( usersTasksDict[user], user, freeDaysCalculator, focusFactorCalculator, dataContainer, planningAssignments, result); var usersToRecalculate = ProcessBlockers( blockersFromOtherUsers, usersBlockersDict, result, user); foreach (short userNumber in usersToRecalculate .Where(usersToNumbersMapping.ContainsKey) .Select(u => usersToNumbersMapping[u])) { if (usersToProcess.Count > 0 && usersToProcess[usersToProcess.Count - 1] == userNumber) continue; usersToProcess.Add(userNumber); } if (usersToProcess.Count == 2*numbersToUsersMapping.Keys.Count) processedUsers.RemoveAt(0); processedUsers.Add(usersToProcess[0]); usersToProcess.RemoveAt(0); if (CheckCycle(processedUsers)) throw new InvalidOperationException("Cycle blockers collision!"); } return result; }
internal static WorkItemVerificationResult VerifyChildrenExistance(WorkItem leadTask, DataContainer dataContainer) { if (dataContainer.LeadTaskChildrenDict.ContainsKey(leadTask.Id) && dataContainer.LeadTaskChildrenDict[leadTask.Id].Count > 0) return new WorkItemVerificationResult {Result = VerificationResult.Ok}; return new WorkItemVerificationResult { Result = VerificationResult.Warning, Messages = new List<string>(1) { Messages.LeadTaskHasNoChildren() }, }; }
internal static Dictionary<int, string> Make( Dictionary<string, List<string>> usersToPlanByDiscipline, List<Tuple<int, string>> planningAssignments, DataContainer data) { var result = new Dictionary<int, string>(planningAssignments.Count); var usersWork = new Dictionary<string, double>(); foreach (Tuple<int, string> assignment in planningAssignments) { WorkItem workItem = data.WiDict[assignment.Item1]; if (!assignment.Item2.IsUnassigned()) { if (!usersWork.ContainsKey(assignment.Item2)) usersWork.Add(assignment.Item2, 0); usersWork[assignment.Item2] += GetWork(workItem); continue; } string discinpline = workItem.Discipline(); if (!usersToPlanByDiscipline.ContainsKey(discinpline)) continue; var availableUsers = usersToPlanByDiscipline[discinpline]; if (availableUsers.Count == 0) continue; double min = int.MaxValue; bool assigned = false; string minUser = null; foreach (string availableUser in availableUsers) { if (!usersWork.ContainsKey(availableUser)) { usersWork.Add(availableUser, GetWork(workItem)); result.Add(assignment.Item1, availableUser); assigned = true; break; } if (min <= usersWork[availableUser]) continue; min = usersWork[availableUser]; minUser = availableUser; } if (assigned) continue; if (minUser != null) { if (assignment.Item2.IsUnassigned()) result.Add(assignment.Item1, minUser); usersWork[minUser] += GetWork(workItem); } } return result; }
private void AppendLeadTasks(DataContainer dataContainer, IEnumerable<WorkItem> leadTasks) { foreach (WorkItem leadTask in leadTasks) { var leadTaskLinkDict = WorkItemParser.ParseLinks(leadTask); dataContainer.LeadTaskChildrenDict.Add( leadTask.Id, leadTaskLinkDict.ContainsKey(WorkItemLinkType.Child) ? leadTaskLinkDict[WorkItemLinkType.Child] : new List<int>()); dataContainer.WiDict.Add(leadTask.Id, leadTask); if (leadTaskLinkDict.ContainsKey(WorkItemLinkType.BlockedBy)) dataContainer.BlockersDict.Add(leadTask.Id, leadTaskLinkDict[WorkItemLinkType.BlockedBy]); } }
internal DataContainer ProcessLeadTasks( string tfsUrl, List<WorkItem> leadTasks, Action<int> progressReportHandler) { var result = new DataContainer { WiDict = new Dictionary<int, WorkItem>(), BlockersDict = new Dictionary<int, List<int>>(), LeadTaskChildrenDict = new Dictionary<int, List<int>>(), }; AppendLeadTasks(result, leadTasks); using (var wiqlAccessor = new TfsWiqlAccessor(tfsUrl)) { List<int> ltChildrenIds = result.LeadTaskChildrenDict.Values.SelectMany(i => i).ToList(); AppendTasks( ltChildrenIds, null, result, wiqlAccessor, progressReportHandler); CleanDict( result.LeadTaskChildrenDict, result.WiDict, false, true, wiqlAccessor); CleanDict( result.BlockersDict, result.WiDict, true, false, wiqlAccessor); InitExternalBlockers(result, wiqlAccessor); } return result; }
private static Dictionary<string, HashSet<int>> ScheduleUserTasks( IEnumerable<Tuple<WorkItem, WorkItem>> userTasks, string user, FreeDaysCalculator freeDaysCalculator, FocusFactorCalculator focusFactorCalculator, DataContainer dataContainer, Dictionary<int, string> planningAssignments, Dictionary<int, Tuple<int?, int>> scheduledTasksDict) { var nonBlockedTasks = new List<Tuple<WorkItem, WorkItem>>(); var activeBlockedTasks = new List<Tuple<WorkItem, WorkItem>>(); var proposedBlockedTasks = new List<Tuple<WorkItem, WorkItem>>(); foreach (Tuple<WorkItem, WorkItem> tuple in userTasks) { if (tuple.Item1.IsActive()) { if (!dataContainer.BlockersDict.ContainsKey(tuple.Item1.Id)) nonBlockedTasks.Add(tuple); else activeBlockedTasks.Add(tuple); } else if (tuple.Item1.IsProposed()) { if (!dataContainer.BlockersDict.ContainsKey(tuple.Item1.Id)) nonBlockedTasks.Add(tuple); else proposedBlockedTasks.Add(tuple); } } var schedule = AppendNonBlockedTasks( nonBlockedTasks, user, scheduledTasksDict, freeDaysCalculator, focusFactorCalculator); var result = new Dictionary<string, HashSet<int>>(); AppendBlockedTasks( proposedBlockedTasks, schedule, dataContainer, planningAssignments, focusFactorCalculator, scheduledTasksDict, result); AppendBlockedTasks( activeBlockedTasks, schedule, dataContainer, planningAssignments, focusFactorCalculator, scheduledTasksDict, result); int currentDay = 0; foreach (var pair in schedule) { bool isTaskActive = pair.Item1.Item1.IsActive(); int startDayIndex = isTaskActive ? 0 : currentDay; int vacationDaysCount = freeDaysCalculator.GetVacationsDaysCount( user, startDayIndex, pair.Item2); scheduledTasksDict[pair.Item1.Item1.Id] = new Tuple<int?, int>(startDayIndex, pair.Item2 + vacationDaysCount); currentDay += vacationDaysCount; currentDay += isTaskActive ? Math.Max(pair.Item2 - currentDay, 0) : pair.Item2; } return result; }
private void InitExternalBlockers(DataContainer dataContainer, TfsWiqlAccessor wiqlAccessor) { if (dataContainer.BlockersDict.Count == 0) return; var notFound = new HashSet<int>(); foreach (var pair in dataContainer.BlockersDict) { foreach (int blockerId in pair.Value.Where(i => !dataContainer.WiDict.ContainsKey(i))) { notFound.Add(blockerId); } } if (notFound.Count == 0) return; var workItems = wiqlAccessor.QueryWorkItemsByIds(notFound, null); for (int i = 0; i < workItems.Count; i++) { WorkItem workItem = workItems[i]; dataContainer.WiDict[workItem.Id] = workItem; } }
internal static WorkItemVerificationResult VerifyNoProposedChildTask(WorkItem leadTask, DataContainer dataContainer) { if ((leadTask.IsProposed()) && dataContainer.LeadTaskChildrenDict.ContainsKey(leadTask.Id)) { foreach (int childTaskId in dataContainer.LeadTaskChildrenDict[leadTask.Id]) { if (!dataContainer.WiDict.ContainsKey(childTaskId)) continue; WorkItem task = dataContainer.WiDict[childTaskId]; if (!task.IsProposed()) return new WorkItemVerificationResult { Result = VerificationResult.Error, Messages = new List<string>(1) {Messages.ProposedLeadTaskHasNotProposedChild()}, }; } } return new WorkItemVerificationResult { Result = VerificationResult.Ok }; }
private void RefreshData() { string currentUser = null; string currentSprint = null; Invoke(new Action(() => { loadLeadTasksButton.Enabled = false; makeScheduleButton.Enabled = false; refreshButton.Enabled = false; if (usersFilterСomboBox.SelectedItem != null) currentUser = usersFilterСomboBox.SelectedItem.ToString(); if (sprintFilterComboBox.SelectedItem != null) currentSprint = sprintFilterComboBox.SelectedItem.ToString(); usersLabel.Enabled = false; usersFilterСomboBox.Enabled = false; scheduleDataGridView.Rows.Clear(); Text = GetFirstShortName(); })); try { var leadTasksCollection = GetLastLeadTasks(); var leadTasks = new List<WorkItem>(leadTasksCollection.Count); var oldSecond = s_stateContainer.WorkMode == WorkMode.AreaFirst ? m_config.LastIterationPaths : m_config.LastAreaPaths; var newSecond = new List<string>(); foreach (WorkItem leadTask in leadTasksCollection) { if (s_stateContainer.WorkMode != WorkMode.Query) { string second = s_stateContainer.GetParamForSecond(leadTask); if (!oldSecond.Contains(second) && !newSecond.Contains(second)) newSecond.Add(second); if (!s_stateContainer.IsSecondFromStateContains(second)) continue; } leadTasks.Add(leadTask); } m_lastProcessedData = s_dataFiller.ProcessLeadTasks( tfsUrlTextBox.Text, leadTasks, ReportProgress); Invoke(new Action(() => { bool isDateChanged = scheduleDataGridView.Columns[s_viewColumnsIndexes.FirstDateColumnIndex].HeaderText != DateTime.Now.ToString("dd.MM"); if (isDateChanged) ScheduleColumnsPresenter.InitColumns( scheduleDataGridView, s_viewColumnsIndexes.FirstDateColumnIndex, 1); m_viewFiltersApplier = s_dataPresenter.PresentData( m_lastProcessedData, null, null, s_viewColumnsIndexes, s_freeDaysCalculator, m_focusFactorCalculator, scheduleDataGridView); workersComboBox.DataSource = m_viewFiltersApplier.Users; vacationsButton.Enabled = m_viewFiltersApplier.Users.Count > 0; var users2 = new List<string>(m_viewFiltersApplier.Users); users2.Insert(0, string.Empty); usersFilterСomboBox.DataSource = users2; if (!string.IsNullOrEmpty(currentUser) && m_viewFiltersApplier.Users.Contains(currentUser)) { usersFilterСomboBox.SelectedItem = currentUser; m_viewFiltersApplier.FilterDataByUser(currentUser); } if (!string.IsNullOrEmpty(currentSprint) && m_viewFiltersApplier.Sprints.Contains(currentSprint)) { sprintFilterComboBox.SelectedItem = currentSprint; m_viewFiltersApplier.FilterDataBySprint(currentSprint); } usersFilterСomboBox.Enabled = true; usersLabel.Enabled = true; makeScheduleButton.Enabled = true; loadLeadTasksButton.Enabled = true; refreshButton.Enabled = true; if (newSecond.Count > 0) { refreshButton.BackColor = Color.Yellow; secondToolTip.SetToolTip(refreshButton, Resources.NewItems + Environment.NewLine + string.Join(Environment.NewLine, newSecond)); } })); } catch (Exception exc) { HandleException(exc, Resources.LeadTasksParsingError); Invoke( new Action(() => { makeScheduleButton.Enabled = true; loadLeadTasksButton.Enabled = true; refreshButton.Enabled = true; })); } }
internal void FillTaskInfo( ViewFiltersBuilder viewFiltersBuilder, WorkItem task, List<WorkItem> siblings, WorkItem leadTask, DataGridViewRow taskRow, DataContainer data, Dictionary<int, string> planningAssignments, List<string> allUsers, List<int> blockerIds) { var priorityCell = taskRow.Cells[m_viewColumnsIndexes.PriorityColumnIndex]; priorityCell.Value = task.Priority(); priorityCell.SetColorByState(task); priorityCell.ToolTipText = task.State; var idCell = taskRow.Cells[m_viewColumnsIndexes.IdColumnIndex]; idCell.Value = task.Id; var verificationResult = WorkItemVerifier.VerifyTaskPriority(task, leadTask.Priority()); if (verificationResult.Result != VerificationResult.Ok) { idCell.SetColorByVerification(verificationResult.Result); idCell.ToolTipText = verificationResult.AllMessagesString; } else { verificationResult = WorkItemVerifier.VerifyTaskWithParentOnSameIteration(task, leadTask); if (verificationResult.Result != VerificationResult.Ok) { idCell.SetColorByVerification(verificationResult.Result); idCell.ToolTipText = verificationResult.AllMessagesString; } } var titleCell = taskRow.Cells[m_viewColumnsIndexes.TitleColumnIndex]; titleCell.Value = task.Title; titleCell.ToolTipText = task.Discipline() + " " + task.Title; titleCell.Style.BackColor = priorityCell.Style.BackColor; var blockersCell = taskRow.Cells[m_viewColumnsIndexes.BlockersColumnIndex]; if (blockerIds != null) { string blockerIdsStr = string.Join(",", blockerIds); blockersCell.Value = blockerIdsStr; verificationResult = WorkItemVerifier.VerifyNonChildBlockerExistance(blockerIds, siblings); if (verificationResult.Result == VerificationResult.Ok) verificationResult = WorkItemVerifier.VerifyActiveTaskBlocking(task, blockerIds); if (verificationResult.Result == VerificationResult.Ok) { blockerIdsStr = string.Join(Environment.NewLine, blockerIds.Select(b => data.WiDict[b].Title)); blockersCell.ToolTipText = blockerIdsStr; } else { blockersCell.SetColorByVerification(verificationResult.Result); blockersCell.ToolTipText = verificationResult.AllMessagesString; } } if (!string.IsNullOrEmpty(task.BlockingReason())) { if (!string.IsNullOrEmpty(blockersCell.ToolTipText)) blockersCell.ToolTipText += Environment.NewLine; else blockersCell.Value = task.BlockingReason(); blockersCell.ToolTipText += "Blocking Reason: " + task.BlockingReason(); } var assignedCell = taskRow.Cells[m_viewColumnsIndexes.AssignedToColumnIndex]; var comboBoxCell = assignedCell as DataGridViewComboBoxCell; if (comboBoxCell != null) comboBoxCell.DataSource = allUsers; assignedCell.Value = planningAssignments.GetAssignee(task); verificationResult = WorkItemVerifier.VerifyAssignation(task); if (verificationResult.Result != VerificationResult.Ok) { assignedCell.SetColorByVerification(verificationResult.Result); assignedCell.ToolTipText = verificationResult.AllMessagesString; } var workCell = taskRow.Cells[m_viewColumnsIndexes.WorkColumnIndex]; workCell.Value = task.IsActive() ? task.Remaining() : task.Estimate(); workCell.Style.BackColor = priorityCell.Style.BackColor; }
internal bool FillLeadTaskInfo( ViewFiltersBuilder viewFiltersBuilder, WorkItem leadTask, DataGridViewRow leadTaskRow, DataContainer data, List<int> blockersIds) { var priorityCell = leadTaskRow.Cells[m_viewColumnsIndexes.PriorityColumnIndex]; priorityCell.Value = leadTask.Priority(); priorityCell.SetColorByState(leadTask); priorityCell.ToolTipText = leadTask.IsDevCompleted() ? WorkItemState.DevCompleted : leadTask.State; var iterationCell = leadTaskRow.Cells[m_viewColumnsIndexes.IterationColumnIndex]; string iteration = leadTask.IterationPath; int ind = iteration.IndexOf(m_iterationSeparator); if (ind != -1) iteration = iteration.Substring(ind + 1); iterationCell.Value = iteration; var sprintCell = leadTaskRow.Cells[m_viewColumnsIndexes.SprintColumnIndex]; sprintCell.Value = leadTask.Sprint(); var idCell = leadTaskRow.Cells[m_viewColumnsIndexes.IdColumnIndex]; idCell.Value = leadTask.Id; idCell.ToolTipText = leadTask.IterationPath; idCell.Style.BackColor = priorityCell.Style.BackColor; var verificationResult = WorkItemVerifier.VerifyChildrenExistance(leadTask, data); if (verificationResult.Result != VerificationResult.Ok) { idCell.SetColorByVerification(verificationResult.Result); idCell.ToolTipText += Environment.NewLine + verificationResult.AllMessagesString; } var docsCell = leadTaskRow.Cells[m_viewColumnsIndexes.DocsColumnIndex]; bool result; verificationResult = WorkItemVerifier.VerifyDocumentsAgreement(leadTask); if (verificationResult.Result == VerificationResult.Ok) { docsCell.Style.BackColor = priorityCell.Style.BackColor; result = true; } else { docsCell.Value = verificationResult.AddidtionalData; docsCell.SetColorByVerification(verificationResult.Result); docsCell.ToolTipText = verificationResult.AllMessagesString; result = false; } var titleCell = leadTaskRow.Cells[m_viewColumnsIndexes.TitleColumnIndex]; titleCell.Value = leadTask.Title; titleCell.Style.Font = new Font( titleCell.Style.Font ?? titleCell.OwningColumn.DefaultCellStyle.Font ?? m_dataGridView.ColumnHeadersDefaultCellStyle.Font, FontStyle.Underline); titleCell.Style.BackColor = priorityCell.Style.BackColor; verificationResult = WorkItemVerifier.VerifyNoProposedChildTask(leadTask, data); if (verificationResult.Result != VerificationResult.Ok) { priorityCell.SetColorByVerification(verificationResult.Result); priorityCell.ToolTipText = verificationResult.AllMessagesString; } var blockersCell = leadTaskRow.Cells[m_viewColumnsIndexes.BlockersColumnIndex]; verificationResult = WorkItemVerifier.VerifyBlockersExistance(blockersIds); if (verificationResult.Result != VerificationResult.Ok) { blockersCell.SetColorByVerification(verificationResult.Result); blockersCell.Value = verificationResult.AllMessagesString; } if (!string.IsNullOrEmpty(leadTask.BlockingReason())) { if (!string.IsNullOrEmpty(leadTaskRow.Cells[4].ToolTipText)) blockersCell.ToolTipText += Environment.NewLine; else blockersCell.Value = leadTask.BlockingReason(); blockersCell.ToolTipText += "Blocking Reason: " + leadTask.BlockingReason(); } leadTaskRow.Cells[m_viewColumnsIndexes.AssignedToColumnIndex].Value = leadTask.AssignedTo(); return result; }
private void ProcessData() { s_stateContainer.LastTfsUrl = tfsUrlTextBox.Text; try { List<WorkItem> leadTasks = GetLeadTasks(); m_lastProcessedData = s_dataFiller.ProcessLeadTasks( s_stateContainer.LastTfsUrl, leadTasks, ReportProgress); } catch (Exception exc) { HandleException(exc, Resources.LeadTasksParsingError); Invoke( new Action(() => { makeScheduleButton.Enabled = true; loadLeadTasksButton.Enabled = true; queryTextBox.Enabled = true; percentLabel.Visible = false; })); return; } Invoke(new Action(() => { try { m_viewFiltersApplier = s_dataPresenter.PresentData( m_lastProcessedData, null, null, s_viewColumnsIndexes, s_freeDaysCalculator, m_focusFactorCalculator, scheduleDataGridView); } catch (Exception exc) { HandleException(exc, Resources.LeadTasksParsingError); Invoke(new Action(() => { makeScheduleButton.Enabled = true; loadLeadTasksButton.Enabled = true; queryTextBox.Enabled = true; })); return; } workersComboBox.DataSource = m_viewFiltersApplier.Users.Where(u => !u.IsUnassigned()).ToList(); vacationsButton.Enabled = m_viewFiltersApplier.Users.Count > 0; var users = new List<string>(m_viewFiltersApplier.Users); users.Insert(0, string.Empty); usersFilterСomboBox.DataSource = users; usersFilterСomboBox.Enabled = true; usersLabel.Enabled = true; var sprints = new List<string>(m_viewFiltersApplier.Sprints); sprints.Insert(0, string.Empty); sprintFilterComboBox.DataSource = sprints; sprintFilterComboBox.Enabled = true; sprintLabel.Enabled = true; makeScheduleButton.Enabled = true; loadLeadTasksButton.Enabled = true; holidaysButton.Enabled = true; queryTextBox.Enabled = true; refreshButton.Enabled = true; planButton.Enabled = true; percentLabel.Visible = false; mainTabControl.SelectTab(dataTabPage); })); }
private static void AppendBlockedTasks( IEnumerable<Tuple<WorkItem, WorkItem>> blockedTasks, List<Tuple<Tuple<WorkItem, WorkItem>, int>> schedule, DataContainer dataContainer, Dictionary<int, string> planningAssignments, FocusFactorCalculator focusFactorCalculator, Dictionary<int, Tuple<int?, int>> scheduledTasksDict, Dictionary<string, HashSet<int>> usersBlockers) { var comparer = new TaskPriorityComparer(); foreach (var tuple in blockedTasks) { WorkItem blockedTask = tuple.Item1; var finishData = GetFinishDateForBlockedTask( blockedTask, dataContainer, planningAssignments, focusFactorCalculator, scheduledTasksDict); if (finishData.Item1 == null) { schedule.Add(new Tuple<Tuple<WorkItem, WorkItem>, int>(tuple, 0)); } else { double? remaining = tuple.Item1.IsActive() ? blockedTask.Remaining() : blockedTask.Estimate(); int taskDaysCount = remaining == null ? 0 : focusFactorCalculator.CalculateDaysByTime( remaining.Value, planningAssignments.GetAssignee(tuple.Item1)); int startDay = 0; bool added = false; for (int i = 0; i < schedule.Count; i++) { var taskData = schedule[i]; if (taskData.Item1.Item1.IsActive()) continue; if (startDay > finishData.Item1.Value && comparer.Compare(tuple, taskData.Item1) < 0) { schedule.Insert(i, new Tuple<Tuple<WorkItem, WorkItem>, int>(tuple, taskDaysCount)); added = true; break; } startDay += taskData.Item1.Item1.IsActive() ? Math.Max(taskData.Item2 - startDay, 0) : taskData.Item2; } if (!added) schedule.Add(new Tuple<Tuple<WorkItem, WorkItem>, int>(tuple, taskDaysCount)); } foreach (var userBlockersPair in finishData.Item2) { HashSet<int> blockers; if (usersBlockers.ContainsKey(userBlockersPair.Key)) { blockers = usersBlockers[userBlockersPair.Key]; } else { blockers = new HashSet<int>(); usersBlockers.Add(userBlockersPair.Key, blockers); } foreach (int blockerId in userBlockersPair.Value) { blockers.Add(blockerId); } } } }
private void AppendTasks( List<int> childrenIds, int? rootLeadTasskId, DataContainer dataContainer, TfsWiqlAccessor wiqlAccessor, Action<int> progressReportHandler) { if (childrenIds.Count == 0) return; var childrenTasks = wiqlAccessor.QueryWorkItemsByIds( childrenIds, progressReportHandler == null ? null : new Action<int>(x => progressReportHandler(LoadingPart * x / 100))); for (int i = 0; i < childrenTasks.Count; i++) { WorkItem task = childrenTasks[i]; if (!dataContainer.WiDict.ContainsKey(task.Id)) dataContainer.WiDict.Add(task.Id, task); if (task.IsClosed()) continue; if (task.Type.Name != WorkItemType.Task) continue; List<int> taskBlockersIds = WorkItemParser.GetRelationsByType(task, WorkItemLinkType.BlockedBy); if (taskBlockersIds.Count > 0) dataContainer.BlockersDict.Add(task.Id, taskBlockersIds); var taskLinkDict = WorkItemParser.ParseLinks(task); int? currentParentLtId = rootLeadTasskId; if (currentParentLtId == null && taskLinkDict.ContainsKey(WorkItemLinkType.Parent)) { int ltId = taskLinkDict[WorkItemLinkType.Parent][0]; if (dataContainer.LeadTaskChildrenDict.ContainsKey(ltId)) currentParentLtId = ltId; } if (currentParentLtId != null) { var ltChildren = dataContainer.LeadTaskChildrenDict[currentParentLtId.Value]; if (!ltChildren.Contains(task.Id)) ltChildren.Add(task.Id); } if (taskLinkDict.ContainsKey(WorkItemLinkType.Child)) AppendTasks( taskLinkDict[WorkItemLinkType.Child], currentParentLtId, dataContainer, wiqlAccessor, null); if (progressReportHandler != null) progressReportHandler(LoadingPart + (100 - LoadingPart) * i / childrenTasks.Count); } }
private static Tuple<int?, Dictionary<string, HashSet<int>>> GetFinishDateForBlockedTask( WorkItem blockedTask, DataContainer dataContainer, Dictionary<int, string> planningAssignments, FocusFactorCalculator focusFactorCalculator, Dictionary<int, Tuple<int?, int>> scheduledTasksDict) { int? finish = GetFinishDay( blockedTask, planningAssignments, focusFactorCalculator, scheduledTasksDict); Dictionary<string, HashSet<int>> userBlockersDict; if (dataContainer.BlockersDict.ContainsKey(blockedTask.Id)) { userBlockersDict = new Dictionary<string, HashSet<int>>(); foreach (int blockerId in dataContainer.BlockersDict[blockedTask.Id]) { WorkItem blocker = dataContainer.WiDict[blockerId]; var blockerData = GetFinishDateForBlockedTask( blocker, dataContainer, planningAssignments, focusFactorCalculator, scheduledTasksDict); int? currentFinish = GetFinishDay( blocker, planningAssignments, focusFactorCalculator, scheduledTasksDict); currentFinish = MaxDay(currentFinish, blockerData.Item1); finish = MaxDay(finish, currentFinish); foreach (var blockerAssignData in blockerData.Item2) { if (!userBlockersDict.ContainsKey(blockerAssignData.Key)) userBlockersDict.Add(blockerAssignData.Key, new HashSet<int>()); var ids = userBlockersDict[blockerAssignData.Key]; foreach (int parentBlockerId in blockerAssignData.Value) { ids.Add(parentBlockerId); } } string blockerAssignee = planningAssignments.GetAssignee(blocker); if (userBlockersDict.ContainsKey(blockerAssignee)) userBlockersDict[blockerAssignee].Add(blockerId); else userBlockersDict.Add(blockerAssignee, new HashSet<int> {blockerId}); } } else { userBlockersDict = new Dictionary<string, HashSet<int>>(0); } var result = new Tuple<int?, Dictionary<string, HashSet<int>>>(finish, userBlockersDict); return result; }
private static void AddBlockerRow( DataGridView dgv, ViewFiltersBuilder viewFiltersBuilder, WorkItemInfoFiller workItemInfoFiller, DataContainer data, Dictionary<int, string> planningAssignments, int blockerId) { dgv.Rows.Add(new DataGridViewRow()); var blockerRow = dgv.Rows[dgv.Rows.Count - 1]; WorkItem blocker = data.WiDict[blockerId]; workItemInfoFiller.FillBlockerInfo( blockerRow, blocker, planningAssignments); viewFiltersBuilder.MarkBlockerRow(blockerRow); }
internal static int AddTaskRow( DataGridView dgv, ViewFiltersBuilder viewFiltersBuilder, WorkItemInfoFiller workItemInfoFiller, ViewColumnsIndexes viewColumnsIndexes, FreeDaysCalculator freeDaysCalculator, FocusFactorCalculator focusFactorCalculator, WorkItem task, List<WorkItem> siblings, WorkItem leadTask, DataContainer data, Dictionary<int, string> planningAssignments, List<string> allUsers, Dictionary<int, int> alreadyAdded, Dictionary<string, int> tasksByUser, Dictionary<int, Tuple<int?, int>> tasksSchedule) { if (alreadyAdded.ContainsKey(task.Id)) return viewColumnsIndexes.FirstDateColumnIndex; var nextInds = new List<int>(); List<int> blockerIds = ProcessBlockers( dgv, viewFiltersBuilder, workItemInfoFiller, viewColumnsIndexes, freeDaysCalculator, focusFactorCalculator, data, planningAssignments, allUsers, task, siblings, leadTask, alreadyAdded, nextInds, tasksByUser, tasksSchedule); dgv.Rows.Add(new DataGridViewRow()); var taskRow = dgv.Rows[dgv.Rows.Count - 1]; workItemInfoFiller.FillTaskInfo( viewFiltersBuilder, task, siblings, leadTask, taskRow, data, planningAssignments, allUsers, blockerIds); viewFiltersBuilder.MarkTaskRow(taskRow); if (blockerIds != null) foreach (int blockerId in blockerIds) { AddBlockerRow( dgv, viewFiltersBuilder, workItemInfoFiller, data, planningAssignments, blockerId); } if (task.IsResolved()) { alreadyAdded.Add(task.Id, viewColumnsIndexes.FirstDateColumnIndex); return viewColumnsIndexes.FirstDateColumnIndex; } string assignedTo = planningAssignments.GetAssignee(task); if (!assignedTo.IsUnassigned() && tasksByUser.ContainsKey(assignedTo)) nextInds.Add(tasksByUser[assignedTo]); int maxNextInd = viewColumnsIndexes.FirstDateColumnIndex; if (nextInds.Count > 0) maxNextInd = nextInds.Max(); string userMark = GetUserMark(assignedTo); Tuple<int?, int> taskSchedule = null; int nextInd; if (tasksSchedule != null && tasksSchedule.ContainsKey(task.Id)) taskSchedule = tasksSchedule[task.Id]; if (taskSchedule != null && taskSchedule.Item1 != null) { nextInd = ScheduleFiller.AddDatesFromSchedule( viewColumnsIndexes, freeDaysCalculator, taskRow, taskSchedule.Item1.Value, taskSchedule.Item2, assignedTo, userMark); } else { nextInd = task.IsProposed() ? ScheduleFiller.AddDatesProposed( viewColumnsIndexes, freeDaysCalculator, focusFactorCalculator, task, taskRow, maxNextInd, assignedTo, userMark, true) : ScheduleFiller.AddDatesActive( viewColumnsIndexes, freeDaysCalculator, focusFactorCalculator, task, taskRow, maxNextInd, assignedTo, userMark); } alreadyAdded.Add(task.Id, nextInd); tasksByUser[assignedTo] = nextInd; return nextInd; }
private static List<int> ProcessBlockers( DataGridView dgv, ViewFiltersBuilder viewFiltersBuilder, WorkItemInfoFiller workItemInfoFiller, ViewColumnsIndexes viewColumnsIndexes, FreeDaysCalculator freeDaysCalculator, FocusFactorCalculator focusFactorCalculator, DataContainer data, Dictionary<int, string> planningAssignments, List<string> allUsers, WorkItem task, List<WorkItem> childrenTasks, WorkItem leadTask, Dictionary<int, int> alreadyAdded, List<int> nextInds, Dictionary<string, int> tasksByUser, Dictionary<int, Tuple<int?, int>> tasksSchedule) { if (!data.BlockersDict.ContainsKey(task.Id)) return null; var blockerIds = data.BlockersDict[task.Id]; var blokers = blockerIds .Where(b => data.WiDict.ContainsKey(b)) .Select(b => data.WiDict[b]) .OrderBy(b => b.Priority()) .ToList(); foreach (var blocker in blokers) { if (alreadyAdded.ContainsKey(blocker.Id)) { nextInds.Add(alreadyAdded[blocker.Id]); continue; } var blockerSiblingTask = childrenTasks.FirstOrDefault(t => t.Id == blocker.Id); if (blockerSiblingTask != null) { int blockerNextInd = AddTaskRow( dgv, viewFiltersBuilder, workItemInfoFiller, viewColumnsIndexes, freeDaysCalculator, focusFactorCalculator, blockerSiblingTask, childrenTasks, leadTask, data, planningAssignments, allUsers, alreadyAdded, tasksByUser, tasksSchedule); nextInds.Add(blockerNextInd); } } return blockerIds; }
internal ViewFiltersApplier PresentData( DataContainer data, Dictionary<int, string> planningAssignments, List<string> allUsers, ViewColumnsIndexes viewColumnsIndexes, FreeDaysCalculator freeDaysCalculator, FocusFactorCalculator focusFactorCalculator, DataGridView dgv) { var tasksSchedule = WorkItemsScheduler.MakeSchedule( data, planningAssignments, freeDaysCalculator, focusFactorCalculator); var alreadyAdded = new Dictionary<int, int>(); var tasksByUser = new Dictionary<string, int>(); var resultBuilder = new ViewFiltersBuilder(dgv, viewColumnsIndexes); var workItemInfoFiller = new WorkItemInfoFiller(dgv, viewColumnsIndexes); foreach (var leadTaskChildren in data.LeadTaskChildrenDict) { var leadTask = data.WiDict[leadTaskChildren.Key]; int nextLtInd = RowsAdder.AddLeadTaskRow( dgv, resultBuilder, workItemInfoFiller, viewColumnsIndexes, freeDaysCalculator, focusFactorCalculator, leadTask, data, planningAssignments); int ltRowInd = dgv.Rows.Count - 1; var childrenTasks = leadTaskChildren.Value .Where(i => data.WiDict.ContainsKey(i)) .Select(i => data.WiDict[i]) .OrderBy(i => i.Priority() ?? 999) .ToList(); if (childrenTasks.Count > 0) { int lastTaskInd = childrenTasks .Select(task => RowsAdder.AddTaskRow( dgv, resultBuilder, workItemInfoFiller, viewColumnsIndexes, freeDaysCalculator, focusFactorCalculator, task, childrenTasks, leadTask, data, planningAssignments, allUsers, alreadyAdded, tasksByUser, tasksSchedule)) .Max(); ScheduleFiller.ColorFdOutDays( viewColumnsIndexes, freeDaysCalculator, dgv.Rows[ltRowInd], nextLtInd, lastTaskInd); } var notAccessableChildren = leadTaskChildren.Value .Where(i => !data.WiDict.ContainsKey(i)) .ToList(); foreach (int notAccessableChildId in notAccessableChildren) { dgv.Rows.Add(new DataGridViewRow()); var taskRow = dgv.Rows[dgv.Rows.Count - 1]; workItemInfoFiller.FillNotAccessibleTaskInfo(viewColumnsIndexes, taskRow, notAccessableChildId); resultBuilder.MarkTaskRow(taskRow); } } return resultBuilder.Build(); }
private static Dictionary<string, List<Tuple<WorkItem, WorkItem>>> SeparateByUser( DataContainer dataContainer, Dictionary<int, string> planningAssignments) { var result = new Dictionary<string, List<Tuple<WorkItem, WorkItem>>>(); foreach (var ltChildrenPair in dataContainer.LeadTaskChildrenDict) { WorkItem lt = dataContainer.WiDict[ltChildrenPair.Key]; foreach (int childId in ltChildrenPair.Value) { WorkItem child = dataContainer.WiDict[childId]; string assignee = planningAssignments.GetAssignee(child); var childTuple = new Tuple<WorkItem, WorkItem>(child, lt); if (!result.ContainsKey(assignee)) result.Add(assignee, new List<Tuple<WorkItem, WorkItem>> { childTuple }); else result[assignee].Add(childTuple); } } return result; }