diff --git a/src/applications/maniphest/query/ManiphestTaskQuery.php b/src/applications/maniphest/query/ManiphestTaskQuery.php --- a/src/applications/maniphest/query/ManiphestTaskQuery.php +++ b/src/applications/maniphest/query/ManiphestTaskQuery.php @@ -53,6 +53,9 @@ private $needSubscriberPHIDs; private $needProjectPHIDs; + private $blockingTasks; + private $blockedTasks; + const DEFAULT_PAGE_SIZE = 1000; public function withAuthors(array $authors) { @@ -161,6 +164,34 @@ return $this; } + /** + * True returns tasks that are blocking other tasks only. + * False returns tasks that are not blocking other tasks only. + * Null returns tasks regardless of blocking status. + */ + public function withBlockingTasks($mode) { + $this->blockingTasks = $mode; + return $this; + } + + public function shouldJoinBlockingTasks() { + return $this->blockingTasks !== null; + } + + /** + * True returns tasks that are blocked by other tasks only. + * False returns tasks that are not blocked by other tasks only. + * Null returns tasks regardless of blocked by status. + */ + public function withBlockedTasks($mode) { + $this->blockedTasks = $mode; + return $this; + } + + public function shouldJoinBlockedTasks() { + return $this->blockedTasks !== null; + } + public function withDateCreatedBefore($date_created_before) { $this->dateCreatedBefore = $date_created_before; return $this; @@ -207,6 +238,7 @@ $where[] = $this->buildStatusWhereClause($conn); $where[] = $this->buildStatusesWhereClause($conn); $where[] = $this->buildPrioritiesWhereClause($conn); + $where[] = $this->buildDependenciesWhereClause($conn); $where[] = $this->buildAuthorWhereClause($conn); $where[] = $this->buildOwnerWhereClause($conn); $where[] = $this->buildProjectWhereClause($conn); @@ -520,6 +552,38 @@ $fulltext_results); } + private function buildDependenciesWhereClause( + AphrontDatabaseConnection $conn) { + + if (!$this->shouldJoinBlockedTasks() && + !$this->shouldJoinBlockingTasks()) { + return null; + } + + $parts = array(); + if ($this->blockingTasks === true) { + $parts[] = qsprintf( + $conn, + 'blocking.dst IS NOT NULL'); + } else if ($this->blockingTasks === false) { + $parts[] = qsprintf( + $conn, + 'blocking.dst IS NULL'); + } + + if ($this->blockedTasks === true) { + $parts[] = qsprintf( + $conn, + 'blocked.dst IS NOT NULL'); + } else if ($this->blockedTasks === false) { + $parts[] = qsprintf( + $conn, + 'blocked.dst IS NULL'); + } + + return '('.implode(') OR (', $parts).')'; + } + private function buildProjectWhereClause(AphrontDatabaseConnection $conn) { if (!$this->projectPHIDs && !$this->includeNoProject) { return null; @@ -699,6 +763,23 @@ PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); } + if ($this->shouldJoinBlockingTasks()) { + $joins[] = qsprintf( + $conn_r, + 'LEFT JOIN %T blocking ON blocking.src = task.phid '. + 'AND blocking.type = %d', + $edge_table, + ManiphestTaskDependedOnByTaskEdgeType::EDGECONST); + } + if ($this->shouldJoinBlockedTasks()) { + $joins[] = qsprintf( + $conn_r, + 'LEFT JOIN %T blocked ON blocked.src = task.phid '. + 'AND blocked.type = %d', + $edge_table, + ManiphestTaskDependsOnTaskEdgeType::EDGECONST); + } + if ($this->anyProjectPHIDs || $this->anyUserProjectPHIDs) { $joins[] = qsprintf( $conn_r, @@ -766,6 +847,8 @@ private function buildGroupClause(AphrontDatabaseConnection $conn_r) { $joined_multiple_rows = (count($this->projectPHIDs) > 1) || (count($this->anyProjectPHIDs) > 1) || + $this->shouldJoinBlockingTasks() || + $this->shouldJoinBlockedTasks() || ($this->getApplicationSearchMayJoinMultipleRows()); $joined_project_name = ($this->groupBy == self::GROUP_PROJECT); diff --git a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php --- a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php +++ b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php @@ -67,6 +67,13 @@ 'priorities', $this->readListFromRequest($request, 'priorities')); + $saved->setParameter( + 'blocking', + $this->readBoolFromRequest($request, 'blocking')); + $saved->setParameter( + 'blocked', + $this->readBoolFromRequest($request, 'blocked')); + $saved->setParameter('group', $request->getStr('group')); $saved->setParameter('order', $request->getStr('order')); @@ -152,6 +159,10 @@ $query->withPriorities($priorities); } + + $query->withBlockingTasks($saved->getParameter('blocking')); + $query->withBlockedTasks($saved->getParameter('blocked')); + $this->applyOrderByToQuery( $query, $this->getOrderValues(), @@ -302,6 +313,23 @@ isset($priorities[$pri])); } + $blocking_control = id(new AphrontFormSelectControl()) + ->setLabel(pht('Blocking')) + ->setName('blocking') + ->setValue($this->getBoolFromQuery($saved, 'blocking')) + ->setOptions(array( + '' => pht('Show All Tasks'), + 'true' => pht('Show Tasks Blocking Other Tasks'), + 'false' => pht('Show Tasks Not Blocking Other Tasks'),)); + $blocked_control = id(new AphrontFormSelectControl()) + ->setLabel(pht('Blocked')) + ->setName('blocked') + ->setValue($this->getBoolFromQuery($saved, 'blocked')) + ->setOptions(array( + '' => pht('Show All Tasks'), + 'true' => pht('Show Tasks Blocked By Other Tasks'), + 'false' => pht('Show Tasks Not Blocked By Other Tasks'),)); + $ids = $saved->getParameter('ids', array()); $builtin_orders = $this->getOrderOptions(); @@ -377,7 +405,9 @@ ->setLabel(pht('Contains Words')) ->setValue($saved->getParameter('fulltext'))) ->appendChild($status_control) - ->appendChild($priority_control); + ->appendChild($priority_control) + ->appendChild($blocking_control) + ->appendChild($blocked_control); if (!$this->getIsBoardView()) { $form