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

Begin modularizing main menu items

Summary:
Ref T10077. Ref T8918. The way the main menu is built is not very modular and fairly hacky.

It assumes menus are provided by applications, but this isn't exactly true. Notably, the "Quick Create" menu is not per-application.

The current method of building this menu is very inefficient (see T10077). Particularly, we have to build it //twice// because we need to build it once to render the item and then again to render the dropdown options.

Start cleaning this up. This diff doesn't actually have any behavioral changes, since I can't swap the menu over until we get rid of all the other items and I haven't extended this to Notifications/Conpherence yet so it doesn't actually fix T8918.

Test Plan: Viewed menus while logged in, logged out, in different applications, in desktop/mobile. Nothing appeared different.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T8918, T10077

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

+418 -209
+12
src/__phutil_library_map__.php
··· 1500 1500 'PHUIListItemView' => 'view/phui/PHUIListItemView.php', 1501 1501 'PHUIListView' => 'view/phui/PHUIListView.php', 1502 1502 'PHUIListViewTestCase' => 'view/layout/__tests__/PHUIListViewTestCase.php', 1503 + 'PHUIMainMenuView' => 'view/phui/PHUIMainMenuView.php', 1503 1504 'PHUIObjectBoxView' => 'view/phui/PHUIObjectBoxView.php', 1504 1505 'PHUIObjectItemListExample' => 'applications/uiexample/examples/PHUIObjectItemListExample.php', 1505 1506 'PHUIObjectItemListView' => 'view/phui/PHUIObjectItemListView.php', ··· 1722 1723 'PhabricatorAuthListController' => 'applications/auth/controller/config/PhabricatorAuthListController.php', 1723 1724 'PhabricatorAuthLoginController' => 'applications/auth/controller/PhabricatorAuthLoginController.php', 1724 1725 'PhabricatorAuthLoginHandler' => 'applications/auth/handler/PhabricatorAuthLoginHandler.php', 1726 + 'PhabricatorAuthMainMenuBarExtension' => 'applications/auth/extension/PhabricatorAuthMainMenuBarExtension.php', 1725 1727 'PhabricatorAuthManagementCachePKCS8Workflow' => 'applications/auth/management/PhabricatorAuthManagementCachePKCS8Workflow.php', 1726 1728 'PhabricatorAuthManagementLDAPWorkflow' => 'applications/auth/management/PhabricatorAuthManagementLDAPWorkflow.php', 1727 1729 'PhabricatorAuthManagementListFactorsWorkflow' => 'applications/auth/management/PhabricatorAuthManagementListFactorsWorkflow.php', ··· 2363 2365 'PhabricatorHelpDocumentationController' => 'applications/help/controller/PhabricatorHelpDocumentationController.php', 2364 2366 'PhabricatorHelpEditorProtocolController' => 'applications/help/controller/PhabricatorHelpEditorProtocolController.php', 2365 2367 'PhabricatorHelpKeyboardShortcutController' => 'applications/help/controller/PhabricatorHelpKeyboardShortcutController.php', 2368 + 'PhabricatorHelpMainMenuBarExtension' => 'applications/help/extension/PhabricatorHelpMainMenuBarExtension.php', 2366 2369 'PhabricatorHeraldApplication' => 'applications/herald/application/PhabricatorHeraldApplication.php', 2367 2370 'PhabricatorHighSecurityRequestExceptionHandler' => 'aphront/handler/PhabricatorHighSecurityRequestExceptionHandler.php', 2368 2371 'PhabricatorHomeApplication' => 'applications/home/application/PhabricatorHomeApplication.php', ··· 2480 2483 'PhabricatorMailSetupCheck' => 'applications/config/check/PhabricatorMailSetupCheck.php', 2481 2484 'PhabricatorMailTarget' => 'applications/metamta/replyhandler/PhabricatorMailTarget.php', 2482 2485 'PhabricatorMailgunConfigOptions' => 'applications/config/option/PhabricatorMailgunConfigOptions.php', 2486 + 'PhabricatorMainMenuBarExtension' => 'view/page/menu/PhabricatorMainMenuBarExtension.php', 2483 2487 'PhabricatorMainMenuSearchView' => 'view/page/menu/PhabricatorMainMenuSearchView.php', 2484 2488 'PhabricatorMainMenuView' => 'view/page/menu/PhabricatorMainMenuView.php', 2485 2489 'PhabricatorManagementWorkflow' => 'infrastructure/management/PhabricatorManagementWorkflow.php', ··· 2724 2728 'PhabricatorPeopleLogQuery' => 'applications/people/query/PhabricatorPeopleLogQuery.php', 2725 2729 'PhabricatorPeopleLogSearchEngine' => 'applications/people/query/PhabricatorPeopleLogSearchEngine.php', 2726 2730 'PhabricatorPeopleLogsController' => 'applications/people/controller/PhabricatorPeopleLogsController.php', 2731 + 'PhabricatorPeopleMainMenuBarExtension' => 'applications/people/extension/PhabricatorPeopleMainMenuBarExtension.php', 2727 2732 'PhabricatorPeopleNewController' => 'applications/people/controller/PhabricatorPeopleNewController.php', 2728 2733 'PhabricatorPeopleNoOwnerDatasource' => 'applications/people/typeahead/PhabricatorPeopleNoOwnerDatasource.php', 2729 2734 'PhabricatorPeopleOwnerDatasource' => 'applications/people/typeahead/PhabricatorPeopleOwnerDatasource.php', ··· 3091 3096 'PhabricatorSettingsAdjustController' => 'applications/settings/controller/PhabricatorSettingsAdjustController.php', 3092 3097 'PhabricatorSettingsApplication' => 'applications/settings/application/PhabricatorSettingsApplication.php', 3093 3098 'PhabricatorSettingsMainController' => 'applications/settings/controller/PhabricatorSettingsMainController.php', 3099 + 'PhabricatorSettingsMainMenuBarExtension' => 'applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php', 3094 3100 'PhabricatorSettingsPanel' => 'applications/settings/panel/PhabricatorSettingsPanel.php', 3095 3101 'PhabricatorSetupCheck' => 'applications/config/check/PhabricatorSetupCheck.php', 3096 3102 'PhabricatorSetupCheckTestCase' => 'applications/config/check/__tests__/PhabricatorSetupCheckTestCase.php', ··· 5615 5621 'PHUIListItemView' => 'AphrontTagView', 5616 5622 'PHUIListView' => 'AphrontTagView', 5617 5623 'PHUIListViewTestCase' => 'PhabricatorTestCase', 5624 + 'PHUIMainMenuView' => 'AphrontView', 5618 5625 'PHUIObjectBoxView' => 'AphrontView', 5619 5626 'PHUIObjectItemListExample' => 'PhabricatorUIExample', 5620 5627 'PHUIObjectItemListView' => 'AphrontTagView', ··· 5863 5870 'PhabricatorAuthListController' => 'PhabricatorAuthProviderConfigController', 5864 5871 'PhabricatorAuthLoginController' => 'PhabricatorAuthController', 5865 5872 'PhabricatorAuthLoginHandler' => 'Phobject', 5873 + 'PhabricatorAuthMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 5866 5874 'PhabricatorAuthManagementCachePKCS8Workflow' => 'PhabricatorAuthManagementWorkflow', 5867 5875 'PhabricatorAuthManagementLDAPWorkflow' => 'PhabricatorAuthManagementWorkflow', 5868 5876 'PhabricatorAuthManagementListFactorsWorkflow' => 'PhabricatorAuthManagementWorkflow', ··· 6631 6639 'PhabricatorHelpDocumentationController' => 'PhabricatorHelpController', 6632 6640 'PhabricatorHelpEditorProtocolController' => 'PhabricatorHelpController', 6633 6641 'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController', 6642 + 'PhabricatorHelpMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 6634 6643 'PhabricatorHeraldApplication' => 'PhabricatorApplication', 6635 6644 'PhabricatorHighSecurityRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler', 6636 6645 'PhabricatorHomeApplication' => 'PhabricatorApplication', ··· 6748 6757 'PhabricatorMailSetupCheck' => 'PhabricatorSetupCheck', 6749 6758 'PhabricatorMailTarget' => 'Phobject', 6750 6759 'PhabricatorMailgunConfigOptions' => 'PhabricatorApplicationConfigOptions', 6760 + 'PhabricatorMainMenuBarExtension' => 'Phobject', 6751 6761 'PhabricatorMainMenuSearchView' => 'AphrontView', 6752 6762 'PhabricatorMainMenuView' => 'AphrontView', 6753 6763 'PhabricatorManagementWorkflow' => 'PhutilArgumentWorkflow', ··· 7037 7047 'PhabricatorPeopleLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 7038 7048 'PhabricatorPeopleLogSearchEngine' => 'PhabricatorApplicationSearchEngine', 7039 7049 'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController', 7050 + 'PhabricatorPeopleMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 7040 7051 'PhabricatorPeopleNewController' => 'PhabricatorPeopleController', 7041 7052 'PhabricatorPeopleNoOwnerDatasource' => 'PhabricatorTypeaheadDatasource', 7042 7053 'PhabricatorPeopleOwnerDatasource' => 'PhabricatorTypeaheadCompositeDatasource', ··· 7488 7499 'PhabricatorSettingsAdjustController' => 'PhabricatorController', 7489 7500 'PhabricatorSettingsApplication' => 'PhabricatorApplication', 7490 7501 'PhabricatorSettingsMainController' => 'PhabricatorController', 7502 + 'PhabricatorSettingsMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 7491 7503 'PhabricatorSettingsPanel' => 'Phobject', 7492 7504 'PhabricatorSetupCheck' => 'Phobject', 7493 7505 'PhabricatorSetupCheckTestCase' => 'PhabricatorTestCase',
-42
src/applications/auth/application/PhabricatorAuthApplication.php
··· 38 38 return array(); 39 39 } 40 40 41 - public function buildMainMenuItems( 42 - PhabricatorUser $user, 43 - PhabricatorController $controller = null) { 44 - 45 - $items = array(); 46 - 47 - if ($user->isLoggedIn()) { 48 - $item = id(new PHUIListItemView()) 49 - ->addClass('core-menu-item') 50 - ->setName(pht('Log Out')) 51 - ->setIcon('fa-sign-out') 52 - ->setWorkflow(true) 53 - ->setHref('/logout/') 54 - ->setSelected(($controller instanceof PhabricatorLogoutController)) 55 - ->setAural(pht('Log Out')) 56 - ->setOrder(900); 57 - $items[] = $item; 58 - } else { 59 - if ($controller instanceof PhabricatorAuthController) { 60 - // Don't show the "Login" item on auth controllers, since they're 61 - // generally all related to logging in anyway. 62 - } else { 63 - $uri = new PhutilURI('/auth/start/'); 64 - if ($controller) { 65 - $path = $controller->getRequest()->getPath(); 66 - $uri->setQueryParam('next', $path); 67 - } 68 - $item = id(new PHUIListItemView()) 69 - ->addClass('core-menu-item') 70 - ->setName(pht('Log In')) 71 - // TODO: Login icon? 72 - ->setIcon('fa-sign-in') 73 - ->setHref($uri) 74 - ->setAural(pht('Log In')) 75 - ->setOrder(900); 76 - $items[] = $item; 77 - } 78 - } 79 - 80 - return $items; 81 - } 82 - 83 41 public function getApplicationGroup() { 84 42 return self::GROUP_ADMIN; 85 43 }
+73
src/applications/auth/extension/PhabricatorAuthMainMenuBarExtension.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthMainMenuBarExtension 4 + extends PhabricatorMainMenuBarExtension { 5 + 6 + const MAINMENUBARKEY = 'auth'; 7 + 8 + public function isExtensionEnabledForViewer(PhabricatorUser $viewer) { 9 + return true; 10 + } 11 + 12 + public function buildMainMenus() { 13 + $viewer = $this->getViewer(); 14 + 15 + if ($viewer->isLoggedIn()) { 16 + return array( 17 + $this->buildLogoutMenu(), 18 + ); 19 + } 20 + 21 + $controller = $this->getController(); 22 + if ($controller instanceof PhabricatorAuthController) { 23 + // Don't show the "Login" item on auth controllers, since they're 24 + // generally all related to logging in anyway. 25 + return array(); 26 + } 27 + 28 + return array( 29 + $this->buildLoginMenu(), 30 + ); 31 + } 32 + 33 + private function buildLogoutMenu() { 34 + $controller = $this->getController(); 35 + 36 + $is_selected = ($controller instanceof PhabricatorLogoutController); 37 + 38 + $bar_item = id(new PHUIListItemView()) 39 + ->addClass('core-menu-item') 40 + ->setName(pht('Log Out')) 41 + ->setIcon('fa-sign-out') 42 + ->setWorkflow(true) 43 + ->setHref('/logout/') 44 + ->setSelected($is_selected) 45 + ->setAural(pht('Log Out')); 46 + 47 + return id(new PHUIMainMenuView()) 48 + ->setOrder(900) 49 + ->setMenuBarItem($bar_item); 50 + } 51 + 52 + private function buildLoginMenu() { 53 + $controller = $this->getController(); 54 + 55 + $uri = new PhutilURI('/auth/start/'); 56 + if ($controller) { 57 + $path = $controller->getRequest()->getPath(); 58 + $uri->setQueryParam('next', $path); 59 + } 60 + 61 + $bar_item = id(new PHUIListItemView()) 62 + ->addClass('core-menu-item') 63 + ->setName(pht('Log In')) 64 + ->setIcon('fa-sign-in') 65 + ->setHref($uri) 66 + ->setAural(pht('Log In')); 67 + 68 + return id(new PHUIMainMenuView()) 69 + ->setOrder(900) 70 + ->setMenuBarItem($bar_item); 71 + } 72 + 73 + }
-80
src/applications/help/application/PhabricatorHelpApplication.php
··· 25 25 ); 26 26 } 27 27 28 - public function buildMainMenuItems( 29 - PhabricatorUser $user, 30 - PhabricatorController $controller = null) { 31 - 32 - $application = null; 33 - if ($controller) { 34 - $application = $controller->getCurrentApplication(); 35 - } 36 - 37 - $items = array(); 38 - 39 - $help_id = celerity_generate_unique_node_id(); 40 - 41 - Javelin::initBehavior( 42 - 'aphlict-dropdown', 43 - array( 44 - 'bubbleID' => $help_id, 45 - 'dropdownID' => 'phabricator-help-menu', 46 - 'applicationClass' => __CLASS__, 47 - 'local' => true, 48 - 'desktop' => true, 49 - 'right' => true, 50 - )); 51 - 52 - $item = id(new PHUIListItemView()) 53 - ->setIcon('fa-life-ring') 54 - ->addClass('core-menu-item') 55 - ->setID($help_id) 56 - ->setOrder(200); 57 - 58 - $hide = true; 59 - if ($application) { 60 - $help_name = pht('%s Help', $application->getName()); 61 - $item 62 - ->setName($help_name) 63 - ->setHref('/help/documentation/'.get_class($application).'/') 64 - ->setAural($help_name); 65 - $help_items = $application->getHelpMenuItems($user); 66 - if ($help_items) { 67 - $hide = false; 68 - } 69 - } 70 - if ($hide) { 71 - $item->setStyle('display: none'); 72 - } 73 - $items[] = $item; 74 - 75 - return $items; 76 - } 77 - 78 - public function buildMainMenuExtraNodes( 79 - PhabricatorUser $viewer, 80 - PhabricatorController $controller = null) { 81 - 82 - $application = null; 83 - if ($controller) { 84 - $application = $controller->getCurrentApplication(); 85 - } 86 - 87 - $view = null; 88 - if ($application) { 89 - $help_items = $application->getHelpMenuItems($viewer); 90 - if ($help_items) { 91 - $view = new PHUIListView(); 92 - foreach ($help_items as $item) { 93 - $view->addMenuItem($item); 94 - } 95 - } 96 - } 97 - 98 - return phutil_tag( 99 - 'div', 100 - array( 101 - 'id' => 'phabricator-help-menu', 102 - 'class' => 'phabricator-main-menu-dropdown phui-list-sidenav', 103 - 'style' => 'display: none', 104 - ), 105 - $view); 106 - } 107 - 108 28 }
+70
src/applications/help/extension/PhabricatorHelpMainMenuBarExtension.php
··· 1 + <?php 2 + 3 + final class PhabricatorHelpMainMenuBarExtension 4 + extends PhabricatorMainMenuBarExtension { 5 + 6 + const MAINMENUBARKEY = 'help'; 7 + 8 + public function isExtensionEnabledForViewer(PhabricatorUser $viewer) { 9 + return true; 10 + } 11 + 12 + public function buildMainMenus() { 13 + $application = $this->getApplication(); 14 + if (!$application) { 15 + return array(); 16 + } 17 + 18 + $viewer = $this->getViewer(); 19 + $help_links = $application->getHelpMenuItems($viewer); 20 + if (!$help_links) { 21 + return array(); 22 + } 23 + 24 + $help_id = celerity_generate_unique_node_id(); 25 + 26 + Javelin::initBehavior( 27 + 'aphlict-dropdown', 28 + array( 29 + 'bubbleID' => $help_id, 30 + 'dropdownID' => 'phabricator-help-menu', 31 + 'local' => true, 32 + 'desktop' => true, 33 + 'right' => true, 34 + )); 35 + 36 + $help_name = pht('%s Help', $application->getName()); 37 + 38 + $help_item = id(new PHUIListItemView()) 39 + ->setIcon('fa-life-ring') 40 + ->addClass('core-menu-item') 41 + ->setID($help_id) 42 + ->setName($help_name) 43 + ->setHref('/help/documentation/'.get_class($application).'/') 44 + ->setAural($help_name); 45 + 46 + $view = new PHUIListView(); 47 + foreach ($help_links as $help_link) { 48 + $view->addMenuItem($help_link); 49 + } 50 + 51 + $dropdown_menu = phutil_tag( 52 + 'div', 53 + array( 54 + 'id' => 'phabricator-help-menu', 55 + 'class' => 'phabricator-main-menu-dropdown phui-list-sidenav', 56 + 'style' => 'display: none', 57 + ), 58 + $view); 59 + 60 + $help_menu = id(new PHUIMainMenuView()) 61 + ->setOrder(200) 62 + ->setMenuBarItem($help_item) 63 + ->appendChild($dropdown_menu); 64 + 65 + return array( 66 + $help_menu, 67 + ); 68 + } 69 + 70 + }
-42
src/applications/people/application/PhabricatorPeopleApplication.php
··· 123 123 return $status; 124 124 } 125 125 126 - public function buildMainMenuItems( 127 - PhabricatorUser $user, 128 - PhabricatorController $controller = null) { 129 - 130 - $items = array(); 131 - 132 - if ($user->isLoggedIn() && $user->isUserActivated()) { 133 - $profile = id(new PhabricatorPeopleQuery()) 134 - ->setViewer($user) 135 - ->needProfileImage(true) 136 - ->withPHIDs(array($user->getPHID())) 137 - ->executeOne(); 138 - $image = $profile->getProfileImageURI(); 139 - 140 - $item = id(new PHUIListItemView()) 141 - ->setName($user->getUsername()) 142 - ->setHref('/p/'.$user->getUsername().'/') 143 - ->addClass('core-menu-item') 144 - ->setAural(pht('Profile')) 145 - ->setOrder(100); 146 - 147 - $classes = array( 148 - 'phabricator-core-menu-icon', 149 - 'phabricator-core-menu-profile-image', 150 - ); 151 - 152 - $item->appendChild( 153 - phutil_tag( 154 - 'span', 155 - array( 156 - 'class' => implode(' ', $classes), 157 - 'style' => 'background-image: url('.$image.')', 158 - ), 159 - '')); 160 - 161 - $items[] = $item; 162 - } 163 - 164 - return $items; 165 - } 166 - 167 - 168 126 public function getQuickCreateItems(PhabricatorUser $viewer) { 169 127 $items = array(); 170 128
+49
src/applications/people/extension/PhabricatorPeopleMainMenuBarExtension.php
··· 1 + <?php 2 + 3 + final class PhabricatorPeopleMainMenuBarExtension 4 + extends PhabricatorMainMenuBarExtension { 5 + 6 + const MAINMENUBARKEY = 'people'; 7 + 8 + public function buildMainMenus() { 9 + $viewer = $this->getViewer(); 10 + 11 + // TODO: This should get cached. 12 + 13 + $profile = id(new PhabricatorPeopleQuery()) 14 + ->setViewer($viewer) 15 + ->needProfileImage(true) 16 + ->withPHIDs(array($viewer->getPHID())) 17 + ->executeOne(); 18 + $image = $profile->getProfileImageURI(); 19 + 20 + $bar_item = id(new PHUIListItemView()) 21 + ->setName($viewer->getUsername()) 22 + ->setHref('/p/'.$viewer->getUsername().'/') 23 + ->addClass('core-menu-item') 24 + ->setAural(pht('Profile')); 25 + 26 + $classes = array( 27 + 'phabricator-core-menu-icon', 28 + 'phabricator-core-menu-profile-image', 29 + ); 30 + 31 + $bar_item->appendChild( 32 + phutil_tag( 33 + 'span', 34 + array( 35 + 'class' => implode(' ', $classes), 36 + 'style' => 'background-image: url('.$image.')', 37 + ), 38 + '')); 39 + 40 + $profile_menu = id(new PHUIMainMenuView()) 41 + ->setOrder(100) 42 + ->setMenuBarItem($bar_item); 43 + 44 + return array( 45 + $profile_menu, 46 + ); 47 + } 48 + 49 + }
-22
src/applications/settings/application/PhabricatorSettingsApplication.php
··· 40 40 return self::GROUP_UTILITIES; 41 41 } 42 42 43 - public function buildMainMenuItems( 44 - PhabricatorUser $user, 45 - PhabricatorController $controller = null) { 46 - 47 - $items = array(); 48 - 49 - if ($user->isLoggedIn() && $user->isUserActivated()) { 50 - $selected = ($controller instanceof PhabricatorSettingsMainController); 51 - $item = id(new PHUIListItemView()) 52 - ->setName(pht('Settings')) 53 - ->setIcon('fa-wrench') 54 - ->addClass('core-menu-item') 55 - ->setSelected($selected) 56 - ->setHref('/settings/') 57 - ->setAural(pht('Settings')) 58 - ->setOrder(400); 59 - $items[] = $item; 60 - } 61 - 62 - return $items; 63 - } 64 - 65 43 }
+29
src/applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php
··· 1 + <?php 2 + 3 + final class PhabricatorSettingsMainMenuBarExtension 4 + extends PhabricatorMainMenuBarExtension { 5 + 6 + const MAINMENUBARKEY = 'settings'; 7 + 8 + public function buildMainMenus() { 9 + $controller = $this->getController(); 10 + $is_selected = ($controller instanceof PhabricatorSettingsMainController); 11 + 12 + $bar_item = id(new PHUIListItemView()) 13 + ->setName(pht('Settings')) 14 + ->setIcon('fa-wrench') 15 + ->addClass('core-menu-item') 16 + ->setSelected($is_selected) 17 + ->setHref('/settings/') 18 + ->setAural(pht('Settings')); 19 + 20 + $settings_menu = id(new PHUIMainMenuView()) 21 + ->setMenuBarItem($bar_item) 22 + ->setOrder(400); 23 + 24 + return array( 25 + $settings_menu, 26 + ); 27 + } 28 + 29 + }
+88
src/view/page/menu/PhabricatorMainMenuBarExtension.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorMainMenuBarExtension extends Phobject { 4 + 5 + private $viewer; 6 + private $application; 7 + private $controller; 8 + 9 + public function setViewer(PhabricatorUser $viewer) { 10 + $this->viewer = $viewer; 11 + return $this; 12 + } 13 + 14 + public function getViewer() { 15 + return $this->viewer; 16 + } 17 + 18 + public function setApplication(PhabricatorApplication $application) { 19 + $this->application = $application; 20 + return $this; 21 + } 22 + 23 + public function getApplication() { 24 + return $this->application; 25 + } 26 + 27 + public function setController(PhabricatorController $controller) { 28 + $this->controller = $controller; 29 + return $this; 30 + } 31 + 32 + public function getController() { 33 + return $this->controller; 34 + } 35 + 36 + final public function getExtensionKey() { 37 + return $this->getPhobjectClassConstant('MAINMENUBARKEY'); 38 + } 39 + 40 + public function isExtensionEnabled() { 41 + return true; 42 + } 43 + 44 + public function isExtensionEnabledForViewer(PhabricatorUser $viewer) { 45 + if (!$viewer->isLoggedIn()) { 46 + return false; 47 + } 48 + 49 + if (!$viewer->isUserActivated()) { 50 + return false; 51 + } 52 + 53 + // Don't show menus for users with partial sessions. This usually means 54 + // they have logged in but have not made it through MFA, so we don't want 55 + // to show notification counts, saved queries, etc. 56 + if (!$viewer->hasSession()) { 57 + return false; 58 + } 59 + 60 + if ($viewer->getSession()->getIsPartial()) { 61 + return false; 62 + } 63 + 64 + return true; 65 + } 66 + 67 + abstract public function buildMainMenus(); 68 + 69 + final public static function getAllExtensions() { 70 + return id(new PhutilClassMapQuery()) 71 + ->setAncestorClass(__CLASS__) 72 + ->setUniqueMethod('getExtensionKey') 73 + ->execute(); 74 + } 75 + 76 + final public static function getAllEnabledExtensions() { 77 + $extensions = self::getAllExtensions(); 78 + 79 + foreach ($extensions as $key => $extension) { 80 + if (!$extension->isExtensionEnabled()) { 81 + unset($extensions[$key]); 82 + } 83 + } 84 + 85 + return $extensions; 86 + } 87 + 88 + }
+66 -23
src/view/page/menu/PhabricatorMainMenuView.php
··· 30 30 require_celerity_resource('sprite-main-header-css'); 31 31 32 32 $header_id = celerity_generate_unique_node_id(); 33 - $menus = array(); 33 + $menu_bar = array(); 34 34 $alerts = array(); 35 35 $search_button = ''; 36 36 $app_button = ''; ··· 41 41 if (array_filter($menu)) { 42 42 $alerts[] = $menu; 43 43 } 44 - $menus = array_merge($menus, $dropdowns); 44 + $menu_bar = array_merge($menu_bar, $dropdowns); 45 45 $app_button = $this->renderApplicationMenuButton($header_id); 46 46 $search_button = $this->renderSearchMenuButton($header_id); 47 47 } else { ··· 73 73 } 74 74 75 75 $applications = PhabricatorApplication::getAllInstalledApplications(); 76 + 77 + $menus = array(); 78 + $controller = $this->getController(); 76 79 foreach ($applications as $application) { 77 - $menus[] = $application->buildMainMenuExtraNodes( 80 + $app_actions = $application->buildMainMenuItems( 81 + $user, 82 + $controller); 83 + $app_extra = $application->buildMainMenuExtraNodes( 78 84 $user, 79 - $this->getController()); 85 + $controller); 86 + 87 + foreach ($app_actions as $action) { 88 + $menus[] = id(new PHUIMainMenuView()) 89 + ->setMenuBarItem($action) 90 + ->setOrder($action->getOrder()); 91 + } 92 + 93 + if ($app_extra !== null) { 94 + $menus[] = id(new PHUIMainMenuView()) 95 + ->appendChild($app_extra); 96 + } 97 + } 98 + 99 + $extensions = PhabricatorMainMenuBarExtension::getAllEnabledExtensions(); 100 + foreach ($extensions as $extension) { 101 + $extension->setViewer($user); 102 + 103 + $controller = $this->getController(); 104 + if ($controller) { 105 + $extension->setController($controller); 106 + $application = $controller->getCurrentApplication(); 107 + if ($application) { 108 + $extension->setApplication($application); 109 + } 110 + } 111 + } 112 + 113 + foreach ($extensions as $key => $extension) { 114 + if (!$extension->isExtensionEnabledForViewer($extension->getViewer())) { 115 + unset($extensions[$key]); 116 + } 117 + } 118 + 119 + foreach ($extensions as $extension) { 120 + foreach ($extension->buildMainMenus() as $menu) { 121 + $menus[] = $menu; 122 + } 123 + } 124 + 125 + $menus = msort($menus, 'getOrder'); 126 + $bar_items = array(); 127 + foreach ($menus as $menu) { 128 + $menu_bar[] = $menu; 129 + 130 + $item = $menu->getMenuBarItem(); 131 + if ($item === null) { 132 + continue; 133 + } 134 + 135 + $bar_items[] = $item; 80 136 } 81 137 82 - $application_menu = $this->renderApplicationMenu(); 138 + $application_menu = $this->renderApplicationMenu($bar_items); 83 139 $classes = array(); 84 140 $classes[] = 'phabricator-main-menu sprite-main-header'; 85 141 $classes[] = 'phabricator-main-menu-background'; ··· 98 154 $aural, 99 155 $application_menu, 100 156 $search_menu, 101 - $menus, 157 + $menu_bar, 102 158 )); 103 159 } 104 160 ··· 174 230 '')); 175 231 } 176 232 177 - public function renderApplicationMenu() { 233 + private function renderApplicationMenu(array $bar_items) { 178 234 $user = $this->getUser(); 179 - $controller = $this->getController(); 180 - 181 - $applications = PhabricatorApplication::getAllInstalledApplications(); 182 - 183 - $actions = array(); 184 - foreach ($applications as $application) { 185 - $app_actions = $application->buildMainMenuItems($user, $controller); 186 - foreach ($app_actions as $action) { 187 - $actions[] = $action; 188 - } 189 - } 190 - 191 - $actions = msort($actions, 'getOrder'); 192 235 193 236 $view = $this->getApplicationMenu(); 194 237 ··· 199 242 $view->addClass('phabricator-dark-menu'); 200 243 $view->addClass('phabricator-application-menu'); 201 244 202 - if ($actions) { 245 + if ($bar_items) { 203 246 $view->addMenuItem( 204 247 id(new PHUIListItemView()) 205 248 ->setType(PHUIListItemView::TYPE_LABEL) 206 249 ->setName(pht('Actions'))); 207 - foreach ($actions as $action) { 208 - $view->addMenuItem($action); 250 + foreach ($bar_items as $bar_item) { 251 + $view->addMenuItem($bar_item); 209 252 } 210 253 } 211 254
+31
src/view/phui/PHUIMainMenuView.php
··· 1 + <?php 2 + 3 + final class PHUIMainMenuView extends AphrontView { 4 + 5 + private $menuItem; 6 + private $extraContent = array(); 7 + private $order; 8 + 9 + public function setMenuBarItem(PHUIListItemView $menu_item) { 10 + $this->menuItem = $menu_item; 11 + return $this; 12 + } 13 + 14 + public function getMenuBarItem() { 15 + return $this->menuItem; 16 + } 17 + 18 + public function setOrder($order) { 19 + $this->order = $order; 20 + return $this; 21 + } 22 + 23 + public function getOrder() { 24 + return $this->order; 25 + } 26 + 27 + public function render() { 28 + return $this->renderChildren(); 29 + } 30 + 31 + }