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

Modernize "owner" typeahead datasource

Summary: Ref T4420. This one is users plus "upforgrabs". I renamed that to "none" and gave it a special visual style to make it more discoverable. Future diffs will improve this.

Test Plan:
- Used it in global search.
- Used it in batch editor.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T4420

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

+60 -214
+4 -2
src/__phutil_library_map__.php
··· 2333 2333 'PhabricatorTranslationsConfigOptions' => 'applications/config/option/PhabricatorTranslationsConfigOptions.php', 2334 2334 'PhabricatorTrivialTestCase' => 'infrastructure/testing/__tests__/PhabricatorTrivialTestCase.php', 2335 2335 'PhabricatorTwoColumnExample' => 'applications/uiexample/examples/PhabricatorTwoColumnExample.php', 2336 - 'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadCommonDatasourceController.php', 2337 2336 'PhabricatorTypeaheadCompositeDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php', 2338 2337 'PhabricatorTypeaheadDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php', 2339 2338 'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadDatasourceController.php', 2340 2339 'PhabricatorTypeaheadModularDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php', 2341 2340 'PhabricatorTypeaheadMonogramDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadMonogramDatasource.php', 2341 + 'PhabricatorTypeaheadNoOwnerDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadNoOwnerDatasource.php', 2342 + 'PhabricatorTypeaheadOwnerDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadOwnerDatasource.php', 2342 2343 'PhabricatorTypeaheadResult' => 'applications/typeahead/storage/PhabricatorTypeaheadResult.php', 2343 2344 'PhabricatorTypeaheadRuntimeCompositeDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadRuntimeCompositeDatasource.php', 2344 2345 'PhabricatorUIConfigOptions' => 'applications/config/option/PhabricatorUIConfigOptions.php', ··· 5173 5174 'PhabricatorTranslationsConfigOptions' => 'PhabricatorApplicationConfigOptions', 5174 5175 'PhabricatorTrivialTestCase' => 'PhabricatorTestCase', 5175 5176 'PhabricatorTwoColumnExample' => 'PhabricatorUIExample', 5176 - 'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController', 5177 5177 'PhabricatorTypeaheadCompositeDatasource' => 'PhabricatorTypeaheadDatasource', 5178 5178 'PhabricatorTypeaheadDatasource' => 'Phobject', 5179 5179 'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController', 5180 5180 'PhabricatorTypeaheadModularDatasourceController' => 'PhabricatorTypeaheadDatasourceController', 5181 5181 'PhabricatorTypeaheadMonogramDatasource' => 'PhabricatorTypeaheadDatasource', 5182 + 'PhabricatorTypeaheadNoOwnerDatasource' => 'PhabricatorTypeaheadDatasource', 5183 + 'PhabricatorTypeaheadOwnerDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 5182 5184 'PhabricatorTypeaheadRuntimeCompositeDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 5183 5185 'PhabricatorUIConfigOptions' => 'PhabricatorApplicationConfigOptions', 5184 5186 'PhabricatorUIExampleRenderController' => 'PhabricatorController',
+3 -3
src/applications/maniphest/controller/ManiphestBatchEditController.php
··· 63 63 64 64 $projects_source = new PhabricatorProjectDatasource(); 65 65 $mailable_source = new PhabricatorMetaMTAMailableDatasource(); 66 + $owner_source = new PhabricatorTypeaheadOwnerDatasource(); 66 67 67 68 require_celerity_resource('maniphest-batch-editor'); 68 69 Javelin::initBehavior( ··· 76 77 'placeholder' => $projects_source->getPlaceholderText(), 77 78 ), 78 79 'owner' => array( 79 - 'src' => '/typeahead/common/searchowner/', 80 - 'placeholder' => pht( 81 - 'Type a user name or "upforgrabs" to unassign...'), 80 + 'src' => $owner_source->getDatasourceURI(), 81 + 'placeholder' => $owner_source->getPlaceholderText(), 82 82 'limit' => 1, 83 83 ), 84 84 'cc' => array(
+1 -1
src/applications/search/query/PhabricatorSearchApplicationSearchEngine.php
··· 142 142 id(new AphrontFormTokenizerControl()) 143 143 ->setName('ownerPHIDs') 144 144 ->setLabel('Owners') 145 - ->setDatasource('/typeahead/common/searchowner/') 145 + ->setDatasource(new PhabricatorTypeaheadOwnerDatasource()) 146 146 ->setValue($owner_handles)) 147 147 ->appendChild( 148 148 id(new AphrontFormCheckboxControl())
-2
src/applications/typeahead/application/PhabricatorApplicationTypeahead.php
··· 5 5 public function getRoutes() { 6 6 return array( 7 7 '/typeahead/' => array( 8 - 'common/(?P<type>\w+)/' 9 - => 'PhabricatorTypeaheadCommonDatasourceController', 10 8 'class/(?:(?P<class>\w+)/)?' 11 9 => 'PhabricatorTypeaheadModularDatasourceController', 12 10 ),
-179
src/applications/typeahead/controller/PhabricatorTypeaheadCommonDatasourceController.php
··· 1 - <?php 2 - 3 - final class PhabricatorTypeaheadCommonDatasourceController 4 - extends PhabricatorTypeaheadDatasourceController { 5 - 6 - private $type; 7 - 8 - public function shouldAllowPublic() { 9 - return true; 10 - } 11 - 12 - public function willProcessRequest(array $data) { 13 - $this->type = $data['type']; 14 - } 15 - 16 - public function processRequest() { 17 - $request = $this->getRequest(); 18 - $viewer = $request->getUser(); 19 - $query = $request->getStr('q'); 20 - $raw_query = $request->getStr('raw'); 21 - 22 - $need_users = false; 23 - $need_upforgrabs = false; 24 - $need_rich_data = false; 25 - switch ($this->type) { 26 - case 'searchowner': 27 - $need_users = true; 28 - $need_upforgrabs = true; 29 - break; 30 - } 31 - 32 - $results = array(); 33 - 34 - if ($need_upforgrabs) { 35 - $results[] = id(new PhabricatorTypeaheadResult()) 36 - ->setName('upforgrabs (Up For Grabs)') 37 - ->setPHID(ManiphestTaskOwner::OWNER_UP_FOR_GRABS); 38 - } 39 - 40 - if ($need_users) { 41 - $columns = array( 42 - 'isSystemAgent', 43 - 'isAdmin', 44 - 'isDisabled', 45 - 'userName', 46 - 'realName', 47 - 'phid'); 48 - 49 - if ($query) { 50 - // This is an arbitrary limit which is just larger than any limit we 51 - // actually use in the application. 52 - 53 - // TODO: The datasource should pass this in the query. 54 - $limit = 15; 55 - 56 - $user_table = new PhabricatorUser(); 57 - $conn_r = $user_table->establishConnection('r'); 58 - $ids = queryfx_all( 59 - $conn_r, 60 - 'SELECT id FROM %T WHERE username LIKE %> 61 - ORDER BY username ASC LIMIT %d', 62 - $user_table->getTableName(), 63 - $query, 64 - $limit); 65 - $ids = ipull($ids, 'id'); 66 - 67 - if (count($ids) < $limit) { 68 - // If we didn't find enough username hits, look for real name hits. 69 - // We need to pull the entire pagesize so that we end up with the 70 - // right number of items if this query returns many duplicate IDs 71 - // that we've already selected. 72 - 73 - $realname_ids = queryfx_all( 74 - $conn_r, 75 - 'SELECT DISTINCT userID FROM %T WHERE token LIKE %> 76 - ORDER BY token ASC LIMIT %d', 77 - PhabricatorUser::NAMETOKEN_TABLE, 78 - $query, 79 - $limit); 80 - $realname_ids = ipull($realname_ids, 'userID'); 81 - $ids = array_merge($ids, $realname_ids); 82 - 83 - $ids = array_unique($ids); 84 - $ids = array_slice($ids, 0, $limit); 85 - } 86 - 87 - // Always add the logged-in user because some tokenizers autosort them 88 - // first. They'll be filtered out on the client side if they don't 89 - // match the query. 90 - $ids[] = $request->getUser()->getID(); 91 - 92 - if ($ids) { 93 - $users = id(new PhabricatorUser())->loadColumnsWhere( 94 - $columns, 95 - 'id IN (%Ld)', 96 - $ids); 97 - } else { 98 - $users = array(); 99 - } 100 - } else { 101 - $users = id(new PhabricatorUser())->loadColumns($columns); 102 - } 103 - 104 - if ($need_rich_data) { 105 - $phids = mpull($users, 'getPHID'); 106 - $handles = $this->loadViewerHandles($phids); 107 - } 108 - 109 - foreach ($users as $user) { 110 - $closed = null; 111 - if ($user->getIsDisabled()) { 112 - $closed = pht('Disabled'); 113 - } else if ($user->getIsSystemAgent()) { 114 - $closed = pht('Bot/Script'); 115 - } 116 - 117 - $result = id(new PhabricatorTypeaheadResult()) 118 - ->setName($user->getFullName()) 119 - ->setURI('/p/'.$user->getUsername()) 120 - ->setPHID($user->getPHID()) 121 - ->setPriorityString($user->getUsername()) 122 - ->setIcon('fa-user bluegrey') 123 - ->setPriorityType('user') 124 - ->setClosed($closed); 125 - 126 - if ($need_rich_data) { 127 - $display_type = 'User'; 128 - if ($user->getIsAdmin()) { 129 - $display_type = 'Administrator'; 130 - } 131 - $result->setDisplayType($display_type); 132 - $result->setImageURI($handles[$user->getPHID()]->getImageURI()); 133 - } 134 - $results[] = $result; 135 - } 136 - } 137 - 138 - $content = mpull($results, 'getWireFormat'); 139 - 140 - if ($request->isAjax()) { 141 - return id(new AphrontAjaxResponse())->setContent($content); 142 - } 143 - 144 - // If there's a non-Ajax request to this endpoint, show results in a tabular 145 - // format to make it easier to debug typeahead output. 146 - 147 - $rows = array(); 148 - foreach ($results as $result) { 149 - $wire = $result->getWireFormat(); 150 - $rows[] = $wire; 151 - } 152 - 153 - $table = new AphrontTableView($rows); 154 - $table->setHeaders( 155 - array( 156 - 'Name', 157 - 'URI', 158 - 'PHID', 159 - 'Priority', 160 - 'Display Name', 161 - 'Display Type', 162 - 'Image URI', 163 - 'Priority Type', 164 - 'Sprite Class', 165 - )); 166 - 167 - $panel = new AphrontPanelView(); 168 - $panel->setHeader('Typeahead Results'); 169 - $panel->appendChild($table); 170 - 171 - return $this->buildStandardPageResponse( 172 - $panel, 173 - array( 174 - 'title' => pht('Typeahead Results'), 175 - 'device' => true 176 - )); 177 - } 178 - 179 - }
+28
src/applications/typeahead/datasource/PhabricatorTypeaheadNoOwnerDatasource.php
··· 1 + <?php 2 + 3 + final class PhabricatorTypeaheadNoOwnerDatasource 4 + extends PhabricatorTypeaheadDatasource { 5 + 6 + public function getPlaceholderText() { 7 + return pht('Type "none"...'); 8 + } 9 + 10 + public function getDatasourceApplicationClass() { 11 + return null; 12 + } 13 + 14 + public function loadResults() { 15 + $viewer = $this->getViewer(); 16 + $raw_query = $this->getRawQuery(); 17 + 18 + $results = array(); 19 + 20 + $results[] = id(new PhabricatorTypeaheadResult()) 21 + ->setName(pht('None')) 22 + ->setIcon('fa-ban orange') 23 + ->setPHID(ManiphestTaskOwner::OWNER_UP_FOR_GRABS); 24 + 25 + return $results; 26 + } 27 + 28 + }
+17
src/applications/typeahead/datasource/PhabricatorTypeaheadOwnerDatasource.php
··· 1 + <?php 2 + 3 + final class PhabricatorTypeaheadOwnerDatasource 4 + extends PhabricatorTypeaheadCompositeDatasource { 5 + 6 + public function getPlaceholderText() { 7 + return pht('Type a user name or "none"...'); 8 + } 9 + 10 + public function getComponentDatasources() { 11 + return array( 12 + new PhabricatorPeopleDatasource(), 13 + new PhabricatorTypeaheadNoOwnerDatasource(), 14 + ); 15 + } 16 + 17 + }
+7 -27
src/view/form/control/AphrontFormTokenizerControl.php
··· 7 7 private $limit; 8 8 private $placeholder; 9 9 10 - public function setDatasource($datasource) { 10 + public function setDatasource(PhabricatorTypeaheadDatasource $datasource) { 11 11 $this->datasource = $datasource; 12 12 return $this; 13 13 } ··· 43 43 $id = celerity_generate_unique_node_id(); 44 44 } 45 45 46 + $placeholder = null; 46 47 if (!strlen($this->placeholder)) { 47 - $placeholder = $this->getDefaultPlaceholder(); 48 + if ($this->datasource) { 49 + $placeholder = $this->datasource->getPlaceholderText(); 50 + } 48 51 } else { 49 52 $placeholder = $this->placeholder; 50 53 } ··· 59 62 $username = $this->user->getUsername(); 60 63 } 61 64 62 - if ($this->datasource instanceof PhabricatorTypeaheadDatasource) { 65 + $datasource_uri = null; 66 + if ($this->datasource) { 63 67 $datasource_uri = $this->datasource->getDatasourceURI(); 64 - } else { 65 - $datasource_uri = $this->datasource; 66 68 } 67 69 68 70 if (!$this->disableBehavior) { ··· 79 81 80 82 return $template->render(); 81 83 } 82 - 83 - private function getDefaultPlaceholder() { 84 - $datasource = $this->datasource; 85 - 86 - if ($datasource instanceof PhabricatorTypeaheadDatasource) { 87 - return $datasource->getPlaceholderText(); 88 - } 89 - 90 - $matches = null; 91 - if (!preg_match('@^/typeahead/common/(.*)/$@', $datasource, $matches)) { 92 - return null; 93 - } 94 - 95 - $request = $matches[1]; 96 - 97 - $map = array( 98 - 'searchowner' => pht('Type a user name...'), 99 - ); 100 - 101 - return idx($map, $request); 102 - } 103 - 104 84 105 85 }