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

Fully modularize the "Quick Actions" menu

Summary:
Ref T10077. Currently, we issue 6+ queries on every page to build this menu, since the menu is built application-by-application.

Build the menu with dedicated modules instead so a single "EditEngine" module can provide all of them with one query.

I'd like to reduce this to 0 queries but I'm not totally sure what we want to do with this menu.

This change removes these items, because EditEngine can not currently provide them:

- Calendar: Eventually via EditEngine eventually.
- Conpherence: Probably via EditEngine, doesn't seem too important.
- People: Maybe via EditEngine, doesn't seem too important? "Welcome" is likely better?
- Pholio: Eventually via EditEngine.

It adds a bunch of other items as a side effect:

{F1677151}

This reduces the queries issued on every page by ~5.

This also makes quick create actions visible while logged out (see T7073).

Test Plan:
- Viewed menu while logged in.
- Viewed menu while logged out.
- Viewed standalone version of menu.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10077

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

+150 -145
+4
src/__phutil_library_map__.php
··· 2370 2370 'PhabricatorEditEngineConfigurationTransactionQuery' => 'applications/transactions/query/PhabricatorEditEngineConfigurationTransactionQuery.php', 2371 2371 'PhabricatorEditEngineConfigurationViewController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php', 2372 2372 'PhabricatorEditEngineController' => 'applications/transactions/controller/PhabricatorEditEngineController.php', 2373 + 'PhabricatorEditEngineCreateQuickActions' => 'applications/settings/quickmenu/PhabricatorEditEngineCreateQuickActions.php', 2373 2374 'PhabricatorEditEngineExtension' => 'applications/transactions/engineextension/PhabricatorEditEngineExtension.php', 2374 2375 'PhabricatorEditEngineExtensionModule' => 'applications/transactions/engineextension/PhabricatorEditEngineExtensionModule.php', 2375 2376 'PhabricatorEditEngineListController' => 'applications/transactions/controller/PhabricatorEditEngineListController.php', ··· 3191 3192 'PhabricatorQueryOrderItem' => 'infrastructure/query/order/PhabricatorQueryOrderItem.php', 3192 3193 'PhabricatorQueryOrderTestCase' => 'infrastructure/query/order/__tests__/PhabricatorQueryOrderTestCase.php', 3193 3194 'PhabricatorQueryOrderVector' => 'infrastructure/query/order/PhabricatorQueryOrderVector.php', 3195 + 'PhabricatorQuickActions' => 'applications/settings/quickmenu/PhabricatorQuickActions.php', 3194 3196 'PhabricatorRateLimitRequestExceptionHandler' => 'aphront/handler/PhabricatorRateLimitRequestExceptionHandler.php', 3195 3197 'PhabricatorRecaptchaConfigOptions' => 'applications/config/option/PhabricatorRecaptchaConfigOptions.php', 3196 3198 'PhabricatorRecipientHasBadgeEdgeType' => 'applications/badges/edge/PhabricatorRecipientHasBadgeEdgeType.php', ··· 6962 6964 'PhabricatorEditEngineConfigurationTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 6963 6965 'PhabricatorEditEngineConfigurationViewController' => 'PhabricatorEditEngineController', 6964 6966 'PhabricatorEditEngineController' => 'PhabricatorApplicationTransactionController', 6967 + 'PhabricatorEditEngineCreateQuickActions' => 'PhabricatorQuickActions', 6965 6968 'PhabricatorEditEngineExtension' => 'Phobject', 6966 6969 'PhabricatorEditEngineExtensionModule' => 'PhabricatorConfigModule', 6967 6970 'PhabricatorEditEngineListController' => 'PhabricatorEditEngineController', ··· 7916 7919 'Phobject', 7917 7920 'Iterator', 7918 7921 ), 7922 + 'PhabricatorQuickActions' => 'Phobject', 7919 7923 'PhabricatorRateLimitRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler', 7920 7924 'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions', 7921 7925 'PhabricatorRecipientHasBadgeEdgeType' => 'PhabricatorEdgeType',
-11
src/applications/base/PhabricatorApplication.php
··· 335 335 } 336 336 337 337 338 - /** 339 - * Build items for the "quick create" menu. 340 - * 341 - * @param PhabricatorUser The viewing user. 342 - * @return list<PHUIListItemView> List of menu items. 343 - */ 344 - public function getQuickCreateItems(PhabricatorUser $viewer) { 345 - return array(); 346 - } 347 - 348 - 349 338 /* -( Application Management )--------------------------------------------- */ 350 339 351 340
-12
src/applications/calendar/application/PhabricatorCalendarApplication.php
··· 73 73 ); 74 74 } 75 75 76 - public function getQuickCreateItems(PhabricatorUser $viewer) { 77 - $items = array(); 78 - 79 - $item = id(new PHUIListItemView()) 80 - ->setName(pht('Calendar Event')) 81 - ->setIcon('fa-calendar') 82 - ->setHref($this->getBaseURI().'event/create/'); 83 - $items[] = $item; 84 - 85 - return $items; 86 - } 87 - 88 76 public function getMailCommandObjects() { 89 77 return array( 90 78 'event' => array(
-13
src/applications/conpherence/application/PhabricatorConpherenceApplication.php
··· 48 48 ); 49 49 } 50 50 51 - public function getQuickCreateItems(PhabricatorUser $viewer) { 52 - $items = array(); 53 - 54 - $item = id(new PHUIListItemView()) 55 - ->setName(pht('Conpherence Room')) 56 - ->setIcon('fa-comments') 57 - ->setWorkflow(true) 58 - ->setHref($this->getBaseURI().'new/'); 59 - $items[] = $item; 60 - 61 - return $items; 62 - } 63 - 64 51 public function getQuicksandURIPatternBlacklist() { 65 52 return array( 66 53 '/conpherence/.*',
+21 -43
src/applications/home/application/PhabricatorHomeApplication.php
··· 42 42 PhabricatorUser $user, 43 43 PhabricatorController $controller = null) { 44 44 45 - $quick_create_items = $this->loadAllQuickCreateItems($user); 46 45 $items = array(); 47 - 48 - if ($user->isLoggedIn() && 49 - $user->isUserActivated() && 50 - $quick_create_items) { 51 - $create_id = celerity_generate_unique_node_id(); 52 - Javelin::initBehavior( 53 - 'aphlict-dropdown', 54 - array( 55 - 'bubbleID' => $create_id, 56 - 'dropdownID' => 'phabricator-quick-create-menu', 57 - 'local' => true, 58 - 'desktop' => true, 59 - 'right' => true, 60 - )); 61 - 62 - $item = id(new PHUIListItemView()) 63 - ->setName(pht('Create New...')) 64 - ->setIcon('fa-plus') 65 - ->addClass('core-menu-item') 66 - ->setHref('/home/create/') 67 - ->addSigil('quick-create-menu') 68 - ->setID($create_id) 69 - ->setAural(pht('Quick Create')) 70 - ->setOrder(300); 71 - $items[] = $item; 72 - } 73 - 74 - return $items; 75 - } 46 + $create_id = celerity_generate_unique_node_id(); 76 47 77 - public function loadAllQuickCreateItems(PhabricatorUser $viewer) { 78 - $applications = id(new PhabricatorApplicationQuery()) 79 - ->setViewer($viewer) 80 - ->withInstalled(true) 81 - ->execute(); 48 + Javelin::initBehavior( 49 + 'aphlict-dropdown', 50 + array( 51 + 'bubbleID' => $create_id, 52 + 'dropdownID' => 'phabricator-quick-create-menu', 53 + 'local' => true, 54 + 'desktop' => true, 55 + 'right' => true, 56 + )); 82 57 83 - $items = array(); 84 - foreach ($applications as $application) { 85 - $app_items = $application->getQuickCreateItems($viewer); 86 - foreach ($app_items as $app_item) { 87 - $items[] = $app_item; 88 - } 89 - } 58 + $item = id(new PHUIListItemView()) 59 + ->setName(pht('Quick Actions')) 60 + ->setIcon('fa-plus') 61 + ->addClass('core-menu-item') 62 + ->setHref('/home/create/') 63 + ->addSigil('quick-create-menu') 64 + ->setID($create_id) 65 + ->setAural(pht('Quick Actions')) 66 + ->setOrder(300); 67 + $items[] = $item; 90 68 91 69 return $items; 92 70 } ··· 95 73 PhabricatorUser $viewer, 96 74 PhabricatorController $controller = null) { 97 75 98 - $items = $this->loadAllQuickCreateItems($viewer); 76 + $items = PhabricatorQuickActions::loadMenuItemsForUser($viewer); 99 77 100 78 $view = null; 101 79 if ($items) {
+1 -1
src/applications/home/controller/PhabricatorHomeQuickCreateController.php
··· 6 6 public function handleRequest(AphrontRequest $request) { 7 7 $viewer = $this->getViewer(); 8 8 9 - $items = $this->getCurrentApplication()->loadAllQuickCreateItems($viewer); 9 + $items = PhabricatorQuickActions::loadMenuItemsForUser($viewer); 10 10 11 11 $list = id(new PHUIObjectItemListView()) 12 12 ->setUser($viewer);
-6
src/applications/maniphest/application/PhabricatorManiphestApplication.php
··· 90 90 return $status; 91 91 } 92 92 93 - public function getQuickCreateItems(PhabricatorUser $viewer) { 94 - return id(new ManiphestEditEngine()) 95 - ->setViewer($viewer) 96 - ->loadQuickCreateItems(); 97 - } 98 - 99 93 public function supportsEmailIntegration() { 100 94 return true; 101 95 }
-6
src/applications/paste/application/PhabricatorPasteApplication.php
··· 76 76 ); 77 77 } 78 78 79 - public function getQuickCreateItems(PhabricatorUser $viewer) { 80 - return id(new PhabricatorPasteEditEngine()) 81 - ->setViewer($viewer) 82 - ->loadQuickCreateItems(); 83 - } 84 - 85 79 public function getMailCommandObjects() { 86 80 return array( 87 81 'paste' => array(
-25
src/applications/people/application/PhabricatorPeopleApplication.php
··· 127 127 return $status; 128 128 } 129 129 130 - public function getQuickCreateItems(PhabricatorUser $viewer) { 131 - $items = array(); 132 - 133 - $can_create = PhabricatorPolicyFilter::hasCapability( 134 - $viewer, 135 - $this, 136 - PeopleCreateUsersCapability::CAPABILITY); 137 - 138 - if ($can_create) { 139 - $item = id(new PHUIListItemView()) 140 - ->setName(pht('User Account')) 141 - ->setIcon('fa-users') 142 - ->setHref($this->getBaseURI().'create/'); 143 - $items[] = $item; 144 - } else if ($viewer->getIsAdmin()) { 145 - $item = id(new PHUIListItemView()) 146 - ->setName(pht('Bot Account')) 147 - ->setIcon('fa-android') 148 - ->setHref($this->getBaseURI().'new/bot/'); 149 - $items[] = $item; 150 - } 151 - 152 - return $items; 153 - } 154 - 155 130 public function getApplicationSearchDocumentTypes() { 156 131 return array( 157 132 PhabricatorPeopleUserPHIDType::TYPECONST,
-12
src/applications/pholio/application/PhabricatorPholioApplication.php
··· 59 59 ); 60 60 } 61 61 62 - public function getQuickCreateItems(PhabricatorUser $viewer) { 63 - $items = array(); 64 - 65 - $item = id(new PHUIListItemView()) 66 - ->setName(pht('Pholio Mock')) 67 - ->setIcon('fa-picture-o') 68 - ->setHref($this->getBaseURI().'create/'); 69 - $items[] = $item; 70 - 71 - return $items; 72 - } 73 - 74 62 protected function getCustomCapabilities() { 75 63 return array( 76 64 PholioDefaultViewCapability::CAPABILITY => array(
-6
src/applications/project/application/PhabricatorProjectApplication.php
··· 108 108 ); 109 109 } 110 110 111 - public function getQuickCreateItems(PhabricatorUser $viewer) { 112 - return id(new PhabricatorProjectEditEngine()) 113 - ->setViewer($viewer) 114 - ->loadQuickCreateItems(); 115 - } 116 - 117 111 protected function getCustomCapabilities() { 118 112 return array( 119 113 ProjectCreateProjectsCapability::CAPABILITY => array(),
+46
src/applications/settings/quickmenu/PhabricatorEditEngineCreateQuickActions.php
··· 1 + <?php 2 + 3 + final class PhabricatorEditEngineCreateQuickActions 4 + extends PhabricatorQuickActions { 5 + 6 + const QUICKACTIONSKEY = 'editengine.create'; 7 + 8 + public function getQuickMenuItems() { 9 + $viewer = $this->getViewer(); 10 + 11 + $engines = PhabricatorEditEngine::getAllEditEngines(); 12 + 13 + foreach ($engines as $key => $engine) { 14 + if (!$engine->hasQuickCreateActions()) { 15 + unset($engines[$key]); 16 + } 17 + } 18 + 19 + if (!$engines) { 20 + return array(); 21 + } 22 + 23 + $engine_keys = array_keys($engines); 24 + 25 + $configs = id(new PhabricatorEditEngineConfigurationQuery()) 26 + ->setViewer($viewer) 27 + ->withEngineKeys($engine_keys) 28 + ->withIsDefault(true) 29 + ->withIsDisabled(false) 30 + ->execute(); 31 + $configs = msort($configs, 'getCreateSortKey'); 32 + $configs = mgroup($configs, 'getEngineKey'); 33 + 34 + $items = array(); 35 + foreach ($engines as $key => $engine) { 36 + $engine_configs = idx($configs, $key, array()); 37 + $engine_items = $engine->newQuickCreateActions($engine_configs); 38 + foreach ($engine_items as $engine_item) { 39 + $items[] = $engine_item; 40 + } 41 + } 42 + 43 + return $items; 44 + } 45 + 46 + }
+54
src/applications/settings/quickmenu/PhabricatorQuickActions.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorQuickActions extends Phobject { 4 + 5 + private $viewer; 6 + 7 + public function setViewer(PhabricatorUser $viewer) { 8 + $this->viewer = $viewer; 9 + return $this; 10 + } 11 + 12 + public function getViewer() { 13 + return $this->viewer; 14 + } 15 + 16 + public function isEnabled() { 17 + return true; 18 + } 19 + 20 + abstract public function getQuickMenuItems(); 21 + 22 + final public function getQuickActionsKey() { 23 + return $this->getPhobjectClassConstant('QUICKACTIONSKEY'); 24 + } 25 + 26 + public static function getAllQuickActions() { 27 + return id(new PhutilClassMapQuery()) 28 + ->setAncestorClass(__CLASS__) 29 + ->setUniqueMethod('getQuickActionsKey') 30 + ->execute(); 31 + } 32 + 33 + public static function loadMenuItemsForUser(PhabricatorUser $viewer) { 34 + $actions = self::getAllQuickActions(); 35 + 36 + foreach ($actions as $key => $action) { 37 + $action->setViewer($viewer); 38 + if (!$action->isEnabled()) { 39 + unset($actions[$key]); 40 + continue; 41 + } 42 + } 43 + 44 + $items = array(); 45 + foreach ($actions as $key => $action) { 46 + foreach ($action->getQuickMenuItems() as $item) { 47 + $items[] = $item; 48 + } 49 + } 50 + 51 + return $items; 52 + } 53 + 54 + }
+24 -10
src/applications/transactions/editengine/PhabricatorEditEngine.php
··· 1972 1972 return $application->getIcon(); 1973 1973 } 1974 1974 1975 - public function loadQuickCreateItems() { 1975 + public function hasQuickCreateActions() { 1976 + if (!$this->isEngineConfigurable()) { 1977 + return false; 1978 + } 1979 + 1980 + return true; 1981 + } 1982 + 1983 + public function newQuickCreateActions(array $configs) { 1976 1984 $items = array(); 1977 1985 1978 - if (!$this->hasCreateCapability()) { 1979 - return $items; 1986 + if (!$configs) { 1987 + return array(); 1980 1988 } 1981 1989 1982 - $configs = $this->loadUsableConfigurationsForCreate(); 1990 + // If the viewer is logged in and can't create objects, don't show the 1991 + // menu item. If they're logged out, we assume they could create objects 1992 + // if they logged in, so we show the item as a hint about how to 1993 + // accomplish the action. 1994 + if ($this->getViewer()->isLoggedIn()) { 1995 + if (!$this->hasCreateCapability()) { 1996 + return array(); 1997 + } 1998 + } 1983 1999 1984 - if (!$configs) { 1985 - // No items to add. 1986 - } else if (count($configs) == 1) { 2000 + if (count($configs) == 1) { 1987 2001 $config = head($configs); 1988 - $items[] = $this->newQuickCreateItem($config); 2002 + $items[] = $this->newQuickCreateAction($config); 1989 2003 } else { 1990 2004 $group_name = $this->getQuickCreateMenuHeaderText(); 1991 2005 ··· 1994 2008 ->setName($group_name); 1995 2009 1996 2010 foreach ($configs as $config) { 1997 - $items[] = $this->newQuickCreateItem($config) 2011 + $items[] = $this->newQuickCreateAction($config) 1998 2012 ->setIndented(true); 1999 2013 } 2000 2014 } ··· 2017 2031 return $configs; 2018 2032 } 2019 2033 2020 - private function newQuickCreateItem( 2034 + private function newQuickCreateAction( 2021 2035 PhabricatorEditEngineConfiguration $config) { 2022 2036 2023 2037 $item_name = $config->getName();