Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/almanac/typeahead/AlmanacInterfaceDatasource.php b/src/applications/almanac/typeahead/AlmanacInterfaceDatasource.php
index 73ae32938b..a5f46ddfb0 100644
--- a/src/applications/almanac/typeahead/AlmanacInterfaceDatasource.php
+++ b/src/applications/almanac/typeahead/AlmanacInterfaceDatasource.php
@@ -1,57 +1,61 @@
<?php
final class AlmanacInterfaceDatasource
extends PhabricatorTypeaheadDatasource {
public function isBrowsable() {
// TODO: We should make this browsable, but need to make the result set
// orderable by device name.
return false;
}
+ public function getBrowseTitle() {
+ return pht('Browse Interfaces');
+ }
+
public function getPlaceholderText() {
return pht('Type an interface name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorAlmanacApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$devices = id(new AlmanacDeviceQuery())
->setViewer($viewer)
->withNamePrefix($raw_query)
->execute();
if ($devices) {
$interfaces = id(new AlmanacInterfaceQuery())
->setViewer($viewer)
->withDevicePHIDs(mpull($devices, 'getPHID'))
->execute();
} else {
$interfaces = array();
}
if ($interfaces) {
$handles = id(new PhabricatorHandleQuery())
->setViewer($viewer)
->withPHIDs(mpull($interfaces, 'getPHID'))
->execute();
} else {
$handles = array();
}
$results = array();
foreach ($handles as $handle) {
$results[] = id(new PhabricatorTypeaheadResult())
->setName($handle->getName())
->setPHID($handle->getPHID());
}
return $results;
}
}
diff --git a/src/applications/almanac/typeahead/AlmanacServiceDatasource.php b/src/applications/almanac/typeahead/AlmanacServiceDatasource.php
index 4cc0d1376a..e5728e1c26 100644
--- a/src/applications/almanac/typeahead/AlmanacServiceDatasource.php
+++ b/src/applications/almanac/typeahead/AlmanacServiceDatasource.php
@@ -1,43 +1,47 @@
<?php
final class AlmanacServiceDatasource
extends PhabricatorTypeaheadDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Services');
+ }
+
public function getPlaceholderText() {
return pht('Type a service name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorAlmanacApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$services = id(new AlmanacServiceQuery())
->withNamePrefix($raw_query)
->setOrder('name');
$services = $this->executeQuery($services);
if ($services) {
$handles = id(new PhabricatorHandleQuery())
->setViewer($viewer)
->withPHIDs(mpull($services, 'getPHID'))
->execute();
} else {
$handles = array();
}
$results = array();
foreach ($handles as $handle) {
$results[] = id(new PhabricatorTypeaheadResult())
->setName($handle->getName())
->setPHID($handle->getPHID());
}
return $results;
}
}
diff --git a/src/applications/diffusion/typeahead/DiffusionArcanistProjectDatasource.php b/src/applications/diffusion/typeahead/DiffusionArcanistProjectDatasource.php
index ce77b56f9b..4f58acfa59 100644
--- a/src/applications/diffusion/typeahead/DiffusionArcanistProjectDatasource.php
+++ b/src/applications/diffusion/typeahead/DiffusionArcanistProjectDatasource.php
@@ -1,35 +1,39 @@
<?php
final class DiffusionArcanistProjectDatasource
extends PhabricatorTypeaheadDatasource {
public function isBrowsable() {
// TODO: We should probably make this browsable, or maybe remove it.
return false;
}
+ public function getBrowseTitle() {
+ return pht('Browse Arcanist Projects');
+ }
+
public function getPlaceholderText() {
return pht('Type an arcanist project name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$results = array();
$arcprojs = id(new PhabricatorRepositoryArcanistProject())->loadAll();
foreach ($arcprojs as $proj) {
$results[] = id(new PhabricatorTypeaheadResult())
->setName($proj->getName())
->setPHID($proj->getPHID());
}
return $results;
}
}
diff --git a/src/applications/diffusion/typeahead/DiffusionAuditorDatasource.php b/src/applications/diffusion/typeahead/DiffusionAuditorDatasource.php
index 471c8a15b7..54c3aa72d9 100644
--- a/src/applications/diffusion/typeahead/DiffusionAuditorDatasource.php
+++ b/src/applications/diffusion/typeahead/DiffusionAuditorDatasource.php
@@ -1,22 +1,26 @@
<?php
final class DiffusionAuditorDatasource
extends PhabricatorTypeaheadCompositeDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Auditors');
+ }
+
public function getPlaceholderText() {
return pht('Type a user, project or package name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
public function getComponentDatasources() {
return array(
new PhabricatorPeopleDatasource(),
new PhabricatorProjectDatasource(),
new PhabricatorOwnersPackageDatasource(),
);
}
}
diff --git a/src/applications/diffusion/typeahead/DiffusionRepositoryDatasource.php b/src/applications/diffusion/typeahead/DiffusionRepositoryDatasource.php
index 995a413d97..4c2b8e1fb0 100644
--- a/src/applications/diffusion/typeahead/DiffusionRepositoryDatasource.php
+++ b/src/applications/diffusion/typeahead/DiffusionRepositoryDatasource.php
@@ -1,35 +1,39 @@
<?php
final class DiffusionRepositoryDatasource
extends PhabricatorTypeaheadDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Repositories');
+ }
+
public function getPlaceholderText() {
return pht('Type a repository name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$query = id(new PhabricatorRepositoryQuery())
->setOrder('name')
->withDatasourceQuery($raw_query);
$repos = $this->executeQuery($query);
$results = array();
foreach ($repos as $repo) {
$results[] = id(new PhabricatorTypeaheadResult())
->setName($repo->getMonogram().' '.$repo->getName())
->setURI('/diffusion/'.$repo->getCallsign().'/')
->setPHID($repo->getPHID())
->setPriorityString($repo->getMonogram());
}
return $results;
}
}
diff --git a/src/applications/diffusion/typeahead/DiffusionSymbolDatasource.php b/src/applications/diffusion/typeahead/DiffusionSymbolDatasource.php
index 0203ff2971..be7a084457 100644
--- a/src/applications/diffusion/typeahead/DiffusionSymbolDatasource.php
+++ b/src/applications/diffusion/typeahead/DiffusionSymbolDatasource.php
@@ -1,54 +1,58 @@
<?php
final class DiffusionSymbolDatasource
extends PhabricatorTypeaheadDatasource {
public function isBrowsable() {
// This is slightly involved to make browsable, and browsing symbols
// does not seem likely to be very useful in any real software project.
return false;
}
+ public function getBrowseTitle() {
+ return pht('Browse Symbols');
+ }
+
public function getPlaceholderText() {
return pht('Type a symbol name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$results = array();
if (strlen($raw_query)) {
$symbols = id(new DiffusionSymbolQuery())
->setViewer($viewer)
->setNamePrefix($raw_query)
->setLimit(15)
->needArcanistProjects(true)
->needRepositories(true)
->needPaths(true)
->execute();
foreach ($symbols as $symbol) {
$lang = $symbol->getSymbolLanguage();
$name = $symbol->getSymbolName();
$type = $symbol->getSymbolType();
$proj = $symbol->getArcanistProject()->getName();
$results[] = id(new PhabricatorTypeaheadResult())
->setName($name)
->setURI($symbol->getURI())
->setPHID(md5($symbol->getURI())) // Just needs to be unique.
->setDisplayName($name)
->setDisplayType(strtoupper($lang).' '.ucwords($type).' ('.$proj.')')
->setPriorityType('symb');
}
}
return $results;
}
}
diff --git a/src/applications/harbormaster/typeahead/HarbormasterBuildDependencyDatasource.php b/src/applications/harbormaster/typeahead/HarbormasterBuildDependencyDatasource.php
index 997e129bb3..08b0be774e 100644
--- a/src/applications/harbormaster/typeahead/HarbormasterBuildDependencyDatasource.php
+++ b/src/applications/harbormaster/typeahead/HarbormasterBuildDependencyDatasource.php
@@ -1,50 +1,54 @@
<?php
final class HarbormasterBuildDependencyDatasource
extends PhabricatorTypeaheadDatasource {
public function isBrowsable() {
// TODO: This should be browsable, but fixing it is involved.
return false;
}
+ public function getBrowseTitle() {
+ return pht('Browse Dependencies');
+ }
+
public function getPlaceholderText() {
return pht('Type another build step name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorHarbormasterApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$plan_phid = $this->getParameter('planPHID');
$step_phid = $this->getParameter('stepPHID');
$steps = id(new HarbormasterBuildStepQuery())
->setViewer($viewer)
->withBuildPlanPHIDs(array($plan_phid))
->execute();
$steps = mpull($steps, null, 'getPHID');
if (count($steps) === 0) {
return array();
}
$results = array();
foreach ($steps as $phid => $step) {
if ($step->getPHID() === $step_phid) {
continue;
}
$results[] = id(new PhabricatorTypeaheadResult())
->setName($step->getName())
->setURI('/')
->setPHID($phid);
}
return $results;
}
}
diff --git a/src/applications/harbormaster/typeahead/HarbormasterBuildPlanDatasource.php b/src/applications/harbormaster/typeahead/HarbormasterBuildPlanDatasource.php
index ceb4a1ff10..cf5b815c57 100644
--- a/src/applications/harbormaster/typeahead/HarbormasterBuildPlanDatasource.php
+++ b/src/applications/harbormaster/typeahead/HarbormasterBuildPlanDatasource.php
@@ -1,40 +1,44 @@
<?php
final class HarbormasterBuildPlanDatasource
extends PhabricatorTypeaheadDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Build Plans');
+ }
+
public function getPlaceholderText() {
return pht('Type a build plan name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorHarbormasterApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$results = array();
$query = id(new HarbormasterBuildPlanQuery())
->setOrder('name')
->withDatasourceQuery($raw_query);
$plans = $this->executeQuery($query);
foreach ($plans as $plan) {
$closed = null;
if ($plan->isDisabled()) {
$closed = pht('Disabled');
}
$results[] = id(new PhabricatorTypeaheadResult())
->setName($plan->getName())
->setClosed($closed)
->setPHID($plan->getPHID());
}
return $results;
}
}
diff --git a/src/applications/legalpad/typeahead/LegalpadDocumentDatasource.php b/src/applications/legalpad/typeahead/LegalpadDocumentDatasource.php
index a536843d0b..a0117ee7b0 100644
--- a/src/applications/legalpad/typeahead/LegalpadDocumentDatasource.php
+++ b/src/applications/legalpad/typeahead/LegalpadDocumentDatasource.php
@@ -1,36 +1,40 @@
<?php
final class LegalpadDocumentDatasource extends PhabricatorTypeaheadDatasource {
public function isBrowsable() {
// TODO: This should be made browsable.
return false;
}
+ public function getBrowseTitle() {
+ return pht('Browse Documents');
+ }
+
public function getPlaceholderText() {
return pht('Type a document name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorLegalpadApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$results = array();
$documents = id(new LegalpadDocumentQuery())
->setViewer($viewer)
->execute();
foreach ($documents as $document) {
$results[] = id(new PhabricatorTypeaheadResult())
->setPHID($document->getPHID())
->setName($document->getMonogram().' '.$document->getTitle());
}
return $results;
}
}
diff --git a/src/applications/macro/typeahead/PhabricatorMacroDatasource.php b/src/applications/macro/typeahead/PhabricatorMacroDatasource.php
index 1d978683cc..b7b7efd630 100644
--- a/src/applications/macro/typeahead/PhabricatorMacroDatasource.php
+++ b/src/applications/macro/typeahead/PhabricatorMacroDatasource.php
@@ -1,37 +1,41 @@
<?php
final class PhabricatorMacroDatasource extends PhabricatorTypeaheadDatasource {
public function getPlaceholderText() {
return pht('Type a macro name...');
}
+ public function getBrowseTitle() {
+ return pht('Browse Macros');
+ }
+
public function getDatasourceApplicationClass() {
return 'PhabricatorMacroApplication';
}
public function loadResults() {
$raw_query = $this->getRawQuery();
$query = id(new PhabricatorMacroQuery())
->setOrder('name')
->withNamePrefix($raw_query);
$macros = $this->executeQuery($query);
$results = array();
foreach ($macros as $macro) {
$closed = null;
if ($macro->getIsDisabled()) {
$closed = pht('Disabled');
}
$results[] = id(new PhabricatorTypeaheadResult())
->setPHID($macro->getPHID())
->setClosed($closed)
->setName($macro->getName());
}
return $results;
}
}
diff --git a/src/applications/mailinglists/typeahead/PhabricatorMailingListDatasource.php b/src/applications/mailinglists/typeahead/PhabricatorMailingListDatasource.php
index b9435e0b4a..cac292e1e5 100644
--- a/src/applications/mailinglists/typeahead/PhabricatorMailingListDatasource.php
+++ b/src/applications/mailinglists/typeahead/PhabricatorMailingListDatasource.php
@@ -1,35 +1,39 @@
<?php
final class PhabricatorMailingListDatasource
extends PhabricatorTypeaheadDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Mailing Lists');
+ }
+
public function getPlaceholderText() {
return pht('Type a mailing list name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorMailingListsApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$query = id(new PhabricatorMailingListQuery());
$lists = $this->executeQuery($query);
$results = array();
foreach ($lists as $list) {
$results[] = id(new PhabricatorTypeaheadResult())
->setName($list->getName())
->setURI($list->getURI())
->setPHID($list->getPHID());
}
// TODO: It would be slightly preferable to do this as part of the query,
// this is just simpler for the moment.
return $this->filterResultsAgainstTokens($results);
}
}
diff --git a/src/applications/maniphest/typeahead/ManiphestTaskPriorityDatasource.php b/src/applications/maniphest/typeahead/ManiphestTaskPriorityDatasource.php
index 568aa0636d..59c9a08042 100644
--- a/src/applications/maniphest/typeahead/ManiphestTaskPriorityDatasource.php
+++ b/src/applications/maniphest/typeahead/ManiphestTaskPriorityDatasource.php
@@ -1,31 +1,35 @@
<?php
final class ManiphestTaskPriorityDatasource
extends PhabricatorTypeaheadDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Priorities');
+ }
+
public function getPlaceholderText() {
return pht('Type a task priority name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorManiphestApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$results = array();
$priority_map = ManiphestTaskPriority::getTaskPriorityMap();
foreach ($priority_map as $value => $name) {
// NOTE: $value is not a PHID but is unique. This'll work.
$results[] = id(new PhabricatorTypeaheadResult())
->setPHID($value)
->setName($name);
}
return $this->filterResultsAgainstTokens($results);
}
}
diff --git a/src/applications/maniphest/typeahead/ManiphestTaskStatusDatasource.php b/src/applications/maniphest/typeahead/ManiphestTaskStatusDatasource.php
index 27b3f90386..7ef047e72e 100644
--- a/src/applications/maniphest/typeahead/ManiphestTaskStatusDatasource.php
+++ b/src/applications/maniphest/typeahead/ManiphestTaskStatusDatasource.php
@@ -1,30 +1,34 @@
<?php
final class ManiphestTaskStatusDatasource
extends PhabricatorTypeaheadDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Statuses');
+ }
+
public function getPlaceholderText() {
return pht('Type a task status name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorManiphestApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$results = array();
$status_map = ManiphestTaskStatus::getTaskStatusMap();
foreach ($status_map as $value => $name) {
// NOTE: $value is not a PHID but is unique. This'll work.
$results[] = id(new PhabricatorTypeaheadResult())
->setPHID($value)
->setName($name);
}
return $this->filterResultsAgainstTokens($results);
}
}
diff --git a/src/applications/meta/typeahead/PhabricatorApplicationDatasource.php b/src/applications/meta/typeahead/PhabricatorApplicationDatasource.php
index 18b6683dfc..b6d4aa3f18 100644
--- a/src/applications/meta/typeahead/PhabricatorApplicationDatasource.php
+++ b/src/applications/meta/typeahead/PhabricatorApplicationDatasource.php
@@ -1,43 +1,47 @@
<?php
final class PhabricatorApplicationDatasource
extends PhabricatorTypeaheadDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Applications');
+ }
+
public function getPlaceholderText() {
return pht('Type an application name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorApplicationsApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$results = array();
$applications = PhabricatorApplication::getAllInstalledApplications();
foreach ($applications as $application) {
$uri = $application->getTypeaheadURI();
if (!$uri) {
continue;
}
$name = $application->getName().' '.$application->getShortDescription();
$img = 'phui-font-fa phui-icon-view '.$application->getFontIcon();
$results[] = id(new PhabricatorTypeaheadResult())
->setName($name)
->setURI($uri)
->setPHID($application->getPHID())
->setPriorityString($application->getName())
->setDisplayName($application->getName())
->setDisplayType($application->getShortDescription())
->setImageuRI($application->getIconURI())
->setPriorityType('apps')
->setImageSprite('phabricator-search-icon '.$img);
}
return $this->filterResultsAgainstTokens($results);
}
}
diff --git a/src/applications/metamta/typeahead/PhabricatorMetaMTAApplicationEmailDatasource.php b/src/applications/metamta/typeahead/PhabricatorMetaMTAApplicationEmailDatasource.php
index 887aecfd80..62c1275c39 100644
--- a/src/applications/metamta/typeahead/PhabricatorMetaMTAApplicationEmailDatasource.php
+++ b/src/applications/metamta/typeahead/PhabricatorMetaMTAApplicationEmailDatasource.php
@@ -1,48 +1,52 @@
<?php
final class PhabricatorMetaMTAApplicationEmailDatasource
extends PhabricatorTypeaheadDatasource {
public function isBrowsable() {
// TODO: Make this browsable.
return false;
}
+ public function getBrowseTitle() {
+ return pht('Browse Email Addresses');
+ }
+
public function getPlaceholderText() {
return pht('Type an application email address...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorMetaMTAApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$emails = id(new PhabricatorMetaMTAApplicationEmailQuery())
->setViewer($viewer)
->withAddressPrefix($raw_query)
->setLimit($this->getLimit())
->execute();
if ($emails) {
$handles = id(new PhabricatorHandleQuery())
->setViewer($viewer)
->withPHIDs(mpull($emails, 'getPHID'))
->execute();
} else {
$handles = array();
}
$results = array();
foreach ($handles as $handle) {
$results[] = id(new PhabricatorTypeaheadResult())
->setName($handle->getName())
->setPHID($handle->getPHID());
}
return $results;
}
}
diff --git a/src/applications/metamta/typeahead/PhabricatorMetaMTAMailableDatasource.php b/src/applications/metamta/typeahead/PhabricatorMetaMTAMailableDatasource.php
index 9d7e2cda7d..804e4498c0 100644
--- a/src/applications/metamta/typeahead/PhabricatorMetaMTAMailableDatasource.php
+++ b/src/applications/metamta/typeahead/PhabricatorMetaMTAMailableDatasource.php
@@ -1,22 +1,26 @@
<?php
final class PhabricatorMetaMTAMailableDatasource
extends PhabricatorTypeaheadCompositeDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Subscribers');
+ }
+
public function getPlaceholderText() {
return pht('Type a user, project, or mailing list name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorMetaMTAApplication';
}
public function getComponentDatasources() {
return array(
new PhabricatorPeopleDatasource(),
new PhabricatorProjectDatasource(),
new PhabricatorMailingListDatasource(),
);
}
}
diff --git a/src/applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php b/src/applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php
index a8658549ec..73105f0908 100644
--- a/src/applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php
+++ b/src/applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php
@@ -1,39 +1,43 @@
<?php
final class PhabricatorOwnersPackageDatasource
extends PhabricatorTypeaheadDatasource {
public function isBrowsable() {
// TODO: Make this browsable.
return false;
}
+ public function getBrowseTitle() {
+ return pht('Browse Packages');
+ }
+
public function getPlaceholderText() {
return pht('Type a package name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorOwnersApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$results = array();
$packages = id(new PhabricatorOwnersPackageQuery())
->setViewer($viewer)
->execute();
foreach ($packages as $package) {
$results[] = id(new PhabricatorTypeaheadResult())
->setName($package->getName())
->setURI('/owners/package/'.$package->getID().'/')
->setPHID($package->getPHID());
}
return $results;
}
}
diff --git a/src/applications/people/typeahead/PhabricatorPeopleDatasource.php b/src/applications/people/typeahead/PhabricatorPeopleDatasource.php
index a2df2750ad..ab1f11cede 100644
--- a/src/applications/people/typeahead/PhabricatorPeopleDatasource.php
+++ b/src/applications/people/typeahead/PhabricatorPeopleDatasource.php
@@ -1,79 +1,83 @@
<?php
final class PhabricatorPeopleDatasource
extends PhabricatorTypeaheadDatasource {
private $enrichResults;
/**
* Controls enriched rendering, for global search. This is a bit hacky and
* should probably be handled in a more general way, but is fairly reasonable
* for now.
*/
public function setEnrichResults($enrich) {
$this->enrichResults = $enrich;
return $this;
}
+ public function getBrowseTitle() {
+ return pht('Browse Users');
+ }
+
public function getPlaceholderText() {
return pht('Type a username...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorPeopleApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$tokens = $this->getTokens();
$query = id(new PhabricatorPeopleQuery())
->setOrderVector(array('username'));
if ($tokens) {
$query->withNameTokens($tokens);
}
$users = $this->executeQuery($query);
if ($this->enrichResults && $users) {
$phids = mpull($users, 'getPHID');
$handles = id(new PhabricatorHandleQuery())
->setViewer($viewer)
->withPHIDs($phids)
->execute();
}
$results = array();
foreach ($users as $user) {
$closed = null;
if ($user->getIsDisabled()) {
$closed = pht('Disabled');
} else if ($user->getIsSystemAgent()) {
$closed = pht('Bot/Script');
}
$result = id(new PhabricatorTypeaheadResult())
->setName($user->getFullName())
->setURI('/p/'.$user->getUsername())
->setPHID($user->getPHID())
->setPriorityString($user->getUsername())
->setPriorityType('user')
->setClosed($closed);
if ($this->enrichResults) {
$display_type = 'User';
if ($user->getIsAdmin()) {
$display_type = 'Administrator';
}
$result->setDisplayType($display_type);
$result->setImageURI($handles[$user->getPHID()]->getImageURI());
}
$results[] = $result;
}
return $results;
}
}
diff --git a/src/applications/people/typeahead/PhabricatorViewerDatasource.php b/src/applications/people/typeahead/PhabricatorViewerDatasource.php
index 92bd48bab0..ef4cbc3a1b 100644
--- a/src/applications/people/typeahead/PhabricatorViewerDatasource.php
+++ b/src/applications/people/typeahead/PhabricatorViewerDatasource.php
@@ -1,57 +1,61 @@
<?php
final class PhabricatorViewerDatasource
extends PhabricatorTypeaheadDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Viewer');
+ }
+
public function getPlaceholderText() {
return pht('Type viewer()...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorPeopleApplication';
}
public function loadResults() {
if ($this->getViewer()->getPHID()) {
$results = array($this->renderViewerFunctionToken());
} else {
$results = array();
}
return $this->filterResultsAgainstTokens($results);
}
protected function canEvaluateFunction($function) {
if (!$this->getViewer()->getPHID()) {
return false;
}
return ($function == 'viewer');
}
protected function evaluateFunction($function, array $argv_list) {
$results = array();
foreach ($argv_list as $argv) {
$results[] = $this->getViewer()->getPHID();
}
return $results;
}
public function renderFunctionTokens($function, array $argv_list) {
$tokens = array();
foreach ($argv_list as $argv) {
$tokens[] = PhabricatorTypeaheadTokenView::newFromTypeaheadResult(
$this->renderViewerFunctionToken());
}
return $tokens;
}
private function renderViewerFunctionToken() {
return $this->newFunctionResult()
->setName(pht('Current Viewer'))
->setPHID('viewer()')
->setIcon('fa-user')
->setUnique(true);
}
}
diff --git a/src/applications/project/typeahead/PhabricatorProjectDatasource.php b/src/applications/project/typeahead/PhabricatorProjectDatasource.php
index 0466ad9950..d38f6fc5b3 100644
--- a/src/applications/project/typeahead/PhabricatorProjectDatasource.php
+++ b/src/applications/project/typeahead/PhabricatorProjectDatasource.php
@@ -1,79 +1,83 @@
<?php
final class PhabricatorProjectDatasource
extends PhabricatorTypeaheadDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Projects');
+ }
+
public function getPlaceholderText() {
return pht('Type a project name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorProjectApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
// Allow users to type "#qa" or "qa" to find "Quality Assurance".
$raw_query = ltrim($raw_query, '#');
$tokens = self::tokenizeString($raw_query);
$query = id(new PhabricatorProjectQuery())
->needImages(true)
->needSlugs(true);
if ($tokens) {
$query->withNameTokens($tokens);
}
$projs = $this->executeQuery($query);
$projs = mpull($projs, null, 'getPHID');
$must_have_cols = $this->getParameter('mustHaveColumns', false);
if ($must_have_cols) {
$columns = id(new PhabricatorProjectColumnQuery())
->setViewer($viewer)
->withProjectPHIDs(array_keys($projs))
->execute();
$has_cols = mgroup($columns, 'getProjectPHID');
} else {
$has_cols = array_fill_keys(array_keys($projs), true);
}
$results = array();
foreach ($projs as $proj) {
if (!isset($has_cols[$proj->getPHID()])) {
continue;
}
$closed = null;
if ($proj->isArchived()) {
$closed = pht('Archived');
}
$all_strings = mpull($proj->getSlugs(), 'getSlug');
$all_strings[] = $proj->getName();
$all_strings = implode(' ', $all_strings);
$proj_result = id(new PhabricatorTypeaheadResult())
->setName($all_strings)
->setDisplayName($proj->getName())
->setDisplayType('Project')
->setURI('/tag/'.$proj->getPrimarySlug().'/')
->setPHID($proj->getPHID())
->setIcon($proj->getIcon())
->setColor($proj->getColor())
->setPriorityType('proj')
->setClosed($closed);
$proj_result->setImageURI($proj->getProfileImageURI());
$results[] = $proj_result;
}
return $results;
}
}
diff --git a/src/applications/project/typeahead/PhabricatorProjectLogicalAndDatasource.php b/src/applications/project/typeahead/PhabricatorProjectLogicalAndDatasource.php
index 18748ce8a7..a3016820a0 100644
--- a/src/applications/project/typeahead/PhabricatorProjectLogicalAndDatasource.php
+++ b/src/applications/project/typeahead/PhabricatorProjectLogicalAndDatasource.php
@@ -1,32 +1,36 @@
<?php
final class PhabricatorProjectLogicalAndDatasource
extends PhabricatorTypeaheadCompositeDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Projects');
+ }
+
public function getPlaceholderText() {
return pht('Type a project name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorProjectApplication';
}
public function getComponentDatasources() {
return array(
new PhabricatorProjectDatasource(),
);
}
protected function didEvaluateTokens(array $results) {
foreach ($results as $key => $result) {
if (is_string($result)) {
$results[$key] = new PhabricatorQueryConstraint(
PhabricatorQueryConstraint::OPERATOR_AND,
$result);
}
}
return $results;
}
}
diff --git a/src/applications/project/typeahead/PhabricatorProjectLogicalDatasource.php b/src/applications/project/typeahead/PhabricatorProjectLogicalDatasource.php
index 17afb30c99..1bce988339 100644
--- a/src/applications/project/typeahead/PhabricatorProjectLogicalDatasource.php
+++ b/src/applications/project/typeahead/PhabricatorProjectLogicalDatasource.php
@@ -1,24 +1,28 @@
<?php
final class PhabricatorProjectLogicalDatasource
extends PhabricatorTypeaheadCompositeDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Projects');
+ }
+
public function getPlaceholderText() {
- return pht('Type a project name or selector...');
+ return pht('Type a project name or function...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorProjectApplication';
}
public function getComponentDatasources() {
return array(
new PhabricatorProjectNoProjectsDatasource(),
new PhabricatorProjectLogicalAndDatasource(),
new PhabricatorProjectLogicalOrNotDatasource(),
new PhabricatorProjectLogicalViewerDatasource(),
new PhabricatorProjectLogicalUserDatasource(),
);
}
}
diff --git a/src/applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php b/src/applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php
index c784179b7d..306e63f21a 100644
--- a/src/applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php
+++ b/src/applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php
@@ -1,115 +1,119 @@
<?php
final class PhabricatorProjectLogicalOrNotDatasource
extends PhabricatorTypeaheadCompositeDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Projects');
+ }
+
public function getPlaceholderText() {
return pht('Type any(<project>) or not(<project>)...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorProjectApplication';
}
public function getComponentDatasources() {
return array(
new PhabricatorProjectDatasource(),
);
}
public function getDatasourceFunctions() {
return array(
'any' => array(
'name' => pht('Find results in any of several projects.'),
),
'not' => array(
'name' => pht('Find results not in specific projects.'),
),
);
}
protected function didLoadResults(array $results) {
$function = $this->getCurrentFunction();
$return_any = ($function !== 'not');
$return_not = ($function !== 'any');
$return = array();
foreach ($results as $result) {
$result
->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION)
->setIcon('fa-asterisk');
if ($return_any) {
$return[] = id(clone $result)
->setPHID('any('.$result->getPHID().')')
->setDisplayName(pht('In Any: %s', $result->getDisplayName()))
->setName($result->getName().' any');
}
if ($return_not) {
$return[] = id(clone $result)
->setPHID('not('.$result->getPHID().')')
->setDisplayName(pht('Not In: %s', $result->getDisplayName()))
->setName($result->getName().' not');
}
}
return $return;
}
protected function evaluateFunction($function, array $argv_list) {
$phids = array();
foreach ($argv_list as $argv) {
$phids[] = head($argv);
}
$operator = array(
'any' => PhabricatorQueryConstraint::OPERATOR_OR,
'not' => PhabricatorQueryConstraint::OPERATOR_NOT,
);
$results = array();
foreach ($phids as $phid) {
$results[] = new PhabricatorQueryConstraint(
$operator[$function],
$phid);
}
return $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()) {
if ($function == 'any') {
$token->setValue(pht('In Any: Invalid Project'));
} else {
$token->setValue(pht('Not In: Invalid Project'));
}
} else {
$token
->setIcon('fa-asterisk')
->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION);
if ($function == 'any') {
$token
->setKey('any('.$token->getKey().')')
->setValue(pht('In Any: %s', $token->getValue()));
} else {
$token
->setKey('not('.$token->getKey().')')
->setValue(pht('Not In: %s', $token->getValue()));
}
}
}
return $tokens;
}
}
diff --git a/src/applications/project/typeahead/PhabricatorProjectLogicalUserDatasource.php b/src/applications/project/typeahead/PhabricatorProjectLogicalUserDatasource.php
index ed1ebdc782..06a638075d 100644
--- a/src/applications/project/typeahead/PhabricatorProjectLogicalUserDatasource.php
+++ b/src/applications/project/typeahead/PhabricatorProjectLogicalUserDatasource.php
@@ -1,123 +1,127 @@
<?php
final class PhabricatorProjectLogicalUserDatasource
extends PhabricatorTypeaheadCompositeDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse User Projects');
+ }
+
public function getPlaceholderText() {
return pht('Type projects(<user>)...');
}
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-asterisk')
->setPHID('projects('.$result->getPHID().')')
->setDisplayName(pht("User's 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);
}
$phids = $this->resolvePHIDs($phids);
$projects = id(new PhabricatorProjectQuery())
->setViewer($this->getViewer())
->withMemberPHIDs($phids)
->execute();
$results = array();
foreach ($projects as $project) {
$results[] = new PhabricatorQueryConstraint(
PhabricatorQueryConstraint::OPERATOR_OR,
$project->getPHID());
}
return $results;
}
public function renderFunctionTokens($function, array $argv_list) {
$phids = array();
foreach ($argv_list as $argv) {
$phids[] = head($argv);
}
$phids = $this->resolvePHIDs($phids);
$tokens = $this->renderTokens($phids);
foreach ($tokens as $token) {
if ($token->isInvalid()) {
$token
->setValue(pht("User's Projects: Invalid User"));
} else {
$token
->setIcon('fa-asterisk')
->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION)
->setKey('projects('.$token->getKey().')')
->setValue(pht("User's Projects: %s", $token->getValue()));
}
}
return $tokens;
}
private function resolvePHIDs(array $phids) {
// If we have a function like `projects(alincoln)`, try to resolve the
// username first. This won't happen normally, but can be passed in from
// the query string.
// The user might also give us an invalid username. In this case, we
// preserve it and return it in-place so we get an "invalid" token rendered
// in the UI. This shows the user where the issue is and best represents
// the user's input.
$usernames = array();
foreach ($phids as $key => $phid) {
if (phid_get_type($phid) != PhabricatorPeopleUserPHIDType::TYPECONST) {
$usernames[$key] = $phid;
}
}
if ($usernames) {
$users = id(new PhabricatorPeopleQuery())
->setViewer($this->getViewer())
->withUsernames($usernames)
->execute();
$users = mpull($users, null, 'getUsername');
foreach ($usernames as $key => $username) {
$user = idx($users, $username);
if ($user) {
$phids[$key] = $user->getPHID();
}
}
}
return $phids;
}
}
diff --git a/src/applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php b/src/applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php
index 7e76cd5762..4285462d54 100644
--- a/src/applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php
+++ b/src/applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php
@@ -1,80 +1,84 @@
<?php
final class PhabricatorProjectLogicalViewerDatasource
extends PhabricatorTypeaheadDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Viewer Projects');
+ }
+
public function getPlaceholderText() {
return pht('Type viewerprojects()...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorProjectApplication';
}
public function getDatasourceFunctions() {
return array(
'viewerprojects' => array(
'name' => pht("Find results in any of the current viewer's projects."),
),
);
}
public function loadResults() {
if ($this->getViewer()->getPHID()) {
$results = array($this->renderViewerProjectsFunctionToken());
} else {
$results = array();
}
return $this->filterResultsAgainstTokens($results);
}
protected function canEvaluateFunction($function) {
if (!$this->getViewer()->getPHID()) {
return false;
}
return parent::canEvaluateFunction($function);
}
protected function evaluateFunction($function, array $argv_list) {
$viewer = $this->getViewer();
$projects = id(new PhabricatorProjectQuery())
->setViewer($viewer)
->withMemberPHIDs(array($viewer->getPHID()))
->execute();
$phids = mpull($projects, 'getPHID');
$results = array();
foreach ($phids as $phid) {
$results[] = new PhabricatorQueryConstraint(
PhabricatorQueryConstraint::OPERATOR_OR,
$phid);
}
return $results;
}
public function renderFunctionTokens(
$function,
array $argv_list) {
$tokens = array();
foreach ($argv_list as $argv) {
$tokens[] = PhabricatorTypeaheadTokenView::newFromTypeaheadResult(
$this->renderViewerProjectsFunctionToken());
}
return $tokens;
}
private function renderViewerProjectsFunctionToken() {
return $this->newFunctionResult()
->setName(pht('Current Viewer\'s Projects'))
->setPHID('viewerprojects()')
->setIcon('fa-asterisk')
->setUnique(true);
}
}
diff --git a/src/applications/project/typeahead/PhabricatorProjectMembersDatasource.php b/src/applications/project/typeahead/PhabricatorProjectMembersDatasource.php
index 4f8ee3e987..c96d006e56 100644
--- a/src/applications/project/typeahead/PhabricatorProjectMembersDatasource.php
+++ b/src/applications/project/typeahead/PhabricatorProjectMembersDatasource.php
@@ -1,86 +1,90 @@
<?php
final class PhabricatorProjectMembersDatasource
extends PhabricatorTypeaheadCompositeDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Members');
+ }
+
public function getPlaceholderText() {
return pht('Type members(<project>)...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorProjectApplication';
}
public function getComponentDatasources() {
return array(
new PhabricatorProjectDatasource(),
);
}
public function getDatasourceFunctions() {
return array(
'members' => array(
'name' => pht('Find results for members of a project.'),
),
);
}
protected function didLoadResults(array $results) {
foreach ($results as $result) {
$result
->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION)
->setIcon('fa-users')
->setPHID('members('.$result->getPHID().')')
->setDisplayName(pht('Members: %s', $result->getDisplayName()))
->setName($result->getName().' members');
}
return $results;
}
protected function evaluateFunction($function, array $argv_list) {
$phids = array();
foreach ($argv_list as $argv) {
$phids[] = head($argv);
}
$projects = id(new PhabricatorProjectQuery())
->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('Members: Invalid Project'));
} else {
$token
->setIcon('fa-users')
->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION)
->setKey('members('.$token->getKey().')')
->setValue(pht('Members: %s', $token->getValue()));
}
}
return $tokens;
}
}
diff --git a/src/applications/project/typeahead/PhabricatorProjectNoProjectsDatasource.php b/src/applications/project/typeahead/PhabricatorProjectNoProjectsDatasource.php
index d4f569e78c..ed24e5e88b 100644
--- a/src/applications/project/typeahead/PhabricatorProjectNoProjectsDatasource.php
+++ b/src/applications/project/typeahead/PhabricatorProjectNoProjectsDatasource.php
@@ -1,62 +1,66 @@
<?php
final class PhabricatorProjectNoProjectsDatasource
extends PhabricatorTypeaheadDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Not In Any Projects');
+ }
+
public function getPlaceholderText() {
return pht('Type "not in any projects"...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorProjectApplication';
}
public function getDatasourceFunctions() {
return array(
'null' => array(
'name' => pht('Find results which are not in any projects.'),
),
);
}
public function loadResults() {
$results = array(
$this->buildNullResult(),
);
return $this->filterResultsAgainstTokens($results);
}
protected function evaluateFunction($function, array $argv_list) {
$results = array();
foreach ($argv_list as $argv) {
$results[] = new PhabricatorQueryConstraint(
PhabricatorQueryConstraint::OPERATOR_NULL,
'empty');
}
return $results;
}
public function renderFunctionTokens($function, array $argv_list) {
$results = array();
foreach ($argv_list as $argv) {
$results[] = PhabricatorTypeaheadTokenView::newFromTypeaheadResult(
$this->buildNullResult());
}
return $results;
}
private function buildNullResult() {
$name = pht('Not In Any Projects');
return $this->newFunctionResult()
->setUnique(true)
->setPHID('null()')
->setIcon('fa-ban')
->setName('null '.$name)
->setDisplayName($name);
}
}
diff --git a/src/applications/project/typeahead/PhabricatorProjectOrUserDatasource.php b/src/applications/project/typeahead/PhabricatorProjectOrUserDatasource.php
index 2024fa3b8b..224828ee68 100644
--- a/src/applications/project/typeahead/PhabricatorProjectOrUserDatasource.php
+++ b/src/applications/project/typeahead/PhabricatorProjectOrUserDatasource.php
@@ -1,17 +1,21 @@
<?php
final class PhabricatorProjectOrUserDatasource
extends PhabricatorTypeaheadCompositeDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Users and Projects');
+ }
+
public function getPlaceholderText() {
return pht('Type a user or project name...');
}
public function getComponentDatasources() {
return array(
new PhabricatorPeopleDatasource(),
new PhabricatorProjectDatasource(),
);
}
}
diff --git a/src/applications/search/typeahead/PhabricatorSearchDatasource.php b/src/applications/search/typeahead/PhabricatorSearchDatasource.php
index fde4438bbd..65feed5fd2 100644
--- a/src/applications/search/typeahead/PhabricatorSearchDatasource.php
+++ b/src/applications/search/typeahead/PhabricatorSearchDatasource.php
@@ -1,24 +1,28 @@
<?php
final class PhabricatorSearchDatasource
extends PhabricatorTypeaheadCompositeDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Results');
+ }
+
public function getPlaceholderText() {
return pht('Type an object name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorSearchApplication';
}
public function getComponentDatasources() {
return array(
id(new PhabricatorPeopleDatasource())->setEnrichResults(true),
new PhabricatorProjectDatasource(),
new PhabricatorApplicationDatasource(),
new PhabricatorTypeaheadMonogramDatasource(),
new DiffusionSymbolDatasource(),
);
}
}
diff --git a/src/applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php b/src/applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php
index 773c031e43..dcca0782bb 100644
--- a/src/applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php
+++ b/src/applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php
@@ -1,322 +1,322 @@
<?php
final class PhabricatorTypeaheadModularDatasourceController
extends PhabricatorTypeaheadDatasourceController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$request = $this->getRequest();
$viewer = $request->getUser();
$query = $request->getStr('q');
$offset = $request->getInt('offset');
$select_phid = null;
$is_browse = ($request->getURIData('action') == 'browse');
$select = $request->getStr('select');
if ($select) {
$select = phutil_json_decode($select);
$query = idx($select, 'q');
$offset = idx($select, 'offset');
$select_phid = idx($select, 'phid');
}
// Default this to the query string to make debugging a little bit easier.
$raw_query = nonempty($request->getStr('raw'), $query);
// This makes form submission easier in the debug view.
$class = nonempty($request->getURIData('class'), $request->getStr('class'));
$sources = id(new PhutilSymbolLoader())
->setAncestorClass('PhabricatorTypeaheadDatasource')
->loadObjects();
if (isset($sources[$class])) {
$source = $sources[$class];
$source->setParameters($request->getRequestData());
$source->setViewer($viewer);
// NOTE: Wrapping the source in a Composite datasource ensures we perform
// application visibility checks for the viewer, so we do not need to do
// those separately.
$composite = new PhabricatorTypeaheadRuntimeCompositeDatasource();
$composite->addDatasource($source);
$hard_limit = 1000;
$limit = 100;
$composite
->setViewer($viewer)
->setQuery($query)
->setRawQuery($raw_query)
->setLimit($limit + 1);
if ($is_browse) {
if (!$composite->isBrowsable()) {
return new Aphront404Response();
}
if (($offset + $limit) >= $hard_limit) {
// Offset-based paging is intrinsically slow; hard-cap how far we're
// willing to go with it.
return new Aphront404Response();
}
$composite
->setOffset($offset);
}
$results = $composite->loadResults();
if ($is_browse) {
// If this is a request for a specific token after the user clicks
// "Select", return the token in wire format so it can be added to
// the tokenizer.
if ($select_phid) {
$map = mpull($results, null, 'getPHID');
$token = idx($map, $select_phid);
if (!$token) {
return new Aphront404Response();
}
$payload = array(
'key' => $token->getPHID(),
'token' => $token->getWireFormat(),
);
return id(new AphrontAjaxResponse())->setContent($payload);
}
$format = $request->getStr('format');
switch ($format) {
case 'html':
case 'dialog':
// These are the acceptable response formats.
break;
default:
// Return a dialog if format information is missing or invalid.
$format = 'dialog';
break;
}
$next_link = null;
if (count($results) > $limit) {
$results = array_slice($results, 0, $limit, $preserve_keys = true);
if (($offset + (2 * $limit)) < $hard_limit) {
$next_uri = id(new PhutilURI($request->getRequestURI()))
->setQueryParam('offset', $offset + $limit)
->setQueryParam('format', 'html');
$next_link = javelin_tag(
'a',
array(
'href' => $next_uri,
'class' => 'typeahead-browse-more',
'sigil' => 'typeahead-browse-more',
'mustcapture' => true,
),
pht('More Results'));
} else {
// If the user has paged through more than 1K results, don't
// offer to page any further.
$next_link = javelin_tag(
'div',
array(
'class' => 'typeahead-browse-hard-limit',
),
pht('You reach the edge of the abyss.'));
}
}
$exclude = $request->getStrList('exclude');
$exclude = array_fuse($exclude);
$select = array(
'offset' => $offset,
'q' => $query,
);
$items = array();
foreach ($results as $result) {
$token = PhabricatorTypeaheadTokenView::newFromTypeaheadResult(
$result);
// Disable already-selected tokens.
$disabled = isset($exclude[$result->getPHID()]);
$value = $select + array('phid' => $result->getPHID());
$value = json_encode($value);
$button = phutil_tag(
'button',
array(
'class' => 'small grey',
'name' => 'select',
'value' => $value,
'disabled' => $disabled ? 'disabled' : null,
),
pht('Select'));
$items[] = phutil_tag(
'div',
array(
'class' => 'typeahead-browse-item grouped',
),
array(
$token,
$button,
));
}
$markup = array(
$items,
$next_link,
);
if ($format == 'html') {
$content = array(
'markup' => hsprintf('%s', $markup),
);
return id(new AphrontAjaxResponse())->setContent($content);
}
$this->requireResource('typeahead-browse-css');
$this->initBehavior('typeahead-browse');
$input_id = celerity_generate_unique_node_id();
$frame_id = celerity_generate_unique_node_id();
$config = array(
'inputID' => $input_id,
'frameID' => $frame_id,
'uri' => (string)$request->getRequestURI(),
);
$this->initBehavior('typeahead-search', $config);
$search = javelin_tag(
'input',
array(
'type' => 'text',
'id' => $input_id,
'class' => 'typeahead-browse-input',
'autocomplete' => 'off',
'placeholder' => $source->getPlaceholderText(),
));
$frame = phutil_tag(
'div',
array(
'class' => 'typeahead-browse-frame',
'id' => $frame_id,
),
$markup);
$browser = array(
phutil_tag(
'div',
array(
'class' => 'typeahead-browse-header',
),
$search),
$frame,
);
return $this->newDialog()
->setWidth(AphrontDialogView::WIDTH_FORM)
->setRenderDialogAsDiv(true)
- ->setTitle(get_class($source)) // TODO: Provide nice names.
+ ->setTitle($source->getBrowseTitle())
->appendChild($browser)
->addCancelButton('/', pht('Close'));
}
} else if ($is_browse) {
return new Aphront404Response();
} else {
$results = array();
}
$content = mpull($results, 'getWireFormat');
$content = array_values($content);
if ($request->isAjax()) {
return id(new AphrontAjaxResponse())->setContent($content);
}
// If there's a non-Ajax request to this endpoint, show results in a tabular
// format to make it easier to debug typeahead output.
foreach ($sources as $key => $source) {
// This can happen with composite sources like user or project, as well
// generic ones like NoOwner
if (!$source->getDatasourceApplicationClass()) {
continue;
}
if (!PhabricatorApplication::isClassInstalledForViewer(
$source->getDatasourceApplicationClass(),
$viewer)) {
unset($sources[$key]);
}
}
$options = array_fuse(array_keys($sources));
asort($options);
$form = id(new AphrontFormView())
->setUser($viewer)
->setAction('/typeahead/class/')
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Source Class'))
->setName('class')
->setValue($class)
->setOptions($options))
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Query'))
->setName('q')
->setValue($request->getStr('q')))
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Raw Query'))
->setName('raw')
->setValue($request->getStr('raw')))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Query')));
$form_box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Token Query'))
->setForm($form);
$table = new AphrontTableView($content);
$table->setHeaders(
array(
pht('Name'),
pht('URI'),
pht('PHID'),
pht('Priority'),
pht('Display Name'),
pht('Display Type'),
pht('Image URI'),
pht('Priority Type'),
pht('Icon'),
pht('Closed'),
pht('Sprite'),
));
$result_box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Token Results (%s)', $class))
->appendChild($table);
return $this->buildApplicationPage(
array(
$form_box,
$result_box,
),
array(
'title' => pht('Typeahead Results'),
'device' => false,
));
}
}
diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
index 63f5737f57..4c51deb3a2 100644
--- a/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
+++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
@@ -1,413 +1,418 @@
<?php
/**
* @task functions Token Functions
*/
abstract class PhabricatorTypeaheadDatasource extends Phobject {
private $viewer;
private $query;
private $rawQuery;
private $offset;
private $limit;
private $parameters = array();
private $functionStack = array();
public function setLimit($limit) {
$this->limit = $limit;
return $this;
}
public function getLimit() {
return $this->limit;
}
public function setOffset($offset) {
$this->offset = $offset;
return $this;
}
public function getOffset() {
return $this->offset;
}
public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
return $this;
}
public function getViewer() {
return $this->viewer;
}
public function setRawQuery($raw_query) {
$this->rawQuery = $raw_query;
return $this;
}
public function getRawQuery() {
return $this->rawQuery;
}
public function setQuery($query) {
$this->query = $query;
return $this;
}
public function getQuery() {
return $this->query;
}
public function setParameters(array $params) {
$this->parameters = $params;
return $this;
}
public function getParameters() {
return $this->parameters;
}
public function getParameter($name, $default = null) {
return idx($this->parameters, $name, $default);
}
public function getDatasourceURI() {
$uri = new PhutilURI('/typeahead/class/'.get_class($this).'/');
$uri->setQueryParams($this->parameters);
return (string)$uri;
}
public function getBrowseURI() {
if (!$this->isBrowsable()) {
return null;
}
$uri = new PhutilURI('/typeahead/browse/'.get_class($this).'/');
$uri->setQueryParams($this->parameters);
return (string)$uri;
}
abstract public function getPlaceholderText();
+
+ public function getBrowseTitle() {
+ return get_class($this);
+ }
+
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);
if (!strlen($string)) {
return array();
}
$tokens = preg_split('/\s+|[-\[\]]/', $string);
return array_unique($tokens);
}
public function getTokens() {
return self::tokenizeString($this->getRawQuery());
}
protected function executeQuery(
PhabricatorCursorPagedPolicyAwareQuery $query) {
return $query
->setViewer($this->getViewer())
->setOffset($this->getOffset())
->setLimit($this->getLimit())
->execute();
}
/**
* Can the user browse through results from this datasource?
*
* Browsable datasources allow the user to switch from typeahead mode to
* a browse mode where they can scroll through all results.
*
* By default, datasources are browsable, but some datasources can not
* generate a meaningful result set or can't filter results on the server.
*
* @return bool
*/
public function isBrowsable() {
return true;
}
/**
* Filter a list of results, removing items which don't match the query
* tokens.
*
* This is useful for datasources which return a static list of hard-coded
* or configured results and can't easily do query filtering in a real
* query class. Instead, they can just build the entire result set and use
* this method to filter it.
*
* For datasources backed by database objects, this is often much less
* efficient than filtering at the query level.
*
* @param list<PhabricatorTypeaheadResult> List of typeahead results.
* @return list<PhabricatorTypeaheadResult> Filtered results.
*/
protected function filterResultsAgainstTokens(array $results) {
$tokens = $this->getTokens();
if (!$tokens) {
return $results;
}
$map = array();
foreach ($tokens as $token) {
$map[$token] = strlen($token);
}
foreach ($results as $key => $result) {
$rtokens = self::tokenizeString($result->getName());
// For each token in the query, we need to find a match somewhere
// in the result name.
foreach ($map as $token => $length) {
// Look for a match.
$match = false;
foreach ($rtokens as $rtoken) {
if (!strncmp($rtoken, $token, $length)) {
// This part of the result name has the query token as a prefix.
$match = true;
break;
}
}
if (!$match) {
// We didn't find a match for this query token, so throw the result
// away. Try with the next result.
unset($results[$key]);
break;
}
}
}
return $results;
}
protected function newFunctionResult() {
return id(new PhabricatorTypeaheadResult())
->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION)
->setIcon('fa-asterisk');
}
public function newInvalidToken($name) {
return id(new PhabricatorTypeaheadTokenView())
->setValue($name)
->setIcon('fa-exclamation-circle')
->setTokenType(PhabricatorTypeaheadTokenView::TYPE_INVALID);
}
public function renderTokens(array $values) {
$phids = array();
$setup = array();
$tokens = array();
foreach ($values as $key => $value) {
if (!self::isFunctionToken($value)) {
$phids[$key] = $value;
} else {
$function = $this->parseFunction($value);
if ($function) {
$setup[$function['name']][$key] = $function;
} else {
$name = pht('Invalid Function: %s', $value);
$tokens[$key] = $this->newInvalidToken($name)
->setKey($value);
}
}
}
if ($phids) {
$handles = $this->getViewer()->loadHandles($phids);
foreach ($phids as $key => $phid) {
$handle = $handles[$phid];
$tokens[$key] = PhabricatorTypeaheadTokenView::newFromHandle($handle);
}
}
if ($setup) {
foreach ($setup as $function_name => $argv_list) {
// Render the function tokens.
$function_tokens = $this->renderFunctionTokens(
$function_name,
ipull($argv_list, 'argv'));
// Rekey the function tokens using the original array keys.
$function_tokens = array_combine(
array_keys($argv_list),
$function_tokens);
// For any functions which were invalid, set their value to the
// original input value before it was parsed.
foreach ($function_tokens as $key => $token) {
$type = $token->getTokenType();
if ($type == PhabricatorTypeaheadTokenView::TYPE_INVALID) {
$token->setKey($values[$key]);
}
}
$tokens += $function_tokens;
}
}
return array_select_keys($tokens, array_keys($values));
}
/* -( Token Functions )---------------------------------------------------- */
/**
* @task functions
*/
public function getDatasourceFunctions() {
return array();
}
/**
* @task functions
*/
protected function canEvaluateFunction($function) {
return $this->shouldStripFunction($function);
}
/**
* @task functions
*/
protected function shouldStripFunction($function) {
$functions = $this->getDatasourceFunctions();
return isset($functions[$function]);
}
/**
* @task functions
*/
protected function evaluateFunction($function, array $argv_list) {
throw new PhutilMethodNotImplementedException();
}
/**
* @task functions
*/
public function evaluateTokens(array $tokens) {
$results = array();
$evaluate = array();
foreach ($tokens as $token) {
if (!self::isFunctionToken($token)) {
$results[] = $token;
} else {
$evaluate[] = $token;
}
}
foreach ($evaluate as $function) {
$function = self::parseFunction($function);
if (!$function) {
throw new PhabricatorTypeaheadInvalidTokenException();
}
$name = $function['name'];
$argv = $function['argv'];
foreach ($this->evaluateFunction($name, array($argv)) as $phid) {
$results[] = $phid;
}
}
$results = $this->didEvaluateTokens($results);
return $results;
}
/**
* @task functions
*/
protected function didEvaluateTokens(array $results) {
return $results;
}
/**
* @task functions
*/
public static function isFunctionToken($token) {
// We're looking for a "(" so that a string like "members(q" is identified
// and parsed as a function call. This allows us to start generating
// results immeidately, before the user fully types out "members(quack)".
return (strpos($token, '(') !== false);
}
/**
* @task functions
*/
public function parseFunction($token, $allow_partial = false) {
$matches = null;
if ($allow_partial) {
$ok = preg_match('/^([^(]+)\((.*?)\)?$/', $token, $matches);
} else {
$ok = preg_match('/^([^(]+)\((.*)\)$/', $token, $matches);
}
if (!$ok) {
return null;
}
$function = trim($matches[1]);
if (!$this->canEvaluateFunction($function)) {
return null;
}
return array(
'name' => $function,
'argv' => array(trim($matches[2])),
);
}
/**
* @task functions
*/
public function renderFunctionTokens($function, array $argv_list) {
throw new PhutilMethodNotImplementedException();
}
/**
* @task functions
*/
public function setFunctionStack(array $function_stack) {
$this->functionStack = $function_stack;
return $this;
}
/**
* @task functions
*/
public function getFunctionStack() {
return $this->functionStack;
}
/**
* @task functions
*/
protected function getCurrentFunction() {
return nonempty(last($this->functionStack), null);
}
}
diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadMonogramDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadMonogramDatasource.php
index ebaf3d39d8..4a530d4be3 100644
--- a/src/applications/typeahead/datasource/PhabricatorTypeaheadMonogramDatasource.php
+++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadMonogramDatasource.php
@@ -1,50 +1,54 @@
<?php
final class PhabricatorTypeaheadMonogramDatasource
extends PhabricatorTypeaheadDatasource {
public function isBrowsable() {
// This source isn't meaningfully browsable. Although it's technically
// possible to let users browse through every object on an install, there
// is no use case for it and it doesn't seem worth building.
return false;
}
+ public function getBrowseTitle() {
+ return pht('Browse Objects');
+ }
+
public function getPlaceholderText() {
return pht('Type an object name...');
}
public function getDatasourceApplicationClass() {
return null;
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$results = array();
$objects = id(new PhabricatorObjectQuery())
->setViewer($viewer)
->withNames(array($raw_query))
->execute();
if ($objects) {
$handles = id(new PhabricatorHandleQuery())
->setViewer($viewer)
->withPHIDs(mpull($objects, 'getPHID'))
->execute();
$handle = head($handles);
if ($handle) {
$results[] = id(new PhabricatorTypeaheadResult())
->setName($handle->getFullName())
->setDisplayType($handle->getTypeName())
->setURI($handle->getURI())
->setPHID($handle->getPHID())
->setPriorityType('jump');
}
}
return $results;
}
}
diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadNoOwnerDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadNoOwnerDatasource.php
index 76dd3148d8..61f2c89713 100644
--- a/src/applications/typeahead/datasource/PhabricatorTypeaheadNoOwnerDatasource.php
+++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadNoOwnerDatasource.php
@@ -1,28 +1,32 @@
<?php
final class PhabricatorTypeaheadNoOwnerDatasource
extends PhabricatorTypeaheadDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse No Owner');
+ }
+
public function getPlaceholderText() {
return pht('Type "none"...');
}
public function getDatasourceApplicationClass() {
return null;
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$results = array();
$results[] = id(new PhabricatorTypeaheadResult())
->setName(pht('None'))
->setIcon('fa-ban orange')
->setPHID(ManiphestTaskOwner::OWNER_UP_FOR_GRABS);
return $results;
}
}
diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadOwnerDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadOwnerDatasource.php
index a2aaf4f991..bfd8b090d6 100644
--- a/src/applications/typeahead/datasource/PhabricatorTypeaheadOwnerDatasource.php
+++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadOwnerDatasource.php
@@ -1,17 +1,21 @@
<?php
final class PhabricatorTypeaheadOwnerDatasource
extends PhabricatorTypeaheadCompositeDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Owners');
+ }
+
public function getPlaceholderText() {
return pht('Type a user name or "none"...');
}
public function getComponentDatasources() {
return array(
new PhabricatorPeopleDatasource(),
new PhabricatorTypeaheadNoOwnerDatasource(),
);
}
}
diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadUserParameterizedDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadUserParameterizedDatasource.php
index 96584b6b64..373326ce38 100644
--- a/src/applications/typeahead/datasource/PhabricatorTypeaheadUserParameterizedDatasource.php
+++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadUserParameterizedDatasource.php
@@ -1,20 +1,24 @@
<?php
final class PhabricatorTypeaheadUserParameterizedDatasource
extends PhabricatorTypeaheadCompositeDatasource {
+ public function getBrowseTitle() {
+ return pht('Browse Users');
+ }
+
public function getPlaceholderText() {
- return pht('Type a username or selector...');
+ return pht('Type a username or function...');
}
public function getComponentDatasources() {
$sources = array(
new PhabricatorViewerDatasource(),
new PhabricatorPeopleDatasource(),
new PhabricatorProjectMembersDatasource(),
);
return $sources;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 3, 9:23 PM (1 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
166417
Default Alt Text
(74 KB)

Event Timeline