1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-19 12:00:55 +01:00

Cheat my way through the rest of the typeahead datasources

Summary:
Ref T5750. These are a pain to modernize and most don't matter, so cheat:

  - Mark a bunch nonbrowsable, including some that probably should be browsable but which I don't want to deal with for now.
  - For static datasources, add an easy server-side filter (this isn't really cheating, and is appropriate for the status/priority/application datasources).
  - Make composite sources browsable if their components are browsable.

Test Plan:

  - Tried to browse an unbrowsable source, got a 404.
  - Browsed a composite source.
  - Browsed static sources (priority/status/applications).
  - Browsed normal sources (people/projects).

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T5750

Differential Revision: https://secure.phabricator.com/D12438
This commit is contained in:
epriestley 2015-04-16 11:09:58 -07:00
parent 5eb496bb3e
commit 7db362a4b6
16 changed files with 162 additions and 17 deletions

View file

@ -3,6 +3,12 @@
final class AlmanacInterfaceDatasource final class AlmanacInterfaceDatasource
extends PhabricatorTypeaheadDatasource { 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 getPlaceholderText() { public function getPlaceholderText() {
return pht('Type an interface name...'); return pht('Type an interface name...');
} }

View file

@ -3,6 +3,11 @@
final class DiffusionArcanistProjectDatasource final class DiffusionArcanistProjectDatasource
extends PhabricatorTypeaheadDatasource { extends PhabricatorTypeaheadDatasource {
public function isBrowsable() {
// TODO: We should probably make this browsable, or maybe remove it.
return false;
}
public function getPlaceholderText() { public function getPlaceholderText() {
return pht('Type an arcanist project name...'); return pht('Type an arcanist project name...');
} }

View file

@ -3,6 +3,12 @@
final class DiffusionSymbolDatasource final class DiffusionSymbolDatasource
extends PhabricatorTypeaheadDatasource { 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 getPlaceholderText() { public function getPlaceholderText() {
return pht('Type a symbol name...'); return pht('Type a symbol name...');
} }

View file

@ -3,6 +3,11 @@
final class HarbormasterBuildDependencyDatasource final class HarbormasterBuildDependencyDatasource
extends PhabricatorTypeaheadDatasource { extends PhabricatorTypeaheadDatasource {
public function isBrowsable() {
// TODO: This should be browsable, but fixing it is involved.
return false;
}
public function getPlaceholderText() { public function getPlaceholderText() {
return pht('Type another build step name...'); return pht('Type another build step name...');
} }

View file

@ -2,6 +2,11 @@
final class LegalpadDocumentDatasource extends PhabricatorTypeaheadDatasource { final class LegalpadDocumentDatasource extends PhabricatorTypeaheadDatasource {
public function isBrowsable() {
// TODO: This should be made browsable.
return false;
}
public function getPlaceholderText() { public function getPlaceholderText() {
return pht('Type a document name...'); return pht('Type a document name...');
} }

View file

@ -2,6 +2,11 @@
final class PhabricatorMacroDatasource extends PhabricatorTypeaheadDatasource { final class PhabricatorMacroDatasource extends PhabricatorTypeaheadDatasource {
public function isBrowsable() {
// TODO: This should be made browsable.
return false;
}
public function getPlaceholderText() { public function getPlaceholderText() {
return pht('Type a macro name...'); return pht('Type a macro name...');
} }

View file

@ -3,6 +3,11 @@
final class PhabricatorMailingListDatasource final class PhabricatorMailingListDatasource
extends PhabricatorTypeaheadDatasource { extends PhabricatorTypeaheadDatasource {
public function isBrowsable() {
// TODO: Make this browsable if we don't delete it before then.
return false;
}
public function getPlaceholderText() { public function getPlaceholderText() {
return pht('Type a mailing list name...'); return pht('Type a mailing list name...');
} }

View file

@ -25,7 +25,7 @@ final class ManiphestTaskPriorityDatasource
->setName($name); ->setName($name);
} }
return $results; return $this->filterResultsAgainstTokens($results);
} }
} }

View file

@ -25,6 +25,6 @@ final class ManiphestTaskStatusDatasource
->setName($name); ->setName($name);
} }
return $results; return $this->filterResultsAgainstTokens($results);
} }
} }

View file

@ -37,7 +37,7 @@ final class PhabricatorApplicationDatasource
->setImageSprite('phabricator-search-icon '.$img); ->setImageSprite('phabricator-search-icon '.$img);
} }
return $results; return $this->filterResultsAgainstTokens($results);
} }
} }

View file

@ -3,6 +3,11 @@
final class PhabricatorMetaMTAApplicationEmailDatasource final class PhabricatorMetaMTAApplicationEmailDatasource
extends PhabricatorTypeaheadDatasource { extends PhabricatorTypeaheadDatasource {
public function isBrowsable() {
// TODO: Make this browsable.
return false;
}
public function getPlaceholderText() { public function getPlaceholderText() {
return pht('Type an application email address...'); return pht('Type an application email address...');
} }

View file

@ -3,6 +3,11 @@
final class PhabricatorOwnersPackageDatasource final class PhabricatorOwnersPackageDatasource
extends PhabricatorTypeaheadDatasource { extends PhabricatorTypeaheadDatasource {
public function isBrowsable() {
// TODO: Make this browsable.
return false;
}
public function getPlaceholderText() { public function getPlaceholderText() {
return pht('Type a package name...'); return pht('Type a package name...');
} }

View file

@ -25,6 +25,7 @@ final class PhabricatorTypeaheadModularDatasourceController
if (isset($sources[$class])) { if (isset($sources[$class])) {
$source = $sources[$class]; $source = $sources[$class];
$source->setParameters($request->getRequestData()); $source->setParameters($request->getRequestData());
$source->setViewer($viewer);
// NOTE: Wrapping the source in a Composite datasource ensures we perform // NOTE: Wrapping the source in a Composite datasource ensures we perform
// application visibility checks for the viewer, so we do not need to do // application visibility checks for the viewer, so we do not need to do
@ -40,6 +41,10 @@ final class PhabricatorTypeaheadModularDatasourceController
$hard_limit = 1000; $hard_limit = 1000;
if ($is_browse) { if ($is_browse) {
if (!$composite->isBrowsable()) {
return new Aphront404Response();
}
$limit = 10; $limit = 10;
$offset = $request->getInt('offset'); $offset = $request->getInt('offset');

View file

@ -3,8 +3,20 @@
abstract class PhabricatorTypeaheadCompositeDatasource abstract class PhabricatorTypeaheadCompositeDatasource
extends PhabricatorTypeaheadDatasource { extends PhabricatorTypeaheadDatasource {
private $usable;
abstract public function getComponentDatasources(); abstract public function getComponentDatasources();
public function isBrowsable() {
foreach ($this->getUsableDatasources() as $datasource) {
if (!$datasource->isBrowsable()) {
return false;
}
}
return parent::isBrowsable();
}
public function getDatasourceApplicationClass() { public function getDatasourceApplicationClass() {
return null; return null;
} }
@ -43,26 +55,29 @@ abstract class PhabricatorTypeaheadCompositeDatasource
} }
private function getUsableDatasources() { private function getUsableDatasources() {
$sources = $this->getComponentDatasources(); if ($this->usable === null) {
$sources = $this->getComponentDatasources();
$usable = array(); $usable = array();
foreach ($sources as $source) { foreach ($sources as $source) {
$application_class = $source->getDatasourceApplicationClass(); $application_class = $source->getDatasourceApplicationClass();
if ($application_class) { if ($application_class) {
$result = id(new PhabricatorApplicationQuery()) $result = id(new PhabricatorApplicationQuery())
->setViewer($this->getViewer()) ->setViewer($this->getViewer())
->withClasses(array($application_class)) ->withClasses(array($application_class))
->execute(); ->execute();
if (!$result) { if (!$result) {
continue; continue;
}
} }
}
$usable[] = $source; $usable[] = $source;
}
$this->usable = $usable;
} }
return $usable; return $this->usable;
} }
} }

View file

@ -102,4 +102,75 @@ abstract class PhabricatorTypeaheadDatasource extends Phobject {
->execute(); ->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;
}
} }

View file

@ -3,6 +3,13 @@
final class PhabricatorTypeaheadMonogramDatasource final class PhabricatorTypeaheadMonogramDatasource
extends PhabricatorTypeaheadDatasource { 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 getPlaceholderText() { public function getPlaceholderText() {
return pht('Type an object name...'); return pht('Type an object name...');
} }