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

Show user availability dots (red = away, orange = busy) in typeaheads, tokenizer tokens, and autocompletes

Summary:
Ref T13249. See PHI810. We currently show availability dots in some interfaces (timeline, mentions) but not others (typeheads/tokenizers).

They're potentially quite useful in tokenizers, e.g. when assigning tasks to someone or requesting reviews. Show them in more places.

(The actual rendering here isn't terribly clean, and it would be great to try to unify all these various behaviors some day.)

Test Plan:
{F6212044}

{F6212045}

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13249

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

+141 -40
+26 -26
resources/celerity/map.php
··· 9 9 'names' => array( 10 10 'conpherence.pkg.css' => '3c8a0668', 11 11 'conpherence.pkg.js' => '020aebcf', 12 - 'core.pkg.css' => 'f2319e1f', 13 - 'core.pkg.js' => '5c737607', 12 + 'core.pkg.css' => '261ee8cf', 13 + 'core.pkg.js' => '5ace8a1e', 14 14 'differential.pkg.css' => 'b8df73d4', 15 15 'differential.pkg.js' => '67c9ea4c', 16 16 'diffusion.pkg.css' => '42c75c37', ··· 172 172 'rsrc/css/phui/phui-segment-bar-view.css' => '5166b370', 173 173 'rsrc/css/phui/phui-spacing.css' => 'b05cadc3', 174 174 'rsrc/css/phui/phui-status.css' => 'e5ff8be0', 175 - 'rsrc/css/phui/phui-tag-view.css' => 'a42fe34f', 175 + 'rsrc/css/phui/phui-tag-view.css' => '29409667', 176 176 'rsrc/css/phui/phui-timeline-view.css' => '1e348e4b', 177 177 'rsrc/css/phui/phui-two-column-view.css' => '01e6991e', 178 178 'rsrc/css/phui/workboards/phui-workboard-color.css' => 'e86de308', ··· 441 441 'rsrc/js/core/KeyboardShortcutManager.js' => '37b8a04a', 442 442 'rsrc/js/core/MultirowRowManager.js' => '5b54c823', 443 443 'rsrc/js/core/Notification.js' => 'a9b91e3f', 444 - 'rsrc/js/core/Prefab.js' => 'bf457520', 444 + 'rsrc/js/core/Prefab.js' => '5793d835', 445 445 'rsrc/js/core/ShapedRequest.js' => 'abf88db8', 446 446 'rsrc/js/core/TextAreaUtils.js' => 'f340a484', 447 447 'rsrc/js/core/Title.js' => '43bc9360', ··· 505 505 'rsrc/js/phui/behavior-phui-timer-control.js' => 'f84bcbf4', 506 506 'rsrc/js/phuix/PHUIXActionListView.js' => 'c68f183f', 507 507 'rsrc/js/phuix/PHUIXActionView.js' => 'aaa08f3b', 508 - 'rsrc/js/phuix/PHUIXAutocomplete.js' => '58cc4ab8', 508 + 'rsrc/js/phuix/PHUIXAutocomplete.js' => '8f139ef0', 509 509 'rsrc/js/phuix/PHUIXButtonView.js' => '55a24e84', 510 510 'rsrc/js/phuix/PHUIXDropdownMenu.js' => 'bdce4d78', 511 511 'rsrc/js/phuix/PHUIXExample.js' => 'c2c500a7', ··· 771 771 'phabricator-notification-menu-css' => 'e6962e89', 772 772 'phabricator-object-selector-css' => 'ee77366f', 773 773 'phabricator-phtize' => '2f1db1ed', 774 - 'phabricator-prefab' => 'bf457520', 774 + 'phabricator-prefab' => '5793d835', 775 775 'phabricator-remarkup-css' => '9e627d41', 776 776 'phabricator-search-results-css' => '9ea70ace', 777 777 'phabricator-shaped-request' => 'abf88db8', ··· 847 847 'phui-segment-bar-view-css' => '5166b370', 848 848 'phui-spacing-css' => 'b05cadc3', 849 849 'phui-status-list-view-css' => 'e5ff8be0', 850 - 'phui-tag-view-css' => 'a42fe34f', 850 + 'phui-tag-view-css' => '29409667', 851 851 'phui-theme-css' => '35883b37', 852 852 'phui-timeline-view-css' => '1e348e4b', 853 853 'phui-two-column-view-css' => '01e6991e', ··· 857 857 'phui-workpanel-view-css' => 'bd546a49', 858 858 'phuix-action-list-view' => 'c68f183f', 859 859 'phuix-action-view' => 'aaa08f3b', 860 - 'phuix-autocomplete' => '58cc4ab8', 860 + 'phuix-autocomplete' => '8f139ef0', 861 861 'phuix-button-view' => '55a24e84', 862 862 'phuix-dropdown-menu' => 'bdce4d78', 863 863 'phuix-form-control-view' => '38c1f3fb', ··· 1354 1354 'javelin-stratcom', 1355 1355 'javelin-dom', 1356 1356 ), 1357 + '5793d835' => array( 1358 + 'javelin-install', 1359 + 'javelin-util', 1360 + 'javelin-dom', 1361 + 'javelin-typeahead', 1362 + 'javelin-tokenizer', 1363 + 'javelin-typeahead-preloaded-source', 1364 + 'javelin-typeahead-ondemand-source', 1365 + 'javelin-dom', 1366 + 'javelin-stratcom', 1367 + 'javelin-util', 1368 + ), 1357 1369 '5803b9e7' => array( 1358 1370 'javelin-behavior', 1359 1371 'javelin-util', ··· 1361 1373 'javelin-stratcom', 1362 1374 'javelin-vector', 1363 1375 'javelin-typeahead-static-source', 1364 - ), 1365 - '58cc4ab8' => array( 1366 - 'javelin-install', 1367 - 'javelin-dom', 1368 - 'phuix-icon-view', 1369 - 'phabricator-prefab', 1370 1376 ), 1371 1377 '5902260c' => array( 1372 1378 'javelin-util', ··· 1607 1613 ), 1608 1614 '8e2d9a28' => array( 1609 1615 'phui-theme-css', 1616 + ), 1617 + '8f139ef0' => array( 1618 + 'javelin-install', 1619 + 'javelin-dom', 1620 + 'phuix-icon-view', 1621 + 'phabricator-prefab', 1610 1622 ), 1611 1623 '8f959ad0' => array( 1612 1624 'javelin-behavior', ··· 1894 1906 'javelin-dom', 1895 1907 'javelin-vector', 1896 1908 'javelin-stratcom', 1897 - ), 1898 - 'bf457520' => array( 1899 - 'javelin-install', 1900 - 'javelin-util', 1901 - 'javelin-dom', 1902 - 'javelin-typeahead', 1903 - 'javelin-tokenizer', 1904 - 'javelin-typeahead-preloaded-source', 1905 - 'javelin-typeahead-ondemand-source', 1906 - 'javelin-dom', 1907 - 'javelin-stratcom', 1908 - 'javelin-util', 1909 1909 ), 1910 1910 'c03f2fb4' => array( 1911 1911 'javelin-install',
+10 -1
src/applications/people/typeahead/PhabricatorPeopleDatasource.php
··· 19 19 $viewer = $this->getViewer(); 20 20 21 21 $query = id(new PhabricatorPeopleQuery()) 22 - ->setOrderVector(array('username')); 22 + ->setOrderVector(array('username')) 23 + ->needAvailability(true); 23 24 24 25 if ($this->getPhase() == self::PHASE_PREFIX) { 25 26 $prefix = $this->getPrefixQuery(); ··· 94 95 $display_type = pht('User'); 95 96 } 96 97 $result->setDisplayType($display_type); 98 + } 99 + 100 + $until = $user->getAwayUntil(); 101 + if ($until) { 102 + $availability = $user->getDisplayAvailability(); 103 + $color = PhabricatorCalendarEventInvitee::getAvailabilityColor( 104 + $availability); 105 + $result->setAvailabilityColor($color); 97 106 } 98 107 99 108 $results[] = $result;
+11
src/applications/typeahead/storage/PhabricatorTypeaheadResult.php
··· 19 19 private $autocomplete; 20 20 private $attributes = array(); 21 21 private $phase; 22 + private $availabilityColor; 22 23 23 24 public function setIcon($icon) { 24 25 $this->icon = $icon; ··· 156 157 $this->unique ? 1 : null, 157 158 $this->autocomplete, 158 159 $this->phase, 160 + $this->availabilityColor, 159 161 ); 160 162 while (end($data) === null) { 161 163 array_pop($data); ··· 220 222 221 223 public function getPhase() { 222 224 return $this->phase; 225 + } 226 + 227 + public function setAvailabilityColor($availability_color) { 228 + $this->availabilityColor = $availability_color; 229 + return $this; 230 + } 231 + 232 + public function getAvailabilityColor() { 233 + return $this->availabilityColor; 223 234 } 224 235 225 236 }
+46 -9
src/applications/typeahead/view/PhabricatorTypeaheadTokenView.php
··· 14 14 private $inputName; 15 15 private $value; 16 16 private $tokenType = self::TYPE_OBJECT; 17 + private $availabilityColor; 17 18 18 19 public static function newFromTypeaheadResult( 19 20 PhabricatorTypeaheadResult $result) { ··· 41 42 $token->setColor($handle->getTagColor()); 42 43 } 43 44 45 + $availability = $handle->getAvailability(); 46 + $color = null; 47 + switch ($availability) { 48 + case PhabricatorObjectHandle::AVAILABILITY_PARTIAL: 49 + $color = PHUITagView::COLOR_ORANGE; 50 + break; 51 + case PhabricatorObjectHandle::AVAILABILITY_NONE: 52 + $color = PHUITagView::COLOR_RED; 53 + break; 54 + } 55 + 56 + if ($color !== null) { 57 + $token->setAvailabilityColor($color); 58 + } 59 + 44 60 return $token; 45 61 } 46 62 ··· 106 122 return 'a'; 107 123 } 108 124 125 + public function setAvailabilityColor($availability_color) { 126 + $this->availabilityColor = $availability_color; 127 + return $this; 128 + } 129 + 130 + public function getAvailabilityColor() { 131 + return $this->availabilityColor; 132 + } 133 + 109 134 protected function getTagAttributes() { 110 135 $classes = array(); 111 136 $classes[] = 'jx-tokenizer-token'; ··· 139 164 140 165 $value = $this->getValue(); 141 166 167 + $availability = null; 168 + $availability_color = $this->getAvailabilityColor(); 169 + if ($availability_color) { 170 + $availability = phutil_tag( 171 + 'span', 172 + array( 173 + 'class' => 'phui-tag-dot phui-tag-color-'.$availability_color, 174 + )); 175 + } 176 + 177 + $icon_view = null; 142 178 $icon = $this->getIcon(); 143 179 if ($icon) { 144 - $value = array( 145 - phutil_tag( 146 - 'span', 147 - array( 148 - 'class' => 'phui-icon-view phui-font-fa '.$icon, 149 - )), 150 - $value, 151 - ); 180 + $icon_view = phutil_tag( 181 + 'span', 182 + array( 183 + 'class' => 'phui-icon-view phui-font-fa '.$icon, 184 + )); 152 185 } 153 186 154 187 return array( 155 - $value, 188 + array( 189 + $icon_view, 190 + $availability, 191 + $value, 192 + ), 156 193 phutil_tag( 157 194 'input', 158 195 array(
+4
src/view/form/control/AphrontFormTokenizerControl.php
··· 108 108 'icons' => mpull($tokens, 'getIcon', 'getKey'), 109 109 'types' => mpull($tokens, 'getTokenType', 'getKey'), 110 110 'colors' => mpull($tokens, 'getColor', 'getKey'), 111 + 'availabilityColors' => mpull( 112 + $tokens, 113 + 'getAvailabilityColor', 114 + 'getKey'), 111 115 'limit' => $this->limit, 112 116 'username' => $username, 113 117 'placeholder' => $placeholder,
+8
webroot/rsrc/css/phui/phui-tag-view.css
··· 54 54 border: 1px solid transparent; 55 55 } 56 56 57 + .tokenizer-result .phui-tag-dot { 58 + margin-right: 6px; 59 + } 60 + 61 + .jx-tokenizer-token .phui-tag-dot { 62 + margin-left: 2px; 63 + } 64 + 57 65 .phui-tag-type-state { 58 66 color: #ffffff; 59 67 text-shadow: rgba(100, 100, 100, 0.40) 0px -1px 1px;
+26 -3
webroot/rsrc/js/core/Prefab.js
··· 125 125 var icon; 126 126 var type; 127 127 var color; 128 + var availability_color; 128 129 if (result) { 129 130 icon = result.icon; 130 131 value = result.displayName; 131 132 type = result.tokenType; 132 133 color = result.color; 134 + availability_color = result.availabilityColor; 133 135 } else { 134 136 icon = (config.icons || {})[key]; 135 137 type = (config.types || {})[key]; 136 138 color = (config.colors || {})[key]; 139 + availability_color = (config.availabilityColors || {})[key]; 137 140 } 138 141 139 142 if (icon) { ··· 147 150 JX.DOM.alterClass(container, color, true); 148 151 } 149 152 150 - return [icon, value]; 153 + var dot; 154 + if (availability_color) { 155 + dot = JX.$N( 156 + 'span', 157 + { 158 + className: 'phui-tag-dot phui-tag-color-' + availability_color 159 + }); 160 + } 161 + 162 + return [icon, dot, value]; 151 163 }); 152 164 153 165 if (config.placeholder) { ··· 275 287 icon_ui = JX.Prefab._renderIcon(icon); 276 288 } 277 289 290 + var availability_ui; 291 + var availability_color = fields[16]; 292 + if (availability_color) { 293 + availability_ui = JX.$N( 294 + 'span', 295 + { 296 + className: 'phui-tag-dot phui-tag-color-' + availability_color 297 + }); 298 + } 299 + 278 300 var display = JX.$N( 279 301 'div', 280 302 {className: 'tokenizer-result'}, 281 - [icon_ui, fields[4] || fields[0], closed_ui]); 303 + [icon_ui, availability_ui, fields[4] || fields[0], closed_ui]); 282 304 if (closed) { 283 305 JX.DOM.alterClass(display, 'tokenizer-result-closed', true); 284 306 } ··· 300 322 tokenType: fields[12], 301 323 unique: fields[13] || false, 302 324 autocomplete: fields[14], 303 - sort: JX.TypeaheadNormalizer.normalize(fields[0]) 325 + sort: JX.TypeaheadNormalizer.normalize(fields[0]), 326 + availabilityColor: availability_color 304 327 }; 305 328 }, 306 329
+10 -1
webroot/rsrc/js/phuix/PHUIXAutocomplete.js
··· 185 185 .getNode(); 186 186 } 187 187 188 - var display = JX.$N('span', {}, [icon, map.displayName]); 188 + var dot; 189 + if (map.availabilityColor) { 190 + dot = JX.$N( 191 + 'span', 192 + { 193 + className: 'phui-tag-dot phui-tag-color-' + map.availabilityColor 194 + }); 195 + } 196 + 197 + var display = JX.$N('span', {}, [icon, dot, map.displayName]); 189 198 JX.DOM.alterClass(display, 'tokenizer-result-closed', !!map.closed); 190 199 191 200 map.display = display;