From a372627fcd5454cb7073da9e5e65f49532261c8d Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 28 Jul 2016 10:47:40 -0700 Subject: [PATCH] Provide URI/API support for querying subtasks/parents of a particular task Summary: Ref T8126. Ref T4788. This adds a way to query by parent or subtask. I plan to link to this from the task graph (e.g., {nav View > Search Subtasks} or similar, in a dropdown on the "Task Graph" element) as a way to let us bail out if tasks have 300 subtasks and send the user to a big query result list. That'll give us more flexibility to tailor the UI for reasonable numbers of tasks. There's no UI for this unless you specify a query yourself, so the only ways to get to it are: - Manually put `?parentIDs=...` into the URI. - Use the API. - Future link from task graphs. It doesn't seem too useful to me on its own, outside of the context of links from tasks. Test Plan: - Manually put `?parentIDs=...` and `?subtaskIDs=...` into Maniphest query UI, got expected results. Reviewers: chad Reviewed By: chad Maniphest Tasks: T4788, T8126 Differential Revision: https://secure.phabricator.com/D16341 --- .../maniphest/query/ManiphestTaskQuery.php | 51 +++++++++++++++++-- .../query/ManiphestTaskSearchEngine.php | 18 +++++++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/applications/maniphest/query/ManiphestTaskQuery.php b/src/applications/maniphest/query/ManiphestTaskQuery.php index f01346af1e..8d2fe79735 100644 --- a/src/applications/maniphest/query/ManiphestTaskQuery.php +++ b/src/applications/maniphest/query/ManiphestTaskQuery.php @@ -22,6 +22,8 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery { private $bridgedObjectPHIDs; private $hasOpenParents; private $hasOpenSubtasks; + private $parentTaskIDs; + private $subtaskIDs; private $fullTextSearch = ''; @@ -161,6 +163,16 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery { return $this; } + public function withParentTaskIDs(array $ids) { + $this->parentTaskIDs = $ids; + return $this; + } + + public function withSubtaskIDs(array $ids) { + $this->subtaskIDs = $ids; + return $this; + } + public function withDateCreatedBefore($date_created_before) { $this->dateCreatedBefore = $date_created_before; return $this; @@ -512,10 +524,11 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery { $edge_table = PhabricatorEdgeConfig::TABLE_NAME_EDGE; $task_table = $this->newResultObject()->getTableName(); + $parent_type = ManiphestTaskDependedOnByTaskEdgeType::EDGECONST; + $subtask_type = ManiphestTaskDependsOnTaskEdgeType::EDGECONST; + $joins = array(); if ($this->hasOpenParents !== null) { - $parent_type = ManiphestTaskDependedOnByTaskEdgeType::EDGECONST; - if ($this->hasOpenParents) { $join_type = 'JOIN'; } else { @@ -539,8 +552,6 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery { } if ($this->hasOpenSubtasks !== null) { - $subtask_type = ManiphestTaskDependsOnTaskEdgeType::EDGECONST; - if ($this->hasOpenSubtasks) { $join_type = 'JOIN'; } else { @@ -602,6 +613,36 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery { break; } + if ($this->parentTaskIDs !== null) { + $joins[] = qsprintf( + $conn, + 'JOIN %T e_has_parent + ON e_has_parent.src = task.phid + AND e_has_parent.type = %d + JOIN %T has_parent + ON e_has_parent.dst = has_parent.phid + AND has_parent.id IN (%Ld)', + $edge_table, + $parent_type, + $task_table, + $this->parentTaskIDs); + } + + if ($this->subtaskIDs !== null) { + $joins[] = qsprintf( + $conn, + 'JOIN %T e_has_subtask + ON e_has_subtask.src = task.phid + AND e_has_subtask.type = %d + JOIN %T has_subtask + ON e_has_subtask.dst = has_subtask.phid + AND has_subtask.id IN (%Ld)', + $edge_table, + $subtask_type, + $task_table, + $this->subtaskIDs); + } + $joins[] = parent::buildJoinClauseParts($conn); return $joins; @@ -611,6 +652,8 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery { $joined_multiple_rows = ($this->hasOpenParents !== null) || ($this->hasOpenSubtasks !== null) || + ($this->parentTaskIDs !== null) || + ($this->subtaskIDs !== null) || $this->shouldGroupQueryResultRows(); $joined_project_name = ($this->groupBy == self::GROUP_PROJECT); diff --git a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php index 63d1688f5f..0022940542 100644 --- a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php +++ b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php @@ -92,6 +92,14 @@ final class ManiphestTaskSearchEngine pht('(Show All)'), pht('Show Only Tasks With Open Subtasks'), pht('Show Only Tasks Without Open Subtasks')), + id(new PhabricatorIDsSearchField()) + ->setLabel(pht('Parent IDs')) + ->setKey('parentIDs') + ->setAliases(array('parentID')), + id(new PhabricatorIDsSearchField()) + ->setLabel(pht('Subtask IDs')) + ->setKey('subtaskIDs') + ->setAliases(array('subtaskID')), id(new PhabricatorSearchSelectField()) ->setLabel(pht('Group By')) ->setKey('group') @@ -125,6 +133,8 @@ final class ManiphestTaskSearchEngine 'fulltext', 'hasParents', 'hasSubtasks', + 'parentIDs', + 'subtaskIDs', 'group', 'order', 'ids', @@ -196,6 +206,14 @@ final class ManiphestTaskSearchEngine $query->withFullTextSearch($map['fulltext']); } + if ($map['parentIDs']) { + $query->withParentTaskIDs($map['parentIDs']); + } + + if ($map['subtaskIDs']) { + $query->withSubtaskIDs($map['subtaskIDs']); + } + $group = idx($map, 'group'); $group = idx($this->getGroupValues(), $group); if ($group) {