mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-27 01:02:42 +01:00
Add contextual typeahead function documentation
Summary: Ref T4100. This integration into the "Browse" dialog is probably a little more heavy-handed than we should shoot for. Test Plan: {F377131} {F377132} Reviewers: btrahan, chad Reviewed By: chad Subscribers: epriestley Maniphest Tasks: T4100 Differential Revision: https://secure.phabricator.com/D12482
This commit is contained in:
parent
6193548b46
commit
bae0a85dbc
12 changed files with 292 additions and 7 deletions
|
@ -2639,6 +2639,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorTypeaheadCompositeDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php',
|
'PhabricatorTypeaheadCompositeDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php',
|
||||||
'PhabricatorTypeaheadDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php',
|
'PhabricatorTypeaheadDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php',
|
||||||
'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadDatasourceController.php',
|
'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadDatasourceController.php',
|
||||||
|
'PhabricatorTypeaheadFunctionHelpController' => 'applications/typeahead/controller/PhabricatorTypeaheadFunctionHelpController.php',
|
||||||
'PhabricatorTypeaheadInvalidTokenException' => 'applications/typeahead/exception/PhabricatorTypeaheadInvalidTokenException.php',
|
'PhabricatorTypeaheadInvalidTokenException' => 'applications/typeahead/exception/PhabricatorTypeaheadInvalidTokenException.php',
|
||||||
'PhabricatorTypeaheadModularDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php',
|
'PhabricatorTypeaheadModularDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php',
|
||||||
'PhabricatorTypeaheadMonogramDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadMonogramDatasource.php',
|
'PhabricatorTypeaheadMonogramDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadMonogramDatasource.php',
|
||||||
|
@ -6054,6 +6055,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorTypeaheadCompositeDatasource' => 'PhabricatorTypeaheadDatasource',
|
'PhabricatorTypeaheadCompositeDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||||
'PhabricatorTypeaheadDatasource' => 'Phobject',
|
'PhabricatorTypeaheadDatasource' => 'Phobject',
|
||||||
'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController',
|
'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController',
|
||||||
|
'PhabricatorTypeaheadFunctionHelpController' => 'PhabricatorTypeaheadDatasourceController',
|
||||||
'PhabricatorTypeaheadInvalidTokenException' => 'Exception',
|
'PhabricatorTypeaheadInvalidTokenException' => 'Exception',
|
||||||
'PhabricatorTypeaheadModularDatasourceController' => 'PhabricatorTypeaheadDatasourceController',
|
'PhabricatorTypeaheadModularDatasourceController' => 'PhabricatorTypeaheadDatasourceController',
|
||||||
'PhabricatorTypeaheadMonogramDatasource' => 'PhabricatorTypeaheadDatasource',
|
'PhabricatorTypeaheadMonogramDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||||
|
|
|
@ -20,7 +20,20 @@ final class ManiphestNoOwnerDatasource
|
||||||
public function getDatasourceFunctions() {
|
public function getDatasourceFunctions() {
|
||||||
return array(
|
return array(
|
||||||
'none' => array(
|
'none' => array(
|
||||||
'name' => pht('Find results which are not assigned.'),
|
'name' => pht('No Owner'),
|
||||||
|
'summary' => pht('Find results which are not assigned.'),
|
||||||
|
'description' => pht(
|
||||||
|
'This function includes results which have no owner. Use a query '.
|
||||||
|
'like this to find unassigned results:'.
|
||||||
|
"\n\n".
|
||||||
|
'> none()'.
|
||||||
|
"\n\n".
|
||||||
|
'If you combine this function with other functions, the query will '.
|
||||||
|
'return results which match the other selectors //or// have no '.
|
||||||
|
'owner. For example, this query will find results which are owned '.
|
||||||
|
'by `alincoln`, and will also find results which have no owner:'.
|
||||||
|
"\n\n".
|
||||||
|
'> alincoln, none()'),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,54 @@ final class PhabricatorProjectLogicalOrNotDatasource
|
||||||
public function getDatasourceFunctions() {
|
public function getDatasourceFunctions() {
|
||||||
return array(
|
return array(
|
||||||
'any' => array(
|
'any' => array(
|
||||||
'name' => pht('Find results in any of several projects.'),
|
'name' => pht('In Any: ...'),
|
||||||
|
'arguments' => pht('project'),
|
||||||
|
'summary' => pht('Find results in any of several projects.'),
|
||||||
|
'description' => pht(
|
||||||
|
'This function allows you to find results in one of several '.
|
||||||
|
'projects. Another way to think of this function is that it '.
|
||||||
|
'allows you to perform an "or" query.'.
|
||||||
|
"\n\n".
|
||||||
|
'By default, if you enter several projects, results are returned '.
|
||||||
|
'only if they belong to all of the projects you enter. That is, '.
|
||||||
|
'this query will only return results in //both// projects:'.
|
||||||
|
"\n\n".
|
||||||
|
'> ios, android'.
|
||||||
|
"\n\n".
|
||||||
|
'If you want to find results in any of several projects, you can '.
|
||||||
|
'use the `any()` function. For example, you can use this query to '.
|
||||||
|
'find results which are in //either// project:'.
|
||||||
|
"\n\n".
|
||||||
|
'> any(ios), any(android)'.
|
||||||
|
"\n\n".
|
||||||
|
'You can combine the `any()` function with normal project tokens '.
|
||||||
|
'to refine results. For example, use this query to find bugs in '.
|
||||||
|
'//either// iOS or Android:'.
|
||||||
|
"\n\n".
|
||||||
|
'> bug, any(ios), any(android)'),
|
||||||
),
|
),
|
||||||
'not' => array(
|
'not' => array(
|
||||||
'name' => pht('Find results not in specific projects.'),
|
'name' => pht('Not In: ...'),
|
||||||
|
'arguments' => pht('project'),
|
||||||
|
'summary' => pht('Find results not in specific projects.'),
|
||||||
|
'description' => pht(
|
||||||
|
'This function allows you to find results which are not in '.
|
||||||
|
'one or more projects. For example, use this query to find '.
|
||||||
|
'results which are not associated with a specific project:'.
|
||||||
|
"\n\n".
|
||||||
|
'> not(vanilla)'.
|
||||||
|
"\n\n".
|
||||||
|
'You can exclude multiple projects. This will cause the query '.
|
||||||
|
'to return only results which are not in any of the excluded '.
|
||||||
|
'projects:'.
|
||||||
|
"\n\n".
|
||||||
|
'> not(vanilla), not(chocolate)'.
|
||||||
|
"\n\n".
|
||||||
|
'You can combine this function with other functions to refine '.
|
||||||
|
'results. For example, use this query to find iOS results which '.
|
||||||
|
'are not bugs:'.
|
||||||
|
"\n\n".
|
||||||
|
'> ios, not(bug)'),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,17 @@ final class PhabricatorProjectLogicalUserDatasource
|
||||||
public function getDatasourceFunctions() {
|
public function getDatasourceFunctions() {
|
||||||
return array(
|
return array(
|
||||||
'projects' => array(
|
'projects' => array(
|
||||||
'name' => pht("Find results in any of a user's projects."),
|
'name' => pht('Projects: ...'),
|
||||||
|
'arguments' => pht('username'),
|
||||||
|
'summary' => pht("Find results in any of a user's projects."),
|
||||||
|
'description' => pht(
|
||||||
|
'This function allows you to find results associated with any '.
|
||||||
|
'of the projects a specified user is a member of. For example, '.
|
||||||
|
'this will find results associated with all of the projects '.
|
||||||
|
'`alincoln` is a member of:'.
|
||||||
|
"\n\n".
|
||||||
|
'> projects(alincoln)'.
|
||||||
|
"\n\n"),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,19 @@ final class PhabricatorProjectLogicalViewerDatasource
|
||||||
public function getDatasourceFunctions() {
|
public function getDatasourceFunctions() {
|
||||||
return array(
|
return array(
|
||||||
'viewerprojects' => array(
|
'viewerprojects' => array(
|
||||||
'name' => pht("Find results in any of the current viewer's projects."),
|
'name' => pht("Current Viewer's Projects"),
|
||||||
|
'summary' => pht(
|
||||||
|
"Find results in any of the current viewer's projects."),
|
||||||
|
'description' => pht(
|
||||||
|
"This function matches results in any of the current viewing ".
|
||||||
|
"user's projects:".
|
||||||
|
"\n\n".
|
||||||
|
"> viewerprojects()".
|
||||||
|
"\n\n".
|
||||||
|
"This normally means //your// projects, but if you save a query ".
|
||||||
|
"using this function and send it to someone else, it will mean ".
|
||||||
|
"//their// projects when they run it (they become the currnet ".
|
||||||
|
"viewer). This can be useful for building dashboard panels."),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,14 @@ final class PhabricatorProjectMembersDatasource
|
||||||
public function getDatasourceFunctions() {
|
public function getDatasourceFunctions() {
|
||||||
return array(
|
return array(
|
||||||
'members' => array(
|
'members' => array(
|
||||||
'name' => pht('Find results for members of a project.'),
|
'name' => pht('Members: ...'),
|
||||||
|
'arguments' => pht('project'),
|
||||||
|
'summary' => pht('Find results for members of a project.'),
|
||||||
|
'description' => pht(
|
||||||
|
'This function allows you to find results for any of the members '.
|
||||||
|
'of a project:'.
|
||||||
|
"\n\n".
|
||||||
|
'> members(frontend)'),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,15 @@ final class PhabricatorProjectNoProjectsDatasource
|
||||||
public function getDatasourceFunctions() {
|
public function getDatasourceFunctions() {
|
||||||
return array(
|
return array(
|
||||||
'null' => array(
|
'null' => array(
|
||||||
'name' => pht('Find results which are not in any projects.'),
|
'name' => pht('Not In Any Projects'),
|
||||||
|
'summary' => pht('Find results which are not in any projects.'),
|
||||||
|
'description' => pht(
|
||||||
|
'This function matches results which are not associated with any '.
|
||||||
|
'projects. It is usually most often used to find objects which '.
|
||||||
|
'might have slipped through the cracks and not been organized '.
|
||||||
|
'properly.'.
|
||||||
|
"\n\n".
|
||||||
|
"> null()"),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@ final class PhabricatorTypeaheadApplication extends PhabricatorApplication {
|
||||||
'/typeahead/' => array(
|
'/typeahead/' => array(
|
||||||
'(?P<action>browse|class)/(?:(?P<class>\w+)/)?'
|
'(?P<action>browse|class)/(?:(?P<class>\w+)/)?'
|
||||||
=> 'PhabricatorTypeaheadModularDatasourceController',
|
=> 'PhabricatorTypeaheadModularDatasourceController',
|
||||||
|
'help/(?P<class>\w+)/'
|
||||||
|
=> 'PhabricatorTypeaheadFunctionHelpController',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorTypeaheadFunctionHelpController
|
||||||
|
extends PhabricatorTypeaheadDatasourceController {
|
||||||
|
|
||||||
|
public function shouldAllowPublic() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$class = $request->getURIData('class');
|
||||||
|
|
||||||
|
$sources = id(new PhutilSymbolLoader())
|
||||||
|
->setAncestorClass('PhabricatorTypeaheadDatasource')
|
||||||
|
->loadObjects();
|
||||||
|
if (!isset($sources[$class])) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$source = $sources[$class];
|
||||||
|
|
||||||
|
$application_class = $source->getDatasourceApplicationClass();
|
||||||
|
if ($application_class) {
|
||||||
|
$result = id(new PhabricatorApplicationQuery())
|
||||||
|
->setViewer($this->getViewer())
|
||||||
|
->withClasses(array($application_class))
|
||||||
|
->execute();
|
||||||
|
if (!$result) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$source->setViewer($viewer);
|
||||||
|
|
||||||
|
$title = pht('Typeahead Function Help');
|
||||||
|
|
||||||
|
$functions = $source->getAllDatasourceFunctions();
|
||||||
|
ksort($functions);
|
||||||
|
|
||||||
|
$content = array();
|
||||||
|
|
||||||
|
$content[] = '= '.pht('Overview');
|
||||||
|
$content[] = pht(
|
||||||
|
'Typeahead functions are an advanced feature which allow you to build '.
|
||||||
|
'more powerful queries. This document explains functions available '.
|
||||||
|
'for the selected control.'.
|
||||||
|
"\n\n".
|
||||||
|
'Note that different controls support //different// functions '.
|
||||||
|
'(depending on what the control is doing), so these specific functions '.
|
||||||
|
'may not work everywhere. You can always check the help for a control '.
|
||||||
|
'to review which functions are available for that control.');
|
||||||
|
|
||||||
|
$table = array();
|
||||||
|
|
||||||
|
$table_header = array(
|
||||||
|
pht('Function'),
|
||||||
|
pht('Token Name'),
|
||||||
|
pht('Summary'),
|
||||||
|
);
|
||||||
|
$table[] = '| '.implode(' | ', $table_header).' |';
|
||||||
|
$table[] = '|---|---|---|';
|
||||||
|
|
||||||
|
foreach ($functions as $function => $spec) {
|
||||||
|
$spec = $spec + array(
|
||||||
|
'summary' => null,
|
||||||
|
'arguments' => null,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (idx($spec, 'arguments')) {
|
||||||
|
$signature = '**'.$function.'(**//'.$spec['arguments'].'//**)**';
|
||||||
|
} else {
|
||||||
|
$signature = '**'.$function.'()**';
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = idx($spec, 'name', '');
|
||||||
|
$summary = idx($spec, 'summary', '');
|
||||||
|
|
||||||
|
$table[] = '| '.$signature.' | '.$name.' | '.$summary.' |';
|
||||||
|
}
|
||||||
|
|
||||||
|
$table = implode("\n", $table);
|
||||||
|
$content[] = '= '.pht('Function Quick Reference');
|
||||||
|
$content[] = pht(
|
||||||
|
'This table briefly describes available functions for this control. '.
|
||||||
|
'For details on a particular function, see the corresponding section '.
|
||||||
|
'below.');
|
||||||
|
$content[] = $table;
|
||||||
|
|
||||||
|
$content[] = '= '.pht('Using Typeahead Functions');
|
||||||
|
$content[] = pht(
|
||||||
|
'In addition to typing user and project names to build queries, you can '.
|
||||||
|
'also type the names of special functions which give you more options '.
|
||||||
|
'and the ability to express more complex queries.'.
|
||||||
|
"\n\n".
|
||||||
|
'Functions have an internal name (like `viewer()`) and a '.
|
||||||
|
'human-readable name, like `Current Viewer`. In general, you can type '.
|
||||||
|
'either one to select the function. You can also click the '.
|
||||||
|
'{nav icon=search} button on any typeahead control to browse available '.
|
||||||
|
'functions and find this documentation.'.
|
||||||
|
"\n\n".
|
||||||
|
'This documentation uses the internal names to make it clear where '.
|
||||||
|
'tokens begin and end. Specifically, you will find queries written '.
|
||||||
|
'out like this in the documentation: '.
|
||||||
|
"\n\n".
|
||||||
|
'> viewer(), alincoln'.
|
||||||
|
"\n\n".
|
||||||
|
'When this query is actually shown in the control, it will look more '.
|
||||||
|
'like this:'.
|
||||||
|
"\n\n".
|
||||||
|
'> {nav Current Viewer} {nav alincoln (Abraham Lincoln)}');
|
||||||
|
|
||||||
|
|
||||||
|
$middot = "\xC2\xB7";
|
||||||
|
foreach ($functions as $function => $spec) {
|
||||||
|
$arguments = idx($spec, 'arguments', '');
|
||||||
|
$name = idx($spec, 'name');
|
||||||
|
$content[] = '= '.$function.'('.$arguments.') '.$middot.' '.$name;
|
||||||
|
$content[] = $spec['description'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = implode("\n\n", $content);
|
||||||
|
|
||||||
|
$content_box = PhabricatorMarkupEngine::renderOneObject(
|
||||||
|
id(new PhabricatorMarkupOneOff())->setContent($content),
|
||||||
|
'default',
|
||||||
|
$viewer);
|
||||||
|
|
||||||
|
$header = id(new PHUIHeaderView())
|
||||||
|
->setHeader($title);
|
||||||
|
|
||||||
|
$document = id(new PHUIDocumentView())
|
||||||
|
->setHeader($header)
|
||||||
|
->setFontKit(PHUIDocumentView::FONT_SOURCE_SANS)
|
||||||
|
->appendChild($content_box);
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
|
$crumbs->addTextCrumb(pht('Function Help'));
|
||||||
|
|
||||||
|
return $this->buildApplicationPage(
|
||||||
|
array(
|
||||||
|
$crumbs,
|
||||||
|
$document,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'title' => $title,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -222,11 +222,32 @@ final class PhabricatorTypeaheadModularDatasourceController
|
||||||
$frame,
|
$frame,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$function_help = null;
|
||||||
|
if ($source->getAllDatasourceFunctions()) {
|
||||||
|
$reference_uri = '/typeahead/help/'.get_class($source).'/';
|
||||||
|
|
||||||
|
$reference_link = phutil_tag(
|
||||||
|
'a',
|
||||||
|
array(
|
||||||
|
'href' => $reference_uri,
|
||||||
|
'target' => '_blank',
|
||||||
|
),
|
||||||
|
pht('Reference: Advanced Functions'));
|
||||||
|
|
||||||
|
$function_help = array(
|
||||||
|
id(new PHUIIconView())
|
||||||
|
->setIconFont('fa-book'),
|
||||||
|
' ',
|
||||||
|
$reference_link,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->newDialog()
|
return $this->newDialog()
|
||||||
->setWidth(AphrontDialogView::WIDTH_FORM)
|
->setWidth(AphrontDialogView::WIDTH_FORM)
|
||||||
->setRenderDialogAsDiv(true)
|
->setRenderDialogAsDiv(true)
|
||||||
->setTitle($source->getBrowseTitle())
|
->setTitle($source->getBrowseTitle())
|
||||||
->appendChild($browser)
|
->appendChild($browser)
|
||||||
|
->addFooter($function_help)
|
||||||
->addCancelButton('/', pht('Close'));
|
->addCancelButton('/', pht('Close'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,14 @@ abstract class PhabricatorTypeaheadCompositeDatasource
|
||||||
return $this->usable;
|
return $this->usable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAllDatasourceFunctions() {
|
||||||
|
$results = parent::getAllDatasourceFunctions();
|
||||||
|
foreach ($this->getUsableDatasources() as $source) {
|
||||||
|
$results += $source->getAllDatasourceFunctions();
|
||||||
|
}
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
protected function didEvaluateTokens(array $results) {
|
protected function didEvaluateTokens(array $results) {
|
||||||
foreach ($this->getUsableDatasources() as $source) {
|
foreach ($this->getUsableDatasources() as $source) {
|
||||||
$results = $source->didEvaluateTokens($results);
|
$results = $source->didEvaluateTokens($results);
|
||||||
|
|
|
@ -276,6 +276,14 @@ abstract class PhabricatorTypeaheadDatasource extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task functions
|
||||||
|
*/
|
||||||
|
public function getAllDatasourceFunctions() {
|
||||||
|
return $this->getDatasourceFunctions();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @task functions
|
* @task functions
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue