diff --git a/src/applications/differential/view/DifferentialRevisionListView.php b/src/applications/differential/view/DifferentialRevisionListView.php
index 74e3f7633f..7ab0f2d183 100644
--- a/src/applications/differential/view/DifferentialRevisionListView.php
+++ b/src/applications/differential/view/DifferentialRevisionListView.php
@@ -1,186 +1,180 @@
 <?php
 
 /**
  * Render a table of Differential revisions.
  */
 final class DifferentialRevisionListView extends AphrontView {
 
   private $revisions;
   private $handles;
-  private $highlightAge;
   private $header;
   private $noDataString;
   private $noBox;
   private $background = null;
   private $unlandedDependencies = array();
 
   public function setUnlandedDependencies(array $unlanded_dependencies) {
     $this->unlandedDependencies = $unlanded_dependencies;
     return $this;
   }
 
   public function getUnlandedDependencies() {
     return $this->unlandedDependencies;
   }
 
   public function setNoDataString($no_data_string) {
     $this->noDataString = $no_data_string;
     return $this;
   }
 
   public function setHeader($header) {
     $this->header = $header;
     return $this;
   }
 
   public function setRevisions(array $revisions) {
     assert_instances_of($revisions, 'DifferentialRevision');
     $this->revisions = $revisions;
     return $this;
   }
 
-  public function setHighlightAge($bool) {
-    $this->highlightAge = $bool;
-    return $this;
-  }
-
   public function setNoBox($box) {
     $this->noBox = $box;
     return $this;
   }
 
   public function setBackground($background) {
     $this->background = $background;
     return $this;
   }
 
   public function getRequiredHandlePHIDs() {
     $phids = array();
     foreach ($this->revisions as $revision) {
       $phids[] = array($revision->getAuthorPHID());
 
       // TODO: Switch to getReviewerStatus(), but not all callers pass us
       // revisions with this data loaded.
       $phids[] = $revision->getReviewers();
     }
     return array_mergev($phids);
   }
 
   public function setHandles(array $handles) {
     assert_instances_of($handles, 'PhabricatorObjectHandle');
     $this->handles = $handles;
     return $this;
   }
 
   public function render() {
     $viewer = $this->getViewer();
 
     $this->initBehavior('phabricator-tooltips', array());
     $this->requireResource('aphront-tooltip-css');
 
     $list = new PHUIObjectItemListView();
 
     foreach ($this->revisions as $revision) {
       $item = id(new PHUIObjectItemView())
         ->setUser($viewer);
 
       $icons = array();
 
       $phid = $revision->getPHID();
       $flag = $revision->getFlag($viewer);
       if ($flag) {
         $flag_class = PhabricatorFlagColor::getCSSClass($flag->getColor());
         $icons['flag'] = phutil_tag(
           'div',
           array(
             'class' => 'phabricator-flag-icon '.$flag_class,
           ),
           '');
       }
 
       if ($revision->getDrafts($viewer)) {
         $icons['draft'] = true;
       }
 
       $modified = $revision->getDateModified();
 
       if (isset($icons['flag'])) {
         $item->addHeadIcon($icons['flag']);
       }
 
       $item->setObjectName('D'.$revision->getID());
       $item->setHeader($revision->getTitle());
       $item->setHref('/D'.$revision->getID());
 
       if (isset($icons['draft'])) {
         $draft = id(new PHUIIconView())
           ->setIcon('fa-comment yellow')
           ->addSigil('has-tooltip')
           ->setMetadata(
             array(
               'tip' => pht('Unsubmitted Comments'),
             ));
         $item->addAttribute($draft);
       }
 
       // Author
       $author_handle = $this->handles[$revision->getAuthorPHID()];
       $item->addByline(pht('Author: %s', $author_handle->renderLink()));
 
       $unlanded = idx($this->unlandedDependencies, $phid);
       if ($unlanded) {
         $item->addAttribute(
           array(
             id(new PHUIIconView())->setIcon('fa-chain-broken', 'red'),
             ' ',
             pht('Open Dependencies'),
           ));
       }
 
       $reviewers = array();
       // TODO: As above, this should be based on `getReviewerStatus()`.
       foreach ($revision->getReviewers() as $reviewer) {
         $reviewers[] = $this->handles[$reviewer]->renderLink();
       }
       if (!$reviewers) {
         $reviewers = phutil_tag('em', array(), pht('None'));
       } else {
         $reviewers = phutil_implode_html(', ', $reviewers);
       }
 
       $item->addAttribute(pht('Reviewers: %s', $reviewers));
       $item->setEpoch($revision->getDateModified());
 
       if ($revision->isClosed()) {
         $item->setDisabled(true);
       }
 
       $item->setStatusIcon(
         $revision->getStatusIcon(),
         $revision->getStatusDisplayName());
 
       $list->addItem($item);
     }
 
     $list->setNoDataString($this->noDataString);
 
 
     if ($this->header && !$this->noBox) {
       $list->setFlush(true);
       $list = id(new PHUIObjectBoxView())
         ->setBackground($this->background)
         ->setObjectList($list);
 
       if ($this->header instanceof PHUIHeaderView) {
         $list->setHeader($this->header);
       } else {
         $list->setHeaderText($this->header);
       }
     } else {
       $list->setHeader($this->header);
     }
 
     return $list;
   }
 
 }
diff --git a/src/applications/home/controller/PhabricatorHomeMainController.php b/src/applications/home/controller/PhabricatorHomeMainController.php
index 7bc8b06573..592478c894 100644
--- a/src/applications/home/controller/PhabricatorHomeMainController.php
+++ b/src/applications/home/controller/PhabricatorHomeMainController.php
@@ -1,411 +1,230 @@
 <?php
 
 final class PhabricatorHomeMainController extends PhabricatorHomeController {
 
-  private $minipanels = array();
-
   public function shouldAllowPublic() {
     return true;
   }
 
   public function isGlobalDragAndDropUploadEnabled() {
     return true;
   }
 
   public function handleRequest(AphrontRequest $request) {
-    $user = $request->getUser();
+    $viewer = $request->getViewer();
 
     $dashboard = PhabricatorDashboardInstall::getDashboard(
-      $user,
-      $user->getPHID(),
+      $viewer,
+      $viewer->getPHID(),
       get_class($this->getCurrentApplication()));
 
     if (!$dashboard) {
       $dashboard = PhabricatorDashboardInstall::getDashboard(
-        $user,
+        $viewer,
         PhabricatorHomeApplication::DASHBOARD_DEFAULT,
         get_class($this->getCurrentApplication()));
     }
 
     if ($dashboard) {
       $content = id(new PhabricatorDashboardRenderingEngine())
-        ->setViewer($user)
+        ->setViewer($viewer)
         ->setDashboard($dashboard)
         ->renderDashboard();
     } else {
-      $project_query = new PhabricatorProjectQuery();
-      $project_query->setViewer($user);
-      $project_query->withMemberPHIDs(array($user->getPHID()));
-      $projects = $project_query->execute();
-
-      $content = $this->buildMainResponse($projects);
+      $content = $this->buildMainResponse();
     }
 
     if (!$request->getURIData('only')) {
       $nav = $this->buildNav();
       $nav->appendChild(
         array(
           $content,
-          id(new PhabricatorGlobalUploadTargetView())->setUser($user),
+          id(new PhabricatorGlobalUploadTargetView())->setUser($viewer),
         ));
       $content = $nav;
     }
 
     return $this->newPage()
       ->setTitle('Phabricator')
       ->addClass('phabricator-home')
       ->appendChild($content);
 
   }
 
-  private function buildMainResponse(array $projects) {
-    assert_instances_of($projects, 'PhabricatorProject');
-    $viewer = $this->getRequest()->getUser();
+  private function buildMainResponse() {
+    require_celerity_resource('phabricator-dashboard-css');
+    $viewer = $this->getViewer();
 
     $has_maniphest = PhabricatorApplication::isClassInstalledForViewer(
       'PhabricatorManiphestApplication',
       $viewer);
 
-    $has_audit = PhabricatorApplication::isClassInstalledForViewer(
-      'PhabricatorAuditApplication',
+    $has_diffusion = PhabricatorApplication::isClassInstalledForViewer(
+      'PhabricatorDiffusionApplication',
       $viewer);
 
     $has_differential = PhabricatorApplication::isClassInstalledForViewer(
       'PhabricatorDifferentialApplication',
       $viewer);
 
+    $revision_panel = null;
+    if ($has_differential) {
+      $revision_panel = $this->buildRevisionPanel();
+    }
+
+    $tasks_panel = null;
     if ($has_maniphest) {
-      $unbreak_panel = $this->buildUnbreakNowPanel();
-      $triage_panel = $this->buildNeedsTriagePanel($projects);
       $tasks_panel = $this->buildTasksPanel();
-    } else {
-      $unbreak_panel = null;
-      $triage_panel = null;
-      $tasks_panel = null;
     }
 
-    if ($has_audit) {
-      $audit_panel = $this->buildAuditPanel();
-      $commit_panel = $this->buildCommitPanel();
-    } else {
-      $audit_panel = null;
-      $commit_panel = null;
+    $repository_panel = null;
+    if ($has_diffusion) {
+      $repository_panel = $this->buildRepositoryPanel();
     }
 
-    if (PhabricatorEnv::getEnvConfig('welcome.html') !== null) {
-      $welcome_panel = $this->buildWelcomePanel();
-    } else {
-      $welcome_panel = null;
-    }
+    $feed_panel = $this->buildFeedPanel();
 
-    if ($has_differential) {
-      $revision_panel = $this->buildRevisionPanel();
-    } else {
-      $revision_panel = null;
-    }
+    $dashboard = id(new AphrontMultiColumnView())
+      ->setFluidlayout(true)
+      ->setGutter(AphrontMultiColumnView::GUTTER_LARGE);
 
-    $home = phutil_tag(
+    $main_panel = phutil_tag(
       'div',
       array(
         'class' => 'homepage-panel',
       ),
       array(
-        $welcome_panel,
-        $unbreak_panel,
-        $triage_panel,
         $revision_panel,
         $tasks_panel,
-        $audit_panel,
-        $commit_panel,
-        $this->minipanels,
+        $repository_panel,
       ));
-      return $home;
-  }
-
-  private function buildUnbreakNowPanel() {
-    $unbreak_now = PhabricatorEnv::getEnvConfig(
-      'maniphest.priorities.unbreak-now');
-    if (!$unbreak_now) {
-      return null;
-    }
-
-    $user = $this->getRequest()->getUser();
-
-    $task_query = id(new ManiphestTaskQuery())
-      ->setViewer($user)
-      ->withStatuses(ManiphestTaskStatus::getOpenStatusConstants())
-      ->withPriorities(array($unbreak_now))
-      ->needProjectPHIDs(true)
-      ->setLimit(10);
-
-    $tasks = $task_query->execute();
-
-    if (!$tasks) {
-      return $this->renderMiniPanel(
-        pht('No "Unbreak Now!" Tasks'),
-        pht('Nothing appears to be critically broken right now.'));
-    }
-
-    $href = urisprintf(
-      '/maniphest/?statuses=open()&priorities=%s#R',
-      $unbreak_now);
-    $title = pht('Unbreak Now!');
-    $panel = new PHUIObjectBoxView();
-    $panel->setHeader($this->renderSectionHeader($title, $href));
-    $panel->setObjectList($this->buildTaskListView($tasks));
-
-    return $panel;
-  }
-
-  private function buildNeedsTriagePanel(array $projects) {
-    assert_instances_of($projects, 'PhabricatorProject');
-
-    $needs_triage = PhabricatorEnv::getEnvConfig(
-      'maniphest.priorities.needs-triage');
-    if (!$needs_triage) {
-      return null;
-    }
-
-    $user = $this->getRequest()->getUser();
-    if (!$user->isLoggedIn()) {
-      return null;
-    }
-
-    if ($projects) {
-      $task_query = id(new ManiphestTaskQuery())
-        ->setViewer($user)
-        ->withStatuses(ManiphestTaskStatus::getOpenStatusConstants())
-        ->withPriorities(array($needs_triage))
-        ->withEdgeLogicPHIDs(
-          PhabricatorProjectObjectHasProjectEdgeType::EDGECONST,
-          PhabricatorQueryConstraint::OPERATOR_OR,
-          mpull($projects, 'getPHID'))
-        ->needProjectPHIDs(true)
-        ->setLimit(10);
-      $tasks = $task_query->execute();
-    } else {
-      $tasks = array();
-    }
-
-    if (!$tasks) {
-      return $this->renderMiniPanel(
-        pht('No "Needs Triage" Tasks'),
-        pht('No tasks tagged with projects you are a member of need triage.'));
-    }
-
-    $title = pht('Needs Triage');
-    $href = urisprintf(
-      '/maniphest/?statuses=open()&priorities=%s&projects=projects(%s)#R',
-      $needs_triage,
-      $user->getPHID());
-    $panel = new PHUIObjectBoxView();
-    $panel->setHeader($this->renderSectionHeader($title, $href));
-    $panel->setObjectList($this->buildTaskListView($tasks));
-
-    return $panel;
-  }
-
-  private function buildRevisionPanel() {
-    $viewer = $this->getViewer();
-
-    $revisions = PhabricatorDifferentialApplication::loadNeedAttentionRevisions(
-      $viewer);
-
-    if (!$revisions) {
-      return $this->renderMiniPanel(
-        pht('No Waiting Revisions'),
-        pht('No revisions are waiting on you.'));
-    }
-
-    $title = pht('Revisions Waiting on You');
-    $href = '/differential/';
-    $panel = new PHUIObjectBoxView();
-    $panel->setHeader($this->renderSectionHeader($title, $href));
-
-    $revision_view = id(new DifferentialRevisionListView())
-      ->setHighlightAge(true)
-      ->setRevisions($revisions)
-      ->setUser($viewer);
-
-    $phids = array_merge(
-      array($viewer->getPHID()),
-      $revision_view->getRequiredHandlePHIDs());
-    $handles = $this->loadViewerHandles($phids);
+    $dashboard->addColumn($main_panel, 'thirds');
 
-    $revision_view->setHandles($handles);
-
-    $list_view = $revision_view->render();
-
-    $panel->setObjectList($list_view);
-
-    return $panel;
-  }
-
-  private function buildWelcomePanel() {
-    $panel = new PHUIObjectBoxView();
-    $panel->setHeaderText(pht('Welcome'));
-    $panel->appendChild(
-      phutil_safe_html(
-        PhabricatorEnv::getEnvConfig('welcome.html')));
-
-    return $panel;
-  }
-
-  private function buildTasksPanel() {
-    $user = $this->getRequest()->getUser();
-    $user_phid = $user->getPHID();
-
-    $task_query = id(new ManiphestTaskQuery())
-      ->setViewer($user)
-      ->withStatuses(ManiphestTaskStatus::getOpenStatusConstants())
-      ->setGroupBy(ManiphestTaskQuery::GROUP_PRIORITY)
-      ->withOwners(array($user_phid))
-      ->needProjectPHIDs(true)
-      ->setLimit(10);
-
-    $tasks = $task_query->execute();
-
-
-    if (!$tasks) {
-      return $this->renderMiniPanel(
-        pht('No Assigned Tasks'),
-        pht('You have no assigned tasks.'));
-    }
-
-    $title = pht('Assigned Tasks');
-    $href = '/maniphest/query/assigned/';
-    $panel = new PHUIObjectBoxView();
-    $panel->setHeader($this->renderSectionHeader($title, $href));
-    $panel->setObjectList($this->buildTaskListView($tasks));
-
-    return $panel;
-  }
-
-  private function buildTaskListView(array $tasks) {
-    assert_instances_of($tasks, 'ManiphestTask');
-    $user = $this->getRequest()->getUser();
-
-    $phids = array_merge(
-      array_filter(mpull($tasks, 'getOwnerPHID')),
-      array_mergev(mpull($tasks, 'getProjectPHIDs')));
-
-    $handles = $this->loadViewerHandles($phids);
+    $side_panel = phutil_tag(
+      'div',
+      array(
+        'class' => 'homepage-side-panel',
+      ),
+      array(
+        $feed_panel,
+      ));
+    $dashboard->addColumn($side_panel, 'third');
 
-    $view = new ManiphestTaskListView();
-    $view->setTasks($tasks);
-    $view->setUser($user);
-    $view->setHandles($handles);
+      $view = id(new PHUIBoxView())
+        ->addClass('dashboard-view')
+        ->appendChild($dashboard);
 
-    return $view;
+      return $view;
   }
 
-  private function renderSectionHeader($title, $href) {
+  private function buildHomepagePanel($title, $href, $view) {
     $title = phutil_tag(
       'a',
       array(
         'href' => $href,
       ),
       $title);
+
     $icon = id(new PHUIIconView())
       ->setIcon('fa-search')
       ->setHref($href);
+
     $header = id(new PHUIHeaderView())
       ->setHeader($title)
       ->addActionItem($icon);
-    return $header;
-  }
 
-  private function renderMiniPanel($title, $body) {
-    $panel = new PHUIInfoView();
-    $panel->setSeverity(PHUIInfoView::SEVERITY_NODATA);
-    $panel->appendChild(
-      phutil_tag(
-        'p',
-        array(
-        ),
-        array(
-          phutil_tag('strong', array(), $title.': '),
-          $body,
-        )));
-    $this->minipanels[] = $panel;
-  }
+    $box = id(new PHUIObjectBoxView())
+      ->setHeader($header);
 
-  public function buildAuditPanel() {
-    $request = $this->getRequest();
-    $user = $request->getUser();
-
-    $phids = PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($user);
-
-    $query = id(new DiffusionCommitQuery())
-      ->setViewer($user)
-      ->withNeedsAuditByPHIDs($phids)
-      ->withAuditStatus(DiffusionCommitQuery::AUDIT_STATUS_OPEN)
-      ->needAuditRequests(true)
-      ->needCommitData(true)
-      ->setLimit(10);
+    if ($view->getObjectList()) {
+      $box->setObjectList($view->getObjectList());
+    }
+    if ($view->getContent()) {
+      $box->appendChild($view->getContent());
+    }
 
-    $commits = $query->execute();
+    return $box;
+  }
 
-    if (!$commits) {
-      return $this->renderMinipanel(
-        pht('No Audits'),
-        pht('No commits are waiting for you to audit them.'));
+  private function buildRevisionPanel() {
+    $viewer = $this->getViewer();
+    if (!$viewer->isLoggedIn()) {
+      return null;
     }
 
-    $view = id(new PhabricatorAuditListView())
-      ->setCommits($commits)
-      ->setUser($user);
+    $engine = new DifferentialRevisionSearchEngine();
+    $engine->setViewer($viewer);
+    $saved = $engine->buildSavedQueryFromBuiltin('active');
+    $query = $engine->buildQueryFromSavedQuery($saved);
+    $pager = $engine->newPagerForSavedQuery($saved);
+    $pager->setPageSize(15);
+    $results = $engine->executeQuery($query, $pager);
+    $view = $engine->renderResults($results, $saved);
 
-    $phids = $view->getRequiredHandlePHIDs();
-    $handles = $this->loadViewerHandles($phids);
-    $view->setHandles($handles);
+    $title = pht('Active Revisions');
+    $href = '/differential/query/active/';
 
-    $title = pht('Audits');
-    $href = '/audit/';
-    $panel = new PHUIObjectBoxView();
-    $panel->setHeader($this->renderSectionHeader($title, $href));
-    $panel->setObjectList($view);
-
-    return $panel;
+    return $this->buildHomepagePanel($title, $href, $view);
   }
 
-  public function buildCommitPanel() {
-    $request = $this->getRequest();
-    $user = $request->getUser();
+  private function buildTasksPanel() {
+    $viewer = $this->getViewer();
 
-    $phids = array($user->getPHID());
+    $query = 'assigned';
+    $title = pht('Assigned Tasks');
+    $href = '/maniphest/query/assigned/';
+    if (!$viewer->isLoggedIn()) {
+      $query = 'open';
+      $title = pht('Open Tasks');
+      $href = '/maniphest/query/open/';
+    }
+
+    $engine = new ManiphestTaskSearchEngine();
+    $engine->setViewer($viewer);
+    $saved = $engine->buildSavedQueryFromBuiltin($query);
+    $query = $engine->buildQueryFromSavedQuery($saved);
+    $pager = $engine->newPagerForSavedQuery($saved);
+    $pager->setPageSize(15);
+    $results = $engine->executeQuery($query, $pager);
+    $view = $engine->renderResults($results, $saved);
+
+    return $this->buildHomepagePanel($title, $href, $view);
+  }
 
-    $query = id(new DiffusionCommitQuery())
-      ->setViewer($user)
-      ->withAuthorPHIDs($phids)
-      ->withAuditStatus(DiffusionCommitQuery::AUDIT_STATUS_CONCERN)
-      ->needCommitData(true)
-      ->needAuditRequests(true)
-      ->setLimit(10);
+  public function buildFeedPanel() {
+    $viewer = $this->getViewer();
 
-    $commits = $query->execute();
+    $engine = new PhabricatorFeedSearchEngine();
+    $engine->setViewer($viewer);
+    $saved = $engine->buildSavedQueryFromBuiltin('all');
+    $query = $engine->buildQueryFromSavedQuery($saved);
+    $pager = $engine->newPagerForSavedQuery($saved);
+    $pager->setPageSize(40);
+    $results = $engine->executeQuery($query, $pager);
+    $view = $engine->renderResults($results, $saved);
 
-    if (!$commits) {
-      return $this->renderMinipanel(
-        pht('No Problem Commits'),
-        pht('No one has raised concerns with your commits.'));
-    }
+    $title = pht('Recent Activity');
+    $href = '/feed/';
 
-    $view = id(new PhabricatorAuditListView())
-      ->setCommits($commits)
-      ->setUser($user);
+    return $this->buildHomepagePanel($title, $href, $view);
+  }
+
+  public function buildRepositoryPanel() {
+    $viewer = $this->getViewer();
 
-    $phids = $view->getRequiredHandlePHIDs();
-    $handles = $this->loadViewerHandles($phids);
-    $view->setHandles($handles);
+    $engine = new PhabricatorRepositorySearchEngine();
+    $engine->setViewer($viewer);
+    $saved = $engine->buildSavedQueryFromBuiltin('active');
+    $query = $engine->buildQueryFromSavedQuery($saved);
+    $pager = $engine->newPagerForSavedQuery($saved);
+    $pager->setPageSize(5);
+    $results = $engine->executeQuery($query, $pager);
+    $view = $engine->renderResults($results, $saved);
 
-    $title = pht('Problem Commits');
-    $href = '/audit/';
-    $panel = new PHUIObjectBoxView();
-    $panel->setHeader($this->renderSectionHeader($title, $href));
-    $panel->setObjectList($view);
+    $title = pht('Active Repositories');
+    $href = '/diffusion/';
 
-    return $panel;
+    return $this->buildHomepagePanel($title, $href, $view);
   }
 
 }
diff --git a/src/applications/maniphest/view/ManiphestTaskResultListView.php b/src/applications/maniphest/view/ManiphestTaskResultListView.php
index 52f4a3b2d6..9e28e89d8d 100644
--- a/src/applications/maniphest/view/ManiphestTaskResultListView.php
+++ b/src/applications/maniphest/view/ManiphestTaskResultListView.php
@@ -1,270 +1,271 @@
 <?php
 
 final class ManiphestTaskResultListView extends ManiphestView {
 
   private $tasks;
   private $savedQuery;
   private $canEditPriority;
   private $canBatchEdit;
   private $showBatchControls;
 
   public function setSavedQuery(PhabricatorSavedQuery $query) {
     $this->savedQuery = $query;
     return $this;
   }
 
   public function setTasks(array $tasks) {
     $this->tasks = $tasks;
     return $this;
   }
 
   public function setCanEditPriority($can_edit_priority) {
     $this->canEditPriority = $can_edit_priority;
     return $this;
   }
 
   public function setCanBatchEdit($can_batch_edit) {
     $this->canBatchEdit = $can_batch_edit;
     return $this;
   }
 
   public function setShowBatchControls($show_batch_controls) {
     $this->showBatchControls = $show_batch_controls;
     return $this;
   }
 
   public function render() {
     $viewer = $this->getUser();
     $tasks = $this->tasks;
     $query = $this->savedQuery;
 
     // If we didn't match anything, just pick up the default empty state.
     if (!$tasks) {
       return id(new PHUIObjectItemListView())
-        ->setUser($viewer);
+        ->setUser($viewer)
+        ->setNoDataString(pht('No tasks found.'));
     }
 
     $group_parameter = nonempty($query->getParameter('group'), 'priority');
     $order_parameter = nonempty($query->getParameter('order'), 'priority');
 
     $handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks);
     $groups = $this->groupTasks(
       $tasks,
       $group_parameter,
       $handles);
 
     $can_edit_priority = $this->canEditPriority;
 
     $can_drag = ($order_parameter == 'priority') &&
                 ($can_edit_priority) &&
                 ($group_parameter == 'none' || $group_parameter == 'priority');
 
     if (!$viewer->isLoggedIn()) {
       // TODO: (T7131) Eventually, we conceivably need to make each task
       // draggable individually, since the user may be able to edit some but
       // not others.
       $can_drag = false;
     }
 
     $result = array();
 
     $lists = array();
     foreach ($groups as $group => $list) {
       $task_list = new ManiphestTaskListView();
       $task_list->setShowBatchControls($this->showBatchControls);
       if ($can_drag) {
         $task_list->setShowSubpriorityControls(true);
       }
       $task_list->setUser($viewer);
       $task_list->setTasks($list);
       $task_list->setHandles($handles);
 
       $header = id(new PHUIHeaderView())
         ->addSigil('task-group')
         ->setMetadata(array('priority' => head($list)->getPriority()))
         ->setHeader(pht('%s (%s)', $group, phutil_count($list)));
 
       $lists[] = id(new PHUIObjectBoxView())
         ->setHeader($header)
         ->setObjectList($task_list);
 
     }
 
     if ($can_drag) {
       Javelin::initBehavior(
         'maniphest-subpriority-editor',
         array(
           'uri'   =>  '/maniphest/subpriority/',
         ));
     }
 
     return array(
       $lists,
       $this->showBatchControls ? $this->renderBatchEditor($query) : null,
     );
   }
 
 
   private function groupTasks(array $tasks, $group, array $handles) {
     assert_instances_of($tasks, 'ManiphestTask');
     assert_instances_of($handles, 'PhabricatorObjectHandle');
 
     $groups = $this->getTaskGrouping($tasks, $group);
 
     $results = array();
     foreach ($groups as $label_key => $tasks) {
       $label = $this->getTaskLabelName($group, $label_key, $handles);
       $results[$label][] = $tasks;
     }
     foreach ($results as $label => $task_groups) {
       $results[$label] = array_mergev($task_groups);
     }
 
     return $results;
   }
 
   private function getTaskGrouping(array $tasks, $group) {
     switch ($group) {
       case 'priority':
         return mgroup($tasks, 'getPriority');
       case 'status':
         return mgroup($tasks, 'getStatus');
       case 'assigned':
         return mgroup($tasks, 'getOwnerPHID');
       case 'project':
         return mgroup($tasks, 'getGroupByProjectPHID');
       default:
         return array(pht('Tasks') => $tasks);
     }
   }
 
   private function getTaskLabelName($group, $label_key, array $handles) {
     switch ($group) {
       case 'priority':
         return ManiphestTaskPriority::getTaskPriorityName($label_key);
       case 'status':
         return ManiphestTaskStatus::getTaskStatusFullName($label_key);
       case 'assigned':
         if ($label_key) {
           return $handles[$label_key]->getFullName();
         } else {
           return pht('(Not Assigned)');
         }
       case 'project':
         if ($label_key) {
           return $handles[$label_key]->getFullName();
         } else {
           // This may mean "No Projects", or it may mean the query has project
           // constraints but the task is only in constrained projects (in this
           // case, we don't show the group because it would always have all
           // of the tasks). Since distinguishing between these two cases is
           // messy and the UI is reasonably clear, label generically.
           return pht('(Ungrouped)');
         }
       default:
         return pht('Tasks');
     }
   }
 
   private function renderBatchEditor(PhabricatorSavedQuery $saved_query) {
     $user = $this->getUser();
 
     if (!$this->canBatchEdit) {
       return null;
     }
 
     if (!$user->isLoggedIn()) {
       // Don't show the batch editor or excel export for logged-out users.
       // Technically we //could// let them export, but ehh.
       return null;
     }
 
     Javelin::initBehavior(
       'maniphest-batch-selector',
       array(
         'selectAll'   => 'batch-select-all',
         'selectNone'  => 'batch-select-none',
         'submit'      => 'batch-select-submit',
         'status'      => 'batch-select-status-cell',
         'idContainer' => 'batch-select-id-container',
         'formID'      => 'batch-select-form',
       ));
 
     $select_all = javelin_tag(
       'a',
       array(
         'href'        => '#',
         'mustcapture' => true,
         'class'       => 'grey button',
         'id'          => 'batch-select-all',
       ),
       pht('Select All'));
 
     $select_none = javelin_tag(
       'a',
       array(
         'href'        => '#',
         'mustcapture' => true,
         'class'       => 'grey button',
         'id'          => 'batch-select-none',
       ),
       pht('Clear Selection'));
 
     $submit = phutil_tag(
       'button',
       array(
         'id'          => 'batch-select-submit',
         'disabled'    => 'disabled',
         'class'       => 'disabled',
       ),
       pht("Batch Edit Selected \xC2\xBB"));
 
     $export = javelin_tag(
       'a',
       array(
         'href' => '/maniphest/export/'.$saved_query->getQueryKey().'/',
         'class' => 'grey button',
       ),
       pht('Export to Excel'));
 
     $hidden = phutil_tag(
       'div',
       array(
         'id' => 'batch-select-id-container',
       ),
       '');
 
     $editor = hsprintf(
         '<table class="maniphest-batch-editor-layout">'.
           '<tr>'.
             '<td>%s%s</td>'.
             '<td>%s</td>'.
             '<td id="batch-select-status-cell">%s</td>'.
             '<td class="batch-select-submit-cell">%s%s</td>'.
           '</tr>'.
         '</table>',
       $select_all,
       $select_none,
       $export,
       '',
       $submit,
       $hidden);
 
     $editor = phabricator_form(
       $user,
       array(
         'method' => 'POST',
         'action' => '/maniphest/batch/',
         'id'     => 'batch-select-form',
       ),
       $editor);
 
     $box = id(new PHUIObjectBoxView())
       ->setHeaderText(pht('Batch Task Editor'))
       ->appendChild($editor);
 
     $content = phutil_tag_div('maniphest-batch-editor', $box);
 
     return $content;
   }
 }