diff --git a/src/applications/diffusion/controller/DiffusionController.php b/src/applications/diffusion/controller/DiffusionController.php index f75a75f389..a0baac4180 100644 --- a/src/applications/diffusion/controller/DiffusionController.php +++ b/src/applications/diffusion/controller/DiffusionController.php @@ -1,333 +1,209 @@ getRequest()); $this->diffusionRequest = $drequest; } } public function setDiffusionRequest(DiffusionRequest $request) { $this->diffusionRequest = $request; return $this; } protected function getDiffusionRequest() { if (!$this->diffusionRequest) { throw new Exception("No Diffusion request object!"); } return $this->diffusionRequest; } - final protected function buildSideNav($selected, $has_change_view) { - $nav = new AphrontSideNavFilterView(); - $nav->setBaseURI(new PhutilURI('')); - - $navs = array( - 'history' => pht('History View'), - 'browse' => pht('Browse View'), - 'change' => pht('Change View'), - ); - - if (!$has_change_view) { - unset($navs['change']); - } - - $drequest = $this->getDiffusionRequest(); - $branch = $drequest->loadBranch(); - - if ($branch && $branch->getLintCommit()) { - $navs['lint'] = pht('Lint View'); - } - - $selected_href = null; - foreach ($navs as $action => $name) { - $href = $drequest->generateURI( - array( - 'action' => $action, - )); - if ($action == $selected) { - $selected_href = $href; - } - - $nav->addFilter($href, $name, $href); - } - $nav->selectFilter($selected_href, null); - - // TODO: URI encoding might need to be sorted out for this link. - - $nav->addFilter( - '', - pht("Search Owners \xE2\x86\x97"), - '/owners/view/search/'. - '?repository='.phutil_escape_uri($drequest->getCallsign()). - '&path='.phutil_escape_uri('/'.$drequest->getPath())); - - return $nav; - } - public function buildCrumbs(array $spec = array()) { $crumbs = $this->buildApplicationCrumbs(); $crumb_list = $this->buildCrumbList($spec); foreach ($crumb_list as $crumb) { $crumbs->addCrumb($crumb); } return $crumbs; } private function buildCrumbList(array $spec = array()) { $spec = $spec + array( 'commit' => null, 'tags' => null, 'branches' => null, 'view' => null, ); $crumb_list = array(); // On the home page, we don't have a DiffusionRequest. if ($this->diffusionRequest) { $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); } else { $drequest = null; $repository = null; } if (!$repository) { return $crumb_list; } $callsign = $repository->getCallsign(); $repository_name = 'r'.$callsign; if (!$spec['commit'] && !$spec['tags'] && !$spec['branches']) { $branch_name = $drequest->getBranch(); if ($branch_name) { $repository_name .= ' ('.$branch_name.')'; } } $crumb = id(new PhabricatorCrumbView()) ->setName($repository_name); if (!$spec['view'] && !$spec['commit'] && !$spec['tags'] && !$spec['branches']) { $crumb_list[] = $crumb; return $crumb_list; } $crumb->setHref( $drequest->generateURI( array( 'action' => 'branch', 'path' => '/', ))); $crumb_list[] = $crumb; $raw_commit = $drequest->getRawCommit(); if ($spec['tags']) { $crumb = new PhabricatorCrumbView(); if ($spec['commit']) { $crumb->setName( pht("Tags for %s", 'r'.$callsign.$raw_commit)); $crumb->setHref($drequest->generateURI( array( 'action' => 'commit', 'commit' => $raw_commit, ))); } else { $crumb->setName(pht('Tags')); } $crumb_list[] = $crumb; return $crumb_list; } if ($spec['branches']) { $crumb = id(new PhabricatorCrumbView()) ->setName(pht('Branches')); $crumb_list[] = $crumb; return $crumb_list; } if ($spec['commit']) { $crumb = id(new PhabricatorCrumbView()) ->setName("r{$callsign}{$raw_commit}") ->setHref("r{$callsign}{$raw_commit}"); $crumb_list[] = $crumb; return $crumb_list; } $crumb = new PhabricatorCrumbView(); $view = $spec['view']; - $path = null; - if (isset($spec['path'])) { - $path = $drequest->getPath(); - } - - if ($raw_commit) { - $commit_link = DiffusionView::linkCommit( - $repository, - $raw_commit); - } else { - $commit_link = ''; - } - switch ($view) { case 'history': $view_name = pht('History'); break; case 'browse': $view_name = pht('Browse'); break; case 'lint': $view_name = pht('Lint'); break; case 'change': $view_name = pht('Change'); break; } - $uri_params = array( - 'action' => $view, - ); - $crumb = id(new PhabricatorCrumbView()) ->setName($view_name); - if ($view == 'browse' || $view == 'change' || $view == 'history') { - $crumb_list[] = $crumb; - return $crumb_list; - } - - $crumb->setHref($drequest->generateURI( - array( - 'path' => '', - ) + $uri_params)); $crumb_list[] = $crumb; - - $path_parts = explode('/', $path); - do { - $last = array_pop($path_parts); - } while (count($path_parts) && $last == ''); - - $path_sections = array(); - $thus_far = ''; - foreach ($path_parts as $path_part) { - $thus_far .= $path_part.'/'; - $path_sections[] = '/'; - $path_sections[] = phutil_tag( - 'a', - array( - 'href' => $drequest->generateURI( - array( - 'path' => $thus_far, - ) + $uri_params), - ), - $path_part); - } - - $path_sections[] = '/'.$last; - - $crumb_list[] = id(new PhabricatorCrumbView()) - ->setName($path_sections); - - $last_crumb = array_pop($crumb_list); - - if ($raw_commit) { - $jump_link = phutil_tag( - 'a', - array( - 'href' => $drequest->generateURI( - array( - 'commit' => '', - ) + $uri_params), - ), - pht('Jump to HEAD')); - - $name = $last_crumb->getName(); - $name = hsprintf('%s @ %s (%s)', $name, $commit_link, $jump_link); - $last_crumb->setName($name); - } else if ($spec['view'] != 'lint') { - $name = $last_crumb->getName(); - $name = hsprintf('%s @ HEAD', $name); - $last_crumb->setName($name); - } - - $crumb_list[] = $last_crumb; - return $crumb_list; } protected function callConduitWithDiffusionRequest( $method, array $params = array()) { $user = $this->getRequest()->getUser(); $drequest = $this->getDiffusionRequest(); return DiffusionQuery::callConduitWithDiffusionRequest( $user, $drequest, $method, $params); } protected function getRepositoryControllerURI( PhabricatorRepository $repository, $path) { return $this->getApplicationURI($repository->getCallsign().'/'.$path); } protected function renderPathLinks(DiffusionRequest $drequest, $action) { $path = $drequest->getPath(); $path_parts = array_filter(explode('/', trim($path, '/'))); $links = array(); if ($path_parts) { $links[] = phutil_tag( 'a', array( 'href' => $drequest->generateURI( array( 'action' => $action, 'path' => '', )), ), 'r'.$drequest->getRepository()->getCallsign().'/'); $accum = ''; $last_key = last_key($path_parts); foreach ($path_parts as $key => $part) { $links[] = ' '; $accum .= '/'.$part; if ($key === $last_key) { $links[] = $part; } else { $links[] = phutil_tag( 'a', array( 'href' => $drequest->generateURI( array( 'action' => $action, 'path' => $accum, )), ), $part.'/'); } } } else { $links[] = 'r'.$drequest->getRepository()->getCallsign().'/'; } return $links; } } diff --git a/src/applications/diffusion/controller/DiffusionLintController.php b/src/applications/diffusion/controller/DiffusionLintController.php index c97f71c49d..ff4ca65700 100644 --- a/src/applications/diffusion/controller/DiffusionLintController.php +++ b/src/applications/diffusion/controller/DiffusionLintController.php @@ -1,236 +1,348 @@ getRequest(); $user = $this->getRequest()->getUser(); $drequest = $this->diffusionRequest; if ($request->getStr('lint') !== null) { $controller = new DiffusionLintDetailsController($request); $controller->setDiffusionRequest($drequest); $controller->setCurrentApplication($this->getCurrentApplication()); return $this->delegateToController($controller); } $owners = array(); if (!$drequest) { if (!$request->getArr('owner')) { - $owners[$user->getPHID()] = $user->getFullName(); + if ($user->isLoggedIn()) { + $owners[$user->getPHID()] = $user->getFullName(); + } } else { $phids = $request->getArr('owner'); $phid = reset($phids); $handles = $this->loadViewerHandles(array($phid)); $owners[$phid] = $handles[$phid]->getFullName(); } } $codes = $this->loadLintCodes(array_keys($owners)); if ($codes && !$drequest) { + // TODO: Build some real Query classes for this stuff. + $branches = id(new PhabricatorRepositoryBranch())->loadAllWhere( 'id IN (%Ld)', array_unique(ipull($codes, 'branchID'))); - $repositories = id(new PhabricatorRepository())->loadAllWhere( - 'id IN (%Ld)', - array_unique(mpull($branches, 'getRepositoryID'))); + $repositories = id(new PhabricatorRepositoryQuery()) + ->setViewer($user) + ->withIDs(mpull($branches, 'getRepositoryID')) + ->execute(); $drequests = array(); foreach ($branches as $id => $branch) { + if (empty($repositories[$branch->getRepositoryID()])) { + continue; + } + $drequests[$id] = DiffusionRequest::newFromDictionary(array( 'user' => $user, 'repository' => $repositories[$branch->getRepositoryID()], 'branch' => $branch->getName(), )); } } $rows = array(); + $total = 0; foreach ($codes as $code) { if (!$this->diffusionRequest) { - $drequest = $drequests[$code['branchID']]; + $drequest = idx($drequests, $code['branchID']); } + if (!$drequest) { + continue; + } + + $total += $code['n']; + $rows[] = array( hsprintf( '%s', $drequest->generateURI(array( 'action' => 'lint', 'lint' => $code['code'], )), $code['n']), hsprintf( '%s', $drequest->generateURI(array( 'action' => 'browse', 'lint' => $code['code'], )), $code['files']), hsprintf( '%s', $drequest->generateURI(array('action' => 'lint')), $drequest->getCallsign()), ArcanistLintSeverity::getStringForSeverity($code['maxSeverity']), $code['code'], $code['maxName'], $code['maxDescription'], ); } $table = id(new AphrontTableView($rows)) ->setHeaders(array( pht('Problems'), pht('Files'), pht('Repository'), pht('Severity'), pht('Code'), pht('Name'), pht('Example'), )) ->setColumnVisibility(array(true, true, !$this->diffusionRequest)) ->setColumnClasses(array('n', 'n', '', '', 'pri', '', '')); $content = array(); $link = null; - if ($this->diffusionRequest) { - $link = hsprintf( - '%s', - $drequest->generateURI(array( - 'action' => 'lint', - 'lint' => '', - )), - pht('Switch to List View')); - - } else { + if (!$this->diffusionRequest) { $form = id(new AphrontFormView()) ->setUser($user) ->setMethod('GET') ->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/users/') ->setLimit(1) ->setName('owner') ->setLabel(pht('Owner')) ->setValue($owners)) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Filter')); $content[] = id(new AphrontListFilterView())->appendChild($form); } $content[] = id(new AphrontPanelView()) - ->setHeader(pht('%d Lint Message(s)', array_sum(ipull($codes, 'n')))) + ->setNoBackground(true) ->setCaption($link) ->appendChild($table); $title = array('Lint'); $crumbs = $this->buildCrumbs( array( 'branch' => true, 'path' => true, 'view' => 'lint', )); + if ($this->diffusionRequest) { $title[] = $drequest->getCallsign(); - $content = $this->buildSideNav('lint', false) - ->setCrumbs($crumbs) - ->appendChild($content); } else { - array_unshift($content, $crumbs); + $crumbs->addCrumb( + id(new PhabricatorCrumbView()) + ->setName(pht('All Lint'))); + } + + if ($this->diffusionRequest) { + $branch = $drequest->loadBranch(); + + $header = id(new PHUIHeaderView()) + ->setHeader($this->renderPathLinks($drequest, 'lint')) + ->setUser($user) + ->setPolicyObject($drequest->getRepository()); + $actions = $this->buildActionView($drequest); + $properties = $this->buildPropertyView( + $drequest, + $branch, + $total); + } else { + $header = null; + $actions = null; + $properties = null; } + return $this->buildApplicationPage( - $content, + array( + $crumbs, + $header, + $actions, + $properties, + $content, + ), array( 'title' => $title, - 'device' => true, - )); + )); } private function loadLintCodes(array $owner_phids) { $drequest = $this->diffusionRequest; $conn = id(new PhabricatorRepository())->establishConnection('r'); $where = array('1 = 1'); if ($drequest) { $branch = $drequest->loadBranch(); if (!$branch) { return array(); } $where[] = qsprintf($conn, 'branchID = %d', $branch->getID()); if ($drequest->getPath() != '') { $path = '/'.$drequest->getPath(); $is_dir = (substr($path, -1) == '/'); $where[] = ($is_dir ? qsprintf($conn, 'path LIKE %>', $path) : qsprintf($conn, 'path = %s', $path)); } } if ($owner_phids) { $or = array(); $or[] = qsprintf($conn, 'authorPHID IN (%Ls)', $owner_phids); $paths = array(); $packages = id(new PhabricatorOwnersOwner()) ->loadAllWhere('userPHID IN (%Ls)', $owner_phids); if ($packages) { $paths = id(new PhabricatorOwnersPath())->loadAllWhere( 'packageID IN (%Ld)', mpull($packages, 'getPackageID')); } if ($paths) { $repositories = id(new PhabricatorRepository())->loadAllWhere( 'phid IN (%Ls)', array_unique(mpull($paths, 'getRepositoryPHID'))); $repositories = mpull($repositories, 'getID', 'getPHID'); $branches = id(new PhabricatorRepositoryBranch())->loadAllWhere( 'repositoryID IN (%Ld)', $repositories); $branches = mgroup($branches, 'getRepositoryID'); } foreach ($paths as $path) { $branch = idx($branches, $repositories[$path->getRepositoryPHID()]); if ($branch) { $condition = qsprintf( $conn, '(branchID IN (%Ld) AND path LIKE %>)', array_keys($branch), $path->getPath()); if ($path->getExcluded()) { $where[] = 'NOT '.$condition; } else { $or[] = $condition; } } } $where[] = '('.implode(' OR ', $or).')'; } return queryfx_all( $conn, 'SELECT branchID, code, MAX(severity) AS maxSeverity, MAX(name) AS maxName, MAX(description) AS maxDescription, COUNT(DISTINCT path) AS files, COUNT(*) AS n FROM %T WHERE %Q GROUP BY branchID, code ORDER BY n DESC', PhabricatorRepository::TABLE_LINTMESSAGE, implode(' AND ', $where)); } + protected function buildActionView(DiffusionRequest $drequest) { + $viewer = $this->getRequest()->getUser(); + + $view = id(new PhabricatorActionListView()) + ->setUser($viewer); + + $list_uri = $drequest->generateURI( + array( + 'action' => 'lint', + 'lint' => '', + )); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('View As List')) + ->setHref($list_uri) + ->setIcon('transcript')); + + $history_uri = $drequest->generateURI( + array( + 'action' => 'history', + )); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('View History')) + ->setHref($history_uri) + ->setIcon('history')); + + $browse_uri = $drequest->generateURI( + array( + 'action' => 'browse', + )); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Browse Content')) + ->setHref($browse_uri) + ->setIcon('file')); + + return $view; + } + + protected function buildPropertyView( + DiffusionRequest $drequest, + PhabricatorRepositoryBranch $branch, + $total) { + + $viewer = $this->getRequest()->getUser(); + + $view = id(new PhabricatorPropertyListView()) + ->setUser($viewer); + + $callsign = $drequest->getRepository()->getCallsign(); + $lint_commit = $branch->getLintCommit(); + + $view->addProperty( + pht('Lint Commit'), + phutil_tag( + 'a', + array( + 'href' => $drequest->generateURI( + array( + 'action' => 'commit', + 'commit' => $lint_commit, + )), + ), + $drequest->getRepository()->formatCommitName($lint_commit))); + + $view->addProperty( + pht('Total Messages'), + pht('%s', new PhutilNumber($total))); + + return $view; + } + + } diff --git a/src/applications/diffusion/controller/DiffusionLintDetailsController.php b/src/applications/diffusion/controller/DiffusionLintDetailsController.php index 2e3c729b23..d9437e6f12 100644 --- a/src/applications/diffusion/controller/DiffusionLintDetailsController.php +++ b/src/applications/diffusion/controller/DiffusionLintDetailsController.php @@ -1,152 +1,140 @@ getRequest()->getInt('offset', 0); $drequest = $this->getDiffusionRequest(); $branch = $drequest->loadBranch(); $messages = $this->loadLintMessages($branch, $limit, $offset); $is_dir = (substr('/'.$drequest->getPath(), -1) == '/'); $authors = $this->loadViewerHandles(ipull($messages, 'authorPHID')); $rows = array(); foreach ($messages as $message) { $path = hsprintf( '%s', $drequest->generateURI(array( 'action' => 'lint', 'path' => $message['path'], )), substr($message['path'], strlen($drequest->getPath()) + 1)); $line = hsprintf( '%s', $drequest->generateURI(array( 'action' => 'browse', 'path' => $message['path'], 'line' => $message['line'], 'commit' => $branch->getLintCommit(), )), $message['line']); $author = $message['authorPHID']; if ($author && $authors[$author]) { $author = $authors[$author]->renderLink(); } $rows[] = array( $path, $line, $author, ArcanistLintSeverity::getStringForSeverity($message['severity']), $message['name'], $message['description'], ); } $table = id(new AphrontTableView($rows)) ->setHeaders(array( pht('Path'), pht('Line'), pht('Author'), pht('Severity'), pht('Name'), pht('Description'), )) ->setColumnClasses(array('', 'n')) ->setColumnVisibility(array($is_dir)); $content = array(); $pager = id(new AphrontPagerView()) ->setPageSize($limit) ->setOffset($offset) ->setHasMorePages(count($messages) >= $limit) ->setURI($this->getRequest()->getRequestURI(), 'offset'); - $lint = $drequest->getLint(); - $link = hsprintf( - '%s', - $drequest->generateURI(array( - 'action' => 'lint', - 'lint' => null, - )), - pht('Switch to Grouped View')); - $content[] = id(new AphrontPanelView()) - ->setHeader( - ($lint != '' ? $lint." \xC2\xB7 " : ''). - pht('%d Lint Message(s)', count($messages))) - ->setCaption($link) + ->setNoBackground(true) ->appendChild($table) ->appendChild($pager); - $nav = $this->buildSideNav('lint', false); - $nav->appendChild($content); $crumbs = $this->buildCrumbs( array( 'branch' => true, 'path' => true, 'view' => 'lint', )); - $nav->setCrumbs($crumbs); return $this->buildApplicationPage( - $nav, + array( + $crumbs, + $content, + ), array( 'device' => true, 'title' => array( pht('Lint'), $drequest->getRepository()->getCallsign(), ))); } private function loadLintMessages( PhabricatorRepositoryBranch $branch, $limit, $offset) { $drequest = $this->getDiffusionRequest(); if (!$branch) { return array(); } $conn = $branch->establishConnection('r'); $where = array( qsprintf($conn, 'branchID = %d', $branch->getID()), ); if ($drequest->getPath() != '') { $path = '/'.$drequest->getPath(); $is_dir = (substr($path, -1) == '/'); $where[] = ($is_dir ? qsprintf($conn, 'path LIKE %>', $path) : qsprintf($conn, 'path = %s', $path)); } if ($drequest->getLint() != '') { $where[] = qsprintf( $conn, 'code = %s', $drequest->getLint()); } return queryfx_all( $conn, 'SELECT * FROM %T WHERE %Q ORDER BY path, code, line LIMIT %d OFFSET %d', PhabricatorRepository::TABLE_LINTMESSAGE, implode(' AND ', $where), $limit, $offset); } }