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

Allow menu items to render their own content; make Dashboard items render on-page

Summary:
Ref T11957. When you click a dashboard item, it now sends you to `/<app>/item/view/123/`, which renders the proper crumbs, navigation, etc., with the dashboard as page content.

This works as you'd expect in Projects:

{F2508568}

It's sliiiightly odd in Favorites since we nuke the nav menu, but seems basically fine?

{F2508571}

Test Plan:
- Created a dashboard panel on a project.
- Clicked it, saw it render.
- Made it the default panel, viewed project default screen, saw dashboard.
- Disabled every panel I could, still saw reasonable behavior (this is silly anyway).

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T11957

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

+113 -27
+1 -1
src/applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php
··· 7 7 return true; 8 8 } 9 9 10 - protected function getItemURI($path) { 10 + public function getItemURI($path) { 11 11 $object = $this->getProfileObject(); 12 12 $custom = $this->getCustomPHID(); 13 13
+1 -1
src/applications/home/engine/PhabricatorHomeProfileMenuEngine.php
··· 7 7 return true; 8 8 } 9 9 10 - protected function getItemURI($path) { 10 + public function getItemURI($path) { 11 11 $object = $this->getProfileObject(); 12 12 $custom = $this->getCustomPHID(); 13 13
+1 -1
src/applications/people/engine/PhabricatorPeopleProfileMenuEngine.php
··· 10 10 return false; 11 11 } 12 12 13 - protected function getItemURI($path) { 13 + public function getItemURI($path) { 14 14 $user = $this->getProfileObject(); 15 15 $username = $user->getUsername(); 16 16 $username = phutil_escape_uri($username);
+2 -1
src/applications/project/controller/PhabricatorProjectViewController.php
··· 25 25 $controller_object = new PhabricatorProjectBoardViewController(); 26 26 break; 27 27 case PhabricatorProject::ITEM_PROFILE: 28 - default: 29 28 $controller_object = new PhabricatorProjectProfileController(); 30 29 break; 30 + default: 31 + return $engine->buildResponse(); 31 32 } 32 33 33 34 return $this->delegateToController($controller_object);
+1 -1
src/applications/project/engine/PhabricatorProjectProfileMenuEngine.php
··· 7 7 return true; 8 8 } 9 9 10 - protected function getItemURI($path) { 10 + public function getItemURI($path) { 11 11 $project = $this->getProfileObject(); 12 12 $id = $project->getID(); 13 13 return "/project/{$id}/item/{$path}";
-5
src/applications/project/menuitem/PhabricatorProjectManageProfileMenuItem.php
··· 18 18 return false; 19 19 } 20 20 21 - public function canMakeDefault( 22 - PhabricatorProfileMenuItemConfiguration $config) { 23 - return true; 24 - } 25 - 26 21 public function getDisplayName( 27 22 PhabricatorProfileMenuItemConfiguration $config) { 28 23 $name = $config->getMenuItemProperty('name');
+39 -16
src/applications/search/engine/PhabricatorProfileMenuEngine.php
··· 82 82 return $this->showNavigation; 83 83 } 84 84 85 - abstract protected function getItemURI($path); 85 + abstract public function getItemURI($path); 86 86 abstract protected function isMenuEngineConfigurable(); 87 87 88 88 abstract protected function getBuiltinProfileItems($object); ··· 102 102 $request = $controller->getRequest(); 103 103 104 104 $item_action = $request->getURIData('itemAction'); 105 + if (!$item_action) { 106 + $item_action = 'view'; 107 + } 105 108 106 109 // If the engine is not configurable, don't respond to any of the editing 107 110 // or configuration routes. ··· 136 139 } 137 140 } 138 141 142 + if (!$selected_item) { 143 + if ($item_action == 'view') { 144 + $selected_item = $this->getDefaultItem(); 145 + } 146 + } 147 + 139 148 switch ($item_action) { 140 149 case 'view': 141 150 case 'info': ··· 159 168 } 160 169 161 170 $navigation = $this->buildNavigation(); 162 - $navigation->selectFilter('item.configure'); 163 171 164 172 $crumbs = $controller->buildApplicationCrumbsForEditEngine(); 165 - switch ($this->getMenuType()) { 166 - case 'personal': 167 - $crumbs->addTextCrumb(pht('Personal')); 168 - break; 169 - case 'global': 170 - $crumbs->addTextCrumb(pht('Global')); 171 - break; 173 + 174 + // TODO: This stuff might need a little tweaking at some point, since it 175 + // causes "Global" and "Personal" to show up in contexts where they don't 176 + // make sense, notably Projects. 177 + if ($item_action != 'view') { 178 + $navigation->selectFilter('item.configure'); 179 + switch ($this->getMenuType()) { 180 + case 'personal': 181 + $crumbs->addTextCrumb(pht('Personal')); 182 + break; 183 + case 'global': 184 + $crumbs->addTextCrumb(pht('Global')); 185 + break; 186 + } 172 187 } 173 188 174 189 switch ($item_action) { 175 190 case 'view': 191 + $navigation->selectFilter($selected_item->getItemIdentifier()); 192 + 176 193 $content = $this->buildItemViewContent($selected_item); 194 + $crumbs->addTextCrumb($selected_item->getDisplayName()); 195 + if (!$content) { 196 + return new Aphront404Response(); 197 + } 177 198 break; 178 199 case 'configure': 179 200 $content = $this->buildItemConfigureContent($item_list); ··· 225 246 if ($this->getShowNavigation()) { 226 247 $page->setNavigation($navigation); 227 248 } 249 + 228 250 return $page; 229 251 } 230 252 ··· 269 291 if (count($items) == 1) { 270 292 $item = head($items); 271 293 if ($item->getKey() === null) { 272 - $builtin_key = $menu_item->getBuiltinKey(); 273 - $item_phid = $menu_item->getPHID(); 274 - if ($builtin_key !== null) { 275 - $item->setKey($builtin_key); 276 - } else if ($item_phid !== null) { 277 - $item->setKey($item_phid); 278 - } 294 + $item_identifier = $menu_item->getItemIdentifier(); 295 + $item->setKey($item_identifier); 279 296 } 280 297 } 281 298 ··· 326 343 foreach ($stored_items as $stored_item) { 327 344 $impl = $stored_item->getMenuItem(); 328 345 $impl->setViewer($viewer); 346 + $impl->setEngine($this); 329 347 } 330 348 331 349 // Merge the stored items into the builtin items. If a builtin item has ··· 442 460 443 461 $item = clone $item; 444 462 $item->setViewer($viewer); 463 + $item->setEngine($this); 445 464 446 465 $builtin 447 466 ->setProfilePHID($object->getPHID()) ··· 546 565 ->setURI($this->getConfigureURI()); 547 566 } 548 567 568 + private function buildItemViewContent( 569 + PhabricatorProfileMenuItemConfiguration $item) { 570 + return $item->newPageContent(); 571 + } 549 572 550 573 private function buildItemConfigureContent(array $items) { 551 574 $viewer = $this->getViewer();
+31 -1
src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php
··· 21 21 return true; 22 22 } 23 23 24 + public function canMakeDefault( 25 + PhabricatorProfileMenuItemConfiguration $config) { 26 + return true; 27 + } 28 + 24 29 public function attachDashboard($dashboard) { 25 30 $this->dashboard = $dashboard; 26 31 return $this; ··· 28 33 29 34 public function getDashboard() { 30 35 $dashboard = $this->dashboard; 36 + 31 37 if (!$dashboard) { 32 38 return null; 33 39 } else if ($dashboard->isArchived()) { 34 40 return null; 35 41 } 42 + 36 43 return $dashboard; 44 + } 45 + 46 + public function newPageContent( 47 + PhabricatorProfileMenuItemConfiguration $config) { 48 + $viewer = $this->getViewer(); 49 + 50 + $dashboard_phid = $config->getMenuItemProperty('dashboardPHID'); 51 + 52 + // Reload the dashboard to attach panels, which we need for rendering. 53 + $dashboard = id(new PhabricatorDashboardQuery()) 54 + ->setViewer($viewer) 55 + ->withPHIDs(array($dashboard_phid)) 56 + ->needPanels(true) 57 + ->executeOne(); 58 + if (!$dashboard) { 59 + return null; 60 + } 61 + 62 + $engine = id(new PhabricatorDashboardRenderingEngine()) 63 + ->setViewer($viewer) 64 + ->setDashboard($dashboard); 65 + 66 + return $engine->renderDashboard(); 37 67 } 38 68 39 69 public function willBuildNavigationItems(array $items) { ··· 100 130 101 131 $icon = $dashboard->getIcon(); 102 132 $name = $this->getDisplayName($config); 103 - $href = $dashboard->getViewURI(); 133 + $href = $this->getItemViewURI($config); 104 134 105 135 $item = $this->newItem() 106 136 ->setHref($href)
+24
src/applications/search/menuitem/PhabricatorProfileMenuItem.php
··· 3 3 abstract class PhabricatorProfileMenuItem extends Phobject { 4 4 5 5 private $viewer; 6 + private $engine; 6 7 7 8 final public function buildNavigationMenuItems( 8 9 PhabricatorProfileMenuItemConfiguration $config) { ··· 55 56 return $this->viewer; 56 57 } 57 58 59 + public function setEngine(PhabricatorProfileMenuEngine $engine) { 60 + $this->engine = $engine; 61 + return $this; 62 + } 63 + 64 + public function getEngine() { 65 + return $this->engine; 66 + } 67 + 58 68 final public function getMenuItemKey() { 59 69 return $this->getPhobjectClassConstant('MENUITEMKEY'); 60 70 } ··· 68 78 69 79 protected function newItem() { 70 80 return new PHUIListItemView(); 81 + } 82 + 83 + public function newPageContent( 84 + PhabricatorProfileMenuItemConfiguration $config) { 85 + return null; 86 + } 87 + 88 + public function getItemViewURI( 89 + PhabricatorProfileMenuItemConfiguration $config) { 90 + 91 + $engine = $this->getEngine(); 92 + $key = $config->getItemIdentifier(); 93 + 94 + return $engine->getItemURI("view/{$key}/"); 71 95 } 72 96 73 97 public function validateTransactions(
+13
src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php
··· 185 185 return ($this->getVisibility() === self::VISIBILITY_DEFAULT); 186 186 } 187 187 188 + public function getItemIdentifier() { 189 + $id = $this->getID(); 190 + 191 + if ($id) { 192 + return (int)$id; 193 + } 194 + 195 + return $this->getBuiltinKey(); 196 + } 197 + 198 + public function newPageContent() { 199 + return $this->getMenuItem()->newPageContent($this); 200 + } 188 201 189 202 /* -( PhabricatorPolicyInterface )----------------------------------------- */ 190 203