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:
parent
5eb496bb3e
commit
7db362a4b6
16 changed files with 162 additions and 17 deletions
|
@ -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...');
|
||||||
}
|
}
|
||||||
|
|
|
@ -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...');
|
||||||
}
|
}
|
||||||
|
|
|
@ -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...');
|
||||||
}
|
}
|
||||||
|
|
|
@ -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...');
|
||||||
}
|
}
|
||||||
|
|
|
@ -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...');
|
||||||
}
|
}
|
||||||
|
|
|
@ -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...');
|
||||||
}
|
}
|
||||||
|
|
|
@ -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...');
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ final class ManiphestTaskPriorityDatasource
|
||||||
->setName($name);
|
->setName($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $results;
|
return $this->filterResultsAgainstTokens($results);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,6 @@ final class ManiphestTaskStatusDatasource
|
||||||
->setName($name);
|
->setName($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $results;
|
return $this->filterResultsAgainstTokens($results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ final class PhabricatorApplicationDatasource
|
||||||
->setImageSprite('phabricator-search-icon '.$img);
|
->setImageSprite('phabricator-search-icon '.$img);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $results;
|
return $this->filterResultsAgainstTokens($results);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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...');
|
||||||
}
|
}
|
||||||
|
|
|
@ -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...');
|
||||||
}
|
}
|
||||||
|
|
|
@ -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');
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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...');
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue