From 4948a21959bd6e420ee32af222b32a50e81ae1c7 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 1 Mar 2017 16:49:41 -0800 Subject: [PATCH] Allow tasks to be searched by subtype Summary: Ref T12314. Allow tasks to be queried by subtype using a typeahead. Open to a better default icon. I'll probably let you configure them later. Just hide this constraint if there's only one subtype. Test Plan: - Searched for subtypes. - Verified that the control hides if there is only one subtype. {F3492293} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12314 Differential Revision: https://secure.phabricator.com/D17444 --- src/__phutil_library_map__.php | 2 + .../query/ManiphestTaskSearchEngine.php | 18 ++++++++ .../ManiphestTaskSubtypeDatasource.php | 44 +++++++++++++++++++ .../search/field/PhabricatorSearchField.php | 29 ++++++++++++ .../PhabricatorEditEngineSubtype.php | 4 ++ 5 files changed, 97 insertions(+) create mode 100644 src/applications/maniphest/typeahead/ManiphestTaskSubtypeDatasource.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 5d3a74fc30..23c923dc25 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1525,6 +1525,7 @@ phutil_register_library_map(array( 'ManiphestTaskStatusHeraldAction' => 'applications/maniphest/herald/ManiphestTaskStatusHeraldAction.php', 'ManiphestTaskStatusHeraldField' => 'applications/maniphest/herald/ManiphestTaskStatusHeraldField.php', 'ManiphestTaskStatusTestCase' => 'applications/maniphest/constants/__tests__/ManiphestTaskStatusTestCase.php', + 'ManiphestTaskSubtypeDatasource' => 'applications/maniphest/typeahead/ManiphestTaskSubtypeDatasource.php', 'ManiphestTaskTestCase' => 'applications/maniphest/__tests__/ManiphestTaskTestCase.php', 'ManiphestTaskTitleHeraldField' => 'applications/maniphest/herald/ManiphestTaskTitleHeraldField.php', 'ManiphestTransaction' => 'applications/maniphest/storage/ManiphestTransaction.php', @@ -6424,6 +6425,7 @@ phutil_register_library_map(array( 'ManiphestTaskStatusHeraldAction' => 'HeraldAction', 'ManiphestTaskStatusHeraldField' => 'ManiphestTaskHeraldField', 'ManiphestTaskStatusTestCase' => 'PhabricatorTestCase', + 'ManiphestTaskSubtypeDatasource' => 'PhabricatorTypeaheadDatasource', 'ManiphestTaskTestCase' => 'PhabricatorTestCase', 'ManiphestTaskTitleHeraldField' => 'ManiphestTaskHeraldField', 'ManiphestTransaction' => 'PhabricatorApplicationTransaction', diff --git a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php index d8f5ab493a..53efaf0bbc 100644 --- a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php +++ b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php @@ -44,6 +44,11 @@ final class ManiphestTaskSearchEngine } protected function buildCustomSearchFields() { + // Hide the "Subtypes" constraint from the web UI if the install only + // defines one task subtype, since it isn't of any use in this case. + $subtype_map = id(new ManiphestTask())->newEditEngineSubtypeMap(); + $hide_subtypes = (count($subtype_map) == 1); + return array( id(new PhabricatorOwnersSearchField()) ->setLabel(pht('Assigned To')) @@ -73,6 +78,14 @@ final class ManiphestTaskSearchEngine pht('Search for tasks with given priorities.')) ->setConduitParameterType(new ConduitIntListParameterType()) ->setDatasource(new ManiphestTaskPriorityDatasource()), + id(new PhabricatorSearchDatasourceField()) + ->setLabel(pht('Subtypes')) + ->setKey('subtypes') + ->setAliases(array('subtype')) + ->setDescription( + pht('Search for tasks with given subtypes.')) + ->setDatasource(new ManiphestTaskSubtypeDatasource()) + ->setIsHidden($hide_subtypes), id(new PhabricatorSearchTextField()) ->setLabel(pht('Contains Words')) ->setKey('fulltext'), @@ -130,6 +143,7 @@ final class ManiphestTaskSearchEngine 'subscriberPHIDs', 'statuses', 'priorities', + 'subtypes', 'fulltext', 'hasParents', 'hasSubtasks', @@ -178,6 +192,10 @@ final class ManiphestTaskSearchEngine $query->withPriorities($map['priorities']); } + if ($map['subtypes']) { + $query->withSubtypes($map['subtypes']); + } + if ($map['createdStart']) { $query->withDateCreatedAfter($map['createdStart']); } diff --git a/src/applications/maniphest/typeahead/ManiphestTaskSubtypeDatasource.php b/src/applications/maniphest/typeahead/ManiphestTaskSubtypeDatasource.php new file mode 100644 index 0000000000..2678e946b4 --- /dev/null +++ b/src/applications/maniphest/typeahead/ManiphestTaskSubtypeDatasource.php @@ -0,0 +1,44 @@ +buildResults(); + return $this->filterResultsAgainstTokens($results); + } + + protected function renderSpecialTokens(array $values) { + return $this->renderTokensFromResults($this->buildResults(), $values); + } + + private function buildResults() { + $results = array(); + + $subtype_map = id(new ManiphestTask())->newEditEngineSubtypeMap(); + foreach ($subtype_map as $key => $subtype) { + + $result = id(new PhabricatorTypeaheadResult()) + ->setIcon($subtype->getIcon()) + ->setPHID($key) + ->setName($subtype->getName()); + + $results[$key] = $result; + } + + return $results; + } + +} diff --git a/src/applications/search/field/PhabricatorSearchField.php b/src/applications/search/field/PhabricatorSearchField.php index f45befead6..099fbdcc51 100644 --- a/src/applications/search/field/PhabricatorSearchField.php +++ b/src/applications/search/field/PhabricatorSearchField.php @@ -17,6 +17,7 @@ abstract class PhabricatorSearchField extends Phobject { private $aliases = array(); private $errors = array(); private $description; + private $isHidden; /* -( Configuring Fields )------------------------------------------------- */ @@ -188,6 +189,30 @@ abstract class PhabricatorSearchField extends Phobject { } + /** + * Hide this field from the web UI. + * + * @param bool True to hide the field from the web UI. + * @return this + * @task config + */ + public function setIsHidden($is_hidden) { + $this->isHidden = $is_hidden; + return $this; + } + + + /** + * Should this field be hidden from the web UI? + * + * @return bool True to hide the field in the web UI. + * @task config + */ + public function getIsHidden() { + return $this->isHidden; + } + + /* -( Handling Errors )---------------------------------------------------- */ @@ -273,6 +298,10 @@ abstract class PhabricatorSearchField extends Phobject { protected function renderControl() { + if ($this->getIsHidden()) { + return null; + } + $control = $this->newControl(); if (!$control) { diff --git a/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php b/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php index 6c03e17ee4..ff14ae239b 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php @@ -27,6 +27,10 @@ final class PhabricatorEditEngineSubtype return $this->name; } + public function getIcon() { + return 'fa-drivers-license-o'; + } + public static function validateSubtypeKey($subtype) { if (strlen($subtype) > 64) { throw new Exception(