diff --git a/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php index 7487a234d..8d062e86c 100644 --- a/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php @@ -1,458 +1,458 @@ getResourceURIMapRules() + array( - '/(?:(?P(?:jump|apps))/)?' => + '/(?:(?P(?:jump))/)?' => 'PhabricatorDirectoryMainController', '/(?:(?Pfeed)/)' => array( 'public/' => 'PhabricatorFeedPublicStreamController', '(?:(?P[^/]+)/)?' => 'PhabricatorDirectoryMainController', ), '/typeahead/' => array( 'common/(?P\w+)/' => 'PhabricatorTypeaheadCommonDatasourceController', ), '/login/' => array( '' => 'PhabricatorLoginController', 'email/' => 'PhabricatorEmailLoginController', 'etoken/(?P\w+)/' => 'PhabricatorEmailTokenController', 'refresh/' => 'PhabricatorRefreshCSRFController', 'validate/' => 'PhabricatorLoginValidateController', 'mustverify/' => 'PhabricatorMustVerifyEmailController', ), '/logout/' => 'PhabricatorLogoutController', '/oauth/' => array( '(?P\w+)/' => array( 'login/' => 'PhabricatorOAuthLoginController', 'diagnose/' => 'PhabricatorOAuthDiagnosticsController', 'unlink/' => 'PhabricatorOAuthUnlinkController', ), ), '/ldap/' => array( 'login/' => 'PhabricatorLDAPLoginController', 'unlink/' => 'PhabricatorLDAPUnlinkController', ), '/oauthserver/' => array( 'auth/' => 'PhabricatorOAuthServerAuthController', 'test/' => 'PhabricatorOAuthServerTestController', 'token/' => 'PhabricatorOAuthServerTokenController', 'clientauthorization/' => array( '' => 'PhabricatorOAuthClientAuthorizationListController', 'delete/(?P[^/]+)/' => 'PhabricatorOAuthClientAuthorizationDeleteController', 'edit/(?P[^/]+)/' => 'PhabricatorOAuthClientAuthorizationEditController', ), 'client/' => array( '' => 'PhabricatorOAuthClientListController', 'create/' => 'PhabricatorOAuthClientEditController', 'delete/(?P[^/]+)/' => 'PhabricatorOAuthClientDeleteController', 'edit/(?P[^/]+)/' => 'PhabricatorOAuthClientEditController', 'view/(?P[^/]+)/' => 'PhabricatorOAuthClientViewController', ), ), '/xhprof/' => array( 'list/(?P[^/]+)/' => 'PhabricatorXHProfSampleListController', 'profile/(?P[^/]+)/' => 'PhabricatorXHProfProfileController', ), '/~/' => 'DarkConsoleController', '/search/' => array( '' => 'PhabricatorSearchController', '(?P[^/]+)/' => 'PhabricatorSearchController', 'attach/(?P[^/]+)/(?P\w+)/(?:(?P\w+)/)?' => 'PhabricatorSearchAttachController', 'select/(?P\w+)/' => 'PhabricatorSearchSelectController', 'index/(?P[^/]+)/' => 'PhabricatorSearchIndexController', ), '/status/' => 'PhabricatorStatusController', '/help/' => array( 'keyboardshortcut/' => 'PhabricatorHelpKeyboardShortcutController', ), '/phame/' => array( '' => 'PhameAllPostListController', 'post/' => array( '' => 'PhameUserPostListController', 'delete/(?P[^/]+)/' => 'PhamePostDeleteController', 'edit/(?P[^/]+)/' => 'PhamePostEditController', 'new/' => 'PhamePostEditController', 'preview/' => 'PhamePostPreviewController', 'view/(?P[^/]+)/' => 'PhamePostViewController', ), 'draft/' => array( '' => 'PhameDraftListController', 'new/' => 'PhamePostEditController', ), 'blog/' => array( '' => 'PhameUserBlogListController', 'all/' => 'PhameAllBlogListController', 'new/' => 'PhameBlogEditController', 'delete/(?P[^/]+)/' => 'PhameBlogDeleteController', 'edit/(?P[^/]+)/' => 'PhameBlogEditController', 'view/(?P[^/]+)/' => 'PhameBlogViewController', ), 'posts/' => array( '' => 'PhameUserPostListController', '(?P\w+)/' => 'PhameBloggerPostListController', '(?P\w+)/(?P.+/)' => 'PhamePostViewController', ), ), '/calendar/' => array( '' => 'PhabricatorCalendarBrowseController', ), '/drydock/' => array( '' => 'DrydockResourceListController', 'resource/' => 'DrydockResourceListController', 'resource/allocate/' => 'DrydockResourceAllocateController', 'host/' => array( '' => 'DrydockHostListController', 'edit/' => 'DrydockHostEditController', 'edit/(?P\d+)/' => 'DrydockhostEditController', ), 'lease/' => 'DrydockLeaseListController', 'log/' => 'DrydockLogController', ), '/chatlog/' => array( '' => 'PhabricatorChatLogChannelListController', 'channel/(?P[^/]+)/' => 'PhabricatorChatLogChannelLogController', ), '/notification/' => array( '(?:(?Pall|unread)/)?' => 'PhabricatorNotificationListController', 'panel/' => 'PhabricatorNotificationPanelController', 'individual/' => 'PhabricatorNotificationIndividualController', 'status/' => 'PhabricatorNotificationStatusController', 'clear/' => 'PhabricatorNotificationClearController', ), '/phortune/' => array( 'stripe/' => array( 'testpaymentform/' => 'PhortuneStripeTestPaymentFormController', ), ), ); } protected function getResourceURIMapRules() { return array( '/res/' => array( '(?Ppkg/)?'. '(?P[a-f0-9]{8})/'. '(?P.+\.(?:css|js|jpg|png|swf|gif))' => 'CelerityResourceController', ), ); } public function buildRequest() { $request = new AphrontRequest($this->getHost(), $this->getPath()); $request->setRequestData($_GET + $_POST); $request->setApplicationConfiguration($this); return $request; } public function handleException(Exception $ex) { $request = $this->getRequest(); // For Conduit requests, return a Conduit response. if ($request->isConduit()) { $response = new ConduitAPIResponse(); $response->setErrorCode(get_class($ex)); $response->setErrorInfo($ex->getMessage()); return id(new AphrontJSONResponse()) ->setContent($response->toDictionary()); } // For non-workflow requests, return a Ajax response. if ($request->isAjax() && !$request->isJavelinWorkflow()) { $response = new AphrontAjaxResponse(); $response->setError( array( 'code' => get_class($ex), 'info' => $ex->getMessage(), )); return $response; } $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); $user = $request->getUser(); if (!$user) { // If we hit an exception very early, we won't have a user. $user = new PhabricatorUser(); } if ($ex instanceof PhabricatorPolicyException) { if (!$user->isLoggedIn()) { // If the user isn't logged in, just give them a login form. This is // probably a generally more useful response than a policy dialog that // they have to click through to get a login form. // // Possibly we should add a header here like "you need to login to see // the thing you are trying to look at". $login_controller = new PhabricatorLoginController($request); return $login_controller->processRequest(); } $content = '
'. phutil_escape_html($ex->getMessage()). '
'; $dialog = new AphrontDialogView(); $dialog ->setTitle( $is_serious ? 'Access Denied' : "You Shall Not Pass") ->setClass('aphront-access-dialog') ->setUser($user) ->appendChild($content); if ($this->getRequest()->isAjax()) { $dialog->addCancelButton('/', 'Close'); } else { $dialog->addCancelButton('/', $is_serious ? 'OK' : 'Away With Thee'); } $response = new AphrontDialogResponse(); $response->setDialog($dialog); return $response; } if ($ex instanceof AphrontUsageException) { $error = new AphrontErrorView(); $error->setTitle(phutil_escape_html($ex->getTitle())); $error->appendChild(phutil_escape_html($ex->getMessage())); $view = new PhabricatorStandardPageView(); $view->setRequest($this->getRequest()); $view->appendChild($error); $response = new AphrontWebpageResponse(); $response->setContent($view->render()); return $response; } // Always log the unhandled exception. phlog($ex); $class = phutil_escape_html(get_class($ex)); $message = phutil_escape_html($ex->getMessage()); if ($ex instanceof AphrontQuerySchemaException) { $message .= "\n\n". "NOTE: This usually indicates that the MySQL schema has not been ". "properly upgraded. Run 'bin/storage upgrade' to ensure your ". "schema is up to date."; } if (PhabricatorEnv::getEnvConfig('phabricator.show-stack-traces')) { $trace = $this->renderStackTrace($ex->getTrace(), $user); } else { $trace = null; } $content = '
'. '
'.$message.'
'. $trace. '
'; $dialog = new AphrontDialogView(); $dialog ->setTitle('Unhandled Exception ("'.$class.'")') ->setClass('aphront-exception-dialog') ->setUser($user) ->appendChild($content); if ($this->getRequest()->isAjax()) { $dialog->addCancelButton('/', 'Close'); } $response = new AphrontDialogResponse(); $response->setDialog($dialog); return $response; } public function willSendResponse(AphrontResponse $response) { return $response; } public function build404Controller() { return array(new Phabricator404Controller($this->getRequest()), array()); } public function buildRedirectController($uri) { return array( new PhabricatorRedirectController($this->getRequest()), array( 'uri' => $uri, )); } private function renderStackTrace($trace, PhabricatorUser $user) { $libraries = PhutilBootloader::getInstance()->getAllLibraries(); $version = PhabricatorEnv::getEnvConfig('phabricator.version'); if (preg_match('/[^a-f0-9]/i', $version)) { $version = ''; } // TODO: Make this configurable? $path = 'https://secure.phabricator.com/diffusion/%s/browse/master/src/'; $callsigns = array( 'arcanist' => 'ARC', 'phutil' => 'PHU', 'phabricator' => 'P', ); $rows = array(); $depth = count($trace); foreach ($trace as $part) { $lib = null; $file = idx($part, 'file'); $relative = $file; foreach ($libraries as $library) { $root = phutil_get_library_root($library); if (Filesystem::isDescendant($file, $root)) { $lib = $library; $relative = Filesystem::readablePath($file, $root); break; } } $where = ''; if (isset($part['class'])) { $where .= $part['class'].'::'; } if (isset($part['function'])) { $where .= $part['function'].'()'; } if ($file) { if (isset($callsigns[$lib])) { $attrs = array('title' => $file); try { $attrs['href'] = $user->loadEditorLink( '/src/'.$relative, $part['line'], $callsigns[$lib]); } catch (Exception $ex) { // The database can be inaccessible. } if (empty($attrs['href'])) { $attrs['href'] = sprintf($path, $callsigns[$lib]). str_replace(DIRECTORY_SEPARATOR, '/', $relative). ($version && $lib == 'phabricator' ? ';'.$version : ''). '$'.$part['line']; $attrs['target'] = '_blank'; } $file_name = phutil_render_tag( 'a', $attrs, phutil_escape_html($relative)); } else { $file_name = phutil_render_tag( 'span', array( 'title' => $file, ), phutil_escape_html($relative)); } $file_name = $file_name.' : '.(int)$part['line']; } else { $file_name = '(Internal)'; } $rows[] = array( $depth--, phutil_escape_html($lib), $file_name, phutil_escape_html($where), ); } $table = new AphrontTableView($rows); $table->setHeaders( array( 'Depth', 'Library', 'File', 'Where', )); $table->setColumnClasses( array( 'n', '', '', 'wide', )); return '
'. '
Stack Trace
'. $table->render(). '
'; } } diff --git a/src/applications/directory/controller/PhabricatorDirectoryController.php b/src/applications/directory/controller/PhabricatorDirectoryController.php index 756e16c70..41524dc44 100644 --- a/src/applications/directory/controller/PhabricatorDirectoryController.php +++ b/src/applications/directory/controller/PhabricatorDirectoryController.php @@ -1,50 +1,50 @@ buildStandardPageView(); $page->setBaseURI('/'); $page->setTitle(idx($data, 'title')); $page->setGlyph("\xE2\x9A\x92"); $page->appendChild($view); $response = new AphrontWebpageResponse(); return $response->setContent($page->render()); } public function buildNav() { $user = $this->getRequest()->getUser(); $nav = new AphrontSideNavFilterView(); $nav->setBaseURI(new PhutilURI('/')); $nav->addLabel('Phabricator'); $nav->addFilter('home', 'Tactical Command', '/'); $nav->addFilter('jump', 'Jump Nav'); $nav->addFilter('feed', 'Feed'); $nav->addSpacer(); - $nav->addFilter('apps', 'More Stuff'); + $nav->addFilter('applications', 'More Stuff'); return $nav; } } diff --git a/src/applications/directory/controller/PhabricatorDirectoryMainController.php b/src/applications/directory/controller/PhabricatorDirectoryMainController.php index a1407d160..ff9a8a561 100644 --- a/src/applications/directory/controller/PhabricatorDirectoryMainController.php +++ b/src/applications/directory/controller/PhabricatorDirectoryMainController.php @@ -1,851 +1,686 @@ filter = idx($data, 'filter'); $this->subfilter = idx($data, 'subfilter'); } public function processRequest() { $user = $this->getRequest()->getUser(); $nav = $this->buildNav(); $this->filter = $nav->selectFilter($this->filter, 'home'); switch ($this->filter) { case 'jump': - case 'apps': break; case 'home': case 'feed': $project_query = new PhabricatorProjectQuery(); $project_query->setViewer($user); $project_query->withMemberPHIDs(array($user->getPHID())); $projects = $project_query->execute(); break; default: throw new Exception("Unknown filter '{$this->filter}'!"); } switch ($this->filter) { case 'feed': return $this->buildFeedResponse($nav, $projects); case 'jump': return $this->buildJumpResponse($nav); - case 'apps': - return $this->buildAppsResponse($nav); default: return $this->buildMainResponse($nav, $projects); } } private function buildMainResponse($nav, array $projects) { assert_instances_of($projects, 'PhabricatorProject'); if (PhabricatorEnv::getEnvConfig('maniphest.enabled')) { $unbreak_panel = $this->buildUnbreakNowPanel(); $triage_panel = $this->buildNeedsTriagePanel($projects); $tasks_panel = $this->buildTasksPanel(); } else { $unbreak_panel = null; $triage_panel = null; $tasks_panel = null; } $flagged_panel = $this->buildFlaggedPanel(); $jump_panel = $this->buildJumpPanel(); $revision_panel = $this->buildRevisionPanel(); $app_panel = $this->buildAppPanel(); $audit_panel = $this->buildAuditPanel(); $commit_panel = $this->buildCommitPanel(); $content = array( $app_panel, $jump_panel, $unbreak_panel, $triage_panel, $revision_panel, $tasks_panel, $flagged_panel, $audit_panel, $commit_panel, ); $nav->appendChild($content); return $this->buildStandardPageResponse( $nav, array( 'title' => 'Phabricator', )); } private function buildJumpResponse($nav) { $request = $this->getRequest(); $jump = $request->getStr('jump'); $response = PhabricatorJumpNavHandler::jumpPostResponse($jump); if ($response) { return $response; } else if ($request->isFormPost()) { $query = new PhabricatorSearchQuery(); $query->setQuery($jump); $query->save(); return id(new AphrontRedirectResponse()) ->setURI('/search/'.$query->getQueryKey().'/'); } $nav->appendChild($this->buildJumpPanel($jump)); return $this->buildStandardPageResponse( $nav, array( 'title' => 'Jump Nav', )); } private function buildFeedResponse($nav, array $projects) { assert_instances_of($projects, 'PhabricatorProject'); $subnav = new AphrontSideNavFilterView(); $subnav->setBaseURI(new PhutilURI('/feed/')); $subnav->addFilter('all', 'All Activity', '/feed/'); $subnav->addFilter('projects', 'My Projects'); $nav->appendChild($subnav); $filter = $subnav->selectFilter($this->subfilter, 'all'); switch ($filter) { case 'all': $view = $this->buildFeedView(array()); break; case 'projects': if ($projects) { $phids = mpull($projects, 'getPHID'); $view = $this->buildFeedView($phids); } else { $view = new AphrontErrorView(); $view->setSeverity(AphrontErrorView::SEVERITY_NODATA); $view->setTitle('No Projects'); $view->appendChild('You have not joined any projects.'); } break; } $subnav->appendChild($view); return $this->buildStandardPageResponse( $nav, array( 'title' => 'Feed', )); } private function buildUnbreakNowPanel() { $user = $this->getRequest()->getUser(); $user_phid = $user->getPHID(); $task_query = new ManiphestTaskQuery(); $task_query->withStatus(ManiphestTaskQuery::STATUS_OPEN); $task_query->withPriority(ManiphestTaskPriority::PRIORITY_UNBREAK_NOW); $task_query->setLimit(10); $tasks = $task_query->execute(); if (!$tasks) { return $this->renderMiniPanel( 'No "Unbreak Now!" Tasks', 'Nothing appears to be critically broken right now.'); } $panel = new AphrontPanelView(); $panel->setHeader('Unbreak Now!'); $panel->setCaption('Open tasks with "Unbreak Now!" priority.'); $panel->addButton( phutil_render_tag( 'a', array( 'href' => '/maniphest/view/all/', 'class' => 'grey button', ), "View All Unbreak Now \xC2\xBB")); $panel->appendChild($this->buildTaskListView($tasks)); return $panel; } private function buildFlaggedPanel() { $user = $this->getRequest()->getUser(); $flag_query = id(new PhabricatorFlagQuery()) ->setViewer($user) ->withOwnerPHIDs(array($user->getPHID())) ->needHandles(true) ->setLimit(10); $flags = $flag_query->execute(); if (!$flags) { return $this->renderMiniPanel( 'No Flags', "You haven't flagged anything."); } $panel = new AphrontPanelView(); $panel->setHeader('Flagged Objects'); $panel->setCaption("Objects you've flagged."); $flag_view = new PhabricatorFlagListView(); $flag_view->setFlags($flags); $flag_view->setUser($user); $panel->appendChild($flag_view); $panel->addButton( phutil_render_tag( 'a', array( 'href' => '/flag/', 'class' => 'grey button', ), "View All Flags \xC2\xBB")); return $panel; } private function buildNeedsTriagePanel(array $projects) { assert_instances_of($projects, 'PhabricatorProject'); $user = $this->getRequest()->getUser(); $user_phid = $user->getPHID(); if ($projects) { $task_query = new ManiphestTaskQuery(); $task_query->withStatus(ManiphestTaskQuery::STATUS_OPEN); $task_query->withPriority(ManiphestTaskPriority::PRIORITY_TRIAGE); $task_query->withProjects(mpull($projects, 'getPHID')); $task_query->withAnyProject(true); $task_query->setLimit(10); $tasks = $task_query->execute(); } else { $tasks = array(); } if (!$tasks) { return $this->renderMiniPanel( 'No "Needs Triage" Tasks', 'No tasks in projects you are a member of '. 'need triage.'); } $panel = new AphrontPanelView(); $panel->setHeader('Needs Triage'); $panel->setCaption( 'Open tasks with "Needs Triage" priority in '. 'projects you are a member of.'); $panel->addButton( phutil_render_tag( 'a', array( // TODO: This should filter to just your projects' need-triage // tasks? 'href' => '/maniphest/view/projecttriage/', 'class' => 'grey button', ), "View All Triage \xC2\xBB")); $panel->appendChild($this->buildTaskListView($tasks)); return $panel; } private function buildRevisionPanel() { $user = $this->getRequest()->getUser(); $user_phid = $user->getPHID(); $revision_query = new DifferentialRevisionQuery(); $revision_query->withStatus(DifferentialRevisionQuery::STATUS_OPEN); $revision_query->withResponsibleUsers(array($user_phid)); $revision_query->needRelationships(true); // NOTE: We need to unlimit this query to hit the responsible user // fast-path. $revision_query->setLimit(null); $revisions = $revision_query->execute(); list($active, $waiting) = DifferentialRevisionQuery::splitResponsible( $revisions, $user_phid); if (!$active) { return $this->renderMiniPanel( 'No Waiting Revisions', 'No revisions are waiting on you.'); } $panel = new AphrontPanelView(); $panel->setHeader('Revisions Waiting on You'); $panel->setCaption('Revisions waiting for you for review or commit.'); $panel->addButton( phutil_render_tag( 'a', array( 'href' => '/differential/', 'class' => 'button grey', ), "View Active Revisions \xC2\xBB")); $revision_view = id(new DifferentialRevisionListView()) ->setHighlightAge(true) ->setRevisions($active) ->setFields(DifferentialRevisionListView::getDefaultFields()) ->setUser($user) ->loadAssets(); $phids = array_merge( array($user_phid), $revision_view->getRequiredHandlePHIDs()); $handles = $this->loadViewerHandles($phids); $revision_view->setHandles($handles); $panel->appendChild($revision_view); return $panel; } private function buildTasksPanel() { $user = $this->getRequest()->getUser(); $user_phid = $user->getPHID(); $task_query = new ManiphestTaskQuery(); $task_query->withStatus(ManiphestTaskQuery::STATUS_OPEN); $task_query->setGroupBy(ManiphestTaskQuery::GROUP_PRIORITY); $task_query->withOwners(array($user_phid)); $task_query->setLimit(10); $tasks = $task_query->execute(); if (!$tasks) { return $this->renderMiniPanel( 'No Assigned Tasks', 'You have no assigned tasks.'); } $panel = new AphrontPanelView(); $panel->setHeader('Assigned Tasks'); $panel->setCaption('Tasks assigned to you.'); $panel->addButton( phutil_render_tag( 'a', array( 'href' => '/maniphest/', 'class' => 'button grey', ), "View Active Tasks \xC2\xBB")); $panel->appendChild($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); $view = new ManiphestTaskListView(); $view->setTasks($tasks); $view->setUser($user); $view->setHandles($handles); return $view; } private function buildFeedView(array $phids) { $request = $this->getRequest(); $user = $request->getUser(); $user_phid = $user->getPHID(); $feed_query = new PhabricatorFeedQuery(); $feed_query->setViewer($user); if ($phids) { $feed_query->setFilterPHIDs($phids); } $pager = new AphrontCursorPagerView(); $pager->readFromRequest($request); $pager->setPageSize(200); $feed = $feed_query->executeWithCursorPager($pager); $builder = new PhabricatorFeedBuilder($feed); $builder->setUser($user); $feed_view = $builder->buildView(); return '
'. '
'. '

Feed

'. '
'. $feed_view->render(). '
'. $pager->render(). '
'. '
'; } private function buildJumpPanel($query=null) { $request = $this->getRequest(); $user = $request->getUser(); $uniq_id = celerity_generate_unique_node_id(); Javelin::initBehavior( 'phabricator-autofocus', array( 'id' => $uniq_id, )); require_celerity_resource('phabricator-jump-nav'); $doc_href = PhabricatorEnv::getDocLink('article/Jump_Nav_User_Guide.html'); $doc_link = phutil_render_tag( 'a', array( 'href' => $doc_href, ), 'Jump Nav User Guide'); $jump_input = phutil_render_tag( 'input', array( 'type' => 'text', 'class' => 'phabricator-jump-nav', 'name' => 'jump', 'id' => $uniq_id, 'value' => $query, )); $jump_caption = phutil_render_tag( 'p', array( 'class' => 'phabricator-jump-nav-caption', ), 'Enter the name of an object like D123 to quickly jump to '. 'it. See '.$doc_link.' or type help.'); $panel = new AphrontPanelView(); $panel->addClass('aphront-unpadded-panel-view'); $panel->appendChild( phabricator_render_form( $user, array( 'action' => '/jump/', 'method' => 'POST', 'class' => 'phabricator-jump-nav-form', ), $jump_input. $jump_caption)); return $panel; } 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('
'); foreach ($nav_buttons as $info) { // Subtitle is optional. list($name, $uri, $icon, $subtitle) = array_merge($info, array(null)); if ($subtitle) { $subtitle = '
'. phutil_escape_html($subtitle). '
'; } $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( '
'. $button. $caption. '
'); } $view->appendChild('
'); return $view; } private function renderMiniPanel($title, $body) { $panel = new AphrontMiniPanelView(); $panel->appendChild( phutil_render_tag( 'p', array( ), ''.$title.': '.$body)); return $panel; } public function buildAuditPanel() { $request = $this->getRequest(); $user = $request->getUser(); $phids = PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($user); $query = new PhabricatorAuditQuery(); $query->withAuditorPHIDs($phids); $query->withStatus(PhabricatorAuditQuery::STATUS_OPEN); $query->withAwaitingUser($user); $query->needCommitData(true); $query->setLimit(10); $audits = $query->execute(); $commits = $query->getCommits(); if (!$audits) { return $this->renderMinipanel( 'No Audits', 'No commits are waiting for you to audit them.'); } $view = new PhabricatorAuditListView(); $view->setAudits($audits); $view->setCommits($commits); $view->setUser($user); $phids = $view->getRequiredHandlePHIDs(); $handles = $this->loadViewerHandles($phids); $view->setHandles($handles); $panel = new AphrontPanelView(); $panel->setHeader('Audits'); $panel->setCaption('Commits awaiting your audit.'); $panel->appendChild($view); $panel->addButton( phutil_render_tag( 'a', array( 'href' => '/audit/', 'class' => 'button grey', ), "View Active Audits \xC2\xBB")); return $panel; } public function buildCommitPanel() { $request = $this->getRequest(); $user = $request->getUser(); $phids = array($user->getPHID()); $query = new PhabricatorAuditCommitQuery(); $query->withAuthorPHIDs($phids); $query->withStatus(PhabricatorAuditQuery::STATUS_OPEN); $query->needCommitData(true); $query->setLimit(10); $commits = $query->execute(); if (!$commits) { return $this->renderMinipanel( 'No Problem Commits', 'No one has raised concerns with your commits.'); } $view = new PhabricatorAuditCommitListView(); $view->setCommits($commits); $view->setUser($user); $phids = $view->getRequiredHandlePHIDs(); $handles = $this->loadViewerHandles($phids); $view->setHandles($handles); $panel = new AphrontPanelView(); $panel->setHeader('Problem Commits'); $panel->setCaption('Commits which auditors have raised concerns about.'); $panel->appendChild($view); $panel->addButton( phutil_render_tag( 'a', array( 'href' => '/audit/', 'class' => 'button grey', ), "View Problem Commits \xC2\xBB")); return $panel; } - public function buildAppsResponse(AphrontSideNavFilterView $nav) { - $user = $this->getRequest()->getUser(); - - $apps = array( - array( - '/repository/', - 'Repositories', - 'Configure tracked source code repositories.', - ), - array( - '/herald/', - 'Herald', - 'Create notification rules. Watch for danger!', - ), - array( - '/file/', - 'Files', - 'Upload and download files. Blob store for Pokemon pictures.', - ), - array( - '/project/', - 'Projects', - 'Group stuff into big piles.', - ), - array( - '/vote/', - 'Slowvote', - 'Create polls. Design by committee.', - ), - array( - '/countdown/', - 'Countdown', - 'Count down to events. Utilize the full capabilities of your ALU.', - ), - array( - '/people/', - 'People', - 'User directory. Sort of a social utility.', - ), - array( - '/owners/', - 'Owners', - 'Keep track of who owns code. Adopt today!', - ), - array( - '/conduit/', - 'Conduit API Console', - 'Web console for Conduit API.', - ), - array( - '/daemon/', - 'Daemon Console', - 'Offline process management.', - ), - array( - '/mail/', - 'MetaMTA', - 'Manage mail delivery. Yo dawg, we heard you like MTAs.', - array( - 'admin' => true, - ), - ), - array( - '/phid/', - 'PHID Manager', - 'Debugging tool for PHIDs.', - ), - array( - '/xhpast/', - 'XHPAST', - 'Web interface to PHP AST tool. Lex XHP AST & CTS FYI, LOL.', - ), - array( - 'http://www.phabricator.com/docs/phabricator/', - 'Phabricator Ducks', - 'Oops, that should say "Docs".', - array( - 'new' => true, - ), - ), - array( - 'http://www.phabricator.com/docs/arcanist/', - 'Arcanist Docs', - 'Words have never been so finely crafted.', - array( - 'new' => true, - ), - ), - array( - 'http://www.phabricator.com/docs/libphutil/', - 'libphutil Docs', - 'Soothing prose; seductive poetry.', - array( - 'new' => true, - ), - ), - array( - 'http://www.phabricator.com/docs/javelin/', - 'Javelin Docs', - 'O, what noble scribe hath penned these words?', - array( - 'new' => true, - ), - ), - array( - '/uiexample/', - 'UI Examples', - 'Phabricator UI elements. A gallery of modern art.', - array( - 'new' => true, - ), - ), - ); - - $out = array(); - foreach ($apps as $app) { - if (empty($app[3])) { - $app[3] = array(); - } - $app[3] += array( - 'admin' => false, - 'new' => false, - ); - list($href, $name, $desc, $options) = $app; - - if ($options['admin'] && !$user->getIsAdmin()) { - continue; - } - - $link = phutil_render_tag( - 'a', - array( - 'href' => $href, - 'target' => $options['new'] ? '_blank' : null, - ), - phutil_escape_html($name)); - - - - $out[] = - '
'. - '

'.$link.'

'. - '

'.phutil_escape_html($desc).'

'. - '
'; - } - - require_celerity_resource('phabricator-directory-css'); - - $out = - '
'. - implode("\n", $out). - '
'; - - $nav->appendChild($out); - - return $this->buildStandardPageResponse( - $nav, - array( - 'title' => 'More Stuff', - )); - } - }