public function render()
 {
     $view = new AphrontNullView();
     $view->appendChild($this->buttons);
     require_celerity_resource('aphront-contextbar-view-css');
     return phutil_tag_div('aphront-contextbar-view', array(phutil_tag_div('aphront-contextbar-core', array(phutil_tag_div('aphront-contextbar-buttons', $view->render()), phutil_tag_div('aphront-contextbar-content', $this->renderChildren()))), phutil_tag('div', array('style' => 'clear: both;'))));
 }
 public function render()
 {
     $view = new AphrontNullView();
     $view->appendChild($this->items);
     require_celerity_resource('aphront-side-nav-view-css');
     return '<table class="aphront-side-nav-view">' . '<tr>' . '<th class="aphront-side-nav-navigation">' . $view->render() . '</th>' . '<td class="aphront-side-nav-content">' . $this->renderChildren() . '</td>' . '</tr>' . '</table>';
 }
 public function buildView()
 {
     if (!$this->user) {
         throw new Exception('Call setUser() before buildView()!');
     }
     $user = $this->user;
     $stories = $this->stories;
     $handles = array();
     if ($stories) {
         $handle_phids = array_mergev(mpull($stories, 'getRequiredHandlePHIDs'));
         $object_phids = array_mergev(mpull($stories, 'getRequiredObjectPHIDs'));
         $handles = id(new PhabricatorObjectHandleData($handle_phids))->loadHandles();
     }
     $null_view = new AphrontNullView();
     require_celerity_resource('phabricator-feed-css');
     $last_date = null;
     foreach ($stories as $story) {
         $story->setHandles($handles);
         $story->setFramed($this->framed);
         $date = ucfirst(phabricator_relative_date($story->getEpoch(), $user));
         if ($date !== $last_date) {
             if ($last_date !== null) {
                 $null_view->appendChild('<div class="phabricator-feed-story-date-separator"></div>');
             }
             $last_date = $date;
             $null_view->appendChild(phutil_render_tag('div', array('class' => 'phabricator-feed-story-date'), phutil_escape_html($date)));
         }
         $view = $story->renderView();
         $view->setViewer($user);
         $null_view->appendChild($view);
     }
     return id(new AphrontNullView())->appendChild('<div class="phabricator-feed-frame">' . $null_view->render() . '</div>');
 }
 public function render()
 {
     $view = new AphrontNullView();
     $view->appendChild($this->buttons);
     require_celerity_resource('aphront-contextbar-view-css');
     return '<div class="aphront-contextbar-view">' . '<div class="aphront-contextbar-core">' . '<div class="aphront-contextbar-buttons">' . $view->render() . '</div>' . '<div class="aphront-contextbar-content">' . $this->renderChildren() . '</div>' . '</div>' . '<div style="clear: both;"></div>' . '</div>';
 }
Esempio n. 5
0
 public function render()
 {
     $view = new AphrontNullView();
     $view->appendChild($this->items);
     if ($this->flexNav) {
         $user = $this->user;
         require_celerity_resource('phabricator-nav-view-css');
         $nav_classes = array();
         $nav_classes[] = 'phabricator-nav';
         $app_id = celerity_generate_unique_node_id();
         $nav_id = null;
         $drag_id = null;
         $content_id = celerity_generate_unique_node_id();
         $collapse_id = null;
         $expand_id = null;
         $local_id = null;
         $local_menu = null;
         $main_id = celerity_generate_unique_node_id();
         $apps = $this->renderApplications();
         $key = PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED;
         if ($user->loadPreferences()->getPreference($key)) {
             $nav_classes[] = 'phabricator-nav-app-collapsed';
         }
         $collapse_id = celerity_generate_unique_node_id();
         $expand_id = celerity_generate_unique_node_id();
         $collapse_button = phutil_render_tag('a', array('href' => '#', 'class' => 'phabricator-nav-app-button-collapse', 'id' => $collapse_id), '&laquo; Collapse');
         $expand_button = phutil_render_tag('a', array('href' => '#', 'class' => 'phabricator-nav-app-button-expand', 'id' => $expand_id), '&raquo;');
         $app_menu = phutil_render_tag('div', array('class' => 'phabricator-nav-col phabricator-nav-app', 'id' => $app_id), $apps->render()) . $expand_button . $collapse_button;
         if ($this->flexible) {
             $drag_id = celerity_generate_unique_node_id();
             $flex_bar = phutil_render_tag('div', array('class' => 'phabricator-nav-drag', 'id' => $drag_id), '');
         } else {
             $flex_bar = null;
         }
         $nav_menu = null;
         if ($this->items) {
             $local_id = celerity_generate_unique_node_id();
             $nav_classes[] = 'has-local-nav';
             $local_menu = phutil_render_tag('div', array('class' => 'phabricator-nav-col phabricator-nav-local', 'id' => $local_id), $view->render());
         }
         Javelin::initBehavior('phabricator-nav', array('mainID' => $main_id, 'appID' => $app_id, 'localID' => $local_id, 'dragID' => $drag_id, 'contentID' => $content_id, 'collapseID' => $collapse_id, 'expandID' => $expand_id, 'collapseKey' => $key));
         if ($this->active && $local_id) {
             Javelin::initBehavior('phabricator-active-nav', array('localID' => $local_id));
         }
         $header_part = '<div class="phabricator-nav-head">' . '<div class="phabricator-nav-head-tablet">' . '<a href="#" class="nav-button nav-button-w nav-button-menu" ' . 'id="tablet-menu1"></a>' . '<a href="#" class="nav-button nav-button-e nav-button-content ' . 'nav-button-selected" id="tablet-menu2"></a>' . '</div>' . '<div class="phabricator-nav-head-phone">' . '<a href="#" class="nav-button nav-button-w nav-button-apps" ' . 'id="phone-menu1"></button>' . '<a href="#" class="nav-button nav-button-menu" ' . 'id="phone-menu2"></button>' . '<a href="#" class="nav-button nav-button-e nav-button-content ' . 'nav-button-selected" id="phone-menu3"></button>' . '</div>' . '</div>';
         return $header_part . phutil_render_tag('div', array('class' => implode(' ', $nav_classes), 'id' => $main_id), $app_menu . $local_menu . $flex_bar . phutil_render_tag('div', array('class' => 'phabricator-nav-content', 'id' => $content_id), $this->renderChildren()));
     } else {
         require_celerity_resource('aphront-side-nav-view-css');
         return '<table class="aphront-side-nav-view">' . '<tr>' . '<th class="aphront-side-nav-navigation">' . $view->render() . '</th>' . '<td class="aphront-side-nav-content">' . $this->renderChildren() . '</td>' . '</tr>' . '</table>';
     }
 }
 public function buildView()
 {
     if (!$this->user) {
         throw new PhutilInvalidStateException('setUser');
     }
     $user = $this->user;
     $stories = $this->stories;
     $null_view = new AphrontNullView();
     require_celerity_resource('phabricator-feed-css');
     $last_date = null;
     foreach ($stories as $story) {
         $story->setHovercard($this->hovercards);
         $date = ucfirst(phabricator_relative_date($story->getEpoch(), $user));
         if ($date !== $last_date) {
             if ($last_date !== null) {
                 $null_view->appendChild(phutil_tag_div('phabricator-feed-story-date-separator'));
             }
             $last_date = $date;
             $header = new PHUIHeaderView();
             $header->setHeader($date);
             $header->setHeaderIcon('fa-calendar msr');
             $null_view->appendChild($header);
         }
         try {
             $view = $story->renderView();
             $view->setUser($user);
             $view = $view->render();
         } catch (Exception $ex) {
             // If rendering failed for any reason, don't fail the entire feed,
             // just this one story.
             $view = id(new PHUIFeedStoryView())->setUser($user)->setChronologicalKey($story->getChronologicalKey())->setEpoch($story->getEpoch())->setTitle(pht('Feed Story Failed to Render (%s)', get_class($story)))->appendChild(pht('%s: %s', get_class($ex), $ex->getMessage()));
         }
         $null_view->appendChild($view);
     }
     $box = id(new PHUIObjectBoxView())->appendChild($null_view);
     if (empty($stories)) {
         $nodatastring = pht('No Stories.');
         if ($this->noDataString) {
             $nodatastring = $this->noDataString;
         }
         $view = id(new PHUIBoxView())->addClass('mlt mlb msr msl')->appendChild($nodatastring);
         $box->appendChild($view);
     }
     return $box;
 }
 public function render()
 {
     $view = new AphrontNullView();
     $view->appendChild($this->items);
     $side_links = null;
     $realname = null;
     $title = null;
     if (!empty($this->profileRealname)) {
         $realname = '<h2 class="phabricator-profile-realname">' . phutil_escape_html($this->profileRealname) . '</h2>';
     }
     if (!empty($this->profileTitle)) {
         $title = '<h2>' . phutil_escape_html($this->profileTitle) . '</h2>';
     }
     if (!empty($this->items)) {
         $side_links = $view->render() . '<hr />';
     }
     require_celerity_resource('phabricator-profile-css');
     return '<table class="phabricator-profile-master-layout">' . '<tr>' . '<td class="phabricator-profile-navigation">' . '<h1>' . phutil_escape_html($this->profileName) . '</h1>' . $realname . $title . '<hr />' . '<img class="phabricator-profile-image" src="' . $this->profilePicture . '"/>' . '<hr />' . $side_links . '</td>' . '<td class="phabricator-profile-content">' . $this->renderChildren() . '</td>' . '</tr>' . '</table>';
 }
 public function handleRequest(AphrontRequest $request)
 {
     $user = $request->getUser();
     $conpherences = array();
     require_celerity_resource('conpherence-notification-css');
     $unread_status = ConpherenceParticipationStatus::BEHIND;
     $participant_data = id(new ConpherenceParticipantQuery())->withParticipantPHIDs(array($user->getPHID()))->setLimit(5)->execute();
     if ($participant_data) {
         $conpherences = id(new ConpherenceThreadQuery())->setViewer($user)->withPHIDs(array_keys($participant_data))->needProfileImage(true)->needTransactions(true)->setTransactionLimit(50)->needParticipantCache(true)->execute();
     }
     if ($conpherences) {
         // re-order the conpherences based on participation data
         $conpherences = array_select_keys($conpherences, array_keys($participant_data));
         $view = new AphrontNullView();
         foreach ($conpherences as $conpherence) {
             $p_data = $participant_data[$conpherence->getPHID()];
             $d_data = $conpherence->getDisplayData($user);
             $classes = array('phabricator-notification', 'conpherence-notification');
             if ($p_data->getParticipationStatus() == $unread_status) {
                 $classes[] = 'phabricator-notification-unread';
             }
             $uri = $this->getApplicationURI($conpherence->getID() . '/');
             $title = $d_data['title'];
             $subtitle = $d_data['subtitle'];
             $unread_count = $d_data['unread_count'];
             $epoch = $d_data['epoch'];
             $image = $d_data['image'];
             $msg_view = id(new ConpherenceMenuItemView())->setUser($user)->setTitle($title)->setSubtitle($subtitle)->setHref($uri)->setEpoch($epoch)->setImageURI($image)->setUnreadCount($unread_count);
             $view->appendChild(javelin_tag('div', array('class' => implode(' ', $classes), 'sigil' => 'notification', 'meta' => array('href' => $uri)), $msg_view));
         }
         $content = $view->render();
     } else {
         $rooms_uri = phutil_tag('a', array('href' => '/conpherence/', 'class' => 'no-room-notification'), pht('You have joined no rooms.'));
         $content = phutil_tag_div('phabricator-notification no-notifications', $rooms_uri);
     }
     $content = hsprintf('<div class="phabricator-notification-header grouped">%s%s</div>' . '%s', phutil_tag('a', array('href' => '/conpherence/'), pht('Rooms')), $this->renderPersistentOption(), $content);
     $unread = id(new ConpherenceParticipantCountQuery())->withParticipantPHIDs(array($user->getPHID()))->withParticipationStatus($unread_status)->execute();
     $unread_count = idx($unread, $user->getPHID(), 0);
     $json = array('content' => $content, 'number' => (int) $unread_count);
     return id(new AphrontAjaxResponse())->setContent($json);
 }
Esempio n. 9
0
 public function render()
 {
     $view = new AphrontNullView();
     $view->appendChild($this->items);
     if ($this->flexNav) {
         require_celerity_resource('phabricator-nav-view-css');
         $nav_id = celerity_generate_unique_node_id();
         $drag_id = celerity_generate_unique_node_id();
         $content_id = celerity_generate_unique_node_id();
         if ($this->flexible) {
             Javelin::initBehavior('phabricator-nav', array('navID' => $nav_id, 'dragID' => $drag_id, 'contentID' => $content_id));
             $flex_bar = phutil_render_tag('div', array('class' => 'phabricator-nav-drag', 'id' => $drag_id), '');
         } else {
             $flex_bar = null;
         }
         return '<div class="phabricator-nav">' . phutil_render_tag('div', array('class' => 'phabricator-nav-col', 'id' => $nav_id), $view->render()) . $flex_bar . phutil_render_tag('div', array('class' => 'phabricator-nav-content', 'id' => $content_id), $this->renderChildren()) . '</div>';
     } else {
         require_celerity_resource('aphront-side-nav-view-css');
         return '<table class="aphront-side-nav-view">' . '<tr>' . '<th class="aphront-side-nav-navigation">' . $view->render() . '</th>' . '<td class="aphront-side-nav-content">' . $this->renderChildren() . '</td>' . '</tr>' . '</table>';
     }
 }
 public function buildView()
 {
     if (!$this->user) {
         throw new Exception('Call setUser() before buildView()!');
     }
     $user = $this->user;
     $stories = $this->stories;
     $null_view = new AphrontNullView();
     require_celerity_resource('phabricator-feed-css');
     $last_date = null;
     foreach ($stories as $story) {
         $story->setFramed($this->framed);
         $story->setHovercard($this->hovercards);
         $date = ucfirst(phabricator_relative_date($story->getEpoch(), $user));
         if ($date !== $last_date) {
             if ($last_date !== null) {
                 $null_view->appendChild(phutil_tag_div('phabricator-feed-story-date-separator'));
             }
             $last_date = $date;
             $header = new PHUIActionHeaderView();
             $header->setHeaderTitle($date);
             $null_view->appendChild($header);
         }
         try {
             $view = $story->renderView();
             $view->setUser($user);
             $view = $view->render();
         } catch (Exception $ex) {
             // If rendering failed for any reason, don't fail the entire feed,
             // just this one story.
             $view = id(new PHUIFeedStoryView())->setUser($user)->setChronologicalKey($story->getChronologicalKey())->setEpoch($story->getEpoch())->setTitle(pht('Feed Story Failed to Render (%s)', get_class($story)))->appendChild(pht('%s: %s', get_class($ex), $ex->getMessage()));
         }
         $null_view->appendChild($view);
     }
     return id(new AphrontNullView())->appendChild($null_view->render());
 }
 public function testHasChildren()
 {
     $view = new AphrontNullView();
     $this->assertFalse($view->hasChildren());
     $values = array(null, '', array(), array(null, ''));
     foreach ($values as $value) {
         $view->appendChild($value);
         $this->assertFalse($view->hasChildren());
     }
     $view->appendChild('!');
     $this->assertTrue($view->hasChildren());
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     if ($request->isFormPost()) {
         // Redirect to GET so URIs can be copy/pasted.
         $task_ids = $request->getStr('set_tasks');
         $task_ids = nonempty($task_ids, null);
         $search_text = $request->getStr('set_search');
         $search_text = nonempty($search_text, null);
         $min_priority = $request->getInt('set_lpriority');
         $min_priority = nonempty($min_priority, null);
         $max_priority = $request->getInt('set_hpriority');
         $max_priority = nonempty($max_priority, null);
         $uri = $request->getRequestURI()->alter('users', $this->getArrToStrList('set_users'))->alter('projects', $this->getArrToStrList('set_projects'))->alter('xprojects', $this->getArrToStrList('set_xprojects'))->alter('owners', $this->getArrToStrList('set_owners'))->alter('authors', $this->getArrToStrList('set_authors'))->alter('lpriority', $min_priority)->alter('hpriority', $max_priority)->alter('tasks', $task_ids)->alter('search', $search_text);
         return id(new AphrontRedirectResponse())->setURI($uri);
     }
     $nav = $this->buildBaseSideNav();
     $has_filter = array('action' => true, 'created' => true, 'subscribed' => true, 'triage' => true, 'projecttriage' => true, 'projectall' => true);
     $query = null;
     $key = $request->getStr('key');
     if (!$key && !$this->view) {
         if ($this->getDefaultQuery()) {
             $key = $this->getDefaultQuery()->getQueryKey();
         }
     }
     if ($key) {
         $query = id(new PhabricatorSearchQuery())->loadOneWhere('queryKey = %s', $key);
     }
     // If the user is running a saved query, load query parameters from that
     // query. Otherwise, build a new query object from the HTTP request.
     if ($query) {
         $nav->selectFilter('Q:' . $query->getQueryKey(), 'custom');
         $this->view = 'custom';
     } else {
         $this->view = $nav->selectFilter($this->view, 'action');
         $query = $this->buildQueryFromRequest();
     }
     // Execute the query.
     list($tasks, $handles, $total_count) = self::loadTasks($query);
     // Extract information we need to render the filters from the query.
     $search_text = $query->getParameter('fullTextSearch');
     $user_phids = $query->getParameter('userPHIDs', array());
     $task_ids = $query->getParameter('taskIDs', array());
     $owner_phids = $query->getParameter('ownerPHIDs', array());
     $author_phids = $query->getParameter('authorPHIDs', array());
     $project_phids = $query->getParameter('projectPHIDs', array());
     $exclude_project_phids = $query->getParameter('excludeProjectPHIDs', array());
     $low_priority = $query->getParameter('lowPriority');
     $high_priority = $query->getParameter('highPriority');
     $page_size = $query->getParameter('limit');
     $page = $query->getParameter('offset');
     $q_status = $query->getParameter('status');
     $q_group = $query->getParameter('group');
     $q_order = $query->getParameter('order');
     $form = id(new AphrontFormView())->setUser($user)->setAction($request->getRequestURI()->alter('key', null)->alter($this->getStatusRequestKey(), $this->getStatusRequestValue($q_status))->alter($this->getOrderRequestKey(), $this->getOrderRequestValue($q_order))->alter($this->getGroupRequestKey(), $this->getGroupRequestValue($q_group)));
     if (isset($has_filter[$this->view])) {
         $tokens = array();
         foreach ($user_phids as $phid) {
             $tokens[$phid] = $handles[$phid]->getFullName();
         }
         $form->appendChild(id(new AphrontFormTokenizerControl())->setDatasource('/typeahead/common/searchowner/')->setName('set_users')->setLabel('Users')->setValue($tokens));
     }
     if ($this->view == 'custom') {
         $form->appendChild(id(new AphrontFormTextControl())->setName('set_search')->setLabel('Search')->setValue($search_text));
         $form->appendChild(id(new AphrontFormTextControl())->setName('set_tasks')->setLabel('Task IDs')->setValue(join(',', $task_ids)));
         $tokens = array();
         foreach ($owner_phids as $phid) {
             $tokens[$phid] = $handles[$phid]->getFullName();
         }
         $form->appendChild(id(new AphrontFormTokenizerControl())->setDatasource('/typeahead/common/searchowner/')->setName('set_owners')->setLabel('Owners')->setValue($tokens));
         $tokens = array();
         foreach ($author_phids as $phid) {
             $tokens[$phid] = $handles[$phid]->getFullName();
         }
         $form->appendChild(id(new AphrontFormTokenizerControl())->setDatasource('/typeahead/common/users/')->setName('set_authors')->setLabel('Authors')->setValue($tokens));
     }
     $tokens = array();
     foreach ($project_phids as $phid) {
         $tokens[$phid] = $handles[$phid]->getFullName();
     }
     if ($this->view != 'projectall' && $this->view != 'projecttriage') {
         $form->appendChild(id(new AphrontFormTokenizerControl())->setDatasource('/typeahead/common/searchproject/')->setName('set_projects')->setLabel('Projects')->setValue($tokens));
     }
     if ($this->view == 'custom') {
         $tokens = array();
         foreach ($exclude_project_phids as $phid) {
             $tokens[$phid] = $handles[$phid]->getFullName();
         }
         $form->appendChild(id(new AphrontFormTokenizerControl())->setDatasource('/typeahead/common/projects/')->setName('set_xprojects')->setLabel('Exclude Projects')->setValue($tokens));
         $priority = ManiphestTaskPriority::getLowestPriority();
         if ($low_priority) {
             $priority = $low_priority;
         }
         $form->appendChild(id(new AphrontFormSelectControl())->setLabel('Min Priority')->setName('set_lpriority')->setValue($priority)->setOptions(array_reverse(ManiphestTaskPriority::getTaskPriorityMap(), true)));
         $priority = ManiphestTaskPriority::getHighestPriority();
         if ($high_priority) {
             $priority = $high_priority;
         }
         $form->appendChild(id(new AphrontFormSelectControl())->setLabel('Max Priority')->setName('set_hpriority')->setValue($priority)->setOptions(ManiphestTaskPriority::getTaskPriorityMap()));
     }
     $form->appendChild($this->renderStatusControl($q_status))->appendChild($this->renderGroupControl($q_group))->appendChild($this->renderOrderControl($q_order));
     $submit = id(new AphrontFormSubmitControl())->setValue('Filter Tasks');
     // Only show "Save..." for novel queries which have some kind of query
     // parameters set.
     if ($this->view === 'custom' && empty($key) && $request->getRequestURI()->getQueryParams()) {
         $submit->addCancelButton('/maniphest/custom/edit/?key=' . $query->getQueryKey(), 'Save Custom Query...');
     }
     $form->appendChild($submit);
     $create_uri = new PhutilURI('/maniphest/task/create/');
     if ($project_phids) {
         // If we have project filters selected, use them as defaults for task
         // creation.
         $create_uri->setQueryParam('projects', implode(';', $project_phids));
     }
     $filter = new AphrontListFilterView();
     $filter->addButton(phutil_render_tag('a', array('href' => (string) $create_uri, 'class' => 'green button'), 'Create New Task'));
     if (empty($key)) {
         $filter->appendChild($form);
     }
     $nav->appendChild($filter);
     $have_tasks = false;
     foreach ($tasks as $group => $list) {
         if (count($list)) {
             $have_tasks = true;
             break;
         }
     }
     require_celerity_resource('maniphest-task-summary-css');
     $list_container = new AphrontNullView();
     $list_container->appendChild('<div class="maniphest-list-container">');
     if (!$have_tasks) {
         $list_container->appendChild('<h1 class="maniphest-task-group-header">' . 'No matching tasks.' . '</h1>');
     } else {
         $pager = new AphrontPagerView();
         $pager->setURI($request->getRequestURI(), 'offset');
         $pager->setPageSize($page_size);
         $pager->setOffset($page);
         $pager->setCount($total_count);
         $cur = $pager->getOffset() + 1;
         $max = min($pager->getOffset() + $page_size, $total_count);
         $tot = $total_count;
         $cur = number_format($cur);
         $max = number_format($max);
         $tot = number_format($tot);
         $list_container->appendChild('<div class="maniphest-total-result-count">' . "Displaying tasks {$cur} - {$max} of {$tot}." . '</div>');
         $selector = new AphrontNullView();
         $group = $query->getParameter('group');
         $order = $query->getParameter('order');
         $is_draggable = $group == 'priority' || $group == 'none' && $order == 'priority';
         $lists = new AphrontNullView();
         $lists->appendChild('<div class="maniphest-group-container">');
         foreach ($tasks as $group => $list) {
             $task_list = new ManiphestTaskListView();
             $task_list->setShowBatchControls(true);
             if ($is_draggable) {
                 $task_list->setShowSubpriorityControls(true);
             }
             $task_list->setUser($user);
             $task_list->setTasks($list);
             $task_list->setHandles($handles);
             $count = number_format(count($list));
             $lists->appendChild(javelin_render_tag('h1', array('class' => 'maniphest-task-group-header', 'sigil' => 'task-group', 'meta' => array('priority' => head($list)->getPriority())), phutil_escape_html($group) . ' (' . $count . ')'));
             $lists->appendChild($task_list);
         }
         $lists->appendChild('</div>');
         $selector->appendChild($lists);
         $selector->appendChild($this->renderBatchEditor($query));
         $form_id = celerity_generate_unique_node_id();
         $selector = phabricator_render_form($user, array('method' => 'POST', 'action' => '/maniphest/batch/', 'id' => $form_id), $selector->render());
         $list_container->appendChild($selector);
         $list_container->appendChild($pager);
         Javelin::initBehavior('maniphest-subpriority-editor', array('root' => $form_id, 'uri' => '/maniphest/subpriority/'));
     }
     $list_container->appendChild('</div>');
     $nav->appendChild($list_container);
     return $this->buildStandardPageResponse($nav, array('title' => 'Task List'));
 }
 public function buildView()
 {
     $stories = $this->stories;
     $stories = mpull($stories, null, 'getChronologicalKey');
     // Aggregate notifications. Generally, we can aggregate notifications only
     // by object, e.g. "a updated T123" and "b updated T123" can become
     // "a and b updated T123", but we can't combine "a updated T123" and
     // "a updated T234" into "a updated T123 and T234" because there would be
     // nowhere sensible for the notification to link to, and no reasonable way
     // to unambiguously clear it.
     // Each notification emits keys it can aggregate on. For instance, if this
     // story is "a updated T123", it might emit a key like this:
     //
     //   task:phid123:unread => PhabricatorFeedStoryManiphestAggregate
     //
     // All the unread notifications about the task with PHID "phid123" will
     // emit the same key, telling us we can aggregate them into a single
     // story of type "PhabricatorFeedStoryManiphestAggregate", which could
     // read like "a and b updated T123".
     //
     // A story might be able to aggregate in multiple ways. Although this is
     // unlikely for stories in a notification context, stories in a feed context
     // can also aggregate by actor:
     //
     //   task:phid123   => PhabricatorFeedStoryManiphestAggregate
     //   actor:user123  => PhabricatorFeedStoryActorAggregate
     //
     // This means the story can either become "a and b updated T123" or
     // "a updated T123 and T456". When faced with multiple possibilities, it's
     // our job to choose the best aggregation.
     //
     // For now, we use a simple greedy algorithm and repeatedly select the
     // aggregate story which consumes the largest number of individual stories
     // until no aggregate story exists that consumes more than one story.
     // Build up a map of all the possible aggregations.
     $chronokey_map = array();
     $aggregation_map = array();
     $agg_types = array();
     foreach ($stories as $chronokey => $story) {
         $chronokey_map[$chronokey] = $story->getNotificationAggregations();
         foreach ($chronokey_map[$chronokey] as $key => $type) {
             $agg_types[$key] = $type;
             $aggregation_map[$key]['keys'][$chronokey] = true;
         }
     }
     // Repeatedly select the largest available aggregation until none remain.
     $aggregated_stories = array();
     while ($aggregation_map) {
         // Count the size of each aggregation, removing any which will consume
         // fewer than 2 stories.
         foreach ($aggregation_map as $key => $dict) {
             $size = count($dict['keys']);
             if ($size > 1) {
                 $aggregation_map[$key]['size'] = $size;
             } else {
                 unset($aggregation_map[$key]);
             }
         }
         // If we're out of aggregations, break out.
         if (!$aggregation_map) {
             break;
         }
         // Select the aggregation we're going to make, and remove it from the
         // map.
         $aggregation_map = isort($aggregation_map, 'size');
         $agg_info = idx(last($aggregation_map), 'keys');
         $agg_key = last_key($aggregation_map);
         unset($aggregation_map[$agg_key]);
         // Select all the stories it aggregates, and remove them from the master
         // list of stories and from all other possible aggregations.
         $sub_stories = array();
         foreach ($agg_info as $chronokey => $ignored) {
             $sub_stories[$chronokey] = $stories[$chronokey];
             unset($stories[$chronokey]);
             foreach ($chronokey_map[$chronokey] as $key => $type) {
                 unset($aggregation_map[$key]['keys'][$chronokey]);
             }
             unset($chronokey_map[$chronokey]);
         }
         // Build the aggregate story.
         krsort($sub_stories);
         $story_class = $agg_types[$agg_key];
         $conv = array(head($sub_stories)->getStoryData());
         $new_story = newv($story_class, $conv);
         $new_story->setAggregateStories($sub_stories);
         $aggregated_stories[] = $new_story;
     }
     // Combine the aggregate stories back into the list of stories.
     $stories = array_merge($stories, $aggregated_stories);
     $stories = mpull($stories, null, 'getChronologicalKey');
     krsort($stories);
     $null_view = new AphrontNullView();
     foreach ($stories as $story) {
         try {
             $view = $story->renderView();
         } catch (Exception $ex) {
             // TODO: Render a nice debuggable notice instead?
             continue;
         }
         $null_view->appendChild($view->renderNotification($this->user));
     }
     return $null_view;
 }
 private function buildAppPanel()
 {
     require_celerity_resource('phabricator-app-buttons-css');
     $nav_buttons = array();
     $nav_buttons[] = array('Differential', '/differential/', 'differential', 'Code Reviews');
     if (PhabricatorEnv::getEnvConfig('maniphest.enabled')) {
         $nav_buttons[] = array('Maniphest', '/maniphest/', 'maniphest', 'Tasks');
         $nav_buttons[] = array('Create Task', '/maniphest/task/create/', 'create-task');
     }
     $nav_buttons[] = array('Upload File', '/file/', 'upload-file', 'Share Files');
     $nav_buttons[] = array('Create Paste', '/paste/', 'create-paste', 'Share Text');
     if (PhabricatorEnv::getEnvConfig('phriction.enabled')) {
         $nav_buttons[] = array('Phriction', '/w/', 'phriction', 'Browse Wiki');
     }
     $nav_buttons[] = array('Diffusion', '/diffusion/', 'diffusion', 'Browse Code');
     $nav_buttons[] = array('Audit', '/audit/', 'audit', 'Audit Code');
     $view = new AphrontNullView();
     $view->appendChild('<div class="phabricator-app-buttons">');
     foreach ($nav_buttons as $info) {
         // Subtitle is optional.
         list($name, $uri, $icon, $subtitle) = array_merge($info, array(null));
         if ($subtitle) {
             $subtitle = '<div class="phabricator-app-subtitle">' . phutil_escape_html($subtitle) . '</div>';
         }
         $button = phutil_render_tag('a', array('href' => $uri, 'class' => 'app-button icon-' . $icon), phutil_render_tag('div', array('class' => 'app-icon icon-' . $icon), ''));
         $caption = phutil_render_tag('a', array('href' => $uri, 'class' => 'phabricator-button-caption'), phutil_escape_html($name) . $subtitle);
         $view->appendChild('<div class="phabricator-app-button">' . $button . $caption . '</div>');
     }
     $view->appendChild('<div style="clear: both;"></div></div>');
     return $view;
 }
 private function buildAddCommentView(PhabricatorRepositoryCommit $commit, array $audit_requests)
 {
     assert_instances_of($audit_requests, 'PhabricatorRepositoryAuditRequest');
     $user = $this->getRequest()->getUser();
     $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
     Javelin::initBehavior('differential-keyboard-navigation', array('haunt' => null));
     $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), 'diffusion-audit-' . $commit->getID());
     if ($draft) {
         $draft = $draft->getDraft();
     } else {
         $draft = null;
     }
     $actions = $this->getAuditActions($commit, $audit_requests);
     $form = id(new AphrontFormView())->setUser($user)->setAction('/audit/addcomment/')->addHiddenInput('commit', $commit->getPHID())->appendChild(id(new AphrontFormSelectControl())->setLabel('Action')->setName('action')->setID('audit-action')->setOptions($actions))->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Comments')->setName('content')->setValue($draft)->setID('audit-content')->setCaption(phutil_render_tag('a', array('href' => PhabricatorEnv::getDoclink('article/Remarkup_Reference.html'), 'tabindex' => '-1', 'target' => '_blank'), 'Formatting Reference')))->appendChild(id(new AphrontFormSubmitControl())->setValue($is_serious ? 'Submit' : 'Cook the Books'));
     $panel = new AphrontPanelView();
     $panel->setHeader($is_serious ? 'Audit Commit' : 'Creative Accounting');
     $panel->appendChild($form);
     require_celerity_resource('phabricator-transaction-view-css');
     Javelin::initBehavior('audit-preview', array('uri' => '/audit/preview/' . $commit->getID() . '/', 'preview' => 'audit-preview', 'content' => 'audit-content', 'action' => 'audit-action'));
     $preview_panel = '<div class="aphront-panel-preview">
     <div id="audit-preview">
       <div class="aphront-panel-preview-loading-text">
         Loading preview...
       </div>
     </div>
   </div>';
     $view = new AphrontNullView();
     $view->appendChild($panel);
     $view->appendChild($preview_panel);
     return $view;
 }
 public function buildView()
 {
     $stories = $this->parseStories();
     $null_view = new AphrontNullView();
     foreach ($stories as $story) {
         try {
             $view = $story->renderView();
         } catch (Exception $ex) {
             // TODO: Render a nice debuggable notice instead?
             continue;
         }
         $view->setShowTimestamp($this->getShowTimestamps());
         $null_view->appendChild($view->renderNotification($this->user));
     }
     return $null_view;
 }