diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2953,13 +2953,16 @@ 'PhabricatorDashboardPortalEditEngine' => 'applications/dashboard/editor/PhabricatorDashboardPortalEditEngine.php', 'PhabricatorDashboardPortalEditor' => 'applications/dashboard/editor/PhabricatorDashboardPortalEditor.php', 'PhabricatorDashboardPortalListController' => 'applications/dashboard/controller/portal/PhabricatorDashboardPortalListController.php', + 'PhabricatorDashboardPortalMenuItem' => 'applications/dashboard/menuitem/PhabricatorDashboardPortalMenuItem.php', 'PhabricatorDashboardPortalNameTransaction' => 'applications/dashboard/xaction/portal/PhabricatorDashboardPortalNameTransaction.php', 'PhabricatorDashboardPortalPHIDType' => 'applications/dashboard/phid/PhabricatorDashboardPortalPHIDType.php', + 'PhabricatorDashboardPortalProfileMenuEngine' => 'applications/dashboard/engine/PhabricatorDashboardPortalProfileMenuEngine.php', 'PhabricatorDashboardPortalQuery' => 'applications/dashboard/query/PhabricatorDashboardPortalQuery.php', 'PhabricatorDashboardPortalSearchConduitAPIMethod' => 'applications/dashboard/conduit/PhabricatorDashboardPortalSearchConduitAPIMethod.php', 'PhabricatorDashboardPortalSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardPortalSearchEngine.php', 'PhabricatorDashboardPortalStatus' => 'applications/dashboard/constants/PhabricatorDashboardPortalStatus.php', 'PhabricatorDashboardPortalTransaction' => 'applications/dashboard/storage/PhabricatorDashboardPortalTransaction.php', + 'PhabricatorDashboardPortalTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardPortalTransactionQuery.php', 'PhabricatorDashboardPortalTransactionType' => 'applications/dashboard/xaction/portal/PhabricatorDashboardPortalTransactionType.php', 'PhabricatorDashboardPortalViewController' => 'applications/dashboard/controller/portal/PhabricatorDashboardPortalViewController.php', 'PhabricatorDashboardProfileController' => 'applications/dashboard/controller/PhabricatorDashboardProfileController.php', @@ -8924,13 +8927,16 @@ 'PhabricatorDashboardPortalEditEngine' => 'PhabricatorEditEngine', 'PhabricatorDashboardPortalEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorDashboardPortalListController' => 'PhabricatorDashboardPortalController', + 'PhabricatorDashboardPortalMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorDashboardPortalNameTransaction' => 'PhabricatorDashboardPortalTransactionType', 'PhabricatorDashboardPortalPHIDType' => 'PhabricatorPHIDType', + 'PhabricatorDashboardPortalProfileMenuEngine' => 'PhabricatorProfileMenuEngine', 'PhabricatorDashboardPortalQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorDashboardPortalSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PhabricatorDashboardPortalSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorDashboardPortalStatus' => 'Phobject', 'PhabricatorDashboardPortalTransaction' => 'PhabricatorModularTransaction', + 'PhabricatorDashboardPortalTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorDashboardPortalTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorDashboardPortalViewController' => 'PhabricatorDashboardPortalController', 'PhabricatorDashboardProfileController' => 'PhabricatorController', diff --git a/src/applications/dashboard/application/PhabricatorDashboardApplication.php b/src/applications/dashboard/application/PhabricatorDashboardApplication.php --- a/src/applications/dashboard/application/PhabricatorDashboardApplication.php +++ b/src/applications/dashboard/application/PhabricatorDashboardApplication.php @@ -27,6 +27,9 @@ } public function getRoutes() { + $menu_rules = $this->getProfileMenuRouting( + 'PhabricatorDashboardPortalViewController'); + return array( '/W(?P\d+)' => 'PhabricatorDashboardPanelViewController', '/dashboard/' => array( @@ -62,8 +65,10 @@ 'PhabricatorDashboardPortalListController', $this->getEditRoutePattern('edit/') => 'PhabricatorDashboardPortalEditController', - 'view/(?P\d)/' => - 'PhabricatorDashboardPortalViewController', + 'view/(?P\d)/' => array( + '' => 'PhabricatorDashboardPortalViewController', + ) + $menu_rules, + ), ); } diff --git a/src/applications/dashboard/controller/portal/PhabricatorDashboardPortalViewController.php b/src/applications/dashboard/controller/portal/PhabricatorDashboardPortalViewController.php --- a/src/applications/dashboard/controller/portal/PhabricatorDashboardPortalViewController.php +++ b/src/applications/dashboard/controller/portal/PhabricatorDashboardPortalViewController.php @@ -3,13 +3,24 @@ final class PhabricatorDashboardPortalViewController extends PhabricatorDashboardPortalController { + private $portal; + + public function setPortal(PhabricatorDashboardPortal $portal) { + $this->portal = $portal; + return $this; + } + + public function getPortal() { + return $this->portal; + } + public function shouldAllowPublic() { return true; } public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); - $id = $request->getURIData('id'); + $id = $request->getURIData('portalID'); $portal = id(new PhabricatorDashboardPortalQuery()) ->setViewer($viewer) @@ -19,16 +30,30 @@ return new Aphront404Response(); } - $content = $portal->getObjectName(); + $this->setPortal($portal); + + $engine = id(new PhabricatorDashboardPortalProfileMenuEngine()) + ->setProfileObject($portal) + ->setController($this); + + return $engine->buildResponse(); + } + + protected function buildApplicationCrumbs() { + $crumbs = parent::buildApplicationCrumbs(); + + $portal = $this->getPortal(); + if ($portal) { + $crumbs->addTextCrumb($portal->getName(), $portal->getURI()); + } + + return $crumbs; + } - return $this->newPage() - ->setTitle( - array( - pht('Portal'), - $portal->getName(), - )) - ->setPageObjectPHIDs(array($portal->getPHID())) - ->appendChild($content); + public function newTimelineView() { + return $this->buildTransactionTimeline( + $this->getPortal(), + new PhabricatorDashboardPortalTransactionQuery()); } } diff --git a/src/applications/dashboard/editor/PhabricatorDashboardPortalEditEngine.php b/src/applications/dashboard/editor/PhabricatorDashboardPortalEditEngine.php --- a/src/applications/dashboard/editor/PhabricatorDashboardPortalEditEngine.php +++ b/src/applications/dashboard/editor/PhabricatorDashboardPortalEditEngine.php @@ -58,7 +58,11 @@ } protected function getObjectViewURI($object) { - return $object->getURI(); + if ($this->getIsCreate()) { + return $object->getURI(); + } else { + return '/portal/view/'.$object->getID().'/view/manage/'; + } } protected function getEditorURI() { diff --git a/src/applications/dashboard/engine/PhabricatorDashboardPortalProfileMenuEngine.php b/src/applications/dashboard/engine/PhabricatorDashboardPortalProfileMenuEngine.php new file mode 100644 --- /dev/null +++ b/src/applications/dashboard/engine/PhabricatorDashboardPortalProfileMenuEngine.php @@ -0,0 +1,38 @@ +getProfileObject(); + + return $portal->getURI().$path; + } + + protected function getBuiltinProfileItems($object) { + $items = array(); + + $items[] = $this->newManageItem(); + + $items[] = $this->newItem() + ->setMenuItemKey(PhabricatorDashboardPortalMenuItem::MENUITEMKEY) + ->setBuiltinKey('manage'); + + return $items; + } + + protected function newNoMenuItemsView() { + return $this->newEmptyView( + pht('New Portal'), + pht('Use "Edit Menu" to add menu items to this portal.')); + } + +} diff --git a/src/applications/dashboard/menuitem/PhabricatorDashboardPortalMenuItem.php b/src/applications/dashboard/menuitem/PhabricatorDashboardPortalMenuItem.php new file mode 100644 --- /dev/null +++ b/src/applications/dashboard/menuitem/PhabricatorDashboardPortalMenuItem.php @@ -0,0 +1,117 @@ +getMenuItemProperty('name'); + + if (strlen($name)) { + return $name; + } + + return $this->getDefaultName(); + } + + public function buildEditEngineFields( + PhabricatorProfileMenuItemConfiguration $config) { + return array( + id(new PhabricatorTextEditField()) + ->setKey('name') + ->setLabel(pht('Name')) + ->setPlaceholder($this->getDefaultName()) + ->setValue($config->getMenuItemProperty('name')), + ); + } + + protected function newNavigationMenuItems( + PhabricatorProfileMenuItemConfiguration $config) { + $viewer = $this->getViewer(); + + if (!$viewer->isLoggedIn()) { + return array(); + } + + $href = $this->getItemViewURI($config); + $name = $this->getDisplayName($config); + $icon = 'fa-pencil'; + + $item = $this->newItem() + ->setHref($href) + ->setName($name) + ->setIcon($icon); + + return array( + $item, + ); + } + + public function newPageContent( + PhabricatorProfileMenuItemConfiguration $config) { + $viewer = $this->getViewer(); + $engine = $this->getEngine(); + $portal = $engine->getProfileObject(); + $controller = $engine->getController(); + + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Manage Portal')); + + $edit_uri = urisprintf( + '/portal/edit/%d/', + $portal->getID()); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $portal, + PhabricatorPolicyCapability::CAN_EDIT); + + $curtain = $controller->newCurtainView($portal) + ->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Edit Portal')) + ->setIcon('fa-pencil') + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit) + ->setHref($edit_uri)); + + $timeline = $controller->newTimelineView() + ->setShouldTerminate(true); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setCurtain($curtain) + ->setMainColumn( + array( + $timeline, + )); + + return $view; + } + + +} diff --git a/src/applications/dashboard/query/PhabricatorDashboardPortalTransactionQuery.php b/src/applications/dashboard/query/PhabricatorDashboardPortalTransactionQuery.php new file mode 100644 --- /dev/null +++ b/src/applications/dashboard/query/PhabricatorDashboardPortalTransactionQuery.php @@ -0,0 +1,10 @@ +getDisplayName(); + if ($selected_item) { + $page_title = $selected_item->getDisplayName(); + } else { + $page_title = pht('Empty'); + } } switch ($item_action) { case 'view': - $navigation->selectFilter($selected_item->getDefaultMenuItemKey()); - - try { - $content = $this->buildItemViewContent($selected_item); - } catch (Exception $ex) { - $content = id(new PHUIInfoView()) - ->setTitle(pht('Unable to Render Dashboard')) - ->setErrors(array($ex->getMessage())); + if ($selected_item) { + $navigation->selectFilter($selected_item->getDefaultMenuItemKey()); + + try { + $content = $this->buildItemViewContent($selected_item); + } catch (Exception $ex) { + $content = id(new PHUIInfoView()) + ->setTitle(pht('Unable to Render Dashboard')) + ->setErrors(array($ex->getMessage())); + } + + $crumbs->addTextCrumb($selected_item->getDisplayName()); + } else { + $content = $this->newNoMenuItemsView(); } - $crumbs->addTextCrumb($selected_item->getDisplayName()); if (!$content) { - return new Aphront404Response(); + $content = $this->newEmptyView( + pht('Empty'), + pht('There is nothing here.')); } break; case 'configure': @@ -346,6 +361,7 @@ if ($this->navigation) { return $this->navigation; } + $nav = id(new AphrontSideNavFilterView()) ->setIsProfileMenu(true) ->setBaseURI(new PhutilURI($this->getItemURI(''))); @@ -365,6 +381,7 @@ $first_item->willBuildNavigationItems($group); } + $has_items = false; foreach ($menu_items as $menu_item) { if ($menu_item->isDisabled()) { continue; @@ -389,9 +406,18 @@ foreach ($items as $item) { $nav->addMenuItem($item); + $has_items = true; } } + if (!$has_items) { + // If the navigation menu has no items, add an empty label item to + // force it to render something. + $empty_item = id(new PHUIListItemView()) + ->setType(PHUIListItemView::TYPE_LABEL); + $nav->addMenuItem($empty_item); + } + $nav->selectFilter(null); $this->navigation = $nav; @@ -1319,5 +1345,20 @@ return $items; } + final protected function newEmptyView($title, $message) { + return id(new PHUIInfoView()) + ->setTitle($title) + ->setSeverity(PHUIInfoView::SEVERITY_NODATA) + ->setErrors( + array( + $message, + )); + } + + protected function newNoMenuItemsView() { + return $this->newEmptyView( + pht('No Menu Items'), + pht('There are no menu items.')); + } }