diff --git a/src/applications/project/controller/PhabricatorProjectBoardController.php b/src/applications/project/controller/PhabricatorProjectBoardController.php
index 18028a1bd0..04ab714eb0 100644
--- a/src/applications/project/controller/PhabricatorProjectBoardController.php
+++ b/src/applications/project/controller/PhabricatorProjectBoardController.php
@@ -1,13 +1,14 @@
 <?php
 
 abstract class PhabricatorProjectBoardController
   extends PhabricatorProjectController {
 
-  public function buildIconNavView(PhabricatorProject $project) {
-    $id = $project->getID();
-    $nav = parent::buildIconNavView($project);
-    $nav->selectFilter(PhabricatorProject::PANEL_WORKBOARD);
-    $nav->addClass('project-board-nav');
-    return $nav;
+  protected function getProfileMenu() {
+    $menu = parent::getProfileMenu();
+
+    $menu->selectFilter(PhabricatorProject::PANEL_WORKBOARD);
+    $menu->addClass('project-board-nav');
+
+    return $menu;
   }
 }
diff --git a/src/applications/project/controller/PhabricatorProjectBoardViewController.php b/src/applications/project/controller/PhabricatorProjectBoardViewController.php
index 7408e67dd8..571d5b866d 100644
--- a/src/applications/project/controller/PhabricatorProjectBoardViewController.php
+++ b/src/applications/project/controller/PhabricatorProjectBoardViewController.php
@@ -1,789 +1,789 @@
 <?php
 
 final class PhabricatorProjectBoardViewController
   extends PhabricatorProjectBoardController {
 
   const BATCH_EDIT_ALL = 'all';
 
   private $id;
   private $slug;
   private $handles;
   private $queryKey;
   private $filter;
   private $sortKey;
   private $showHidden;
 
   public function shouldAllowPublic() {
     return true;
   }
 
   public function handleRequest(AphrontRequest $request) {
     $viewer = $request->getUser();
     $id = $request->getURIData('id');
 
     $show_hidden = $request->getBool('hidden');
     $this->showHidden = $show_hidden;
 
     $project = id(new PhabricatorProjectQuery())
       ->setViewer($viewer)
       ->needImages(true);
     $id = $request->getURIData('id');
     $slug = $request->getURIData('slug');
     if ($slug) {
       $project->withSlugs(array($slug));
     } else {
       $project->withIDs(array($id));
     }
     $project = $project->executeOne();
     if (!$project) {
       return new Aphront404Response();
     }
 
     $this->setProject($project);
     $this->id = $project->getID();
 
     $sort_key = $request->getStr('order');
     switch ($sort_key) {
       case PhabricatorProjectColumn::ORDER_NATURAL:
       case PhabricatorProjectColumn::ORDER_PRIORITY:
         break;
       default:
         $sort_key = PhabricatorProjectColumn::DEFAULT_ORDER;
         break;
     }
     $this->sortKey = $sort_key;
 
     $column_query = id(new PhabricatorProjectColumnQuery())
       ->setViewer($viewer)
       ->withProjectPHIDs(array($project->getPHID()));
     if (!$show_hidden) {
       $column_query->withStatuses(
         array(PhabricatorProjectColumn::STATUS_ACTIVE));
     }
 
     $columns = $column_query->execute();
     $columns = mpull($columns, null, 'getSequence');
 
     // TODO: Expand the checks here if we add the ability
     // to hide the Backlog column
     if (!$columns) {
       $can_edit = PhabricatorPolicyFilter::hasCapability(
         $viewer,
         $project,
         PhabricatorPolicyCapability::CAN_EDIT);
       if (!$can_edit) {
         return $this->noAccessDialog($project);
       }
       switch ($request->getStr('initialize-type')) {
         case 'backlog-only':
           $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
             $column = PhabricatorProjectColumn::initializeNewColumn($viewer)
               ->setSequence(0)
               ->setProperty('isDefault', true)
               ->setProjectPHID($project->getPHID())
               ->save();
             $column->attachProject($project);
             $columns[0] = $column;
           unset($unguarded);
           break;
         case 'import':
           return id(new AphrontRedirectResponse())
             ->setURI(
               $this->getApplicationURI('board/'.$project->getID().'/import/'));
           break;
         default:
           return $this->initializeWorkboardDialog($project);
           break;
       }
     }
 
     ksort($columns);
 
     $board_uri = $this->getApplicationURI('board/'.$project->getID().'/');
 
     $engine = id(new ManiphestTaskSearchEngine())
       ->setViewer($viewer)
       ->setBaseURI($board_uri)
       ->setIsBoardView(true);
 
     if ($request->isFormPost()) {
       $saved = $engine->buildSavedQueryFromRequest($request);
       $engine->saveQuery($saved);
       $filter_form = id(new AphrontFormView())
         ->setUser($viewer);
       $engine->buildSearchForm($filter_form, $saved);
       if ($engine->getErrors()) {
         return $this->newDialog()
           ->setWidth(AphrontDialogView::WIDTH_FULL)
           ->setTitle(pht('Advanced Filter'))
           ->appendChild($filter_form->buildLayoutView())
           ->setErrors($engine->getErrors())
           ->setSubmitURI($board_uri)
           ->addSubmitButton(pht('Apply Filter'))
           ->addCancelButton($board_uri);
       }
       return id(new AphrontRedirectResponse())->setURI(
         $this->getURIWithState(
           $engine->getQueryResultsPageURI($saved->getQueryKey())));
     }
 
     $query_key = $request->getURIData('queryKey');
     if (!$query_key) {
       $query_key = 'open';
     }
     $this->queryKey = $query_key;
 
     $custom_query = null;
     if ($engine->isBuiltinQuery($query_key)) {
       $saved = $engine->buildSavedQueryFromBuiltin($query_key);
     } else {
       $saved = id(new PhabricatorSavedQueryQuery())
         ->setViewer($viewer)
         ->withQueryKeys(array($query_key))
         ->executeOne();
 
       if (!$saved) {
         return new Aphront404Response();
       }
 
       $custom_query = $saved;
     }
 
     if ($request->getURIData('filter')) {
       $filter_form = id(new AphrontFormView())
         ->setUser($viewer);
       $engine->buildSearchForm($filter_form, $saved);
 
       return $this->newDialog()
         ->setWidth(AphrontDialogView::WIDTH_FULL)
         ->setTitle(pht('Advanced Filter'))
         ->appendChild($filter_form->buildLayoutView())
         ->setSubmitURI($board_uri)
         ->addSubmitButton(pht('Apply Filter'))
         ->addCancelButton($board_uri);
     }
 
     $task_query = $engine->buildQueryFromSavedQuery($saved);
 
     $tasks = $task_query
       ->withEdgeLogicPHIDs(
         PhabricatorProjectObjectHasProjectEdgeType::EDGECONST,
         PhabricatorQueryConstraint::OPERATOR_AND,
         array($project->getPHID()))
       ->setOrder(ManiphestTaskQuery::ORDER_PRIORITY)
       ->setViewer($viewer)
       ->execute();
     $tasks = mpull($tasks, null, 'getPHID');
 
     if ($tasks) {
       $positions = id(new PhabricatorProjectColumnPositionQuery())
         ->setViewer($viewer)
         ->withObjectPHIDs(mpull($tasks, 'getPHID'))
         ->withColumns($columns)
         ->execute();
       $positions = mpull($positions, null, 'getObjectPHID');
     } else {
       $positions = array();
     }
 
     $task_map = array();
     foreach ($tasks as $task) {
       $task_phid = $task->getPHID();
       if (empty($positions[$task_phid])) {
         // This shouldn't normally be possible because we create positions on
         // demand, but we might have raced as an object was removed from the
         // board. Just drop the task if we don't have a position for it.
         continue;
       }
 
       $position = $positions[$task_phid];
       $task_map[$position->getColumnPHID()][] = $task_phid;
     }
 
     // If we're showing the board in "natural" order, sort columns by their
     // column positions.
     if ($this->sortKey == PhabricatorProjectColumn::ORDER_NATURAL) {
       foreach ($task_map as $column_phid => $task_phids) {
         $order = array();
         foreach ($task_phids as $task_phid) {
           if (isset($positions[$task_phid])) {
             $order[$task_phid] = $positions[$task_phid]->getOrderingKey();
           } else {
             $order[$task_phid] = 0;
           }
         }
         asort($order);
         $task_map[$column_phid] = array_keys($order);
       }
     }
 
     $task_can_edit_map = id(new PhabricatorPolicyFilter())
       ->setViewer($viewer)
       ->requireCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT))
       ->apply($tasks);
 
     // If this is a batch edit, select the editable tasks in the chosen column
     // and ship the user into the batch editor.
     $batch_edit = $request->getStr('batch');
     if ($batch_edit) {
       if ($batch_edit !== self::BATCH_EDIT_ALL) {
         $column_id_map = mpull($columns, null, 'getID');
         $batch_column = idx($column_id_map, $batch_edit);
         if (!$batch_column) {
           return new Aphront404Response();
         }
 
         $batch_task_phids = idx($task_map, $batch_column->getPHID(), array());
         foreach ($batch_task_phids as $key => $batch_task_phid) {
           if (empty($task_can_edit_map[$batch_task_phid])) {
             unset($batch_task_phids[$key]);
           }
         }
 
         $batch_tasks = array_select_keys($tasks, $batch_task_phids);
       } else {
         $batch_tasks = $task_can_edit_map;
       }
 
       if (!$batch_tasks) {
         $cancel_uri = $this->getURIWithState($board_uri);
         return $this->newDialog()
           ->setTitle(pht('No Editable Tasks'))
           ->appendParagraph(
             pht(
               'The selected column contains no visible tasks which you '.
               'have permission to edit.'))
           ->addCancelButton($board_uri);
       }
 
       $batch_ids = mpull($batch_tasks, 'getID');
       $batch_ids = implode(',', $batch_ids);
 
       $batch_uri = new PhutilURI('/maniphest/batch/');
       $batch_uri->setQueryParam('board', $this->id);
       $batch_uri->setQueryParam('batch', $batch_ids);
       return id(new AphrontRedirectResponse())
         ->setURI($batch_uri);
     }
 
     $board_id = celerity_generate_unique_node_id();
 
     $board = id(new PHUIWorkboardView())
       ->setUser($viewer)
       ->setID($board_id);
 
     $behavior_config = array(
       'boardID' => $board_id,
       'projectPHID' => $project->getPHID(),
       'moveURI' => $this->getApplicationURI('move/'.$project->getID().'/'),
       'createURI' => $this->getCreateURI(),
       'order' => $this->sortKey,
     );
     $this->initBehavior(
       'project-boards',
       $behavior_config);
 
     $this->handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks);
 
     foreach ($columns as $column) {
       $task_phids = idx($task_map, $column->getPHID(), array());
       $column_tasks = array_select_keys($tasks, $task_phids);
 
       $panel = id(new PHUIWorkpanelView())
         ->setHeader($column->getDisplayName())
         ->setSubHeader($column->getDisplayType())
         ->addSigil('workpanel');
 
       $header_icon = $column->getHeaderIcon();
       if ($header_icon) {
         $panel->setHeaderIcon($header_icon);
       }
 
       if ($column->isHidden()) {
         $panel->addClass('project-panel-hidden');
       }
 
       $column_menu = $this->buildColumnMenu($project, $column);
       $panel->addHeaderAction($column_menu);
 
       $tag_id = celerity_generate_unique_node_id();
       $tag_content_id = celerity_generate_unique_node_id();
 
       $count_tag = id(new PHUITagView())
         ->setType(PHUITagView::TYPE_SHADE)
         ->setShade(PHUITagView::COLOR_BLUE)
         ->setID($tag_id)
         ->setName(phutil_tag('span', array('id' => $tag_content_id), '-'))
         ->setStyle('display: none');
 
       $panel->setHeaderTag($count_tag);
 
       $cards = id(new PHUIObjectItemListView())
         ->setUser($viewer)
         ->setFlush(true)
         ->setAllowEmptyList(true)
         ->addSigil('project-column')
         ->setMetadata(
           array(
             'columnPHID' => $column->getPHID(),
             'countTagID' => $tag_id,
             'countTagContentID' => $tag_content_id,
             'pointLimit' => $column->getPointLimit(),
           ));
 
       foreach ($column_tasks as $task) {
         $owner = null;
         if ($task->getOwnerPHID()) {
           $owner = $this->handles[$task->getOwnerPHID()];
         }
         $can_edit = idx($task_can_edit_map, $task->getPHID(), false);
         $cards->addItem(id(new ProjectBoardTaskCard())
           ->setViewer($viewer)
           ->setTask($task)
           ->setOwner($owner)
           ->setCanEdit($can_edit)
           ->getItem());
       }
       $panel->setCards($cards);
       $board->addPanel($panel);
     }
 
     $sort_menu = $this->buildSortMenu(
       $viewer,
       $sort_key);
 
     $filter_menu = $this->buildFilterMenu(
       $viewer,
       $custom_query,
       $engine,
       $query_key);
 
     $manage_menu = $this->buildManageMenu($project, $show_hidden);
 
     $header_link = phutil_tag(
       'a',
       array(
         'href' => $this->getApplicationURI('profile/'.$project->getID().'/'),
       ),
       $project->getName());
 
     $header = id(new PHUIHeaderView())
       ->setHeader($header_link)
       ->setUser($viewer)
       ->setNoBackground(true)
       ->addActionLink($sort_menu)
       ->addActionLink($filter_menu)
       ->addActionLink($manage_menu)
       ->setPolicyObject($project);
 
     $header_box = id(new PHUIBoxView())
       ->appendChild($header)
       ->addClass('project-board-header');
 
     $board_box = id(new PHUIBoxView())
       ->appendChild($board)
       ->addClass('project-board-wrapper');
 
-    $nav = $this->buildIconNavView($project);
+    $nav = $this->getProfileMenu();
 
     return $this->newPage()
       ->setTitle(pht('%s Board', $project->getName()))
       ->setPageObjectPHIDs(array($project->getPHID()))
       ->setShowFooter(false)
       ->setNavigation($nav)
       ->addQuicksandConfig(
         array(
           'boardConfig' => $behavior_config,
         ))
       ->appendChild(
         array(
           $header_box,
           $board_box,
         ));
   }
 
   private function buildSortMenu(
     PhabricatorUser $viewer,
     $sort_key) {
 
     $sort_icon = id(new PHUIIconView())
       ->setIconFont('fa-sort-amount-asc bluegrey');
 
     $named = array(
       PhabricatorProjectColumn::ORDER_NATURAL => pht('Natural'),
       PhabricatorProjectColumn::ORDER_PRIORITY => pht('Sort by Priority'),
     );
 
     $base_uri = $this->getURIWithState();
 
     $items = array();
     foreach ($named as $key => $name) {
       $is_selected = ($key == $sort_key);
       if ($is_selected) {
         $active_order = $name;
       }
 
       $item = id(new PhabricatorActionView())
         ->setIcon('fa-sort-amount-asc')
         ->setSelected($is_selected)
         ->setName($name);
 
       $uri = $base_uri->alter('order', $key);
       $item->setHref($uri);
 
       $items[] = $item;
     }
 
     $sort_menu = id(new PhabricatorActionListView())
       ->setUser($viewer);
     foreach ($items as $item) {
       $sort_menu->addAction($item);
     }
 
     $sort_button = id(new PHUIButtonView())
       ->setText(pht('Sort: %s', $active_order))
       ->setIcon($sort_icon)
       ->setTag('a')
       ->setHref('#')
       ->addSigil('boards-dropdown-menu')
       ->setMetadata(
         array(
           'items' => hsprintf('%s', $sort_menu),
         ));
 
     return $sort_button;
   }
   private function buildFilterMenu(
     PhabricatorUser $viewer,
     $custom_query,
     PhabricatorApplicationSearchEngine $engine,
     $query_key) {
 
     $filter_icon = id(new PHUIIconView())
       ->setIconFont('fa-search-plus bluegrey');
 
     $named = array(
       'open' => pht('Open Tasks'),
       'all' => pht('All Tasks'),
     );
 
     if ($viewer->isLoggedIn()) {
       $named['assigned'] = pht('Assigned to Me');
     }
 
     if ($custom_query) {
       $named[$custom_query->getQueryKey()] = pht('Custom Filter');
     }
 
     $items = array();
     foreach ($named as $key => $name) {
       $is_selected = ($key == $query_key);
       if ($is_selected) {
         $active_filter = $name;
       }
 
       $is_custom = false;
       if ($custom_query) {
         $is_custom = ($key == $custom_query->getQueryKey());
       }
 
       $item = id(new PhabricatorActionView())
         ->setIcon('fa-search')
         ->setSelected($is_selected)
         ->setName($name);
 
       if ($is_custom) {
         $uri = $this->getApplicationURI(
           'board/'.$this->id.'/filter/query/'.$key.'/');
         $item->setWorkflow(true);
       } else {
         $uri = $engine->getQueryResultsPageURI($key);
       }
 
       $uri = $this->getURIWithState($uri);
       $item->setHref($uri);
 
       $items[] = $item;
     }
 
     $items[] = id(new PhabricatorActionView())
       ->setIcon('fa-cog')
       ->setHref($this->getApplicationURI('board/'.$this->id.'/filter/'))
       ->setWorkflow(true)
       ->setName(pht('Advanced Filter...'));
 
     $filter_menu = id(new PhabricatorActionListView())
         ->setUser($viewer);
     foreach ($items as $item) {
       $filter_menu->addAction($item);
     }
 
     $filter_button = id(new PHUIButtonView())
       ->setText(pht('Filter: %s', $active_filter))
       ->setIcon($filter_icon)
       ->setTag('a')
       ->setHref('#')
       ->addSigil('boards-dropdown-menu')
       ->setMetadata(
         array(
           'items' => hsprintf('%s', $filter_menu),
         ));
 
     return $filter_button;
   }
 
   private function buildManageMenu(
     PhabricatorProject $project,
     $show_hidden) {
 
     $request = $this->getRequest();
     $viewer = $request->getUser();
 
     $can_edit = PhabricatorPolicyFilter::hasCapability(
       $viewer,
       $project,
       PhabricatorPolicyCapability::CAN_EDIT);
 
     $manage_icon = id(new PHUIIconView())
       ->setIconFont('fa-cog bluegrey');
 
     $manage_items = array();
 
     $manage_items[] = id(new PhabricatorActionView())
       ->setIcon('fa-plus')
       ->setName(pht('Add Column'))
       ->setHref($this->getApplicationURI('board/'.$this->id.'/edit/'))
       ->setDisabled(!$can_edit)
       ->setWorkflow(!$can_edit);
 
     $manage_items[] = id(new PhabricatorActionView())
       ->setIcon('fa-exchange')
       ->setName(pht('Reorder Columns'))
       ->setHref($this->getApplicationURI('board/'.$this->id.'/reorder/'))
       ->setDisabled(!$can_edit)
       ->setWorkflow(true);
 
     if ($show_hidden) {
       $hidden_uri = $this->getURIWithState()
         ->setQueryParam('hidden', null);
       $hidden_icon = 'fa-eye-slash';
       $hidden_text = pht('Hide Hidden Columns');
     } else {
       $hidden_uri = $this->getURIWithState()
         ->setQueryParam('hidden', 'true');
       $hidden_icon = 'fa-eye';
       $hidden_text = pht('Show Hidden Columns');
     }
 
     $manage_items[] = id(new PhabricatorActionView())
       ->setIcon($hidden_icon)
       ->setName($hidden_text)
       ->setHref($hidden_uri);
 
     $batch_edit_uri = $request->getRequestURI();
     $batch_edit_uri->setQueryParam('batch', self::BATCH_EDIT_ALL);
     $can_batch_edit = PhabricatorPolicyFilter::hasCapability(
       $viewer,
       PhabricatorApplication::getByClass('PhabricatorManiphestApplication'),
       ManiphestBulkEditCapability::CAPABILITY);
 
     $manage_items[] = id(new PhabricatorActionView())
       ->setIcon('fa-list-ul')
       ->setName(pht('Batch Edit Visible Tasks...'))
       ->setHref($batch_edit_uri)
       ->setDisabled(!$can_batch_edit);
 
     $manage_menu = id(new PhabricatorActionListView())
         ->setUser($viewer);
     foreach ($manage_items as $item) {
       $manage_menu->addAction($item);
     }
 
     $manage_button = id(new PHUIButtonView())
       ->setText(pht('Manage Board'))
       ->setIcon($manage_icon)
       ->setTag('a')
       ->setHref('#')
       ->addSigil('boards-dropdown-menu')
       ->setMetadata(
         array(
           'items' => hsprintf('%s', $manage_menu),
         ));
 
     return $manage_button;
   }
 
   private function buildColumnMenu(
     PhabricatorProject $project,
     PhabricatorProjectColumn $column) {
 
     $request = $this->getRequest();
     $viewer = $request->getUser();
 
     $can_edit = PhabricatorPolicyFilter::hasCapability(
       $viewer,
       $project,
       PhabricatorPolicyCapability::CAN_EDIT);
 
     $column_items = array();
 
     $column_items[] = id(new PhabricatorActionView())
       ->setIcon('fa-plus')
       ->setName(pht('Create Task...'))
       ->setHref($this->getCreateURI())
       ->addSigil('column-add-task')
       ->setMetadata(
         array(
           'columnPHID' => $column->getPHID(),
         ));
 
     $batch_edit_uri = $request->getRequestURI();
     $batch_edit_uri->setQueryParam('batch', $column->getID());
     $can_batch_edit = PhabricatorPolicyFilter::hasCapability(
       $viewer,
       PhabricatorApplication::getByClass('PhabricatorManiphestApplication'),
       ManiphestBulkEditCapability::CAPABILITY);
 
     $column_items[] = id(new PhabricatorActionView())
       ->setIcon('fa-list-ul')
       ->setName(pht('Batch Edit Tasks...'))
       ->setHref($batch_edit_uri)
       ->setDisabled(!$can_batch_edit);
 
     $detail_uri = $this->getApplicationURI(
       'board/'.$this->id.'/column/'.$column->getID().'/');
 
     $column_items[] = id(new PhabricatorActionView())
       ->setIcon('fa-columns')
       ->setName(pht('Column Details'))
       ->setHref($detail_uri);
 
     $can_hide = ($can_edit && !$column->isDefaultColumn());
     $hide_uri = 'board/'.$this->id.'/hide/'.$column->getID().'/';
     $hide_uri = $this->getApplicationURI($hide_uri);
     $hide_uri = $this->getURIWithState($hide_uri);
 
     if (!$column->isHidden()) {
       $column_items[] = id(new PhabricatorActionView())
         ->setName(pht('Hide Column'))
         ->setIcon('fa-eye-slash')
         ->setHref($hide_uri)
         ->setDisabled(!$can_hide)
         ->setWorkflow(true);
     } else {
       $column_items[] = id(new PhabricatorActionView())
         ->setName(pht('Show Column'))
         ->setIcon('fa-eye')
         ->setHref($hide_uri)
         ->setDisabled(!$can_hide)
         ->setWorkflow(true);
     }
 
     $column_menu = id(new PhabricatorActionListView())
       ->setUser($viewer);
     foreach ($column_items as $item) {
       $column_menu->addAction($item);
     }
 
     $column_button = id(new PHUIIconView())
       ->setIconFont('fa-caret-down')
       ->setHref('#')
       ->addSigil('boards-dropdown-menu')
       ->setMetadata(
         array(
           'items' => hsprintf('%s', $column_menu),
         ));
 
     return $column_button;
   }
 
   private function initializeWorkboardDialog(PhabricatorProject $project) {
 
     $instructions = pht('This workboard has not been setup yet.');
     $new_selector = id(new AphrontFormRadioButtonControl())
       ->setName('initialize-type')
       ->setValue('backlog-only')
       ->addButton(
         'backlog-only',
         pht('New Empty Board'),
         pht('Create a new board with just a backlog column.'))
       ->addButton(
         'import',
         pht('Import Columns'),
         pht('Import board columns from another project.'));
 
     $dialog = id(new AphrontDialogView())
       ->setUser($this->getRequest()->getUser())
       ->setTitle(pht('New Workboard'))
       ->addSubmitButton('Continue')
       ->addCancelButton($this->getApplicationURI('view/'.$project->getID().'/'))
       ->appendParagraph($instructions)
       ->appendChild($new_selector);
 
     return id(new AphrontDialogResponse())
       ->setDialog($dialog);
   }
 
   private function noAccessDialog(PhabricatorProject $project) {
 
     $instructions = pht('This workboard has not been setup yet.');
 
     $dialog = id(new AphrontDialogView())
       ->setUser($this->getRequest()->getUser())
       ->setTitle(pht('No Workboard'))
       ->addCancelButton($this->getApplicationURI('view/'.$project->getID().'/'))
       ->appendParagraph($instructions);
 
     return id(new AphrontDialogResponse())
       ->setDialog($dialog);
   }
 
 
   /**
    * Add current state parameters (like order and the visibility of hidden
    * columns) to a URI.
    *
    * This allows actions which toggle or adjust one piece of state to keep
    * the rest of the board state persistent. If no URI is provided, this method
    * starts with the request URI.
    *
    * @param string|null   URI to add state parameters to.
    * @return PhutilURI    URI with state parameters.
    */
   private function getURIWithState($base = null) {
     if ($base === null) {
       $base = $this->getRequest()->getRequestURI();
     }
 
     $base = new PhutilURI($base);
 
     if ($this->sortKey != PhabricatorProjectColumn::DEFAULT_ORDER) {
       $base->setQueryParam('order', $this->sortKey);
     } else {
       $base->setQueryParam('order', null);
     }
 
     $base->setQueryParam('hidden', $this->showHidden ? 'true' : null);
 
     return $base;
   }
 
   private function getCreateURI() {
     $viewer = $this->getViewer();
 
     // TODO: This should be cleaned up, but maybe we're going to make options
     // for each column or board?
     $edit_config = id(new ManiphestEditEngine())
       ->setViewer($viewer)
       ->loadDefaultEditConfiguration();
     if ($edit_config) {
       $form_key = $edit_config->getIdentifier();
       $create_uri = "/maniphest/task/edit/form/{$form_key}/";
     } else {
       $create_uri = '/maniphest/task/edit/';
     }
 
     return $create_uri;
   }
 
 }
diff --git a/src/applications/project/controller/PhabricatorProjectColumnDetailController.php b/src/applications/project/controller/PhabricatorProjectColumnDetailController.php
index 01b520c6c3..ca25c089fb 100644
--- a/src/applications/project/controller/PhabricatorProjectColumnDetailController.php
+++ b/src/applications/project/controller/PhabricatorProjectColumnDetailController.php
@@ -1,122 +1,123 @@
 <?php
 
 final class PhabricatorProjectColumnDetailController
   extends PhabricatorProjectBoardController {
 
   public function handleRequest(AphrontRequest $request) {
     $viewer = $request->getViewer();
     $id = $request->getURIData('id');
     $project_id = $request->getURIData('projectID');
 
     $project = id(new PhabricatorProjectQuery())
       ->setViewer($viewer)
       ->requireCapabilities(
         array(
           PhabricatorPolicyCapability::CAN_VIEW,
         ))
       ->withIDs(array($project_id))
       ->needImages(true)
       ->executeOne();
     if (!$project) {
       return new Aphront404Response();
     }
     $this->setProject($project);
 
     $column = id(new PhabricatorProjectColumnQuery())
       ->setViewer($viewer)
       ->withIDs(array($id))
       ->requireCapabilities(
         array(
           PhabricatorPolicyCapability::CAN_VIEW,
         ))
         ->executeOne();
     if (!$column) {
       return new Aphront404Response();
     }
 
     $timeline = $this->buildTransactionTimeline(
       $column,
       new PhabricatorProjectColumnTransactionQuery());
     $timeline->setShouldTerminate(true);
 
     $title = $column->getDisplayName();
 
     $header = $this->buildHeaderView($column);
     $actions = $this->buildActionView($column);
     $properties = $this->buildPropertyView($column, $actions);
 
     $box = id(new PHUIObjectBoxView())
       ->setHeader($header)
       ->addPropertyList($properties);
 
-    $nav = $this->buildIconNavView($project);
-    $nav->appendChild($box);
-    $nav->appendChild($timeline);
-
-    return $this->buildApplicationPage(
-      $nav,
-      array(
-        'title' => $title,
-      ));
+    $nav = $this->getProfileMenu();
+
+    return $this->newPage()
+      ->setTitle($title)
+      ->setNavigation($nav)
+      ->appendChild(
+        array(
+          $box,
+          $timeline,
+        ));
   }
 
   private function buildHeaderView(PhabricatorProjectColumn $column) {
     $viewer = $this->getRequest()->getUser();
 
     $header = id(new PHUIHeaderView())
       ->setUser($viewer)
       ->setHeader($column->getDisplayName())
       ->setPolicyObject($column);
 
     if ($column->isHidden()) {
       $header->setStatus('fa-ban', 'dark', pht('Hidden'));
     }
 
     return $header;
   }
 
   private function buildActionView(PhabricatorProjectColumn $column) {
     $viewer = $this->getRequest()->getUser();
 
     $id = $column->getID();
     $project_id = $this->getProject()->getID();
     $base_uri = '/board/'.$project_id.'/';
 
     $actions = id(new PhabricatorActionListView())
       ->setUser($viewer);
 
     $can_edit = PhabricatorPolicyFilter::hasCapability(
       $viewer,
       $column,
       PhabricatorPolicyCapability::CAN_EDIT);
 
     $actions->addAction(
       id(new PhabricatorActionView())
         ->setName(pht('Edit Column'))
         ->setIcon('fa-pencil')
         ->setHref($this->getApplicationURI($base_uri.'edit/'.$id.'/'))
         ->setDisabled(!$can_edit)
         ->setWorkflow(!$can_edit));
 
     return $actions;
   }
 
   private function buildPropertyView(
     PhabricatorProjectColumn $column,
     PhabricatorActionListView $actions) {
     $viewer = $this->getRequest()->getUser();
 
     $properties = id(new PHUIPropertyListView())
       ->setUser($viewer)
       ->setObject($column)
       ->setActionList($actions);
 
     $limit = $column->getPointLimit();
     $properties->addProperty(
       pht('Point Limit'),
       $limit ? $limit : pht('No Limit'));
 
     return $properties;
   }
 
 }
diff --git a/src/applications/project/controller/PhabricatorProjectColumnEditController.php b/src/applications/project/controller/PhabricatorProjectColumnEditController.php
index d59c3648fe..77f90b56cb 100644
--- a/src/applications/project/controller/PhabricatorProjectColumnEditController.php
+++ b/src/applications/project/controller/PhabricatorProjectColumnEditController.php
@@ -1,156 +1,154 @@
 <?php
 
 final class PhabricatorProjectColumnEditController
   extends PhabricatorProjectBoardController {
 
   public function handleRequest(AphrontRequest $request) {
     $viewer = $request->getViewer();
     $id = $request->getURIData('id');
     $project_id = $request->getURIData('projectID');
 
     $project = id(new PhabricatorProjectQuery())
       ->setViewer($viewer)
       ->requireCapabilities(
         array(
           PhabricatorPolicyCapability::CAN_VIEW,
           PhabricatorPolicyCapability::CAN_EDIT,
         ))
       ->withIDs(array($project_id))
       ->needImages(true)
       ->executeOne();
 
     if (!$project) {
       return new Aphront404Response();
     }
     $this->setProject($project);
 
     $is_new = ($id ? false : true);
 
     if (!$is_new) {
       $column = id(new PhabricatorProjectColumnQuery())
         ->setViewer($viewer)
         ->withIDs(array($id))
         ->requireCapabilities(
           array(
             PhabricatorPolicyCapability::CAN_VIEW,
             PhabricatorPolicyCapability::CAN_EDIT,
           ))
         ->executeOne();
       if (!$column) {
         return new Aphront404Response();
       }
     } else {
       $column = PhabricatorProjectColumn::initializeNewColumn($viewer);
     }
 
     $e_name = null;
     $e_limit = null;
 
     $v_limit = $column->getPointLimit();
     $v_name = $column->getName();
 
     $validation_exception = null;
     $base_uri = '/board/'.$project_id.'/';
     if ($is_new) {
       // we want to go back to the board
       $view_uri = $this->getApplicationURI($base_uri);
     } else {
       $view_uri = $this->getApplicationURI($base_uri.'column/'.$id.'/');
     }
 
     if ($request->isFormPost()) {
       $v_name = $request->getStr('name');
       $v_limit = $request->getStr('limit');
 
       if ($is_new) {
         $column->setProjectPHID($project->getPHID());
         $column->attachProject($project);
 
         $columns = id(new PhabricatorProjectColumnQuery())
           ->setViewer($viewer)
           ->withProjectPHIDs(array($project->getPHID()))
           ->execute();
 
         $new_sequence = 1;
         if ($columns) {
           $values = mpull($columns, 'getSequence');
           $new_sequence = max($values) + 1;
         }
         $column->setSequence($new_sequence);
       }
 
       $xactions = array();
 
       $type_name = PhabricatorProjectColumnTransaction::TYPE_NAME;
       $xactions[] = id(new PhabricatorProjectColumnTransaction())
         ->setTransactionType($type_name)
         ->setNewValue($v_name);
 
       $type_limit = PhabricatorProjectColumnTransaction::TYPE_LIMIT;
       $xactions[] = id(new PhabricatorProjectColumnTransaction())
         ->setTransactionType($type_limit)
         ->setNewValue($v_limit);
 
       try {
         $editor = id(new PhabricatorProjectColumnTransactionEditor())
           ->setActor($viewer)
           ->setContinueOnNoEffect(true)
           ->setContentSourceFromRequest($request)
           ->applyTransactions($column, $xactions);
         return id(new AphrontRedirectResponse())->setURI($view_uri);
       } catch (PhabricatorApplicationTransactionValidationException $ex) {
         $e_name = $ex->getShortMessage($type_name);
         $e_limit = $ex->getShortMessage($type_limit);
         $validation_exception = $ex;
       }
     }
 
     $form = new AphrontFormView();
     $form
       ->setUser($request->getUser())
       ->appendChild(
         id(new AphrontFormTextControl())
           ->setValue($v_name)
           ->setLabel(pht('Name'))
           ->setName('name')
           ->setError($e_name)
           ->setCaption(
             pht('This will be displayed as the header of the column.')))
       ->appendChild(
         id(new AphrontFormTextControl())
           ->setValue($v_limit)
           ->setLabel(pht('Point Limit'))
           ->setName('limit')
           ->setError($e_limit)
           ->setCaption(
             pht('Maximum number of points of tasks allowed in the column.')));
 
 
     if ($is_new) {
       $title = pht('Create Column');
       $submit = pht('Create Column');
     } else {
       $title = pht('Edit %s', $column->getDisplayName());
       $submit = pht('Save Column');
     }
 
     $form->appendChild(
       id(new AphrontFormSubmitControl())
         ->setValue($submit)
         ->addCancelButton($view_uri));
 
     $form_box = id(new PHUIObjectBoxView())
       ->setHeaderText($title)
       ->setValidationException($validation_exception)
       ->setForm($form);
 
-    $nav = $this->buildIconNavView($project);
-    $nav->appendChild($form_box);
-
-    return $this->buildApplicationPage(
-      $nav,
-      array(
-        'title' => $title,
-      ));
+    $nav = $this->getProfileMenu();
+
+    return $this->newPage()
+      ->setTitle($title)
+      ->setNavigation($nav)
+      ->appendChild($form_box);
   }
 }
diff --git a/src/applications/project/controller/PhabricatorProjectController.php b/src/applications/project/controller/PhabricatorProjectController.php
index c3e333f5fb..0729010480 100644
--- a/src/applications/project/controller/PhabricatorProjectController.php
+++ b/src/applications/project/controller/PhabricatorProjectController.php
@@ -1,147 +1,131 @@
 <?php
 
 abstract class PhabricatorProjectController extends PhabricatorController {
 
   private $project;
+  private $profileMenu;
 
   protected function setProject(PhabricatorProject $project) {
     $this->project = $project;
     return $this;
   }
 
   protected function getProject() {
     return $this->project;
   }
 
   protected function loadProject() {
     $viewer = $this->getViewer();
     $request = $this->getRequest();
 
     $id = $request->getURIData('id');
     $slug = $request->getURIData('slug');
 
     if ($slug) {
       $normal_slug = PhabricatorSlug::normalizeProjectSlug($slug);
       $is_abnormal = ($slug !== $normal_slug);
       $normal_uri = "/tag/{$normal_slug}/";
     } else {
       $is_abnormal = false;
     }
 
     $query = id(new PhabricatorProjectQuery())
       ->setViewer($viewer)
       ->needMembers(true)
       ->needWatchers(true)
       ->needImages(true)
       ->needSlugs(true);
 
     if ($slug) {
       $query->withSlugs(array($slug));
     } else {
       $query->withIDs(array($id));
     }
 
     $policy_exception = null;
     try {
       $project = $query->executeOne();
     } catch (PhabricatorPolicyException $ex) {
       $policy_exception = $ex;
       $project = null;
     }
 
     if (!$project) {
       // This project legitimately does not exist, so just 404 the user.
       if (!$policy_exception) {
         return new Aphront404Response();
       }
 
       // Here, the project exists but the user can't see it. If they are
       // using a non-canonical slug to view the project, redirect to the
       // canonical slug. If they're already using the canonical slug, rethrow
       // the exception to give them the policy error.
       if ($is_abnormal) {
         return id(new AphrontRedirectResponse())->setURI($normal_uri);
       } else {
         throw $policy_exception;
       }
     }
 
     // The user can view the project, but is using a noncanonical slug.
     // Redirect to the canonical slug.
     $primary_slug = $project->getPrimarySlug();
     if ($slug && ($slug !== $primary_slug)) {
       $primary_uri = "/tag/{$primary_slug}/";
       return id(new AphrontRedirectResponse())->setURI($primary_uri);
     }
 
     $this->setProject($project);
 
     return null;
   }
 
   public function buildApplicationMenu() {
-    return $this->buildSideNavView(true)->getMenu();
-  }
+    $menu = $this->newApplicationMenu();
 
-  public function buildSideNavView($for_app = false) {
-    $project = $this->getProject();
+    $profile_menu = $this->getProfileMenu();
+    if ($profile_menu) {
+      $menu->setProfileMenu($profile_menu);
+    }
 
+    $menu->setSearchEngine(new PhabricatorProjectSearchEngine());
 
+    return $menu;
+  }
 
-    $nav = new AphrontSideNavFilterView();
-    $nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
+  protected function getProfileMenu() {
+    if (!$this->profileMenu) {
+      $project = $this->getProject();
+      if ($project) {
+        $viewer = $this->getViewer();
 
-    $viewer = $this->getViewer();
+        $engine = id(new PhabricatorProfilePanelEngine())
+          ->setViewer($viewer)
+          ->setProfileObject($project);
 
-    $id = null;
-    if ($for_app) {
-      if ($project) {
-        $id = $project->getID();
-        $nav->addFilter("profile/{$id}/", pht('Profile'));
-        $nav->addFilter("board/{$id}/", pht('Workboard'));
-        $nav->addFilter("members/{$id}/", pht('Members'));
-        $nav->addFilter("feed/{$id}/", pht('Feed'));
+        $this->profileMenu = $engine->buildNavigation();
       }
-      $nav->addFilter('create', pht('Create Project'));
-    }
-
-    if (!$id) {
-      id(new PhabricatorProjectSearchEngine())
-        ->setViewer($viewer)
-        ->addNavigationItems($nav->getMenu());
     }
 
-    $nav->selectFilter(null);
-
-    return $nav;
-  }
-
-  public function buildIconNavView(PhabricatorProject $project) {
-    $viewer = $this->getViewer();
-
-    $engine = id(new PhabricatorProfilePanelEngine())
-      ->setViewer($viewer)
-      ->setProfileObject($project);
-
-    return $engine->buildNavigation();
+    return $this->profileMenu;
   }
 
   protected function buildApplicationCrumbs() {
     $crumbs = parent::buildApplicationCrumbs();
 
     $project = $this->getProject();
     if ($project) {
       $ancestors = $project->getAncestorProjects();
       $ancestors = array_reverse($ancestors);
       $ancestors[] = $project;
       foreach ($ancestors as $ancestor) {
         $crumbs->addTextCrumb(
           $ancestor->getName(),
           $ancestor->getURI());
       }
     }
 
     return $crumbs;
   }
 
 }
diff --git a/src/applications/project/controller/PhabricatorProjectEditPictureController.php b/src/applications/project/controller/PhabricatorProjectEditPictureController.php
index eff471194f..8828bfae57 100644
--- a/src/applications/project/controller/PhabricatorProjectEditPictureController.php
+++ b/src/applications/project/controller/PhabricatorProjectEditPictureController.php
@@ -1,294 +1,297 @@
 <?php
 
 final class PhabricatorProjectEditPictureController
   extends PhabricatorProjectController {
 
   public function handleRequest(AphrontRequest $request) {
     $viewer = $request->getViewer();
     $id = $request->getURIData('id');
 
     $project = id(new PhabricatorProjectQuery())
       ->setViewer($viewer)
       ->withIDs(array($id))
       ->needImages(true)
       ->requireCapabilities(
         array(
           PhabricatorPolicyCapability::CAN_VIEW,
           PhabricatorPolicyCapability::CAN_EDIT,
         ))
       ->executeOne();
     if (!$project) {
       return new Aphront404Response();
     }
 
+    $this->setProject($project);
+
     $edit_uri = $this->getApplicationURI('profile/'.$project->getID().'/');
     $view_uri = $this->getApplicationURI('profile/'.$project->getID().'/');
 
     $supported_formats = PhabricatorFile::getTransformableImageFormats();
     $e_file = true;
     $errors = array();
 
     if ($request->isFormPost()) {
       $phid = $request->getStr('phid');
       $is_default = false;
       if ($phid == PhabricatorPHIDConstants::PHID_VOID) {
         $phid = null;
         $is_default = true;
       } else if ($phid) {
         $file = id(new PhabricatorFileQuery())
           ->setViewer($viewer)
           ->withPHIDs(array($phid))
           ->executeOne();
       } else {
         if ($request->getFileExists('picture')) {
           $file = PhabricatorFile::newFromPHPUpload(
             $_FILES['picture'],
             array(
               'authorPHID' => $viewer->getPHID(),
               'canCDN' => true,
             ));
         } else {
           $e_file = pht('Required');
           $errors[] = pht(
             'You must choose a file when uploading a new project picture.');
         }
       }
 
       if (!$errors && !$is_default) {
         if (!$file->isTransformableImage()) {
           $e_file = pht('Not Supported');
           $errors[] = pht(
             'This server only supports these image formats: %s.',
             implode(', ', $supported_formats));
         } else {
           $xform = PhabricatorFileTransform::getTransformByKey(
             PhabricatorFileThumbnailTransform::TRANSFORM_PROFILE);
           $xformed = $xform->executeTransform($file);
         }
       }
 
       if (!$errors) {
         if ($is_default) {
           $new_value = null;
         } else {
           $new_value = $xformed->getPHID();
         }
 
         $xactions = array();
         $xactions[] = id(new PhabricatorProjectTransaction())
           ->setTransactionType(PhabricatorProjectTransaction::TYPE_IMAGE)
           ->setNewValue($new_value);
 
         $editor = id(new PhabricatorProjectTransactionEditor())
           ->setActor($viewer)
           ->setContentSourceFromRequest($request)
           ->setContinueOnMissingFields(true)
           ->setContinueOnNoEffect(true);
 
         $editor->applyTransactions($project, $xactions);
 
         return id(new AphrontRedirectResponse())->setURI($edit_uri);
       }
     }
 
     $title = pht('Edit Project Picture');
 
     $form = id(new PHUIFormLayoutView())
       ->setUser($viewer);
 
     $default_image = PhabricatorFile::loadBuiltin($viewer, 'project.png');
 
     $images = array();
 
     $current = $project->getProfileImagePHID();
     $has_current = false;
     if ($current) {
       $files = id(new PhabricatorFileQuery())
         ->setViewer($viewer)
         ->withPHIDs(array($current))
         ->execute();
       if ($files) {
         $file = head($files);
         if ($file->isTransformableImage()) {
           $has_current = true;
           $images[$current] = array(
             'uri' => $file->getBestURI(),
             'tip' => pht('Current Picture'),
           );
         }
       }
     }
 
     $images[PhabricatorPHIDConstants::PHID_VOID] = array(
       'uri' => $default_image->getBestURI(),
       'tip' => pht('Default Picture'),
     );
 
     require_celerity_resource('people-profile-css');
     Javelin::initBehavior('phabricator-tooltips', array());
 
     $buttons = array();
     foreach ($images as $phid => $spec) {
       $button = javelin_tag(
         'button',
         array(
           'class' => 'grey profile-image-button',
           'sigil' => 'has-tooltip',
           'meta' => array(
             'tip' => $spec['tip'],
             'size' => 300,
           ),
         ),
         phutil_tag(
           'img',
           array(
             'height' => 50,
             'width' => 50,
             'src' => $spec['uri'],
           )));
 
       $button = array(
         phutil_tag(
           'input',
           array(
             'type'  => 'hidden',
             'name'  => 'phid',
             'value' => $phid,
           )),
         $button,
       );
 
       $button = phabricator_form(
         $viewer,
         array(
           'class' => 'profile-image-form',
           'method' => 'POST',
         ),
         $button);
 
       $buttons[] = $button;
     }
 
     if ($has_current) {
       $form->appendChild(
         id(new AphrontFormMarkupControl())
           ->setLabel(pht('Current Picture'))
           ->setValue(array_shift($buttons)));
     }
 
     $form->appendChild(
       id(new AphrontFormMarkupControl())
         ->setLabel(pht('Use Picture'))
         ->setValue($buttons));
 
     $launch_id = celerity_generate_unique_node_id();
     $input_id = celerity_generate_unique_node_id();
 
     Javelin::initBehavior(
       'launch-icon-composer',
       array(
         'launchID' => $launch_id,
         'inputID' => $input_id,
       ));
 
     $compose_button = javelin_tag(
       'button',
       array(
         'class' => 'grey',
         'id' => $launch_id,
         'sigil' => 'icon-composer',
       ),
       pht('Choose Icon and Color...'));
 
     $compose_input = javelin_tag(
       'input',
       array(
         'type' => 'hidden',
         'id' => $input_id,
         'name' => 'phid',
       ));
 
     $compose_form = phabricator_form(
       $viewer,
       array(
         'class' => 'profile-image-form',
         'method' => 'POST',
       ),
       array(
         $compose_input,
         $compose_button,
       ));
 
     $form->appendChild(
       id(new AphrontFormMarkupControl())
         ->setLabel(pht('Quick Create'))
         ->setValue($compose_form));
 
     $default_button = javelin_tag(
       'button',
       array(
         'class' => 'grey',
       ),
       pht('Use Project Icon'));
 
     $default_input = javelin_tag(
       'input',
       array(
         'type' => 'hidden',
         'name' => 'projectPHID',
         'value' => $project->getPHID(),
       ));
 
     $default_form = phabricator_form(
       $viewer,
       array(
         'class' => 'profile-image-form',
         'method' => 'POST',
         'action' => '/file/compose/',
        ),
       array(
         $default_input,
         $default_button,
       ));
 
     $form->appendChild(
       id(new AphrontFormMarkupControl())
         ->setLabel(pht('Use Default'))
         ->setValue($default_form));
 
     $upload_form = id(new AphrontFormView())
       ->setUser($viewer)
       ->setEncType('multipart/form-data')
       ->appendChild(
         id(new AphrontFormFileControl())
           ->setName('picture')
           ->setLabel(pht('Upload Picture'))
           ->setError($e_file)
           ->setCaption(
             pht('Supported formats: %s', implode(', ', $supported_formats))))
       ->appendChild(
         id(new AphrontFormSubmitControl())
           ->addCancelButton($edit_uri)
           ->setValue(pht('Upload Picture')));
 
     $form_box = id(new PHUIObjectBoxView())
       ->setHeaderText($title)
       ->setFormErrors($errors)
       ->setForm($form);
 
     $upload_box = id(new PHUIObjectBoxView())
       ->setHeaderText(pht('Upload New Picture'))
       ->setForm($upload_form);
 
-    $nav = $this->buildIconNavView($project);
+    $nav = $this->getProfileMenu();
     $nav->selectFilter(PhabricatorProject::PANEL_PROFILE);
-    $nav->appendChild($form_box);
-    $nav->appendChild($upload_box);
 
-    return $this->buildApplicationPage(
-      $nav,
-      array(
-        'title' => $title,
-      ));
+    return $this->newPage()
+      ->setTitle($title)
+      ->setNavigation($nav)
+      ->appendChild(
+        array(
+          $form_box,
+          $upload_box,
+        ));
   }
 }
diff --git a/src/applications/project/controller/PhabricatorProjectFeedController.php b/src/applications/project/controller/PhabricatorProjectFeedController.php
index 80bb3378e8..a108384088 100644
--- a/src/applications/project/controller/PhabricatorProjectFeedController.php
+++ b/src/applications/project/controller/PhabricatorProjectFeedController.php
@@ -1,62 +1,62 @@
 <?php
 
 final class PhabricatorProjectFeedController
   extends PhabricatorProjectController {
 
   public function shouldAllowPublic() {
     return true;
   }
 
   public function handleRequest(AphrontRequest $request) {
     $viewer = $request->getUser();
 
     $response = $this->loadProject();
     if ($response) {
       return $response;
     }
 
     $project = $this->getProject();
     $id = $project->getID();
 
     $stories = id(new PhabricatorFeedQuery())
       ->setViewer($viewer)
       ->setFilterPHIDs(
         array(
           $project->getPHID(),
         ))
       ->setLimit(50)
       ->execute();
 
     $feed = $this->renderStories($stories);
 
     $box = id(new PHUIObjectBoxView())
       ->setHeaderText(pht('Project Activity'))
       ->appendChild($feed);
 
-    $nav = $this->buildIconNavView($project);
+    $nav = $this->getProfileMenu();
     $nav->selectFilter('feed');
 
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb(pht('Feed'));
 
     return $this->newPage()
       ->setNavigation($nav)
       ->setCrumbs($crumbs)
       ->setTitle(array($project->getName(), pht('Feed')))
       ->appendChild($box);
   }
 
   private function renderStories(array $stories) {
     assert_instances_of($stories, 'PhabricatorFeedStory');
 
     $builder = new PhabricatorFeedBuilder($stories);
     $builder->setUser($this->getRequest()->getUser());
     $builder->setShowHovercards(true);
     $view = $builder->buildView();
 
     return phutil_tag_div(
       'profile-feed',
       $view->render());
   }
 
 }
diff --git a/src/applications/project/controller/PhabricatorProjectListController.php b/src/applications/project/controller/PhabricatorProjectListController.php
index db4ef5b9f5..021cdfbe3f 100644
--- a/src/applications/project/controller/PhabricatorProjectListController.php
+++ b/src/applications/project/controller/PhabricatorProjectListController.php
@@ -1,36 +1,26 @@
 <?php
 
 final class PhabricatorProjectListController
   extends PhabricatorProjectController {
 
   public function shouldAllowPublic() {
     return true;
   }
 
   public function handleRequest(AphrontRequest $request) {
-    $viewer = $request->getViewer();
-    $query_key = $request->getURIData('queryKey');
-
-    $controller = id(new PhabricatorApplicationSearchController())
-      ->setQueryKey($query_key)
-      ->setSearchEngine(new PhabricatorProjectSearchEngine())
-      ->setNavigation($this->buildSideNavView());
-
-    return $this->delegateToController($controller);
-  }
-
-  public function buildApplicationMenu() {
-    return $this->buildSideNavView(true)->getMenu();
+    return id(new PhabricatorProjectSearchEngine())
+      ->setController($this)
+      ->buildResponse();
   }
 
   protected function buildApplicationCrumbs() {
     $crumbs = parent::buildApplicationCrumbs();
 
     id(new PhabricatorProjectEditEngine())
       ->setViewer($this->getViewer())
       ->addActionToCrumbs($crumbs);
 
     return $crumbs;
   }
 
 }
diff --git a/src/applications/project/controller/PhabricatorProjectMembersEditController.php b/src/applications/project/controller/PhabricatorProjectMembersEditController.php
index f45d40d8ae..f485e2997a 100644
--- a/src/applications/project/controller/PhabricatorProjectMembersEditController.php
+++ b/src/applications/project/controller/PhabricatorProjectMembersEditController.php
@@ -1,154 +1,156 @@
 <?php
 
 final class PhabricatorProjectMembersEditController
   extends PhabricatorProjectController {
 
   public function handleRequest(AphrontRequest $request) {
     $viewer = $request->getViewer();
     $id = $request->getURIData('id');
 
     $project = id(new PhabricatorProjectQuery())
       ->setViewer($viewer)
       ->withIDs(array($id))
       ->needMembers(true)
       ->needImages(true)
       ->executeOne();
     if (!$project) {
       return new Aphront404Response();
     }
 
+    $this->setProject($project);
+
     $member_phids = $project->getMemberPHIDs();
 
     if ($request->isFormPost()) {
       $member_spec = array();
 
       $remove = $request->getStr('remove');
       if ($remove) {
         $member_spec['-'] = array_fuse(array($remove));
       }
 
       $add_members = $request->getArr('phids');
       if ($add_members) {
         $member_spec['+'] = array_fuse($add_members);
       }
 
       $type_member = PhabricatorProjectProjectHasMemberEdgeType::EDGECONST;
 
       $xactions = array();
 
       $xactions[] = id(new PhabricatorProjectTransaction())
         ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
         ->setMetadataValue('edge:type', $type_member)
         ->setNewValue($member_spec);
 
       $editor = id(new PhabricatorProjectTransactionEditor($project))
         ->setActor($viewer)
         ->setContentSourceFromRequest($request)
         ->setContinueOnNoEffect(true)
         ->setContinueOnMissingFields(true)
         ->applyTransactions($project, $xactions);
 
       return id(new AphrontRedirectResponse())
         ->setURI($request->getRequestURI());
     }
 
     $member_phids = array_reverse($member_phids);
     $handles = $this->loadViewerHandles($member_phids);
 
     $state = array();
     foreach ($handles as $handle) {
       $state[] = array(
         'phid' => $handle->getPHID(),
         'name' => $handle->getFullName(),
       );
     }
 
     $can_edit = PhabricatorPolicyFilter::hasCapability(
       $viewer,
       $project,
       PhabricatorPolicyCapability::CAN_EDIT);
 
     $supports_edit = $project->supportsEditMembers();
 
     $form_box = null;
     $title = pht('Add Members');
     if ($can_edit && $supports_edit) {
       $header_name = pht('Edit Members');
       $view_uri = $this->getApplicationURI('profile/'.$project->getID().'/');
 
       $form = new AphrontFormView();
       $form
         ->setUser($viewer)
         ->appendControl(
           id(new AphrontFormTokenizerControl())
             ->setName('phids')
             ->setLabel(pht('Add Members'))
             ->setDatasource(new PhabricatorPeopleDatasource()))
         ->appendChild(
           id(new AphrontFormSubmitControl())
             ->addCancelButton($view_uri)
             ->setValue(pht('Add Members')));
       $form_box = id(new PHUIObjectBoxView())
         ->setHeaderText($title)
         ->setForm($form);
     }
 
     $member_list = $this->renderMemberList($project, $handles);
 
-    $nav = $this->buildIconNavView($project);
+    $nav = $this->getProfileMenu();
     $nav->selectFilter(PhabricatorProject::PANEL_MEMBERS);
 
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb(pht('Members'));
 
     return $this->newPage()
       ->setNavigation($nav)
       ->setCrumbs($crumbs)
       ->setTitle(array($project->getName(), $title))
       ->appendChild($form_box)
       ->appendChild($member_list);
   }
 
   private function renderMemberList(
     PhabricatorProject $project,
     array $handles) {
 
     $request = $this->getRequest();
     $viewer = $request->getUser();
 
     $can_edit = PhabricatorPolicyFilter::hasCapability(
       $viewer,
       $project,
       PhabricatorPolicyCapability::CAN_EDIT);
 
     $list = id(new PHUIObjectItemListView())
       ->setNoDataString(pht('This project does not have any members.'));
 
     foreach ($handles as $handle) {
       $remove_uri = $this->getApplicationURI(
         '/members/'.$project->getID().'/remove/?phid='.$handle->getPHID());
 
       $item = id(new PHUIObjectItemView())
         ->setHeader($handle->getFullName())
         ->setHref($handle->getURI())
         ->setImageURI($handle->getImageURI());
 
       if ($can_edit) {
         $item->addAction(
           id(new PHUIListItemView())
             ->setIcon('fa-times')
             ->setName(pht('Remove'))
             ->setHref($remove_uri)
             ->setWorkflow(true));
       }
 
       $list->addItem($item);
     }
 
     $box = id(new PHUIObjectBoxView())
       ->setHeaderText(pht('Members'))
       ->setObjectList($list);
 
     return $box;
   }
 }
diff --git a/src/applications/project/controller/PhabricatorProjectMilestonesController.php b/src/applications/project/controller/PhabricatorProjectMilestonesController.php
index db0810f819..595035bdb7 100644
--- a/src/applications/project/controller/PhabricatorProjectMilestonesController.php
+++ b/src/applications/project/controller/PhabricatorProjectMilestonesController.php
@@ -1,92 +1,92 @@
 <?php
 
 final class PhabricatorProjectMilestonesController
   extends PhabricatorProjectController {
 
   public function shouldAllowPublic() {
     return true;
   }
 
   public function handleRequest(AphrontRequest $request) {
     $viewer = $request->getViewer();
 
     $response = $this->loadProject();
     if ($response) {
       return $response;
     }
 
     $project = $this->getProject();
     $id = $project->getID();
 
     $can_edit = PhabricatorPolicyFilter::hasCapability(
       $viewer,
       $project,
       PhabricatorPolicyCapability::CAN_EDIT);
 
     $has_support = $project->supportsMilestones();
     if ($has_support) {
       $milestones = id(new PhabricatorProjectQuery())
         ->setViewer($viewer)
         ->withParentProjectPHIDs(array($project->getPHID()))
         ->needImages(true)
         ->withIsMilestone(true)
         ->setOrder('newest')
         ->execute();
     } else {
       $milestones = array();
     }
 
     $can_create = $can_edit && $has_support;
 
     if ($project->getHasMilestones()) {
       $button_text = pht('Create Next Milestone');
     } else {
       $button_text = pht('Add Milestones');
     }
 
     $header = id(new PHUIHeaderView())
       ->setHeader(pht('Milestones'))
       ->addActionLink(
         id(new PHUIButtonView())
           ->setTag('a')
           ->setHref("/project/edit/?milestone={$id}")
           ->setIconFont('fa-plus')
           ->setDisabled(!$can_create)
           ->setWorkflow(!$can_create)
           ->setText($button_text));
 
     $box = id(new PHUIObjectBoxView())
       ->setHeader($header);
 
     if (!$has_support) {
       $no_support = pht(
         'This project is a milestone. Milestones can not have their own '.
         'milestones.');
 
       $info_view = id(new PHUIInfoView())
         ->setErrors(array($no_support))
         ->setSeverity(PHUIInfoView::SEVERITY_WARNING);
 
       $box->setInfoView($info_view);
     }
 
     $box->setObjectList(
       id(new PhabricatorProjectListView())
         ->setUser($viewer)
         ->setProjects($milestones)
         ->renderList());
 
-    $nav = $this->buildIconNavView($project);
+    $nav = $this->getProfileMenu();
     $nav->selectFilter(PhabricatorProject::PANEL_MILESTONES);
 
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb(pht('Milestones'));
 
     return $this->newPage()
       ->setNavigation($nav)
       ->setCrumbs($crumbs)
       ->setTitle(array($project->getName(), pht('Milestones')))
       ->appendChild($box);
   }
 
 }
diff --git a/src/applications/project/controller/PhabricatorProjectProfileController.php b/src/applications/project/controller/PhabricatorProjectProfileController.php
index e588681ef5..a2eb5eebe6 100644
--- a/src/applications/project/controller/PhabricatorProjectProfileController.php
+++ b/src/applications/project/controller/PhabricatorProjectProfileController.php
@@ -1,230 +1,230 @@
 <?php
 
 final class PhabricatorProjectProfileController
   extends PhabricatorProjectController {
 
   public function shouldAllowPublic() {
     return true;
   }
 
   public function handleRequest(AphrontRequest $request) {
     $viewer = $request->getUser();
 
     $response = $this->loadProject();
     if ($response) {
       return $response;
     }
 
     $project = $this->getProject();
     $id = $project->getID();
     $picture = $project->getProfileImageURI();
 
     $header = id(new PHUIHeaderView())
       ->setHeader($project->getName())
       ->setUser($viewer)
       ->setPolicyObject($project)
       ->setImage($picture);
 
     if ($project->getStatus() == PhabricatorProjectStatus::STATUS_ACTIVE) {
       $header->setStatus('fa-check', 'bluegrey', pht('Active'));
     } else {
       $header->setStatus('fa-ban', 'red', pht('Archived'));
     }
 
     $actions = $this->buildActionListView($project);
     $properties = $this->buildPropertyListView($project, $actions);
 
     $object_box = id(new PHUIObjectBoxView())
       ->setHeader($header)
       ->addPropertyList($properties);
 
     $timeline = $this->buildTransactionTimeline(
       $project,
       new PhabricatorProjectTransactionQuery());
     $timeline->setShouldTerminate(true);
 
-    $nav = $this->buildIconNavView($project);
+    $nav = $this->getProfileMenu();
     $nav->selectFilter(PhabricatorProject::PANEL_PROFILE);
 
     $crumbs = $this->buildApplicationCrumbs();
 
     return $this->newPage()
       ->setNavigation($nav)
       ->setCrumbs($crumbs)
       ->setTitle($project->getName())
       ->setPageObjectPHIDs(array($project->getPHID()))
       ->appendChild($object_box)
       ->appendChild($timeline);
   }
 
   private function buildActionListView(PhabricatorProject $project) {
     $request = $this->getRequest();
     $viewer = $request->getUser();
 
     $id = $project->getID();
 
     $view = id(new PhabricatorActionListView())
       ->setUser($viewer)
       ->setObject($project);
 
     $can_edit = PhabricatorPolicyFilter::hasCapability(
       $viewer,
       $project,
       PhabricatorPolicyCapability::CAN_EDIT);
 
     $view->addAction(
       id(new PhabricatorActionView())
         ->setName(pht('Edit Details'))
         ->setIcon('fa-pencil')
         ->setHref($this->getApplicationURI("edit/{$id}/"))
         ->setDisabled(!$can_edit)
         ->setWorkflow(!$can_edit));
 
     $view->addAction(
       id(new PhabricatorActionView())
         ->setName(pht('Edit Picture'))
         ->setIcon('fa-picture-o')
         ->setHref($this->getApplicationURI("picture/{$id}/"))
         ->setDisabled(!$can_edit)
         ->setWorkflow(!$can_edit));
 
     if ($project->isArchived()) {
       $view->addAction(
         id(new PhabricatorActionView())
           ->setName(pht('Activate Project'))
           ->setIcon('fa-check')
           ->setHref($this->getApplicationURI("archive/{$id}/"))
           ->setDisabled(!$can_edit)
           ->setWorkflow(true));
     } else {
       $view->addAction(
         id(new PhabricatorActionView())
           ->setName(pht('Archive Project'))
           ->setIcon('fa-ban')
           ->setHref($this->getApplicationURI("archive/{$id}/"))
           ->setDisabled(!$can_edit)
           ->setWorkflow(true));
     }
 
     $can_lock = $can_edit && $this->hasApplicationCapability(
       ProjectCanLockProjectsCapability::CAPABILITY);
 
     if ($project->getIsMembershipLocked()) {
       $lock_name = pht('Unlock Project');
       $lock_icon = 'fa-unlock';
     } else {
       $lock_name = pht('Lock Project');
       $lock_icon = 'fa-lock';
     }
 
     $view->addAction(
       id(new PhabricatorActionView())
         ->setName($lock_name)
         ->setIcon($lock_icon)
         ->setHref($this->getApplicationURI("lock/{$id}/"))
         ->setDisabled(!$can_lock)
         ->setWorkflow(true));
 
     $action = null;
     if (!$project->isUserMember($viewer->getPHID())) {
       $can_join = PhabricatorPolicyFilter::hasCapability(
         $viewer,
         $project,
         PhabricatorPolicyCapability::CAN_JOIN);
 
       $action = id(new PhabricatorActionView())
         ->setUser($viewer)
         ->setRenderAsForm(true)
         ->setHref('/project/update/'.$project->getID().'/join/')
         ->setIcon('fa-plus')
         ->setDisabled(!$can_join)
         ->setName(pht('Join Project'));
       $view->addAction($action);
     } else {
       $action = id(new PhabricatorActionView())
         ->setWorkflow(true)
         ->setHref('/project/update/'.$project->getID().'/leave/')
         ->setIcon('fa-times')
         ->setName(pht('Leave Project...'));
       $view->addAction($action);
 
       if (!$project->isUserWatcher($viewer->getPHID())) {
         $action = id(new PhabricatorActionView())
           ->setWorkflow(true)
           ->setHref('/project/watch/'.$project->getID().'/')
           ->setIcon('fa-eye')
           ->setName(pht('Watch Project'));
         $view->addAction($action);
       } else {
         $action = id(new PhabricatorActionView())
           ->setWorkflow(true)
           ->setHref('/project/unwatch/'.$project->getID().'/')
           ->setIcon('fa-eye-slash')
           ->setName(pht('Unwatch Project'));
         $view->addAction($action);
       }
     }
 
     return $view;
   }
 
   private function buildPropertyListView(
     PhabricatorProject $project,
     PhabricatorActionListView $actions) {
     $request = $this->getRequest();
     $viewer = $request->getUser();
 
     $view = id(new PHUIPropertyListView())
       ->setUser($viewer)
       ->setObject($project)
       ->setActionList($actions);
 
     $hashtags = array();
     foreach ($project->getSlugs() as $slug) {
       $hashtags[] = id(new PHUITagView())
         ->setType(PHUITagView::TYPE_OBJECT)
         ->setName('#'.$slug->getSlug());
     }
 
     if ($hashtags) {
       $view->addProperty(pht('Hashtags'), phutil_implode_html(' ', $hashtags));
     }
 
     $view->addProperty(
       pht('Members'),
       $project->getMemberPHIDs()
         ? $viewer
           ->renderHandleList($project->getMemberPHIDs())
           ->setAsInline(true)
         : phutil_tag('em', array(), pht('None')));
 
     $view->addProperty(
       pht('Watchers'),
       $project->getWatcherPHIDs()
         ? $viewer
           ->renderHandleList($project->getWatcherPHIDs())
           ->setAsInline(true)
         : phutil_tag('em', array(), pht('None')));
 
     $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions(
       $viewer,
       $project);
 
     $view->addProperty(
       pht('Looks Like'),
       $viewer->renderHandle($project->getPHID())->setAsTag(true));
 
     $view->addProperty(
       pht('Joinable By'),
       $descriptions[PhabricatorPolicyCapability::CAN_JOIN]);
 
     $field_list = PhabricatorCustomField::getObjectFields(
       $project,
       PhabricatorCustomField::ROLE_VIEW);
     $field_list->appendFieldsToPropertyList($project, $viewer, $view);
 
     return $view;
   }
 
 
 }
diff --git a/src/applications/project/controller/PhabricatorProjectSubprojectsController.php b/src/applications/project/controller/PhabricatorProjectSubprojectsController.php
index 50f3294c71..e512d12a6e 100644
--- a/src/applications/project/controller/PhabricatorProjectSubprojectsController.php
+++ b/src/applications/project/controller/PhabricatorProjectSubprojectsController.php
@@ -1,91 +1,91 @@
 <?php
 
 final class PhabricatorProjectSubprojectsController
   extends PhabricatorProjectController {
 
   public function shouldAllowPublic() {
     return true;
   }
 
   public function handleRequest(AphrontRequest $request) {
     $viewer = $request->getViewer();
 
     $response = $this->loadProject();
     if ($response) {
       return $response;
     }
 
     $project = $this->getProject();
     $id = $project->getID();
 
     $can_edit = PhabricatorPolicyFilter::hasCapability(
       $viewer,
       $project,
       PhabricatorPolicyCapability::CAN_EDIT);
 
     $has_support = $project->supportsSubprojects();
 
     if ($has_support) {
       $subprojects = id(new PhabricatorProjectQuery())
         ->setViewer($viewer)
         ->withParentProjectPHIDs(array($project->getPHID()))
         ->needImages(true)
         ->withIsMilestone(false)
         ->execute();
     } else {
       $subprojects = array();
     }
 
     $can_create = $can_edit && $has_support;
 
     if ($project->getHasSubprojects()) {
       $button_text = pht('Create Subproject');
     } else {
       $button_text = pht('Add Subprojects');
     }
 
     $header = id(new PHUIHeaderView())
       ->setHeader(pht('Subprojects'))
       ->addActionLink(
         id(new PHUIButtonView())
           ->setTag('a')
           ->setHref("/project/edit/?parent={$id}")
           ->setIconFont('fa-plus')
           ->setDisabled(!$can_create)
           ->setWorkflow(!$can_create)
           ->setText($button_text));
 
     $box = id(new PHUIObjectBoxView())
       ->setHeader($header);
 
     if (!$has_support) {
       $no_support = pht(
         'This project is a milestone. Milestones can not have subprojects.');
 
       $info_view = id(new PHUIInfoView())
         ->setErrors(array($no_support))
         ->setSeverity(PHUIInfoView::SEVERITY_WARNING);
 
       $box->setInfoView($info_view);
     }
 
     $box->setObjectList(
       id(new PhabricatorProjectListView())
         ->setUser($viewer)
         ->setProjects($subprojects)
         ->renderList());
 
-    $nav = $this->buildIconNavView($project);
+    $nav = $this->getProfileMenu();
     $nav->selectFilter(PhabricatorProject::PANEL_SUBPROJECTS);
 
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb(pht('Subprojects'));
 
     return $this->newPage()
       ->setNavigation($nav)
       ->setCrumbs($crumbs)
       ->setTitle(array($project->getName(), pht('Subprojects')))
       ->appendChild($box);
   }
 
 }
diff --git a/src/view/layout/PHUIApplicationMenuView.php b/src/view/layout/PHUIApplicationMenuView.php
index 624b1f982d..f542674de9 100644
--- a/src/view/layout/PHUIApplicationMenuView.php
+++ b/src/view/layout/PHUIApplicationMenuView.php
@@ -1,89 +1,109 @@
 <?php
 
 final class PHUIApplicationMenuView extends Phobject {
 
   private $viewer;
   private $crumbs;
   private $searchEngine;
+  private $profileMenu;
 
   private $items = array();
 
   public function setViewer(PhabricatorUser $viewer) {
     $this->viewer = $viewer;
     return $this;
   }
 
   public function getViewer() {
     return $this->viewer;
   }
 
   public function addLabel($name) {
     $item = id(new PHUIListItemView())
       ->setName($name);
 
     return $this->addItem($item);
   }
 
   public function addLink($name, $href) {
     $item = id(new PHUIListItemView())
       ->setName($name)
       ->setHref($href);
 
     return $this->addItem($item);
   }
 
+  public function setProfileMenu(
+    AphrontSideNavFilterView $nav) {
+    $this->profileMenu = $nav;
+    return $this;
+  }
+
+  public function getProfileMenu() {
+    return $this->profileMenu;
+  }
+
   public function addItem(PHUIListItemView $item) {
     $this->items[] = $item;
     return $this;
   }
 
   public function setSearchEngine(PhabricatorApplicationSearchEngine $engine) {
     $this->searchEngine = $engine;
     return $this;
   }
 
   public function getSearchEngine() {
     return $this->searchEngine;
   }
 
   public function setCrumbs(PHUICrumbsView $crumbs) {
     $this->crumbs = $crumbs;
     return $this;
   }
 
   public function getCrumbs() {
     return $this->crumbs;
   }
 
   public function buildListView() {
     $viewer = $this->getViewer();
 
     $view = id(new PHUIListView())
       ->setUser($viewer);
 
+    $profile_menu = $this->getProfileMenu();
+    if ($profile_menu) {
+      foreach ($profile_menu->getMenu()->getItems() as $item) {
+        $item = clone $item;
+        $item->setRenderNameAsTooltip(false);
+        $view->addMenuItem($item);
+      }
+    }
+
     $crumbs = $this->getCrumbs();
     if ($crumbs) {
       $actions = $crumbs->getActions();
       if ($actions) {
         $view->newLabel(pht('Create'));
         foreach ($crumbs->getActions() as $action) {
           $view->addMenuItem($action);
         }
       }
     }
 
     $engine = $this->getSearchEngine();
     if ($engine) {
       $engine
         ->setViewer($viewer)
         ->addNavigationItems($view);
     }
 
     foreach ($this->items as $item) {
       $view->addMenuItem($item);
     }
 
     return $view;
   }
 
 }