@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+260 -206
+1 -56
src/applications/conduit/controller/PhabricatorConduitConsoleController.php
··· 101 101 ->appendChild($properties); 102 102 103 103 $content[] = $info_box; 104 + $content[] = $method->getMethodDocumentation(); 104 105 $content[] = $form_box; 105 106 $content[] = $this->renderExampleBox($method, null); 106 - 107 - $query = $method->newQueryObject(); 108 - if ($query) { 109 - $orders = $query->getBuiltinOrders(); 110 - 111 - $rows = array(); 112 - foreach ($orders as $key => $order) { 113 - $rows[] = array( 114 - $key, 115 - $order['name'], 116 - implode(', ', $order['vector']), 117 - ); 118 - } 119 - 120 - $table = id(new AphrontTableView($rows)) 121 - ->setHeaders( 122 - array( 123 - pht('Key'), 124 - pht('Description'), 125 - pht('Columns'), 126 - )) 127 - ->setColumnClasses( 128 - array( 129 - 'pri', 130 - '', 131 - 'wide', 132 - )); 133 - $content[] = id(new PHUIObjectBoxView()) 134 - ->setHeaderText(pht('Builtin Orders')) 135 - ->setTable($table); 136 - 137 - $columns = $query->getOrderableColumns(); 138 - 139 - $rows = array(); 140 - foreach ($columns as $key => $column) { 141 - $rows[] = array( 142 - $key, 143 - idx($column, 'unique') ? pht('Yes') : pht('No'), 144 - ); 145 - } 146 - 147 - $table = id(new AphrontTableView($rows)) 148 - ->setHeaders( 149 - array( 150 - pht('Key'), 151 - pht('Unique'), 152 - )) 153 - ->setColumnClasses( 154 - array( 155 - 'pri', 156 - 'wide', 157 - )); 158 - $content[] = id(new PHUIObjectBoxView()) 159 - ->setHeaderText(pht('Column Orders')) 160 - ->setTable($table); 161 - } 162 107 163 108 $crumbs = $this->buildApplicationCrumbs(); 164 109 $crumbs->addTextCrumb($method->getAPIMethodName());
+4
src/applications/conduit/method/ConduitAPIMethod.php
··· 37 37 */ 38 38 abstract public function getMethodDescription(); 39 39 40 + public function getMethodDocumentation() { 41 + return null; 42 + } 43 + 40 44 abstract protected function defineParamTypes(); 41 45 abstract protected function defineReturnType(); 42 46
+4
src/applications/conduit/query/ConduitResultSearchEngineExtension.php
··· 9 9 return true; 10 10 } 11 11 12 + public function getExtensionOrder() { 13 + return 1000; 14 + } 15 + 12 16 public function getExtensionName() { 13 17 return pht('Support for ConduitResultInterface'); 14 18 }
+4
src/applications/policy/engineextension/PhabricatorPolicySearchEngineExtension.php
··· 17 17 return ($object instanceof PhabricatorPolicyInterface); 18 18 } 19 19 20 + public function getExtensionOrder() { 21 + return 6000; 22 + } 23 + 20 24 public function getFieldSpecificationsForConduit($object) { 21 25 return array( 22 26 'policy' => array(
+1 -1
src/applications/project/engineextension/PhabricatorProjectsSearchEngineExtension.php
··· 15 15 } 16 16 17 17 public function getExtensionOrder() { 18 - return 2000; 18 + return 3000; 19 19 } 20 20 21 21 public function supportsObject($object) {
+21 -5
src/applications/search/engine/PhabricatorApplicationSearchEngine.php
··· 1068 1068 $fields[$conduit_key] = $field; 1069 1069 } 1070 1070 1071 - $viewer = $this->requireViewer(); 1072 - foreach ($fields as $key => $field) { 1073 - $field->setViewer($viewer); 1074 - } 1075 - 1076 1071 // These are handled separately for Conduit, so don't show them as 1077 1072 // supported. 1078 1073 unset($fields['ids']); 1079 1074 unset($fields['phids']); 1080 1075 unset($fields['order']); 1081 1076 unset($fields['limit']); 1077 + 1078 + // TODO: Clean these up, shortly. 1079 + $fields = array( 1080 + 'ids' => id(new PhabricatorSearchDatasourceField()) 1081 + ->setKey('ids') 1082 + ->setLabel(pht('IDs')) 1083 + ->setDescription( 1084 + pht('Search for objects with specific IDs.')) 1085 + ->setConduitParameterType(new ConduitIntListParameterType()), 1086 + 'phids' => id(new PhabricatorSearchDatasourceField()) 1087 + ->setKey('phids') 1088 + ->setLabel(pht('PHIDs')) 1089 + ->setDescription( 1090 + pht('Search for objects with specific PHIDs.')) 1091 + ->setConduitParameterType(new ConduitPHIDListParameterType()), 1092 + ) + $fields; 1093 + 1094 + $viewer = $this->requireViewer(); 1095 + foreach ($fields as $key => $field) { 1096 + $field->setViewer($viewer); 1097 + } 1082 1098 1083 1099 return $fields; 1084 1100 }
+218 -141
src/applications/search/engine/PhabricatorSearchEngineAPIMethod.php
··· 39 39 } 40 40 41 41 final public function getMethodDescription() { 42 + return pht( 43 + 'This is a standard **ApplicationSearch** method which will let you '. 44 + 'list, query, or search for objects.'); 45 + } 46 + 47 + final public function getMethodDocumentation() { 42 48 $viewer = $this->getViewer(); 43 49 44 50 $engine = $this->newSearchEngine() ··· 48 54 49 55 $out = array(); 50 56 51 - $out[] = pht(<<<EOTEXT 52 - This is a standard **ApplicationSearch** method which will let you list, query, 53 - or search for objects. 57 + $out[] = $this->buildQueriesBox($engine); 58 + $out[] = $this->buildConstraintsBox($engine); 59 + $out[] = $this->buildOrderBox($engine, $query); 60 + $out[] = $this->buildFieldsBox($engine); 61 + $out[] = $this->buildPagingBox($engine); 54 62 55 - EOTEXT 56 - ); 63 + return $out; 64 + } 57 65 58 - $out[] = pht(<<<EOTEXT 59 - Prebuilt Queries 60 - ---------------- 66 + private function buildQueriesBox( 67 + PhabricatorApplicationSearchEngine $engine) { 68 + $viewer = $this->getViewer(); 61 69 62 - You can use a builtin or saved query as a starting point by passing it with 63 - `queryKey`. If you don't specify a `queryKey`, the query will start with no 64 - constraints. 70 + $info = pht(<<<EOTEXT 71 + You can choose a builtin or saved query as a starting point for filtering 72 + results by selecting it with `queryKey`. If you don't specify a `queryKey`, 73 + the query will start with no constraints. 65 74 66 75 For example, many applications have builtin queries like `"active"` or 67 76 `"open"` to find only active or enabled results. To use a `queryKey`, specify 68 77 it like this: 69 78 70 - ```lang=json 79 + ```lang=json, name="Selecting a Builtin Query" 71 80 { 72 81 ... 73 82 "queryKey": "active", ··· 75 84 } 76 85 ``` 77 86 87 + The table below shows the keys to use to select builtin queries and your 88 + saved queries, but you can also use **any** query you run via the web UI as a 89 + starting point. You can find the key for a query by examining the URI after 90 + running a normal search. 91 + 78 92 You can use these keys to select builtin queries and your configured saved 79 93 queries: 80 94 EOTEXT 81 95 ); 82 96 83 - $head_querykey = pht('Query Key'); 84 - $head_name = pht('Name'); 85 - $head_builtin = pht('Builtin'); 86 - 87 97 $named_queries = $engine->loadAllNamedQueries(); 88 98 89 - $table = array(); 90 - $table[] = "| {$head_querykey} | {$head_name} | {$head_builtin} |"; 91 - $table[] = '|------------------|--------------|-----------------|'; 99 + $rows = array(); 92 100 foreach ($named_queries as $named_query) { 93 - $key = $named_query->getQueryKey(); 94 - $name = $named_query->getQueryName(); 95 101 $builtin = $named_query->getIsBuiltin() 96 102 ? pht('Builtin') 97 103 : pht('Custom'); 98 104 99 - $table[] = "| `{$key}` | {$name} | {$builtin} |"; 105 + $rows[] = array( 106 + $named_query->getQueryKey(), 107 + $named_query->getQueryName(), 108 + $builtin, 109 + ); 100 110 } 101 - $table = implode("\n", $table); 102 - $out[] = $table; 103 111 104 - $out[] = pht(<<<EOTEXT 105 - You can also use **any** query you run via the web UI as a starting point. You 106 - can find the key for a query by examining the URI after running a normal 107 - search. 108 - EOTEXT 109 - ); 112 + $table = id(new AphrontTableView($rows)) 113 + ->setHeaders( 114 + array( 115 + pht('Query Key'), 116 + pht('Name'), 117 + pht('Builtin'), 118 + )) 119 + ->setColumnClasses( 120 + array( 121 + 'prewrap', 122 + 'pri wide', 123 + null, 124 + )); 110 125 111 - $out[] = pht(<<<EOTEXT 112 - Custom Constraints 113 - ------------------ 126 + return id(new PHUIObjectBoxView()) 127 + ->setHeaderText(pht('Builtin and Saved Queries')) 128 + ->setCollapsed(true) 129 + ->appendChild($this->buildRemarkup($info)) 130 + ->appendChild($table); 131 + } 114 132 115 - You can add custom constraints to the basic query by passing `constraints`. 116 - This will let you filter results (for example, show only results with a 117 - certain state, status, or owner). 133 + private function buildConstraintsBox( 134 + PhabricatorApplicationSearchEngine $engine) { 135 + 136 + $info = pht(<<<EOTEXT 137 + You can apply custom constraints by passing a dictionary in `constraints`. 138 + This will let you search for specific sets of results (for example, you may 139 + want show only results with a certain state, status, or owner). 140 + 141 + 142 + If you specify both a `queryKey` and `constraints`, the builtin or saved query 143 + will be applied first as a starting point, then any additional values in 144 + `constraints` will be applied, overwriting the defaults from the original query. 118 145 119 146 Specify constraints like this: 120 147 121 - ```lang=json 148 + ```lang=json, name="Example Custom Constraints" 122 149 { 123 150 ... 124 151 "constraints": { 125 - "authorPHIDs": ["PHID-USER-1111", "PHID-USER-2222"], 126 - "statuses": ["open", "closed"] 152 + "authors": ["PHID-USER-1111", "PHID-USER-2222"], 153 + "statuses": ["open", "closed"], 154 + ... 127 155 }, 128 156 ... 129 157 } 130 158 ``` 131 159 132 - If you specify both a `queryKey` and `constraints`, the basic query 133 - configuration will be applied first as a starting point, then any additional 134 - values in `constraints` will be applied, overwriting the defaults from the 135 - original query. 136 - 137 160 This API endpoint supports these constraints: 138 161 EOTEXT 139 162 ); 140 163 141 - $head_key = pht('Key'); 142 - $head_label = pht('Label'); 143 - $head_type = pht('Type'); 144 - $head_desc = pht('Description'); 145 - 146 - $desc_ids = pht('Search for specific objects by ID.'); 147 - $desc_phids = pht('Search for specific objects by PHID.'); 148 - 149 164 $fields = $engine->getSearchFieldsForConduit(); 150 165 151 - $table = array(); 152 - $table[] = "| {$head_key} | {$head_label} | {$head_type} | {$head_desc} |"; 153 - $table[] = '|-------------|---------------|--------------|--------------|'; 154 - $table[] = "| `ids` | **IDs** | `list<int>` | {$desc_ids} |"; 155 - $table[] = "| `phids` | **PHIDs** | `list<phid>` | {$desc_phids} |"; 166 + $rows = array(); 156 167 foreach ($fields as $field) { 157 168 $key = $field->getConduitKey(); 158 169 $label = $field->getLabel(); 159 170 160 171 $type_object = $field->getConduitParameterType(); 161 172 if ($type_object) { 162 - $type = '`'.$type_object->getTypeName().'`'; 173 + $type = $type_object->getTypeName(); 163 174 $description = $field->getDescription(); 164 175 } else { 165 - $type = ''; 166 - $description = '//'.pht('Not Supported').'//'; 176 + $type = null; 177 + $description = phutil_tag('em', array(), pht('Not supported.')); 167 178 } 168 179 169 - $table[] = "| `{$key}` | **{$label}** | {$type} | {$description}"; 180 + $rows[] = array( 181 + $key, 182 + $label, 183 + $type, 184 + $description, 185 + ); 170 186 } 171 - $table = implode("\n", $table); 172 - $out[] = $table; 187 + 188 + $table = id(new AphrontTableView($rows)) 189 + ->setHeaders( 190 + array( 191 + pht('Key'), 192 + pht('Label'), 193 + pht('Type'), 194 + pht('Description'), 195 + )) 196 + ->setColumnClasses( 197 + array( 198 + 'prewrap', 199 + 'pri', 200 + 'prewrap', 201 + 'wide', 202 + )); 203 + 204 + return id(new PHUIObjectBoxView()) 205 + ->setHeaderText(pht('Custom Query Constraints')) 206 + ->setCollapsed(true) 207 + ->appendChild($this->buildRemarkup($info)) 208 + ->appendChild($table); 209 + } 173 210 211 + private function buildOrderBox( 212 + PhabricatorApplicationSearchEngine $engine, 213 + $query) { 174 214 175 - $out[] = pht(<<<EOTEXT 176 - Result Order 177 - ------------ 215 + $orders_info = pht(<<<EOTEXT 216 + Use `order` to choose an ordering for the results. 178 217 179 - Use `order` to choose an ordering for the results. Either specify a single 180 - key from the builtin orders (these are a set of meaningful, high-level, 181 - human-readable orders) or specify a list of low-level columns. 218 + Either specify a single key from the builtin orders (these are a set of 219 + meaningful, high-level, human-readable orders) or specify a custom list of 220 + low-level columns. 182 221 183 222 To use a high-level order, choose a builtin order from the table below 184 223 and specify it like this: 185 224 186 - ```lang=json 225 + ```lang=json, name="Choosing a Result Order" 187 226 { 188 227 ... 189 228 "order": "newest", ··· 195 234 EOTEXT 196 235 ); 197 236 198 - $head_builtin = pht('Builtin Order'); 199 - $head_label = pht('Label'); 200 - $head_columns = pht('Columns'); 201 - 202 237 $orders = $query->getBuiltinOrders(); 203 238 204 - $table = array(); 205 - $table[] = "| {$head_builtin} | {$head_label} | {$head_columns} |"; 206 - $table[] = '|-----------------|---------------------|-----------------|'; 239 + $rows = array(); 207 240 foreach ($orders as $key => $order) { 208 - $name = $order['name']; 209 - $columns = implode(', ', $order['vector']); 210 - $table[] = "| `{$key}` | {$name} | {$columns} |"; 241 + $rows[] = array( 242 + $key, 243 + $order['name'], 244 + implode(', ', $order['vector']), 245 + ); 211 246 } 212 - $table = implode("\n", $table); 213 - $out[] = $table; 247 + 248 + $orders_table = id(new AphrontTableView($rows)) 249 + ->setHeaders( 250 + array( 251 + pht('Key'), 252 + pht('Description'), 253 + pht('Columns'), 254 + )) 255 + ->setColumnClasses( 256 + array( 257 + 'pri', 258 + '', 259 + 'wide', 260 + )); 214 261 215 - $out[] = pht(<<<EOTEXT 216 - You can choose a low-level column order instead. This is an advanced feature. 262 + $columns_info = pht(<<<EOTEXT 263 + You can choose a low-level column order instead. To do this, provide a list 264 + of columns instead of a single key. This is an advanced feature. 217 265 218 - In your custom order: each column may only be specified once; each column may 219 - be prefixed with "-" to invert the order; the last column must be unique; and 220 - no column other than the last may be unique. 266 + In a custom column order: 267 + 268 + - each column may only be specified once; 269 + - each column may be prefixed with `-` to invert the order; 270 + - the last column must be a unique column, usually `id`; and 271 + - no column other than the last may be unique. 221 272 222 273 To use a low-level order, choose a sequence of columns and specify them like 223 274 this: 224 275 225 - ```lang=json 276 + ```lang=json, name="Using a Custom Order" 226 277 { 227 278 ... 228 279 "order": ["color", "-name", "id"], ··· 234 285 EOTEXT 235 286 ); 236 287 237 - $head_column = pht('Column Key'); 238 - $head_unique = pht('Unique'); 239 - 240 288 $columns = $query->getOrderableColumns(); 241 - 242 - $table = array(); 243 - $table[] = "| {$head_column} | {$head_unique} |"; 244 - $table[] = '|----------------|----------------|'; 289 + $rows = array(); 245 290 foreach ($columns as $key => $column) { 246 - $unique = idx($column, 'unique') 247 - ? pht('Yes') 248 - : pht('No'); 249 - 250 - $table[] = "| `{$key}` | {$unique} |"; 291 + $rows[] = array( 292 + $key, 293 + idx($column, 'unique') ? pht('Yes') : pht('No'), 294 + ); 251 295 } 252 - $table = implode("\n", $table); 253 - $out[] = $table; 254 296 297 + $columns_table = id(new AphrontTableView($rows)) 298 + ->setHeaders( 299 + array( 300 + pht('Key'), 301 + pht('Unique'), 302 + )) 303 + ->setColumnClasses( 304 + array( 305 + 'pri', 306 + 'wide', 307 + )); 255 308 256 - $out[] = pht(<<<EOTEXT 257 - Result Format 258 - ------------- 259 309 260 - The result format is a dictionary with several fields: 310 + return id(new PHUIObjectBoxView()) 311 + ->setHeaderText(pht('Result Ordering')) 312 + ->setCollapsed(true) 313 + ->appendChild($this->buildRemarkup($orders_info)) 314 + ->appendChild($orders_table) 315 + ->appendChild($this->buildRemarkup($columns_info)) 316 + ->appendChild($columns_table); 317 + } 261 318 262 - - `data`: Contains the actual results, as a list of dictionaries. 263 - - `query`: Details about the query which was issued. 264 - - `cursor`: Information about how to issue another query to get the next 265 - (or previous) page of results. See "Paging and Limits" below. 319 + private function buildFieldsBox( 320 + PhabricatorApplicationSearchEngine $engine) { 266 321 267 - EOTEXT 268 - ); 269 - 270 - $out[] = pht(<<<EOTEXT 271 - Fields 272 - ------ 273 - 274 - The `data` field of the result contains a list of results. Each result has 275 - some metadata and a `fields` key, which contains the primary object fields. 322 + $info = pht(<<<EOTEXT 323 + Objects matching your query are returned as a list of dictionaries in the 324 + `data` property of the results. Each dictionary has some metadata and a 325 + `fields` key, which contains the information abou the object that most callers 326 + will be interested in. 276 327 277 328 For example, the results may look something like this: 278 329 279 - ```lang=json 330 + ```lang=json, name="Example Results" 280 331 { 281 332 ... 282 333 "data": [ ··· 306 357 available fields differ from application to application. 307 358 308 359 These are the fields available on this object type: 309 - 310 360 EOTEXT 311 361 ); 312 362 313 - $head_key = pht('Key'); 314 - $head_type = pht('Type'); 315 - $head_description = pht('Description'); 316 - 317 363 $specs = $engine->getAllConduitFieldSpecifications(); 318 364 319 - $table = array(); 320 - $table[] = "| {$head_key} | {$head_type} | {$head_description} |"; 321 - $table[] = '|-------------|--------------|---------------------|'; 365 + $rows = array(); 322 366 foreach ($specs as $key => $spec) { 323 367 $type = idx($spec, 'type'); 324 368 $description = idx($spec, 'description'); 325 - $table[] = "| `{$key}` | `{$type}` | {$description} |"; 369 + $rows[] = array( 370 + $key, 371 + $type, 372 + $description, 373 + ); 326 374 } 327 - $table = implode("\n", $table); 328 - $out[] = $table; 375 + 376 + $table = id(new AphrontTableView($rows)) 377 + ->setHeaders( 378 + array( 379 + pht('Key'), 380 + pht('Type'), 381 + pht('Description'), 382 + )) 383 + ->setColumnClasses( 384 + array( 385 + 'pri', 386 + 'mono', 387 + 'wide', 388 + )); 329 389 330 - $out[] = pht(<<<EOTEXT 331 - Paging and Limits 332 - ----------------- 390 + return id(new PHUIObjectBoxView()) 391 + ->setHeaderText(pht('Object Fields')) 392 + ->setCollapsed(true) 393 + ->appendChild($this->buildRemarkup($info)) 394 + ->appendChild($table); 395 + } 333 396 397 + private function buildPagingBox( 398 + PhabricatorApplicationSearchEngine $engine) { 399 + 400 + $info = pht(<<<EOTEXT 334 401 Queries are limited to returning 100 results at a time. If you want fewer 335 402 results than this, you can use `limit` to specify a smaller limit. 336 403 ··· 338 405 more pages of results. 339 406 340 407 The result structure contains a `cursor` key with information you'll need in 341 - order to fetch the next page. After an initial query, it will usually look 342 - something like this: 408 + order to fetch the next page of results. After an initial query, it will 409 + usually look something like this: 343 410 344 - ```lang=json 411 + ```lang=json, name="Example Cursor Result" 345 412 { 346 413 ... 347 414 "cursor": { ··· 366 433 If you do things correctly, you should get the second page of results, and 367 434 a cursor structure like this: 368 435 369 - ```lang=json 436 + ```lang=json, name="Second Result Page" 370 437 { 371 438 ... 372 439 "cursor": { ··· 387 454 388 455 If `after` is `null`, there is no next page of results available. Likewise, 389 456 if `before` is `null`, there are no previous results available. 390 - 391 457 EOTEXT 392 458 ); 393 459 394 - $out = implode("\n\n", $out); 395 - return $out; 460 + return id(new PHUIObjectBoxView()) 461 + ->setHeaderText(pht('Paging and Limits')) 462 + ->setCollapsed(true) 463 + ->appendChild($this->buildRemarkup($info)); 396 464 } 397 465 466 + private function buildRemarkup($remarkup) { 467 + $viewer = $this->getViewer(); 468 + 469 + $view = new PHUIRemarkupView($viewer, $remarkup); 470 + 471 + return id(new PHUIBoxView()) 472 + ->appendChild($view) 473 + ->addPadding(PHUI::PADDING_LARGE); 474 + } 398 475 }
+4
src/applications/search/engineextension/PhabricatorLiskSearchEngineExtension.php
··· 13 13 return pht('Lisk Builtin Properties'); 14 14 } 15 15 16 + public function getExtensionOrder() { 17 + return 5000; 18 + } 19 + 16 20 public function supportsObject($object) { 17 21 if (!($object instanceof LiskDAO)) { 18 22 return false;
+1 -1
src/applications/search/engineextension/PhabricatorSearchEngineExtension.php
··· 33 33 abstract public function supportsObject($object); 34 34 35 35 public function getExtensionOrder() { 36 - return 5000; 36 + return 7000; 37 37 } 38 38 39 39 public function getSearchFields($object) {
+1 -1
src/applications/spaces/engineextension/PhabricatorSpacesSearchEngineExtension.php
··· 15 15 } 16 16 17 17 public function getExtensionOrder() { 18 - return 3000; 18 + return 4000; 19 19 } 20 20 21 21 public function supportsObject($object) {
+1 -1
src/applications/subscriptions/engineextension/PhabricatorSubscriptionsSearchEngineExtension.php
··· 15 15 } 16 16 17 17 public function getExtensionOrder() { 18 - return 1000; 18 + return 2000; 19 19 } 20 20 21 21 public function supportsObject($object) {