@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.

Include symbols in main typeahead

Summary:
- Include symbols in main typeahead results.
- Simplify the symbol query a bit and extend PhabricatorOffsetPagedQuery. There was some stuff around language ranking that I got rid of, I think the theory there was that mapping file extensions to languages might not work in general but I think it works fine in practice, and we have more config stuff now around guessing languages and getting the mappings right.
- Make it easier to debug the typeahead by showing the results in page format for non-ajax requests.
- When we have too many results, show only the top few of each type.

Depends on D3116, D3117

Test Plan: Used typeahead, got symbols in results. Hit endpoint with non-ajax, got useful debug view.

Reviewers: btrahan, vrana

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T1569

Differential Revision: https://secure.phabricator.com/D3118

+143 -61
+1 -1
src/__celerity_resource_map__.php
··· 1462 1462 ), 1463 1463 'javelin-behavior-phabricator-search-typeahead' => 1464 1464 array( 1465 - 'uri' => '/res/f552b264/rsrc/js/application/core/behavior-search-typeahead.js', 1465 + 'uri' => '/res/046ab274/rsrc/js/application/core/behavior-search-typeahead.js', 1466 1466 'type' => 'js', 1467 1467 'requires' => 1468 1468 array(
+1
src/__phutil_library_map__.php
··· 1477 1477 'DiffusionSvnRequest' => 'DiffusionRequest', 1478 1478 'DiffusionSvnTagListQuery' => 'DiffusionTagListQuery', 1479 1479 'DiffusionSymbolController' => 'DiffusionController', 1480 + 'DiffusionSymbolQuery' => 'PhabricatorOffsetPagedQuery', 1480 1481 'DiffusionTagListController' => 'DiffusionController', 1481 1482 'DiffusionTagListQuery' => 'DiffusionQuery', 1482 1483 'DiffusionTagListView' => 'DiffusionView',
+52 -57
src/applications/diffusion/query/DiffusionSymbolQuery.php
··· 27 27 * 28 28 * @group diffusion 29 29 */ 30 - final class DiffusionSymbolQuery { 30 + final class DiffusionSymbolQuery extends PhabricatorOffsetPagedQuery { 31 31 32 32 private $namePrefix; 33 33 private $name; ··· 35 35 private $projectIDs; 36 36 private $language; 37 37 private $type; 38 - 39 - private $limit = 20; 40 38 41 39 private $needPaths; 42 40 private $needArcanistProject; ··· 94 92 /** 95 93 * @task config 96 94 */ 97 - public function setLimit($limit) { 98 - $this->limit = $limit; 99 - return $this; 100 - } 101 - 102 - 103 - /** 104 - * @task config 105 - */ 106 95 public function needPaths($need_paths) { 107 96 $this->needPaths = $need_paths; 108 97 return $this; ··· 145 134 $symbol = new PhabricatorRepositorySymbol(); 146 135 $conn_r = $symbol->establishConnection('r'); 147 136 137 + $data = queryfx_all( 138 + $conn_r, 139 + 'SELECT * FROM %T %Q %Q %Q', 140 + $symbol->getTableName(), 141 + $this->buildWhereClause($conn_r), 142 + $this->buildOrderClause($conn_r), 143 + $this->buildLimitClause($conn_r)); 144 + 145 + $symbols = $symbol->loadAllFromArray($data); 146 + 147 + if ($symbols) { 148 + if ($this->needPaths) { 149 + $this->loadPaths($symbols); 150 + } 151 + if ($this->needArcanistProjects || $this->needRepositories) { 152 + $this->loadArcanistProjects($symbols); 153 + } 154 + if ($this->needRepositories) { 155 + $this->loadRepositories($symbols); 156 + } 157 + 158 + } 159 + 160 + return $symbols; 161 + } 162 + 163 + 164 + /* -( Internals )---------------------------------------------------------- */ 165 + 166 + 167 + /** 168 + * @task internal 169 + */ 170 + private function buildOrderClause($conn_r) { 171 + return qsprintf( 172 + $conn_r, 173 + 'ORDER BY symbolName ASC'); 174 + } 175 + 176 + 177 + /** 178 + * @task internal 179 + */ 180 + private function buildWhereClause($conn_r) { 148 181 $where = array(); 182 + 149 183 if ($this->name) { 150 184 $where[] = qsprintf( 151 185 $conn_r, ··· 167 201 $this->projectIDs); 168 202 } 169 203 170 - $where = 'WHERE ('.implode(') AND (', $where).')'; 171 - 172 - $data = queryfx_all( 173 - $conn_r, 174 - 'SELECT * FROM %T %Q', 175 - $symbol->getTableName(), 176 - $where); 177 - 178 - // Our ability to match up symbol types and languages probably isn't all 179 - // that great, so use them as hints for ranking rather than hard 180 - // requirements. TODO: Is this really the right choice? 181 - foreach ($data as $key => $row) { 182 - $score = 0; 183 - if ($this->language && $row['symbolLanguage'] == $this->language) { 184 - $score += 2; 185 - } 186 - if ($this->type && $row['symbolType'] == $this->type) { 187 - $score += 1; 188 - } 189 - $data[$key]['score'] = $score; 190 - $data[$key]['id'] = $key; 191 - } 192 - 193 - $data = isort($data, 'score'); 194 - $data = array_reverse($data); 195 - 196 - $data = array_slice($data, 0, $this->limit); 197 - 198 - $symbols = $symbol->loadAllFromArray($data); 199 - 200 - if ($symbols) { 201 - if ($this->needPaths) { 202 - $this->loadPaths($symbols); 203 - } 204 - if ($this->needArcanistProjects || $this->needRepositories) { 205 - $this->loadArcanistProjects($symbols); 206 - } 207 - if ($this->needRepositories) { 208 - $this->loadRepositories($symbols); 209 - } 210 - 204 + if ($this->language) { 205 + $where[] = qsprintf( 206 + $conn_r, 207 + 'symbolLanguage = %s', 208 + $this->language); 211 209 } 212 210 213 - return $symbols; 211 + return $this->formatWhereClause($where); 214 212 } 215 - 216 - 217 - /* -( Internals )---------------------------------------------------------- */ 218 213 219 214 220 215 /**
+64 -1
src/applications/typeahead/controller/PhabricatorTypeaheadCommonDatasourceController.php
··· 40 40 $need_upforgrabs = false; 41 41 $need_arcanist_projects = false; 42 42 $need_noproject = false; 43 + $need_symbols = false; 43 44 switch ($this->type) { 44 45 case 'mainsearch': 45 46 $need_users = true; 46 47 $need_applications = true; 47 48 $need_rich_data = true; 49 + $need_symbols = true; 48 50 break; 49 51 case 'searchowner': 50 52 $need_users = true; ··· 238 240 } 239 241 } 240 242 243 + if ($need_symbols) { 244 + $symbols = id(new DiffusionSymbolQuery()) 245 + ->setNamePrefix($query) 246 + ->setLimit(15) 247 + ->needArcanistProjects(true) 248 + ->needRepositories(true) 249 + ->needPaths(true) 250 + ->execute(); 251 + foreach ($symbols as $symbol) { 252 + $lang = $symbol->getSymbolLanguage(); 253 + $name = $symbol->getSymbolName(); 254 + $type = $symbol->getSymbolType(); 255 + $proj = $symbol->getArcanistProject()->getName(); 256 + 257 + $results[] = id(new PhabricatorTypeaheadResult()) 258 + ->setName($name) 259 + ->setURI($symbol->getURI()) 260 + ->setPHID(md5($symbol->getURI())) // Just needs to be unique. 261 + ->setDisplayName($symbol->getName()) 262 + ->setDisplayType(strtoupper($lang).' '.ucwords($type).' ('.$proj.')') 263 + ->setPriorityType('symb'); 264 + } 265 + } 266 + 241 267 $content = mpull($results, 'getWireFormat'); 242 268 243 - return id(new AphrontAjaxResponse())->setContent($content); 269 + if ($request->isAjax()) { 270 + return id(new AphrontAjaxResponse())->setContent($content); 271 + } 272 + 273 + // If there's a non-Ajax request to this endpoint, show results in a tabular 274 + // format to make it easier to debug typeahead output. 275 + 276 + $rows = array(); 277 + foreach ($results as $result) { 278 + $wire = $result->getWireFormat(); 279 + foreach ($wire as $k => $v) { 280 + $wire[$k] = phutil_escape_html($v); 281 + } 282 + $rows[] = $wire; 283 + } 284 + 285 + $table = new AphrontTableView($rows); 286 + $table->setHeaders( 287 + array( 288 + 'Name', 289 + 'URI', 290 + 'PHID', 291 + 'Priority', 292 + 'Display Name', 293 + 'Display Type', 294 + 'Image URI', 295 + 'Priority Type', 296 + )); 297 + 298 + $panel = new AphrontPanelView(); 299 + $panel->setHeader('Typeahead Results'); 300 + $panel->appendChild($table); 301 + 302 + return $this->buildStandardPageResponse( 303 + $panel, 304 + array( 305 + 'title' => 'Typeahead Results', 306 + )); 244 307 } 245 308 246 309 }
+1 -1
src/applications/typeahead/storage/PhabricatorTypeaheadResult.php
··· 75 75 $this->priorityString, 76 76 $this->displayName, 77 77 $this->displayType, 78 - $this->imageURI, 78 + $this->imageURI ? (string)$this->imageURI : null, 79 79 $this->priorityType, 80 80 ); 81 81 while (end($data) === null) {
+24 -1
webroot/rsrc/js/application/core/behavior-search-typeahead.js
··· 53 53 var type_priority = { 54 54 // TODO: Put jump nav hits like "D123" first. 55 55 'apps' : 2, 56 - 'user' : 3 56 + 'user' : 3, 57 + 'symb' : 4 57 58 }; 58 59 59 60 var tokens = this.tokenize(value); ··· 85 86 86 87 return cmp(u, v); 87 88 }); 89 + 90 + // If we have more results than fit, limit each type of result to 3, so 91 + // we show 3 applications, then 3 users, etc. 92 + var type_count = 0; 93 + var current_type = null; 94 + for (var ii = 0; ii < list.length; ii++) { 95 + if (list.length <= config.limit) { 96 + break; 97 + } 98 + if (list[ii].type != current_type) { 99 + current_type = list[ii].type; 100 + type_count = 1; 101 + } else { 102 + type_count++; 103 + if (type_count > 3) { 104 + list.splice(ii, 1); 105 + ii--; 106 + } 107 + } 108 + } 109 + 88 110 }; 89 111 90 112 datasource.setSortHandler(JX.bind(datasource, sort_handler)); 113 + datasource.setMaximumResultCount(config.limit); 91 114 92 115 var typeahead = new JX.Typeahead(JX.$(config.id), JX.$(config.input)); 93 116 typeahead.setDatasource(datasource);