diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2664,6 +2664,7 @@ 'PhabricatorUserPreferences' => 'applications/settings/storage/PhabricatorUserPreferences.php', 'PhabricatorUserProfile' => 'applications/people/storage/PhabricatorUserProfile.php', 'PhabricatorUserProfileEditor' => 'applications/people/editor/PhabricatorUserProfileEditor.php', + 'PhabricatorUserProjectsDatasource' => 'applications/people/typeahead/PhabricatorUserProjectsDatasource.php', 'PhabricatorUserRealNameField' => 'applications/people/customfield/PhabricatorUserRealNameField.php', 'PhabricatorUserRolesField' => 'applications/people/customfield/PhabricatorUserRolesField.php', 'PhabricatorUserSchemaSpec' => 'applications/people/storage/PhabricatorUserSchemaSpec.php', @@ -6083,6 +6084,7 @@ 'PhabricatorUserPreferences' => 'PhabricatorUserDAO', 'PhabricatorUserProfile' => 'PhabricatorUserDAO', 'PhabricatorUserProfileEditor' => 'PhabricatorApplicationTransactionEditor', + 'PhabricatorUserProjectsDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorUserRealNameField' => 'PhabricatorUserCustomField', 'PhabricatorUserRolesField' => 'PhabricatorUserCustomField', 'PhabricatorUserSchemaSpec' => 'PhabricatorConfigSchemaSpec', diff --git a/src/applications/people/typeahead/PhabricatorUserProjectsDatasource.php b/src/applications/people/typeahead/PhabricatorUserProjectsDatasource.php new file mode 100644 --- /dev/null +++ b/src/applications/people/typeahead/PhabricatorUserProjectsDatasource.php @@ -0,0 +1,85 @@ +)...'); + } + + public function getDatasourceApplicationClass() { + return 'PhabricatorProjectApplication'; + } + + public function getComponentDatasources() { + return array( + new PhabricatorPeopleDatasource(), + ); + } + + public function getDatasourceFunctions() { + return array( + 'projects' => array( + 'name' => pht("Find results in any of a user's projects."), + ), + ); + } + + protected function didLoadResults(array $results) { + foreach ($results as $result) { + $result + ->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION) + ->setIcon('fa-briefcase') + ->setPHID('projects('.$result->getPHID().')') + ->setDisplayName(pht('Projects: %s', $result->getDisplayName())) + ->setName($result->getName().' projects'); + } + + return $results; + } + + protected function evaluateFunction($function, array $argv_list) { + $phids = array(); + foreach ($argv_list as $argv) { + $phids[] = head($argv); + } + + $projects = id(new PhabricatorPeopleQuery()) + ->setViewer($this->getViewer()) + ->needMembers(true) + ->withPHIDs($phids) + ->execute(); + + $results = array(); + foreach ($projects as $project) { + foreach ($project->getMemberPHIDs() as $phid) { + $results[$phid] = $phid; + } + } + + return array_values($results); + } + + public function renderFunctionTokens($function, array $argv_list) { + $phids = array(); + foreach ($argv_list as $argv) { + $phids[] = head($argv); + } + + $tokens = $this->renderTokens($phids); + foreach ($tokens as $token) { + if ($token->isInvalid()) { + $token + ->setValue(pht('Projects: Invalid User')); + } else { + $token + ->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION) + ->setKey('projects('.$token->getKey().')') + ->setValue(pht('Projects: %s', $token->getValue())); + } + } + + return $tokens; + } + +} diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php --- a/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php +++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php @@ -25,10 +25,22 @@ $offset = $this->getOffset(); $limit = $this->getLimit(); + // If the input query is a function like `members(platy`, and we can + // parse the function, we strip the function off and hand the stripped + // query to child sources. This makes it easier to implement function + // sources in terms of real object sources. + $raw_query = $this->getRawQuery(); + if (self::isFunctionToken($raw_query)) { + $function = $this->parseFunction($raw_query, $allow_partial = true); + if ($function) { + $raw_query = head($function['argv']); + } + } + $results = array(); foreach ($this->getUsableDatasources() as $source) { $source - ->setRawQuery($this->getRawQuery()) + ->setRawQuery($raw_query) ->setQuery($this->getQuery()) ->setViewer($this->getViewer()); @@ -36,7 +48,9 @@ $source->setLimit($offset + $limit); } - $results[] = $source->loadResults(); + $source_results = $source->loadResults(); + $source_results = $source->didLoadResults($source_results); + $results[] = $source_results; } $results = array_mergev($results); diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php --- a/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php +++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php @@ -90,6 +90,10 @@ abstract public function getDatasourceApplicationClass(); abstract public function loadResults(); + protected function didLoadResults(array $results) { + return $results; + } + public static function tokenizeString($string) { $string = phutil_utf8_strtolower($string); $string = trim($string); @@ -261,8 +265,17 @@ /** * @task functions */ + public function getDatasourceFunctions() { + return array(); + } + + + /** + * @task functions + */ protected function canEvaluateFunction($function) { - return false; + $functions = $this->getDatasourceFunctions(); + return isset($functions[$function]); } diff --git a/src/applications/typeahead/view/PhabricatorTypeaheadTokenView.php b/src/applications/typeahead/view/PhabricatorTypeaheadTokenView.php --- a/src/applications/typeahead/view/PhabricatorTypeaheadTokenView.php +++ b/src/applications/typeahead/view/PhabricatorTypeaheadTokenView.php @@ -44,6 +44,10 @@ return $token; } + public function isInvalid() { + return ($this->getTokenType() == self::TYPE_INVALID); + } + public function setKey($key) { $this->key = $key; return $this;