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>'; }
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), '« Collapse'); $expand_button = phutil_render_tag('a', array('href' => '#', 'class' => 'phabricator-nav-app-button-expand', 'id' => $expand_id), '»'); $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); }
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; }