From f64ca87bfea01a355f3fbf4fa03c460995b5da99 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 23 Apr 2015 06:47:30 -0700 Subject: [PATCH] Implement open() and closed() Maniphest tokenizer status functions, plus cleanup Summary: Ref T4100. - Make it easy to choose all open or closed tasks. - Make "special" tokenizers composable. - Get `viewer()` generating documentation properly. Test Plan: - Ran queries with new tokens. - Browsed new tokens. - Viewed docs on new tokens. - Used plain status tokens. Reviewers: btrahan Reviewed By: btrahan Subscribers: chad, epriestley Maniphest Tasks: T4100 Differential Revision: https://secure.phabricator.com/D12530 --- src/__phutil_library_map__.php | 6 ++ .../query/ManiphestTaskSearchEngine.php | 5 +- .../ManiphestTaskClosedStatusDatasource.php | 73 +++++++++++++++++++ .../ManiphestTaskOpenStatusDatasource.php | 73 +++++++++++++++++++ .../ManiphestTaskStatusDatasource.php | 3 +- .../ManiphestTaskStatusFunctionDatasource.php | 22 ++++++ .../typeahead/PhabricatorViewerDatasource.php | 22 +++++- ...habricatorTypeaheadCompositeDatasource.php | 15 ++++ .../PhabricatorTypeaheadDatasource.php | 33 +++++++-- 9 files changed, 244 insertions(+), 8 deletions(-) create mode 100644 src/applications/maniphest/typeahead/ManiphestTaskClosedStatusDatasource.php create mode 100644 src/applications/maniphest/typeahead/ManiphestTaskOpenStatusDatasource.php create mode 100644 src/applications/maniphest/typeahead/ManiphestTaskStatusFunctionDatasource.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index d96e09b336..ae043b7eb5 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1045,6 +1045,7 @@ phutil_register_library_map(array( 'ManiphestStatusEmailCommand' => 'applications/maniphest/command/ManiphestStatusEmailCommand.php', 'ManiphestSubpriorityController' => 'applications/maniphest/controller/ManiphestSubpriorityController.php', 'ManiphestTask' => 'applications/maniphest/storage/ManiphestTask.php', + 'ManiphestTaskClosedStatusDatasource' => 'applications/maniphest/typeahead/ManiphestTaskClosedStatusDatasource.php', 'ManiphestTaskDependedOnByTaskEdgeType' => 'applications/maniphest/edge/ManiphestTaskDependedOnByTaskEdgeType.php', 'ManiphestTaskDependsOnTaskEdgeType' => 'applications/maniphest/edge/ManiphestTaskDependsOnTaskEdgeType.php', 'ManiphestTaskDetailController' => 'applications/maniphest/controller/ManiphestTaskDetailController.php', @@ -1055,6 +1056,7 @@ phutil_register_library_map(array( 'ManiphestTaskListController' => 'applications/maniphest/controller/ManiphestTaskListController.php', 'ManiphestTaskListView' => 'applications/maniphest/view/ManiphestTaskListView.php', 'ManiphestTaskMailReceiver' => 'applications/maniphest/mail/ManiphestTaskMailReceiver.php', + 'ManiphestTaskOpenStatusDatasource' => 'applications/maniphest/typeahead/ManiphestTaskOpenStatusDatasource.php', 'ManiphestTaskOwner' => 'applications/maniphest/constants/ManiphestTaskOwner.php', 'ManiphestTaskPHIDType' => 'applications/maniphest/phid/ManiphestTaskPHIDType.php', 'ManiphestTaskPriority' => 'applications/maniphest/constants/ManiphestTaskPriority.php', @@ -1064,6 +1066,7 @@ phutil_register_library_map(array( 'ManiphestTaskSearchEngine' => 'applications/maniphest/query/ManiphestTaskSearchEngine.php', 'ManiphestTaskStatus' => 'applications/maniphest/constants/ManiphestTaskStatus.php', 'ManiphestTaskStatusDatasource' => 'applications/maniphest/typeahead/ManiphestTaskStatusDatasource.php', + 'ManiphestTaskStatusFunctionDatasource' => 'applications/maniphest/typeahead/ManiphestTaskStatusFunctionDatasource.php', 'ManiphestTaskStatusTestCase' => 'applications/maniphest/constants/__tests__/ManiphestTaskStatusTestCase.php', 'ManiphestTaskTestCase' => 'applications/maniphest/__tests__/ManiphestTaskTestCase.php', 'ManiphestTransaction' => 'applications/maniphest/storage/ManiphestTransaction.php', @@ -4335,6 +4338,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationTransactionInterface', 'PhabricatorProjectInterface', ), + 'ManiphestTaskClosedStatusDatasource' => 'PhabricatorTypeaheadDatasource', 'ManiphestTaskDependedOnByTaskEdgeType' => 'PhabricatorEdgeType', 'ManiphestTaskDependsOnTaskEdgeType' => 'PhabricatorEdgeType', 'ManiphestTaskDetailController' => 'ManiphestController', @@ -4345,6 +4349,7 @@ phutil_register_library_map(array( 'ManiphestTaskListController' => 'ManiphestController', 'ManiphestTaskListView' => 'ManiphestView', 'ManiphestTaskMailReceiver' => 'PhabricatorObjectMailReceiver', + 'ManiphestTaskOpenStatusDatasource' => 'PhabricatorTypeaheadDatasource', 'ManiphestTaskOwner' => 'ManiphestConstants', 'ManiphestTaskPHIDType' => 'PhabricatorPHIDType', 'ManiphestTaskPriority' => 'ManiphestConstants', @@ -4354,6 +4359,7 @@ phutil_register_library_map(array( 'ManiphestTaskSearchEngine' => 'PhabricatorApplicationSearchEngine', 'ManiphestTaskStatus' => 'ManiphestConstants', 'ManiphestTaskStatusDatasource' => 'PhabricatorTypeaheadDatasource', + 'ManiphestTaskStatusFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'ManiphestTaskStatusTestCase' => 'PhabricatorTestCase', 'ManiphestTaskTestCase' => 'PhabricatorTestCase', 'ManiphestTransaction' => 'PhabricatorApplicationTransaction', diff --git a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php index 030d5dfdb3..e65ad9be2b 100644 --- a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php +++ b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php @@ -139,7 +139,10 @@ final class ManiphestTaskSearchEngine $query->withOwners($assigned_phids); } + $datasource = id(new ManiphestTaskStatusFunctionDatasource()) + ->setViewer($this->requireViewer()); $statuses = $saved->getParameter('statuses'); + $statuses = $datasource->evaluateTokens($statuses); if ($statuses) { $query->withStatuses($statuses); } @@ -274,7 +277,7 @@ final class ManiphestTaskSearchEngine ->setValue($subscriber_phids)) ->appendControl( id(new AphrontFormTokenizerControl()) - ->setDatasource(new ManiphestTaskStatusDatasource()) + ->setDatasource(new ManiphestTaskStatusFunctionDatasource()) ->setLabel(pht('Statuses')) ->setName('statuses') ->setValue($statuses)) diff --git a/src/applications/maniphest/typeahead/ManiphestTaskClosedStatusDatasource.php b/src/applications/maniphest/typeahead/ManiphestTaskClosedStatusDatasource.php new file mode 100644 index 0000000000..b8ca35cbfb --- /dev/null +++ b/src/applications/maniphest/typeahead/ManiphestTaskClosedStatusDatasource.php @@ -0,0 +1,73 @@ + array( + 'name' => pht('Any Closed Status'), + 'summary' => pht('Find results with any closed status.'), + 'description' => pht( + 'This function includes results which have any closed status.'), + ), + ); + } + + public function loadResults() { + $results = array( + $this->buildClosedResult(), + ); + return $this->filterResultsAgainstTokens($results); + } + + protected function evaluateFunction($function, array $argv_list) { + $results = array(); + + $map = ManiphestTaskStatus::getTaskStatusMap(); + foreach ($argv_list as $argv) { + foreach ($map as $status => $name) { + if (!ManiphestTaskStatus::isOpenStatus($status)) { + $results[] = $status; + } + } + } + + return $results; + } + + public function renderFunctionTokens($function, array $argv_list) { + $results = array(); + + foreach ($argv_list as $argv) { + $results[] = PhabricatorTypeaheadTokenView::newFromTypeaheadResult( + $this->buildClosedResult()); + } + + return $results; + } + + private function buildClosedResult() { + $name = pht('Any Closed Status'); + return $this->newFunctionResult() + ->setName($name.' closed') + ->setDisplayName($name) + ->setPHID(self::FUNCTION_TOKEN) + ->setUnique(true); + } + +} diff --git a/src/applications/maniphest/typeahead/ManiphestTaskOpenStatusDatasource.php b/src/applications/maniphest/typeahead/ManiphestTaskOpenStatusDatasource.php new file mode 100644 index 0000000000..ffc2801bc6 --- /dev/null +++ b/src/applications/maniphest/typeahead/ManiphestTaskOpenStatusDatasource.php @@ -0,0 +1,73 @@ + array( + 'name' => pht('Any Open Status'), + 'summary' => pht('Find results with any open status.'), + 'description' => pht( + 'This function includes results which have any open status.'), + ), + ); + } + + public function loadResults() { + $results = array( + $this->buildOpenResult(), + ); + return $this->filterResultsAgainstTokens($results); + } + + protected function evaluateFunction($function, array $argv_list) { + $results = array(); + + $map = ManiphestTaskStatus::getTaskStatusMap(); + foreach ($argv_list as $argv) { + foreach ($map as $status => $name) { + if (ManiphestTaskStatus::isOpenStatus($status)) { + $results[] = $status; + } + } + } + + return $results; + } + + public function renderFunctionTokens($function, array $argv_list) { + $results = array(); + + foreach ($argv_list as $argv) { + $results[] = PhabricatorTypeaheadTokenView::newFromTypeaheadResult( + $this->buildOpenResult()); + } + + return $results; + } + + private function buildOpenResult() { + $name = pht('Any Open Status'); + return $this->newFunctionResult() + ->setName($name.' open') + ->setDisplayName($name) + ->setPHID(self::FUNCTION_TOKEN) + ->setUnique(true); + } + +} diff --git a/src/applications/maniphest/typeahead/ManiphestTaskStatusDatasource.php b/src/applications/maniphest/typeahead/ManiphestTaskStatusDatasource.php index 7b8ed6ca76..8f7e881a9f 100644 --- a/src/applications/maniphest/typeahead/ManiphestTaskStatusDatasource.php +++ b/src/applications/maniphest/typeahead/ManiphestTaskStatusDatasource.php @@ -20,7 +20,8 @@ final class ManiphestTaskStatusDatasource return $this->filterResultsAgainstTokens($results); } - public function renderTokens(array $values) { + + protected function renderSpecialTokens(array $values) { return $this->renderTokensFromResults($this->buildResults(), $values); } diff --git a/src/applications/maniphest/typeahead/ManiphestTaskStatusFunctionDatasource.php b/src/applications/maniphest/typeahead/ManiphestTaskStatusFunctionDatasource.php new file mode 100644 index 0000000000..0cad8e49cb --- /dev/null +++ b/src/applications/maniphest/typeahead/ManiphestTaskStatusFunctionDatasource.php @@ -0,0 +1,22 @@ + array( + 'name' => pht('Current Viewer'), + 'summary' => pht('Use the current viewing user.'), + 'description' => pht( + 'This function allows you to change the behavior of a query '. + 'based on who is running it. When you use this function, you will '. + 'be the current viewer, so it works like you typed your own '. + 'username.'. + "\n\n". + 'However, if you save a query using this function and send it '. + 'to someone else, it will work like //their// username was the '. + 'one that was typed. This can be useful for building dashboard '. + 'panels that always show relevant information to the user who '. + 'is looking at them.'), + ), + ); + } + public function loadResults() { if ($this->getViewer()->getPHID()) { $results = array($this->renderViewerFunctionToken()); @@ -30,7 +50,7 @@ final class PhabricatorViewerDatasource return false; } - return ($function == 'viewer'); + return parent::canEvaluateFunction($function); } protected function evaluateFunction($function, array $argv_list) { diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php index 21ea9c2061..db9224bf67 100644 --- a/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php +++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php @@ -162,5 +162,20 @@ abstract class PhabricatorTypeaheadCompositeDatasource return parent::renderFunctionTokens($function, $argv_list); } + protected function renderSpecialTokens(array $values) { + $result = array(); + foreach ($this->getUsableDatasources() as $source) { + $special = $source->renderSpecialTokens($values); + foreach ($special as $key => $token) { + $result[$key] = $token; + unset($values[$key]); + } + if (!$values) { + break; + } + } + return $result; + } + } diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php index cdf7208f25..1514f46d5b 100644 --- a/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php +++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php @@ -229,6 +229,24 @@ abstract class PhabricatorTypeaheadDatasource extends Phobject { } } + // Give special non-function tokens which are also not PHIDs (like statuses + // and priorities) an opportunity to render. + $type_unknown = PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN; + $special = array(); + foreach ($values as $key => $value) { + if (phid_get_type($value) == $type_unknown) { + $special[$key] = $value; + } + } + + if ($special) { + $special_tokens = $this->renderSpecialTokens($special); + foreach ($special_tokens as $key => $token) { + $tokens[$key] = $token; + unset($phids[$key]); + } + } + if ($phids) { $handles = $this->getViewer()->loadHandles($phids); foreach ($phids as $key => $phid) { @@ -265,6 +283,10 @@ abstract class PhabricatorTypeaheadDatasource extends Phobject { return array_select_keys($tokens, array_keys($values)); } + protected function renderSpecialTokens(array $values) { + return array(); + } + /* -( Token Functions )---------------------------------------------------- */ @@ -424,12 +446,13 @@ abstract class PhabricatorTypeaheadDatasource extends Phobject { } protected function renderTokensFromResults(array $results, array $values) { - $results = array_select_keys($results, $values); - $tokens = array(); - foreach ($results as $result) { - $tokens[] = PhabricatorTypeaheadTokenView::newFromTypeaheadResult( - $result); + foreach ($values as $key => $value) { + if (empty($results[$value])) { + continue; + } + $tokens[$key] = PhabricatorTypeaheadTokenView::newFromTypeaheadResult( + $results[$value]); } return $tokens;