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

Render browse results with global result style

Summary:
Ref T11034. This seems a little more promising. Two problems at the moment:

- This doesn't actually provide any useful information at all right now.
- Many object types have no profile images.

Test Plan:
{F1695254}

{F1695255}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T11034

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

+258 -52
+2 -2
resources/celerity/map.php
··· 28 28 'rsrc/css/aphront/table-view.css' => '9258e19f', 29 29 'rsrc/css/aphront/tokenizer.css' => '056da01b', 30 30 'rsrc/css/aphront/tooltip.css' => '1a07aea8', 31 - 'rsrc/css/aphront/typeahead-browse.css' => 'd8581d2c', 31 + 'rsrc/css/aphront/typeahead-browse.css' => '8904346a', 32 32 'rsrc/css/aphront/typeahead.css' => 'd4f16145', 33 33 'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af', 34 34 'rsrc/css/application/auth/auth.css' => '0877ed6e', ··· 889 889 'syntax-default-css' => '9923583c', 890 890 'syntax-highlighting-css' => '9fc496d5', 891 891 'tokens-css' => '3d0f239e', 892 - 'typeahead-browse-css' => 'd8581d2c', 892 + 'typeahead-browse-css' => '8904346a', 893 893 'unhandled-exception-css' => '4c96257a', 894 894 ), 895 895 'requires' => array(
+36 -10
src/applications/diffusion/typeahead/DiffusionRepositoryDatasource.php
··· 31 31 "phabricator-search-icon phui-font-fa phui-icon-view {$type_icon}"; 32 32 33 33 $results = array(); 34 - foreach ($repos as $repo) { 35 - $display_name = $repo->getMonogram().' '.$repo->getName(); 34 + foreach ($repos as $repository) { 35 + $monogram = $repository->getMonogram(); 36 + $name = $repository->getName(); 36 37 37 - $name = $display_name; 38 - $slug = $repo->getRepositorySlug(); 38 + $display_name = "{$monogram} {$name}"; 39 + 40 + $parts = array(); 41 + $parts[] = $name; 42 + 43 + $slug = $repository->getRepositorySlug(); 39 44 if (strlen($slug)) { 40 - $name = "{$name} {$slug}"; 45 + $parts[] = $slug; 46 + } 47 + 48 + $callsign = $repository->getCallsign(); 49 + if ($callsign) { 50 + $parts[] = $callsign; 41 51 } 42 52 43 - $results[] = id(new PhabricatorTypeaheadResult()) 53 + foreach ($repository->getAllMonograms() as $monogram) { 54 + $parts[] = $monogram; 55 + } 56 + 57 + $name = implode(' ', $parts); 58 + 59 + $vcs = $repository->getVersionControlSystem(); 60 + $vcs_type = PhabricatorRepositoryType::getNameForRepositoryType($vcs); 61 + 62 + $result = id(new PhabricatorTypeaheadResult()) 44 63 ->setName($name) 45 64 ->setDisplayName($display_name) 46 - ->setURI($repo->getURI()) 47 - ->setPHID($repo->getPHID()) 48 - ->setPriorityString($repo->getMonogram()) 65 + ->setURI($repository->getURI()) 66 + ->setPHID($repository->getPHID()) 67 + ->setPriorityString($repository->getMonogram()) 49 68 ->setPriorityType('repo') 50 69 ->setImageSprite($image_sprite) 51 - ->setDisplayType(pht('Repository')); 70 + ->setDisplayType(pht('Repository')) 71 + ->addAttribute($vcs_type); 72 + 73 + if (!$repository->isTracked()) { 74 + $result->setClosed(pht('Inactive')); 75 + } 76 + 77 + $results[] = $result; 52 78 } 53 79 54 80 return $results;
+4 -1
src/applications/diffusion/typeahead/DiffusionTaggedRepositoriesFunctionDatasource.php
··· 43 43 ->setColor(null) 44 44 ->setPHID('tagged('.$result->getPHID().')') 45 45 ->setDisplayName(pht('Tagged: %s', $result->getDisplayName())) 46 - ->setName('tagged '.$result->getName()); 46 + ->setName('tagged '.$result->getName()) 47 + ->resetAttributes() 48 + ->addAttribute(pht('Function')) 49 + ->addAttribute(pht('Select repositories tagged with this project.')); 47 50 } 48 51 49 52 return $results;
+7
src/applications/drydock/typeahead/DrydockBlueprintDatasource.php
··· 7 7 return pht('Type a blueprint name...'); 8 8 } 9 9 10 + public function getBrowseTitle() { 11 + return pht('Browse Blueprints'); 12 + } 13 + 10 14 public function getDatasourceApplicationClass() { 11 15 return 'PhabricatorDrydockApplication'; 12 16 } ··· 36 40 if ($blueprint->getIsDisabled()) { 37 41 $result->setClosed(pht('Disabled')); 38 42 } 43 + 44 + $result->addAttribute( 45 + $blueprint->getImplementation()->getBlueprintName()); 39 46 40 47 $results[] = $result; 41 48 }
+2 -1
src/applications/maniphest/typeahead/ManiphestTaskClosedStatusDatasource.php
··· 67 67 ->setName($name.' closed') 68 68 ->setDisplayName($name) 69 69 ->setPHID(self::FUNCTION_TOKEN) 70 - ->setUnique(true); 70 + ->setUnique(true) 71 + ->addAttribute(pht('Select any closed status.')); 71 72 } 72 73 73 74 }
+2 -1
src/applications/maniphest/typeahead/ManiphestTaskOpenStatusDatasource.php
··· 67 67 ->setName($name.' open') 68 68 ->setDisplayName($name) 69 69 ->setPHID(self::FUNCTION_TOKEN) 70 - ->setUnique(true); 70 + ->setUnique(true) 71 + ->addAttribute(pht('Select any open status.')); 71 72 } 72 73 73 74 }
+2 -1
src/applications/maniphest/typeahead/ManiphestTaskPriorityDatasource.php
··· 32 32 $result = id(new PhabricatorTypeaheadResult()) 33 33 ->setIcon(ManiphestTaskPriority::getTaskPriorityIcon($value)) 34 34 ->setPHID($value) 35 - ->setName($name); 35 + ->setName($name) 36 + ->addAttribute(pht('Priority')); 36 37 37 38 if (ManiphestTaskPriority::isDisabledPriority($value)) { 38 39 $result->setClosed(pht('Disabled'));
+6
src/applications/maniphest/typeahead/ManiphestTaskStatusDatasource.php
··· 35 35 ->setPHID($value) 36 36 ->setName($name); 37 37 38 + if (ManiphestTaskStatus::isOpenStatus($value)) { 39 + $result->addAttribute(pht('Open Status')); 40 + } else { 41 + $result->addAttribute(pht('Closed Status')); 42 + } 43 + 38 44 if (ManiphestTaskStatus::isDisabledStatus($value)) { 39 45 $result->setClosed(pht('Disabled')); 40 46 }
+2 -1
src/applications/people/typeahead/PhabricatorPeopleAnyOwnerDatasource.php
··· 62 62 ->setDisplayName($name) 63 63 ->setIcon('fa-certificate') 64 64 ->setPHID(self::FUNCTION_TOKEN) 65 - ->setUnique(true); 65 + ->setUnique(true) 66 + ->addAttribute(pht('Select results with any owner.')); 66 67 } 67 68 68 69 }
+25 -17
src/applications/people/typeahead/PhabricatorPeopleDatasource.php
··· 3 3 final class PhabricatorPeopleDatasource 4 4 extends PhabricatorTypeaheadDatasource { 5 5 6 - private $enrichResults; 7 - 8 - /** 9 - * Controls enriched rendering, for global search. This is a bit hacky and 10 - * should probably be handled in a more general way, but is fairly reasonable 11 - * for now. 12 - */ 13 - public function setEnrichResults($enrich) { 14 - $this->enrichResults = $enrich; 15 - return $this; 16 - } 17 - 18 6 public function getBrowseTitle() { 19 7 return pht('Browse Users'); 20 8 } ··· 40 28 41 29 $users = $this->executeQuery($query); 42 30 43 - if ($this->enrichResults && $users) { 31 + $is_browse = $this->getIsBrowse(); 32 + 33 + if ($is_browse && $users) { 44 34 $phids = mpull($users, 'getPHID'); 45 35 $handles = id(new PhabricatorHandleQuery()) 46 36 ->setViewer($viewer) ··· 50 40 51 41 $results = array(); 52 42 foreach ($users as $user) { 43 + $phid = $user->getPHID(); 44 + 53 45 $closed = null; 54 46 if ($user->getIsDisabled()) { 55 47 $closed = pht('Disabled'); ··· 64 56 $result = id(new PhabricatorTypeaheadResult()) 65 57 ->setName($user->getFullName()) 66 58 ->setURI('/p/'.$username.'/') 67 - ->setPHID($user->getPHID()) 59 + ->setPHID($phid) 68 60 ->setPriorityString($username) 69 61 ->setPriorityType('user') 70 62 ->setAutocomplete('@'.$username) ··· 74 66 $result->setIcon('fa-envelope-o'); 75 67 } 76 68 77 - if ($this->enrichResults) { 78 - $display_type = pht('User'); 69 + if ($is_browse) { 70 + $handle = $handles[$phid]; 71 + 72 + $result 73 + ->setIcon($handle->getIcon()) 74 + ->setImageURI($handle->getImageURI()) 75 + ->addAttribute($handle->getSubtitle()); 76 + 77 + if ($user->getIsAdmin()) { 78 + $result->addAttribute( 79 + array( 80 + id(new PHUIIconView())->setIcon('fa-star'), 81 + ' ', 82 + pht('Administrator'), 83 + )); 84 + } 85 + 79 86 if ($user->getIsAdmin()) { 80 87 $display_type = pht('Administrator'); 88 + } else { 89 + $display_type = pht('User'); 81 90 } 82 91 $result->setDisplayType($display_type); 83 - $result->setImageURI($handles[$user->getPHID()]->getImageURI()); 84 92 } 85 93 86 94 $results[] = $result;
+2 -1
src/applications/people/typeahead/PhabricatorPeopleNoOwnerDatasource.php
··· 69 69 ->setDisplayName($name) 70 70 ->setIcon('fa-ban') 71 71 ->setPHID('none()') 72 - ->setUnique(true); 72 + ->setUnique(true) 73 + ->addAttribute(pht('Select results with no owner.')); 73 74 } 74 75 75 76 }
+2 -1
src/applications/people/typeahead/PhabricatorViewerDatasource.php
··· 74 74 ->setName(pht('Current Viewer')) 75 75 ->setPHID('viewer()') 76 76 ->setIcon('fa-user') 77 - ->setUnique(true); 77 + ->setUnique(true) 78 + ->addAttribute(pht('Select current viewer.')); 78 79 } 79 80 80 81 }
+28 -2
src/applications/project/typeahead/PhabricatorProjectDatasource.php
··· 55 55 $has_cols = array_fill_keys(array_keys($projs), true); 56 56 } 57 57 58 + $is_browse = $this->getIsBrowse(); 59 + if ($is_browse && $projs) { 60 + // TODO: This is a little ad-hoc, but we don't currently have 61 + // infrastructure for bulk querying custom fields efficiently. 62 + $table = new PhabricatorProjectCustomFieldStorage(); 63 + $descriptions = $table->loadAllWhere( 64 + 'objectPHID IN (%Ls) AND fieldIndex = %s', 65 + array_keys($projs), 66 + PhabricatorHash::digestForIndex('std:project:internal:description')); 67 + $descriptions = mpull($descriptions, 'getFieldValue', 'getObjectPHID'); 68 + } else { 69 + $descriptions = array(); 70 + } 71 + 58 72 $results = array(); 59 73 foreach ($projs as $proj) { 60 - if (!isset($has_cols[$proj->getPHID()])) { 74 + $phid = $proj->getPHID(); 75 + 76 + if (!isset($has_cols[$phid])) { 61 77 continue; 62 78 } 63 79 ··· 99 115 ->setDisplayName($proj->getDisplayName()) 100 116 ->setDisplayType($proj->getDisplayIconName()) 101 117 ->setURI($proj->getURI()) 102 - ->setPHID($proj->getPHID()) 118 + ->setPHID($phid) 103 119 ->setIcon($proj->getDisplayIconIcon()) 104 120 ->setColor($proj->getColor()) 105 121 ->setPriorityType('proj') ··· 110 126 } 111 127 112 128 $proj_result->setImageURI($proj->getProfileImageURI()); 129 + 130 + if ($is_browse) { 131 + $proj_result->addAttribute($proj->getDisplayIconName()); 132 + 133 + $description = idx($descriptions, $phid); 134 + if (strlen($description)) { 135 + $summary = PhabricatorMarkupEngine::summarize($description); 136 + $proj_result->addAttribute($summary); 137 + } 138 + } 113 139 114 140 $results[] = $proj_result; 115 141 }
+7 -3
src/applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php
··· 86 86 $result 87 87 ->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION) 88 88 ->setIcon('fa-asterisk') 89 - ->setColor(null); 89 + ->setColor(null) 90 + ->resetAttributes() 91 + ->addAttribute(pht('Function')); 90 92 91 93 if ($return_any) { 92 94 $return[] = id(clone $result) 93 95 ->setPHID('any('.$result->getPHID().')') 94 96 ->setDisplayName(pht('In Any: %s', $result->getDisplayName())) 95 - ->setName('any '.$result->getName()); 97 + ->setName('any '.$result->getName()) 98 + ->addAttribute(pht('Include results tagged with this project.')); 96 99 } 97 100 98 101 if ($return_not) { 99 102 $return[] = id(clone $result) 100 103 ->setPHID('not('.$result->getPHID().')') 101 104 ->setDisplayName(pht('Not In: %s', $result->getDisplayName())) 102 - ->setName('not '.$result->getName()); 105 + ->setName('not '.$result->getName()) 106 + ->addAttribute(pht('Exclude results tagged with this project.')); 103 107 } 104 108 } 105 109
+2 -1
src/applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php
··· 96 96 ->setName(pht('Current Viewer\'s Projects')) 97 97 ->setPHID('viewerprojects()') 98 98 ->setIcon('fa-asterisk') 99 - ->setUnique(true); 99 + ->setUnique(true) 100 + ->addAttribute(pht('Select projects current viewer is a member of.')); 100 101 } 101 102 102 103 }
+4 -1
src/applications/project/typeahead/PhabricatorProjectMembersDatasource.php
··· 44 44 ->setColor(null) 45 45 ->setPHID('members('.$result->getPHID().')') 46 46 ->setDisplayName(pht('Members: %s', $result->getDisplayName())) 47 - ->setName($result->getName().' members'); 47 + ->setName($result->getName().' members') 48 + ->resetAttributes() 49 + ->addAttribute(pht('Function')) 50 + ->addAttribute(pht('Select project members.')); 48 51 } 49 52 50 53 return $results;
+2 -1
src/applications/project/typeahead/PhabricatorProjectNoProjectsDatasource.php
··· 68 68 ->setPHID('null()') 69 69 ->setIcon('fa-ban') 70 70 ->setName('null '.$name) 71 - ->setDisplayName($name); 71 + ->setDisplayName($name) 72 + ->addAttribute(pht('Select results with no tags.')); 72 73 } 73 74 74 75 }
+10 -2
src/applications/search/typeahead/PhabricatorSearchDatasource.php
··· 16 16 } 17 17 18 18 public function getComponentDatasources() { 19 - return array( 20 - id(new PhabricatorPeopleDatasource())->setEnrichResults(true), 19 + $sources = array( 20 + new PhabricatorPeopleDatasource(), 21 21 new PhabricatorProjectDatasource(), 22 22 new PhabricatorApplicationDatasource(), 23 23 new PhabricatorTypeaheadMonogramDatasource(), 24 24 new DiffusionRepositoryDatasource(), 25 25 new DiffusionSymbolDatasource(), 26 26 ); 27 + 28 + // These results are always rendered in the full browse display mode, so 29 + // set the browse flag on all component sources. 30 + foreach ($sources as $source) { 31 + $source->setIsBrowse(true); 32 + } 33 + 34 + return $sources; 27 35 } 28 36 29 37 }
+56 -4
src/applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php
··· 65 65 } 66 66 67 67 $composite 68 - ->setOffset($offset); 68 + ->setOffset($offset) 69 + ->setIsBrowse(true); 69 70 } 70 71 71 72 $results = $composite->loadResults(); ··· 142 143 143 144 $items = array(); 144 145 foreach ($results as $result) { 145 - $token = PhabricatorTypeaheadTokenView::newFromTypeaheadResult( 146 - $result); 146 + $information = $this->renderBrowseResult($result); 147 147 148 148 // Disable already-selected tokens. 149 149 $disabled = isset($exclude[$result->getPHID()]); ··· 167 167 'class' => 'typeahead-browse-item grouped', 168 168 ), 169 169 array( 170 - $token, 171 170 $button, 171 + $information, 172 172 )); 173 173 } 174 174 ··· 348 348 return $this->newPage() 349 349 ->setTitle($title) 350 350 ->appendChild($view); 351 + } 352 + 353 + private function renderBrowseResult(PhabricatorTypeaheadResult $result) { 354 + $class = array(); 355 + $style = array(); 356 + $separator = " \xC2\xB7 "; 357 + 358 + $class[] = 'phabricator-main-search-typeahead-result'; 359 + 360 + $name = phutil_tag( 361 + 'div', 362 + array( 363 + 'class' => 'result-name', 364 + ), 365 + $result->getDisplayName()); 366 + 367 + $icon = $result->getIcon(); 368 + $icon = id(new PHUIIconView())->setIcon($icon); 369 + 370 + $attributes = $result->getAttributes(); 371 + $attributes = phutil_implode_html($separator, $attributes); 372 + $attributes = array($icon, ' ', $attributes); 373 + 374 + $closed = $result->getClosed(); 375 + if ($closed) { 376 + $class[] = 'result-closed'; 377 + $attributes = array($closed, $separator, $attributes); 378 + } 379 + 380 + $attributes = phutil_tag( 381 + 'div', 382 + array( 383 + 'class' => 'result-type', 384 + ), 385 + $attributes); 386 + 387 + $image = $result->getImageURI(); 388 + if ($image) { 389 + $style[] = 'background-image: url('.$image.');'; 390 + $class[] = 'has-image'; 391 + } 392 + 393 + return phutil_tag( 394 + 'div', 395 + array( 396 + 'class' => implode(' ', $class), 397 + 'style' => implode(' ', $style), 398 + ), 399 + array( 400 + $name, 401 + $attributes, 402 + )); 351 403 } 352 404 353 405 }
+5
src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php
··· 37 37 } 38 38 39 39 $stack = $this->getFunctionStack(); 40 + $is_browse = $this->getIsBrowse(); 40 41 41 42 $results = array(); 42 43 foreach ($this->getUsableDatasources() as $source) { ··· 68 69 69 70 if ($limit) { 70 71 $source->setLimit($offset + $limit); 72 + } 73 + 74 + if ($is_browse) { 75 + $source->setIsBrowse(true); 71 76 } 72 77 73 78 $source_results = $source->loadResults();
+12 -1
src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
··· 12 12 private $limit; 13 13 private $parameters = array(); 14 14 private $functionStack = array(); 15 + private $isBrowse; 15 16 16 17 public function setLimit($limit) { 17 18 $this->limit = $limit; ··· 69 70 70 71 public function getParameter($name, $default = null) { 71 72 return idx($this->parameters, $name, $default); 73 + } 74 + 75 + public function setIsBrowse($is_browse) { 76 + $this->isBrowse = $is_browse; 77 + return $this; 78 + } 79 + 80 + public function getIsBrowse() { 81 + return $this->isBrowse; 72 82 } 73 83 74 84 public function getDatasourceURI() { ··· 199 209 protected function newFunctionResult() { 200 210 return id(new PhabricatorTypeaheadResult()) 201 211 ->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION) 202 - ->setIcon('fa-asterisk'); 212 + ->setIcon('fa-asterisk') 213 + ->addAttribute(pht('Function')); 203 214 } 204 215 205 216 public function newInvalidToken($name) {
+23
src/applications/typeahead/storage/PhabricatorTypeaheadResult.php
··· 17 17 private $tokenType; 18 18 private $unique; 19 19 private $autocomplete; 20 + private $attributes = array(); 20 21 21 22 public function setIcon($icon) { 22 23 $this->icon = $icon; ··· 186 187 } 187 188 188 189 return null; 190 + } 191 + 192 + public function getImageURI() { 193 + return $this->imageURI; 194 + } 195 + 196 + public function getClosed() { 197 + return $this->closed; 198 + } 199 + 200 + public function resetAttributes() { 201 + $this->attributes = array(); 202 + return $this; 203 + } 204 + 205 + public function getAttributes() { 206 + return $this->attributes; 207 + } 208 + 209 + public function addAttribute($attribute) { 210 + $this->attributes[] = $attribute; 211 + return $this; 189 212 } 190 213 191 214 }
+17 -1
webroot/rsrc/css/aphront/typeahead-browse.css
··· 57 57 58 58 .typeahead-browse-item button { 59 59 float: right; 60 - margin: 2px 6px; 60 + margin: 8px 6px 0; 61 61 } 62 62 63 63 .typeahead-browse-item a.jx-tokenizer-token { 64 64 margin-top: 1px; 65 65 margin-left: 6px; 66 66 } 67 + 68 + .typeahead-browse-item .phabricator-main-search-typeahead-result { 69 + margin: 2px 0; 70 + padding: 0 8px; 71 + } 72 + 73 + .typeahead-browse-item .phabricator-main-search-typeahead-result.has-image { 74 + padding-left: 48px; 75 + } 76 + 77 + .typeahead-browse-item 78 + .phabricator-main-search-typeahead-result.result-closed 79 + .result-name { 80 + text-decoration: line-through; 81 + color: {$lightgreytext}; 82 + }