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

Clean up "*.search" API method documentation pages

Summary:
Ref T9964. Building tables in Remarkup is kind of neat-ish but ends up feeling kind of hacky, and requires weird workarounds if any of the values have `|` in them.

Switch to normal elements instead.

Also move the magic "ids" and "phids" to be more like real fields. I'll clean this up fully in a diff or two, it's just a little tricky because Maniphest has an "ids" field.

Test Plan: {F1024294}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T9964

Differential Revision: https://secure.phabricator.com/D14768
This commit is contained in:
epriestley 2015-12-13 08:45:01 -08:00
parent 99ade500bc
commit fdd2d802d2
11 changed files with 264 additions and 210 deletions

View file

@ -101,65 +101,10 @@ final class PhabricatorConduitConsoleController
->appendChild($properties); ->appendChild($properties);
$content[] = $info_box; $content[] = $info_box;
$content[] = $method->getMethodDocumentation();
$content[] = $form_box; $content[] = $form_box;
$content[] = $this->renderExampleBox($method, null); $content[] = $this->renderExampleBox($method, null);
$query = $method->newQueryObject();
if ($query) {
$orders = $query->getBuiltinOrders();
$rows = array();
foreach ($orders as $key => $order) {
$rows[] = array(
$key,
$order['name'],
implode(', ', $order['vector']),
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
pht('Key'),
pht('Description'),
pht('Columns'),
))
->setColumnClasses(
array(
'pri',
'',
'wide',
));
$content[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Builtin Orders'))
->setTable($table);
$columns = $query->getOrderableColumns();
$rows = array();
foreach ($columns as $key => $column) {
$rows[] = array(
$key,
idx($column, 'unique') ? pht('Yes') : pht('No'),
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
pht('Key'),
pht('Unique'),
))
->setColumnClasses(
array(
'pri',
'wide',
));
$content[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Column Orders'))
->setTable($table);
}
$crumbs = $this->buildApplicationCrumbs(); $crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb($method->getAPIMethodName()); $crumbs->addTextCrumb($method->getAPIMethodName());

View file

@ -37,6 +37,10 @@ abstract class ConduitAPIMethod
*/ */
abstract public function getMethodDescription(); abstract public function getMethodDescription();
public function getMethodDocumentation() {
return null;
}
abstract protected function defineParamTypes(); abstract protected function defineParamTypes();
abstract protected function defineReturnType(); abstract protected function defineReturnType();

View file

@ -9,6 +9,10 @@ final class ConduitResultSearchEngineExtension
return true; return true;
} }
public function getExtensionOrder() {
return 1000;
}
public function getExtensionName() { public function getExtensionName() {
return pht('Support for ConduitResultInterface'); return pht('Support for ConduitResultInterface');
} }

View file

@ -17,6 +17,10 @@ final class PhabricatorPolicySearchEngineExtension
return ($object instanceof PhabricatorPolicyInterface); return ($object instanceof PhabricatorPolicyInterface);
} }
public function getExtensionOrder() {
return 6000;
}
public function getFieldSpecificationsForConduit($object) { public function getFieldSpecificationsForConduit($object) {
return array( return array(
'policy' => array( 'policy' => array(

View file

@ -15,7 +15,7 @@ final class PhabricatorProjectsSearchEngineExtension
} }
public function getExtensionOrder() { public function getExtensionOrder() {
return 2000; return 3000;
} }
public function supportsObject($object) { public function supportsObject($object) {

View file

@ -1068,11 +1068,6 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
$fields[$conduit_key] = $field; $fields[$conduit_key] = $field;
} }
$viewer = $this->requireViewer();
foreach ($fields as $key => $field) {
$field->setViewer($viewer);
}
// These are handled separately for Conduit, so don't show them as // These are handled separately for Conduit, so don't show them as
// supported. // supported.
unset($fields['ids']); unset($fields['ids']);
@ -1080,6 +1075,27 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
unset($fields['order']); unset($fields['order']);
unset($fields['limit']); unset($fields['limit']);
// TODO: Clean these up, shortly.
$fields = array(
'ids' => id(new PhabricatorSearchDatasourceField())
->setKey('ids')
->setLabel(pht('IDs'))
->setDescription(
pht('Search for objects with specific IDs.'))
->setConduitParameterType(new ConduitIntListParameterType()),
'phids' => id(new PhabricatorSearchDatasourceField())
->setKey('phids')
->setLabel(pht('PHIDs'))
->setDescription(
pht('Search for objects with specific PHIDs.'))
->setConduitParameterType(new ConduitPHIDListParameterType()),
) + $fields;
$viewer = $this->requireViewer();
foreach ($fields as $key => $field) {
$field->setViewer($viewer);
}
return $fields; return $fields;
} }

View file

@ -39,6 +39,12 @@ abstract class PhabricatorSearchEngineAPIMethod
} }
final public function getMethodDescription() { final public function getMethodDescription() {
return pht(
'This is a standard **ApplicationSearch** method which will let you '.
'list, query, or search for objects.');
}
final public function getMethodDocumentation() {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$engine = $this->newSearchEngine() $engine = $this->newSearchEngine()
@ -48,26 +54,29 @@ abstract class PhabricatorSearchEngineAPIMethod
$out = array(); $out = array();
$out[] = pht(<<<EOTEXT $out[] = $this->buildQueriesBox($engine);
This is a standard **ApplicationSearch** method which will let you list, query, $out[] = $this->buildConstraintsBox($engine);
or search for objects. $out[] = $this->buildOrderBox($engine, $query);
$out[] = $this->buildFieldsBox($engine);
$out[] = $this->buildPagingBox($engine);
EOTEXT return $out;
); }
$out[] = pht(<<<EOTEXT private function buildQueriesBox(
Prebuilt Queries PhabricatorApplicationSearchEngine $engine) {
---------------- $viewer = $this->getViewer();
You can use a builtin or saved query as a starting point by passing it with $info = pht(<<<EOTEXT
`queryKey`. If you don't specify a `queryKey`, the query will start with no You can choose a builtin or saved query as a starting point for filtering
constraints. results by selecting it with `queryKey`. If you don't specify a `queryKey`,
the query will start with no constraints.
For example, many applications have builtin queries like `"active"` or For example, many applications have builtin queries like `"active"` or
`"open"` to find only active or enabled results. To use a `queryKey`, specify `"open"` to find only active or enabled results. To use a `queryKey`, specify
it like this: it like this:
```lang=json ```lang=json, name="Selecting a Builtin Query"
{ {
... ...
"queryKey": "active", "queryKey": "active",
@ -75,115 +84,145 @@ it like this:
} }
``` ```
The table below shows the keys to use to select builtin queries and your
saved queries, but you can also use **any** query you run via the web UI as a
starting point. You can find the key for a query by examining the URI after
running a normal search.
You can use these keys to select builtin queries and your configured saved You can use these keys to select builtin queries and your configured saved
queries: queries:
EOTEXT EOTEXT
); );
$head_querykey = pht('Query Key');
$head_name = pht('Name');
$head_builtin = pht('Builtin');
$named_queries = $engine->loadAllNamedQueries(); $named_queries = $engine->loadAllNamedQueries();
$table = array(); $rows = array();
$table[] = "| {$head_querykey} | {$head_name} | {$head_builtin} |";
$table[] = '|------------------|--------------|-----------------|';
foreach ($named_queries as $named_query) { foreach ($named_queries as $named_query) {
$key = $named_query->getQueryKey();
$name = $named_query->getQueryName();
$builtin = $named_query->getIsBuiltin() $builtin = $named_query->getIsBuiltin()
? pht('Builtin') ? pht('Builtin')
: pht('Custom'); : pht('Custom');
$table[] = "| `{$key}` | {$name} | {$builtin} |"; $rows[] = array(
} $named_query->getQueryKey(),
$table = implode("\n", $table); $named_query->getQueryName(),
$out[] = $table; $builtin,
$out[] = pht(<<<EOTEXT
You can also use **any** query you run via the web UI as a starting point. You
can find the key for a query by examining the URI after running a normal
search.
EOTEXT
); );
}
$out[] = pht(<<<EOTEXT $table = id(new AphrontTableView($rows))
Custom Constraints ->setHeaders(
------------------ array(
pht('Query Key'),
pht('Name'),
pht('Builtin'),
))
->setColumnClasses(
array(
'prewrap',
'pri wide',
null,
));
You can add custom constraints to the basic query by passing `constraints`. return id(new PHUIObjectBoxView())
This will let you filter results (for example, show only results with a ->setHeaderText(pht('Builtin and Saved Queries'))
certain state, status, or owner). ->setCollapsed(true)
->appendChild($this->buildRemarkup($info))
->appendChild($table);
}
private function buildConstraintsBox(
PhabricatorApplicationSearchEngine $engine) {
$info = pht(<<<EOTEXT
You can apply custom constraints by passing a dictionary in `constraints`.
This will let you search for specific sets of results (for example, you may
want show only results with a certain state, status, or owner).
If you specify both a `queryKey` and `constraints`, the builtin or saved query
will be applied first as a starting point, then any additional values in
`constraints` will be applied, overwriting the defaults from the original query.
Specify constraints like this: Specify constraints like this:
```lang=json ```lang=json, name="Example Custom Constraints"
{ {
... ...
"constraints": { "constraints": {
"authorPHIDs": ["PHID-USER-1111", "PHID-USER-2222"], "authors": ["PHID-USER-1111", "PHID-USER-2222"],
"statuses": ["open", "closed"] "statuses": ["open", "closed"],
...
}, },
... ...
} }
``` ```
If you specify both a `queryKey` and `constraints`, the basic query
configuration will be applied first as a starting point, then any additional
values in `constraints` will be applied, overwriting the defaults from the
original query.
This API endpoint supports these constraints: This API endpoint supports these constraints:
EOTEXT EOTEXT
); );
$head_key = pht('Key');
$head_label = pht('Label');
$head_type = pht('Type');
$head_desc = pht('Description');
$desc_ids = pht('Search for specific objects by ID.');
$desc_phids = pht('Search for specific objects by PHID.');
$fields = $engine->getSearchFieldsForConduit(); $fields = $engine->getSearchFieldsForConduit();
$table = array(); $rows = array();
$table[] = "| {$head_key} | {$head_label} | {$head_type} | {$head_desc} |";
$table[] = '|-------------|---------------|--------------|--------------|';
$table[] = "| `ids` | **IDs** | `list<int>` | {$desc_ids} |";
$table[] = "| `phids` | **PHIDs** | `list<phid>` | {$desc_phids} |";
foreach ($fields as $field) { foreach ($fields as $field) {
$key = $field->getConduitKey(); $key = $field->getConduitKey();
$label = $field->getLabel(); $label = $field->getLabel();
$type_object = $field->getConduitParameterType(); $type_object = $field->getConduitParameterType();
if ($type_object) { if ($type_object) {
$type = '`'.$type_object->getTypeName().'`'; $type = $type_object->getTypeName();
$description = $field->getDescription(); $description = $field->getDescription();
} else { } else {
$type = ''; $type = null;
$description = '//'.pht('Not Supported').'//'; $description = phutil_tag('em', array(), pht('Not supported.'));
} }
$table[] = "| `{$key}` | **{$label}** | {$type} | {$description}"; $rows[] = array(
$key,
$label,
$type,
$description,
);
} }
$table = implode("\n", $table);
$out[] = $table;
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
pht('Key'),
pht('Label'),
pht('Type'),
pht('Description'),
))
->setColumnClasses(
array(
'prewrap',
'pri',
'prewrap',
'wide',
));
$out[] = pht(<<<EOTEXT return id(new PHUIObjectBoxView())
Result Order ->setHeaderText(pht('Custom Query Constraints'))
------------ ->setCollapsed(true)
->appendChild($this->buildRemarkup($info))
->appendChild($table);
}
Use `order` to choose an ordering for the results. Either specify a single private function buildOrderBox(
key from the builtin orders (these are a set of meaningful, high-level, PhabricatorApplicationSearchEngine $engine,
human-readable orders) or specify a list of low-level columns. $query) {
$orders_info = pht(<<<EOTEXT
Use `order` to choose an ordering for the results.
Either specify a single key from the builtin orders (these are a set of
meaningful, high-level, human-readable orders) or specify a custom list of
low-level columns.
To use a high-level order, choose a builtin order from the table below To use a high-level order, choose a builtin order from the table below
and specify it like this: and specify it like this:
```lang=json ```lang=json, name="Choosing a Result Order"
{ {
... ...
"order": "newest", "order": "newest",
@ -195,34 +234,46 @@ These builtin orders are available:
EOTEXT EOTEXT
); );
$head_builtin = pht('Builtin Order');
$head_label = pht('Label');
$head_columns = pht('Columns');
$orders = $query->getBuiltinOrders(); $orders = $query->getBuiltinOrders();
$table = array(); $rows = array();
$table[] = "| {$head_builtin} | {$head_label} | {$head_columns} |";
$table[] = '|-----------------|---------------------|-----------------|';
foreach ($orders as $key => $order) { foreach ($orders as $key => $order) {
$name = $order['name']; $rows[] = array(
$columns = implode(', ', $order['vector']); $key,
$table[] = "| `{$key}` | {$name} | {$columns} |"; $order['name'],
implode(', ', $order['vector']),
);
} }
$table = implode("\n", $table);
$out[] = $table;
$out[] = pht(<<<EOTEXT $orders_table = id(new AphrontTableView($rows))
You can choose a low-level column order instead. This is an advanced feature. ->setHeaders(
array(
pht('Key'),
pht('Description'),
pht('Columns'),
))
->setColumnClasses(
array(
'pri',
'',
'wide',
));
In your custom order: each column may only be specified once; each column may $columns_info = pht(<<<EOTEXT
be prefixed with "-" to invert the order; the last column must be unique; and You can choose a low-level column order instead. To do this, provide a list
no column other than the last may be unique. of columns instead of a single key. This is an advanced feature.
In a custom column order:
- each column may only be specified once;
- each column may be prefixed with `-` to invert the order;
- the last column must be a unique column, usually `id`; and
- no column other than the last may be unique.
To use a low-level order, choose a sequence of columns and specify them like To use a low-level order, choose a sequence of columns and specify them like
this: this:
```lang=json ```lang=json, name="Using a Custom Order"
{ {
... ...
"order": ["color", "-name", "id"], "order": ["color", "-name", "id"],
@ -234,49 +285,49 @@ These low-level columns are available:
EOTEXT EOTEXT
); );
$head_column = pht('Column Key');
$head_unique = pht('Unique');
$columns = $query->getOrderableColumns(); $columns = $query->getOrderableColumns();
$rows = array();
$table = array();
$table[] = "| {$head_column} | {$head_unique} |";
$table[] = '|----------------|----------------|';
foreach ($columns as $key => $column) { foreach ($columns as $key => $column) {
$unique = idx($column, 'unique') $rows[] = array(
? pht('Yes') $key,
: pht('No'); idx($column, 'unique') ? pht('Yes') : pht('No'),
$table[] = "| `{$key}` | {$unique} |";
}
$table = implode("\n", $table);
$out[] = $table;
$out[] = pht(<<<EOTEXT
Result Format
-------------
The result format is a dictionary with several fields:
- `data`: Contains the actual results, as a list of dictionaries.
- `query`: Details about the query which was issued.
- `cursor`: Information about how to issue another query to get the next
(or previous) page of results. See "Paging and Limits" below.
EOTEXT
); );
}
$out[] = pht(<<<EOTEXT $columns_table = id(new AphrontTableView($rows))
Fields ->setHeaders(
------ array(
pht('Key'),
pht('Unique'),
))
->setColumnClasses(
array(
'pri',
'wide',
));
The `data` field of the result contains a list of results. Each result has
some metadata and a `fields` key, which contains the primary object fields. return id(new PHUIObjectBoxView())
->setHeaderText(pht('Result Ordering'))
->setCollapsed(true)
->appendChild($this->buildRemarkup($orders_info))
->appendChild($orders_table)
->appendChild($this->buildRemarkup($columns_info))
->appendChild($columns_table);
}
private function buildFieldsBox(
PhabricatorApplicationSearchEngine $engine) {
$info = pht(<<<EOTEXT
Objects matching your query are returned as a list of dictionaries in the
`data` property of the results. Each dictionary has some metadata and a
`fields` key, which contains the information abou the object that most callers
will be interested in.
For example, the results may look something like this: For example, the results may look something like this:
```lang=json ```lang=json, name="Example Results"
{ {
... ...
"data": [ "data": [
@ -306,31 +357,47 @@ This result structure is standardized across all search methods, but the
available fields differ from application to application. available fields differ from application to application.
These are the fields available on this object type: These are the fields available on this object type:
EOTEXT EOTEXT
); );
$head_key = pht('Key');
$head_type = pht('Type');
$head_description = pht('Description');
$specs = $engine->getAllConduitFieldSpecifications(); $specs = $engine->getAllConduitFieldSpecifications();
$table = array(); $rows = array();
$table[] = "| {$head_key} | {$head_type} | {$head_description} |";
$table[] = '|-------------|--------------|---------------------|';
foreach ($specs as $key => $spec) { foreach ($specs as $key => $spec) {
$type = idx($spec, 'type'); $type = idx($spec, 'type');
$description = idx($spec, 'description'); $description = idx($spec, 'description');
$table[] = "| `{$key}` | `{$type}` | {$description} |"; $rows[] = array(
$key,
$type,
$description,
);
} }
$table = implode("\n", $table);
$out[] = $table;
$out[] = pht(<<<EOTEXT $table = id(new AphrontTableView($rows))
Paging and Limits ->setHeaders(
----------------- array(
pht('Key'),
pht('Type'),
pht('Description'),
))
->setColumnClasses(
array(
'pri',
'mono',
'wide',
));
return id(new PHUIObjectBoxView())
->setHeaderText(pht('Object Fields'))
->setCollapsed(true)
->appendChild($this->buildRemarkup($info))
->appendChild($table);
}
private function buildPagingBox(
PhabricatorApplicationSearchEngine $engine) {
$info = pht(<<<EOTEXT
Queries are limited to returning 100 results at a time. If you want fewer Queries are limited to returning 100 results at a time. If you want fewer
results than this, you can use `limit` to specify a smaller limit. results than this, you can use `limit` to specify a smaller limit.
@ -338,10 +405,10 @@ If you want more results, you'll need to make additional queries to retrieve
more pages of results. more pages of results.
The result structure contains a `cursor` key with information you'll need in The result structure contains a `cursor` key with information you'll need in
order to fetch the next page. After an initial query, it will usually look order to fetch the next page of results. After an initial query, it will
something like this: usually look something like this:
```lang=json ```lang=json, name="Example Cursor Result"
{ {
... ...
"cursor": { "cursor": {
@ -366,7 +433,7 @@ the first call in the `after` parameter when making the second call.
If you do things correctly, you should get the second page of results, and If you do things correctly, you should get the second page of results, and
a cursor structure like this: a cursor structure like this:
```lang=json ```lang=json, name="Second Result Page"
{ {
... ...
"cursor": { "cursor": {
@ -387,12 +454,22 @@ might be useful if you are rendering a web UI for a user and want to provide
If `after` is `null`, there is no next page of results available. Likewise, If `after` is `null`, there is no next page of results available. Likewise,
if `before` is `null`, there are no previous results available. if `before` is `null`, there are no previous results available.
EOTEXT EOTEXT
); );
$out = implode("\n\n", $out); return id(new PHUIObjectBoxView())
return $out; ->setHeaderText(pht('Paging and Limits'))
->setCollapsed(true)
->appendChild($this->buildRemarkup($info));
} }
private function buildRemarkup($remarkup) {
$viewer = $this->getViewer();
$view = new PHUIRemarkupView($viewer, $remarkup);
return id(new PHUIBoxView())
->appendChild($view)
->addPadding(PHUI::PADDING_LARGE);
}
} }

View file

@ -13,6 +13,10 @@ final class PhabricatorLiskSearchEngineExtension
return pht('Lisk Builtin Properties'); return pht('Lisk Builtin Properties');
} }
public function getExtensionOrder() {
return 5000;
}
public function supportsObject($object) { public function supportsObject($object) {
if (!($object instanceof LiskDAO)) { if (!($object instanceof LiskDAO)) {
return false; return false;

View file

@ -33,7 +33,7 @@ abstract class PhabricatorSearchEngineExtension extends Phobject {
abstract public function supportsObject($object); abstract public function supportsObject($object);
public function getExtensionOrder() { public function getExtensionOrder() {
return 5000; return 7000;
} }
public function getSearchFields($object) { public function getSearchFields($object) {

View file

@ -15,7 +15,7 @@ final class PhabricatorSpacesSearchEngineExtension
} }
public function getExtensionOrder() { public function getExtensionOrder() {
return 3000; return 4000;
} }
public function supportsObject($object) { public function supportsObject($object) {

View file

@ -15,7 +15,7 @@ final class PhabricatorSubscriptionsSearchEngineExtension
} }
public function getExtensionOrder() { public function getExtensionOrder() {
return 1000; return 2000;
} }
public function supportsObject($object) { public function supportsObject($object) {