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

Index and surface usage sites for Dashboards

Summary:
Depends on D20397. Ref T13272. Similar to the recent "where are Herald rules used" stuff, show which menus Dashboards are installed in.

This is mostly straightforward, except that I pulled some of the Herald logic into a parent class so it could be shared.

Test Plan: {F6369164}

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13272

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

+306 -61
+3 -3
resources/celerity/map.php
··· 9 9 'names' => array( 10 10 'conpherence.pkg.css' => '3c8a0668', 11 11 'conpherence.pkg.js' => '020aebcf', 12 - 'core.pkg.css' => '9d654dff', 12 + 'core.pkg.css' => '1db0892b', 13 13 'core.pkg.js' => '794952ae', 14 14 'differential.pkg.css' => '8d8360fb', 15 15 'differential.pkg.js' => '67e02996', ··· 164 164 'rsrc/css/phui/phui-invisible-character-view.css' => 'c694c4a4', 165 165 'rsrc/css/phui/phui-left-right.css' => '68513c34', 166 166 'rsrc/css/phui/phui-lightbox.css' => '4ebf22da', 167 - 'rsrc/css/phui/phui-list.css' => '734a1039', 167 + 'rsrc/css/phui/phui-list.css' => 'b05144dd', 168 168 'rsrc/css/phui/phui-object-box.css' => 'f434b6be', 169 169 'rsrc/css/phui/phui-pager.css' => 'd022c7ad', 170 170 'rsrc/css/phui/phui-pinboard-view.css' => '1f08f5d8', ··· 847 847 'phui-invisible-character-view-css' => 'c694c4a4', 848 848 'phui-left-right-css' => '68513c34', 849 849 'phui-lightbox-css' => '4ebf22da', 850 - 'phui-list-view-css' => '734a1039', 850 + 'phui-list-view-css' => 'b05144dd', 851 851 'phui-object-box-css' => 'f434b6be', 852 852 'phui-oi-big-ui-css' => 'fa74cc35', 853 853 'phui-oi-color-css' => 'b517bfa0',
+8 -1
src/__phutil_library_map__.php
··· 3064 3064 'PhabricatorEdgeEditType' => 'applications/transactions/edittype/PhabricatorEdgeEditType.php', 3065 3065 'PhabricatorEdgeEditor' => 'infrastructure/edges/editor/PhabricatorEdgeEditor.php', 3066 3066 'PhabricatorEdgeGraph' => 'infrastructure/edges/util/PhabricatorEdgeGraph.php', 3067 + 'PhabricatorEdgeIndexEngineExtension' => 'applications/search/engineextension/PhabricatorEdgeIndexEngineExtension.php', 3067 3068 'PhabricatorEdgeObject' => 'infrastructure/edges/conduit/PhabricatorEdgeObject.php', 3068 3069 'PhabricatorEdgeObjectQuery' => 'infrastructure/edges/query/PhabricatorEdgeObjectQuery.php', 3069 3070 'PhabricatorEdgeQuery' => 'infrastructure/edges/query/PhabricatorEdgeQuery.php', ··· 4067 4068 'PhabricatorProfileMenuEditor' => 'applications/search/editor/PhabricatorProfileMenuEditor.php', 4068 4069 'PhabricatorProfileMenuEngine' => 'applications/search/engine/PhabricatorProfileMenuEngine.php', 4069 4070 'PhabricatorProfileMenuItem' => 'applications/search/menuitem/PhabricatorProfileMenuItem.php', 4071 + 'PhabricatorProfileMenuItemAffectsObjectEdgeType' => 'applications/search/edge/PhabricatorProfileMenuItemAffectsObjectEdgeType.php', 4070 4072 'PhabricatorProfileMenuItemConfiguration' => 'applications/search/storage/PhabricatorProfileMenuItemConfiguration.php', 4071 4073 'PhabricatorProfileMenuItemConfigurationQuery' => 'applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php', 4072 4074 'PhabricatorProfileMenuItemConfigurationTransaction' => 'applications/search/storage/PhabricatorProfileMenuItemConfigurationTransaction.php', 4073 4075 'PhabricatorProfileMenuItemConfigurationTransactionQuery' => 'applications/search/query/PhabricatorProfileMenuItemConfigurationTransactionQuery.php', 4074 4076 'PhabricatorProfileMenuItemIconSet' => 'applications/search/menuitem/PhabricatorProfileMenuItemIconSet.php', 4077 + 'PhabricatorProfileMenuItemIndexEngineExtension' => 'applications/search/engineextension/PhabricatorProfileMenuItemIndexEngineExtension.php', 4075 4078 'PhabricatorProfileMenuItemPHIDType' => 'applications/search/phidtype/PhabricatorProfileMenuItemPHIDType.php', 4076 4079 'PhabricatorProfileMenuItemView' => 'applications/search/engine/PhabricatorProfileMenuItemView.php', 4077 4080 'PhabricatorProfileMenuItemViewList' => 'applications/search/engine/PhabricatorProfileMenuItemViewList.php', ··· 7292 7295 'HeraldRuleEditor' => 'PhabricatorApplicationTransactionEditor', 7293 7296 'HeraldRuleField' => 'HeraldField', 7294 7297 'HeraldRuleFieldGroup' => 'HeraldFieldGroup', 7295 - 'HeraldRuleIndexEngineExtension' => 'PhabricatorIndexEngineExtension', 7298 + 'HeraldRuleIndexEngineExtension' => 'PhabricatorEdgeIndexEngineExtension', 7296 7299 'HeraldRuleListController' => 'HeraldController', 7297 7300 'HeraldRuleListView' => 'AphrontView', 7298 7301 'HeraldRuleNameTransaction' => 'HeraldRuleTransactionType', ··· 9056 9059 'PhabricatorEdgeEditType' => 'PhabricatorPHIDListEditType', 9057 9060 'PhabricatorEdgeEditor' => 'Phobject', 9058 9061 'PhabricatorEdgeGraph' => 'AbstractDirectedGraph', 9062 + 'PhabricatorEdgeIndexEngineExtension' => 'PhabricatorIndexEngineExtension', 9059 9063 'PhabricatorEdgeObject' => array( 9060 9064 'Phobject', 9061 9065 'PhabricatorPolicyInterface', ··· 10211 10215 'PhabricatorProfileMenuEditor' => 'PhabricatorApplicationTransactionEditor', 10212 10216 'PhabricatorProfileMenuEngine' => 'Phobject', 10213 10217 'PhabricatorProfileMenuItem' => 'Phobject', 10218 + 'PhabricatorProfileMenuItemAffectsObjectEdgeType' => 'PhabricatorEdgeType', 10214 10219 'PhabricatorProfileMenuItemConfiguration' => array( 10215 10220 'PhabricatorSearchDAO', 10216 10221 'PhabricatorPolicyInterface', 10217 10222 'PhabricatorExtendedPolicyInterface', 10218 10223 'PhabricatorApplicationTransactionInterface', 10224 + 'PhabricatorIndexableInterface', 10219 10225 ), 10220 10226 'PhabricatorProfileMenuItemConfigurationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 10221 10227 'PhabricatorProfileMenuItemConfigurationTransaction' => 'PhabricatorApplicationTransaction', 10222 10228 'PhabricatorProfileMenuItemConfigurationTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 10223 10229 'PhabricatorProfileMenuItemIconSet' => 'PhabricatorIconSet', 10230 + 'PhabricatorProfileMenuItemIndexEngineExtension' => 'PhabricatorEdgeIndexEngineExtension', 10224 10231 'PhabricatorProfileMenuItemPHIDType' => 'PhabricatorPHIDType', 10225 10232 'PhabricatorProfileMenuItemView' => 'Phobject', 10226 10233 'PhabricatorProfileMenuItemViewList' => 'Phobject',
+87
src/applications/dashboard/controller/dashboard/PhabricatorDashboardViewController.php
··· 32 32 33 33 $curtain = $this->buildCurtainView($dashboard); 34 34 35 + $usage_box = $this->newUsageView($dashboard); 36 + 35 37 $timeline = $this->buildTransactionTimeline( 36 38 $dashboard, 37 39 new PhabricatorDashboardTransactionQuery()); ··· 53 55 ->setMainColumn( 54 56 array( 55 57 $dashboard_box, 58 + $usage_box, 56 59 $timeline, 57 60 )); 58 61 ··· 108 111 } 109 112 110 113 return $curtain; 114 + } 115 + 116 + private function newUsageView(PhabricatorDashboard $dashboard) { 117 + $viewer = $this->getViewer(); 118 + 119 + $custom_phids = array(); 120 + if ($viewer->getPHID()) { 121 + $custom_phids[] = $viewer->getPHID(); 122 + } 123 + 124 + $items = id(new PhabricatorProfileMenuItemConfigurationQuery()) 125 + ->setViewer($viewer) 126 + ->withAffectedObjectPHIDs( 127 + array( 128 + $dashboard->getPHID(), 129 + )) 130 + ->withCustomPHIDs($custom_phids, $include_global = true) 131 + ->execute(); 132 + 133 + $handle_phids = array(); 134 + foreach ($items as $item) { 135 + $handle_phids[] = $item->getProfilePHID(); 136 + $custom_phid = $item->getCustomPHID(); 137 + if ($custom_phid) { 138 + $handle_phids[] = $custom_phid; 139 + } 140 + } 141 + 142 + if ($handle_phids) { 143 + $handles = $viewer->loadHandles($handle_phids); 144 + } else { 145 + $handles = array(); 146 + } 147 + 148 + $items = msortv($items, 'newUsageSortVector'); 149 + 150 + $rows = array(); 151 + foreach ($items as $item) { 152 + $profile_phid = $item->getProfilePHID(); 153 + $custom_phid = $item->getCustomPHID(); 154 + 155 + $profile = $handles[$profile_phid]->renderLink(); 156 + $profile_icon = $handles[$profile_phid]->getIcon(); 157 + 158 + if ($custom_phid) { 159 + $custom = $handles[$custom_phid]->renderLink(); 160 + } else { 161 + $custom = pht('Global'); 162 + } 163 + 164 + $type = $item->getProfileMenuTypeDescription(); 165 + 166 + $rows[] = array( 167 + id(new PHUIIconView())->setIcon($profile_icon), 168 + $type, 169 + $profile, 170 + $custom, 171 + ); 172 + } 173 + 174 + $usage_table = id(new AphrontTableView($rows)) 175 + ->setHeaders( 176 + array( 177 + null, 178 + pht('Type'), 179 + pht('Menu'), 180 + pht('Global/Personal'), 181 + )) 182 + ->setColumnClasses( 183 + array( 184 + 'center', 185 + null, 186 + 'pri', 187 + 'wide', 188 + )); 189 + 190 + $header_view = id(new PHUIHeaderView()) 191 + ->setHeader(pht('Dashboard Used By')); 192 + 193 + $usage_box = id(new PHUIObjectBoxView()) 194 + ->setTable($usage_table) 195 + ->setHeader($header_view); 196 + 197 + return $usage_box; 111 198 } 112 199 113 200
+1
src/applications/dashboard/phid/PhabricatorDashboardPortalPHIDType.php
··· 34 34 $portal = $objects[$phid]; 35 35 36 36 $handle 37 + ->setIcon('fa-compass') 37 38 ->setName($portal->getName()) 38 39 ->setURI($portal->getURI()); 39 40 }
+5 -40
src/applications/herald/engineextension/HeraldRuleIndexEngineExtension.php
··· 1 1 <?php 2 2 3 3 final class HeraldRuleIndexEngineExtension 4 - extends PhabricatorIndexEngineExtension { 4 + extends PhabricatorEdgeIndexEngineExtension { 5 5 6 6 const EXTENSIONKEY = 'herald.actions'; 7 7 ··· 17 17 return true; 18 18 } 19 19 20 - public function indexObject( 21 - PhabricatorIndexEngine $engine, 22 - $object) { 23 - 24 - $edge_type = HeraldRuleActionAffectsObjectEdgeType::EDGECONST; 25 - 26 - $old_edges = PhabricatorEdgeQuery::loadDestinationPHIDs( 27 - $object->getPHID(), 28 - $edge_type); 29 - $old_edges = array_fuse($old_edges); 30 - 31 - $new_edges = $this->getPHIDsAffectedByActions($object); 32 - $new_edges = array_fuse($new_edges); 33 - 34 - $add_edges = array_diff_key($new_edges, $old_edges); 35 - $rem_edges = array_diff_key($old_edges, $new_edges); 36 - 37 - if (!$add_edges && !$rem_edges) { 38 - return; 39 - } 40 - 41 - $editor = new PhabricatorEdgeEditor(); 42 - 43 - foreach ($add_edges as $phid) { 44 - $editor->addEdge($object->getPHID(), $edge_type, $phid); 45 - } 46 - 47 - foreach ($rem_edges as $phid) { 48 - $editor->removeEdge($object->getPHID(), $edge_type, $phid); 49 - } 50 - 51 - $editor->save(); 20 + protected function getIndexEdgeType() { 21 + return HeraldRuleActionAffectsObjectEdgeType::EDGECONST; 52 22 } 53 23 54 - public function getIndexVersion($object) { 55 - $phids = $this->getPHIDsAffectedByActions($object); 56 - sort($phids); 57 - $phids = implode(':', $phids); 58 - return PhabricatorHash::digestForIndex($phids); 59 - } 24 + protected function getIndexDestinationPHIDs($object) { 25 + $rule = $object; 60 26 61 - private function getPHIDsAffectedByActions(HeraldRule $rule) { 62 27 $viewer = $this->getViewer(); 63 28 64 29 $rule = id(new HeraldRuleQuery())
+8
src/applications/search/edge/PhabricatorProfileMenuItemAffectsObjectEdgeType.php
··· 1 + <?php 2 + 3 + final class PhabricatorProfileMenuItemAffectsObjectEdgeType 4 + extends PhabricatorEdgeType { 5 + 6 + const EDGECONST = 70; 7 + 8 + }
+3
src/applications/search/editor/PhabricatorProfileMenuEditor.php
··· 121 121 return $errors; 122 122 } 123 123 124 + protected function supportsSearch() { 125 + return true; 126 + } 124 127 125 128 }
+50
src/applications/search/engineextension/PhabricatorEdgeIndexEngineExtension.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorEdgeIndexEngineExtension 4 + extends PhabricatorIndexEngineExtension { 5 + 6 + abstract protected function getIndexEdgeType(); 7 + abstract protected function getIndexDestinationPHIDs($object); 8 + 9 + final public function indexObject( 10 + PhabricatorIndexEngine $engine, 11 + $object) { 12 + 13 + $edge_type = $this->getIndexEdgeType(); 14 + 15 + $old_edges = PhabricatorEdgeQuery::loadDestinationPHIDs( 16 + $object->getPHID(), 17 + $edge_type); 18 + $old_edges = array_fuse($old_edges); 19 + 20 + $new_edges = $this->getIndexDestinationPHIDs($object); 21 + $new_edges = array_fuse($new_edges); 22 + 23 + $add_edges = array_diff_key($new_edges, $old_edges); 24 + $rem_edges = array_diff_key($old_edges, $new_edges); 25 + 26 + if (!$add_edges && !$rem_edges) { 27 + return; 28 + } 29 + 30 + $editor = new PhabricatorEdgeEditor(); 31 + 32 + foreach ($add_edges as $phid) { 33 + $editor->addEdge($object->getPHID(), $edge_type, $phid); 34 + } 35 + 36 + foreach ($rem_edges as $phid) { 37 + $editor->removeEdge($object->getPHID(), $edge_type, $phid); 38 + } 39 + 40 + $editor->save(); 41 + } 42 + 43 + final public function getIndexVersion($object) { 44 + $phids = $this->getIndexDestinationPHIDs($object); 45 + sort($phids); 46 + $phids = implode(':', $phids); 47 + return PhabricatorHash::digestForIndex($phids); 48 + } 49 + 50 + }
+28
src/applications/search/engineextension/PhabricatorProfileMenuItemIndexEngineExtension.php
··· 1 + <?php 2 + 3 + final class PhabricatorProfileMenuItemIndexEngineExtension 4 + extends PhabricatorEdgeIndexEngineExtension { 5 + 6 + const EXTENSIONKEY = 'profile.menu.item'; 7 + 8 + public function getExtensionName() { 9 + return pht('Profile Menu Item'); 10 + } 11 + 12 + public function shouldIndexObject($object) { 13 + if (!($object instanceof PhabricatorProfileMenuItemConfiguration)) { 14 + return false; 15 + } 16 + 17 + return true; 18 + } 19 + 20 + protected function getIndexEdgeType() { 21 + return PhabricatorProfileMenuItemAffectsObjectEdgeType::EDGECONST; 22 + } 23 + 24 + protected function getIndexDestinationPHIDs($object) { 25 + return $object->getAffectedObjectPHIDs(); 26 + } 27 + 28 + }
+17 -4
src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php
··· 36 36 return $this->dashboard; 37 37 } 38 38 39 + public function getAffectedObjectPHIDs( 40 + PhabricatorProfileMenuItemConfiguration $config) { 41 + return array( 42 + $this->getDashboardPHID($config), 43 + ); 44 + } 45 + 46 + 39 47 public function newPageContent( 40 48 PhabricatorProfileMenuItemConfiguration $config) { 41 49 $viewer = $this->getViewer(); 42 50 43 - $dashboard_phid = $config->getMenuItemProperty('dashboardPHID'); 51 + $dashboard_phid = $this->getDashboardPHID($config); 44 52 45 53 // Reload the dashboard to attach panels, which we need for rendering. 46 54 $dashboard = id(new PhabricatorDashboardQuery()) ··· 71 79 $viewer = $this->getViewer(); 72 80 $dashboard_phids = array(); 73 81 foreach ($items as $item) { 74 - $dashboard_phids[] = $item->getMenuItemProperty('dashboardPHID'); 82 + $dashboard_phids[] = $this->getDashboardPHID($item); 75 83 } 76 84 77 85 $dashboards = id(new PhabricatorDashboardQuery()) ··· 83 91 84 92 $dashboards = mpull($dashboards, null, 'getPHID'); 85 93 foreach ($items as $item) { 86 - $dashboard_phid = $item->getMenuItemProperty('dashboardPHID'); 94 + $dashboard_phid = $this->getDashboardPHID($item); 87 95 $dashboard = idx($dashboards, $dashboard_phid, null); 88 96 89 97 $menu_item = $item->getMenuItem(); ··· 125 133 ->setLabel(pht('Dashboard')) 126 134 ->setIsRequired(true) 127 135 ->setDatasource(new PhabricatorDashboardDatasource()) 128 - ->setSingleValue($config->getMenuItemProperty('dashboardPHID')), 136 + ->setSingleValue($this->getDashboardPHID($config)), 129 137 id(new PhabricatorTextEditField()) 130 138 ->setKey('name') 131 139 ->setLabel(pht('Name')) ··· 224 232 } 225 233 226 234 return $errors; 235 + } 236 + 237 + private function getDashboardPHID( 238 + PhabricatorProfileMenuItemConfiguration $config) { 239 + return $config->getMenuItemProperty('dashboardPHID'); 227 240 } 228 241 229 242 private function getDashboardHandle() {
+5
src/applications/search/menuitem/PhabricatorProfileMenuItem.php
··· 159 159 )); 160 160 } 161 161 162 + public function getAffectedObjectPHIDs( 163 + PhabricatorProfileMenuItemConfiguration $config) { 164 + return array(); 165 + } 166 + 162 167 }
+38 -6
src/applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php
··· 8 8 private $profilePHIDs; 9 9 private $customPHIDs; 10 10 private $includeGlobal; 11 + private $affectedObjectPHIDs; 11 12 12 13 public function withIDs(array $ids) { 13 14 $this->ids = $ids; ··· 27 28 public function withCustomPHIDs(array $phids, $include_global = false) { 28 29 $this->customPHIDs = $phids; 29 30 $this->includeGlobal = $include_global; 31 + return $this; 32 + } 33 + 34 + public function withAffectedObjectPHIDs(array $phids) { 35 + $this->affectedObjectPHIDs = $phids; 30 36 return $this; 31 37 } 32 38 ··· 44 50 if ($this->ids !== null) { 45 51 $where[] = qsprintf( 46 52 $conn, 47 - 'id IN (%Ld)', 53 + 'config.id IN (%Ld)', 48 54 $this->ids); 49 55 } 50 56 51 57 if ($this->phids !== null) { 52 58 $where[] = qsprintf( 53 59 $conn, 54 - 'phid IN (%Ls)', 60 + 'config.phid IN (%Ls)', 55 61 $this->phids); 56 62 } 57 63 58 64 if ($this->profilePHIDs !== null) { 59 65 $where[] = qsprintf( 60 66 $conn, 61 - 'profilePHID IN (%Ls)', 67 + 'config.profilePHID IN (%Ls)', 62 68 $this->profilePHIDs); 63 69 } 64 70 ··· 66 72 if ($this->customPHIDs && $this->includeGlobal) { 67 73 $where[] = qsprintf( 68 74 $conn, 69 - 'customPHID IN (%Ls) OR customPHID IS NULL', 75 + 'config.customPHID IN (%Ls) OR config.customPHID IS NULL', 70 76 $this->customPHIDs); 71 77 } else if ($this->customPHIDs) { 72 78 $where[] = qsprintf( 73 79 $conn, 74 - 'customPHID IN (%Ls)', 80 + 'config.customPHID IN (%Ls)', 75 81 $this->customPHIDs); 76 82 } else { 77 83 $where[] = qsprintf( 78 84 $conn, 79 - 'customPHID IS NULL'); 85 + 'config.customPHID IS NULL'); 80 86 } 81 87 } 82 88 89 + if ($this->affectedObjectPHIDs !== null) { 90 + $where[] = qsprintf( 91 + $conn, 92 + 'affected.dst IN (%Ls)', 93 + $this->affectedObjectPHIDs); 94 + } 95 + 83 96 return $where; 97 + } 98 + 99 + protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) { 100 + $joins = parent::buildJoinClauseParts($conn); 101 + 102 + if ($this->affectedObjectPHIDs !== null) { 103 + $joins[] = qsprintf( 104 + $conn, 105 + 'JOIN %T affected ON affected.src = config.phid 106 + AND affected.type = %d', 107 + PhabricatorEdgeConfig::TABLE_NAME_EDGE, 108 + PhabricatorProfileMenuItemAffectsObjectEdgeType::EDGECONST); 109 + } 110 + 111 + return $joins; 84 112 } 85 113 86 114 protected function willFilterPage(array $page) { ··· 126 154 127 155 public function getQueryApplicationClass() { 128 156 return 'PhabricatorSearchApplication'; 157 + } 158 + 159 + protected function getPrimaryTableAlias() { 160 + return 'config'; 129 161 } 130 162 131 163 }
+45 -1
src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php
··· 5 5 implements 6 6 PhabricatorPolicyInterface, 7 7 PhabricatorExtendedPolicyInterface, 8 - PhabricatorApplicationTransactionInterface { 8 + PhabricatorApplicationTransactionInterface, 9 + PhabricatorIndexableInterface { 9 10 10 11 protected $profilePHID; 11 12 protected $menuItemKey; ··· 253 254 } 254 255 255 256 return false; 257 + } 258 + 259 + public function getAffectedObjectPHIDs() { 260 + return $this->getMenuItem()->getAffectedObjectPHIDs($this); 261 + } 262 + 263 + public function getProfileMenuTypeDescription() { 264 + $profile_phid = $this->getProfilePHID(); 265 + 266 + $home_phid = id(new PhabricatorHomeApplication())->getPHID(); 267 + if ($profile_phid === $home_phid) { 268 + return pht('Home Menu'); 269 + } 270 + 271 + $favorites_phid = id(new PhabricatorFavoritesApplication())->getPHID(); 272 + if ($profile_phid === $favorites_phid) { 273 + return pht('Favorites Menu'); 274 + } 275 + 276 + switch (phid_get_type($profile_phid)) { 277 + case PhabricatorProjectProjectPHIDType::TYPECONST: 278 + return pht('Project Menu'); 279 + case PhabricatorDashboardPortalPHIDType::TYPECONST: 280 + return pht('Portal Menu'); 281 + } 282 + 283 + return pht('Profile Menu'); 284 + } 285 + 286 + public function newUsageSortVector() { 287 + // Used to sort items in contexts where we're showing the usage of an 288 + // object in menus, like "Dashboard Used By" on Dashboard pages. 289 + 290 + // Sort usage as a custom item after usage as a global item. 291 + if ($this->getCustomPHID()) { 292 + $is_personal = 1; 293 + } else { 294 + $is_personal = 0; 295 + } 296 + 297 + return id(new PhutilSortVector()) 298 + ->addInt($is_personal) 299 + ->addInt($this->getID()); 256 300 } 257 301 258 302
+8 -6
webroot/rsrc/css/phui/phui-list.css
··· 261 261 262 262 /* - Action Icon ----------------------------------------------------------- */ 263 263 264 - .phui-list-sidenav .phui-list-item-has-action-icon .phui-list-item-action-href { 264 + .phabricator-nav-local .phui-list-item-has-action-icon 265 + .phui-list-item-action-href { 265 266 position: absolute; 266 267 width: 28px; 267 268 top: 0; ··· 273 274 display: none; 274 275 } 275 276 276 - .phui-list-sidenav .phui-list-item-has-action-icon.phui-list-item-selected 277 + .phabricator-nav-local .phui-list-item-has-action-icon.phui-list-item-selected 277 278 .phui-list-item-href { 278 279 padding-right: 32px; 279 280 } 280 281 281 - .phui-list-sidenav .phui-list-item-has-action-icon.phui-list-item-selected 282 + .phabricator-nav-local .phui-list-item-has-action-icon.phui-list-item-selected 282 283 .phui-list-item-action-href { 283 284 display: block; 284 285 } 285 286 286 - .phui-list-sidenav .phui-list-item-has-action-icon 287 + .phabricator-nav-local .phui-list-item-has-action-icon 287 288 .phui-list-item-action-href:hover { 288 289 background-color: rgba({$alphablack},.05); 289 290 } 290 291 291 - .phui-list-sidenav .phui-list-item-has-action-icon .phui-list-item-action-icon { 292 + .phabricator-nav-local .phui-list-item-has-action-icon 293 + .phui-list-item-action-icon { 292 294 opacity: 0.5; 293 295 } 294 296 295 - .phui-list-sidenav .phui-list-item-has-action-icon 297 + .phabricator-nav-local .phui-list-item-has-action-icon 296 298 .phui-list-item-action-href:hover 297 299 .phui-list-item-action-icon { 298 300 opacity: 1;