diff --git a/src/applications/diffusion/controller/DiffusionBranchTableController.php b/src/applications/diffusion/controller/DiffusionBranchTableController.php index 7f8ae11f57..04d00f0306 100644 --- a/src/applications/diffusion/controller/DiffusionBranchTableController.php +++ b/src/applications/diffusion/controller/DiffusionBranchTableController.php @@ -1,90 +1,93 @@ loadDiffusionContext(); if ($response) { return $response; } $viewer = $this->getViewer(); $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); $pager = id(new PHUIPagerView()) ->readFromRequest($request); $params = array( 'offset' => $pager->getOffset(), 'limit' => $pager->getPageSize() + 1, ); $contains = $drequest->getSymbolicCommit(); if (strlen($contains)) { $params['contains'] = $contains; } $branches = $this->callConduitWithDiffusionRequest( 'diffusion.branchquery', $params); $branches = $pager->sliceResults($branches); $branches = DiffusionRepositoryRef::loadAllFromDictionaries($branches); $content = null; if (!$branches) { $content = $this->renderStatusMessage( pht('No Branches'), pht('This repository has no branches.')); } else { $commits = id(new DiffusionCommitQuery()) ->setViewer($viewer) ->withIdentifiers(mpull($branches, 'getCommitIdentifier')) ->withRepository($repository) ->execute(); $list = id(new DiffusionBranchListView()) ->setUser($viewer) ->setBranches($branches) ->setCommits($commits) ->setDiffusionRequest($drequest); $content = id(new PHUIObjectBoxView()) ->setHeaderText($repository->getName()) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setTable($list) ->setPager($pager); } $crumbs = $this->buildCrumbs( array( 'branches' => true, )); $crumbs->setBorder(true); $header = id(new PHUIHeaderView()) ->setHeader(pht('Branches')) ->setHeaderIcon('fa-code-fork'); + $tabs = $this->buildTabsView('branch'); + $view = id(new PHUITwoColumnView()) ->setHeader($header) + ->setTabs($tabs) ->setFooter(array( $content, )); return $this->newPage() ->setTitle( array( pht('Branches'), $repository->getDisplayName(), )) ->setCrumbs($crumbs) ->appendChild($view); } } diff --git a/src/applications/diffusion/controller/DiffusionController.php b/src/applications/diffusion/controller/DiffusionController.php index a73285d111..8de17c03a2 100644 --- a/src/applications/diffusion/controller/DiffusionController.php +++ b/src/applications/diffusion/controller/DiffusionController.php @@ -1,413 +1,483 @@ diffusionRequest) { throw new PhutilInvalidStateException('loadDiffusionContext'); } return $this->diffusionRequest; } protected function hasDiffusionRequest() { return (bool)$this->diffusionRequest; } public function willBeginExecution() { $request = $this->getRequest(); // Check if this is a VCS request, e.g. from "git clone", "hg clone", or // "svn checkout". If it is, we jump off into repository serving code to // process the request. $serve_controller = new DiffusionServeController(); if ($serve_controller->isVCSRequest($request)) { return $this->delegateToController($serve_controller); } return parent::willBeginExecution(); } protected function loadDiffusionContextForEdit() { return $this->loadContext( array( 'edit' => true, )); } protected function loadDiffusionContext() { return $this->loadContext(array()); } private function loadContext(array $options) { $request = $this->getRequest(); $viewer = $this->getViewer(); require_celerity_resource('diffusion-repository-css'); $identifier = $this->getRepositoryIdentifierFromRequest($request); $params = $options + array( 'repository' => $identifier, 'user' => $viewer, 'blob' => $this->getDiffusionBlobFromRequest($request), 'commit' => $request->getURIData('commit'), 'path' => $request->getURIData('path'), 'line' => $request->getURIData('line'), 'branch' => $request->getURIData('branch'), 'lint' => $request->getStr('lint'), ); $drequest = DiffusionRequest::newFromDictionary($params); if (!$drequest) { return new Aphront404Response(); } // If the client is making a request like "/diffusion/1/...", but the // repository has a different canonical path like "/diffusion/XYZ/...", // redirect them to the canonical path. $request_path = $request->getPath(); $repository = $drequest->getRepository(); $canonical_path = $repository->getCanonicalPath($request_path); if ($canonical_path !== null) { if ($canonical_path != $request_path) { return id(new AphrontRedirectResponse())->setURI($canonical_path); } } $this->diffusionRequest = $drequest; return null; } protected function getDiffusionBlobFromRequest(AphrontRequest $request) { return $request->getURIData('dblob'); } protected function getRepositoryIdentifierFromRequest( AphrontRequest $request) { $short_name = $request->getURIData('repositoryShortName'); if (strlen($short_name)) { // If the short name ends in ".git", ignore it. $short_name = preg_replace('/\\.git\z/', '', $short_name); return $short_name; } $identifier = $request->getURIData('repositoryCallsign'); if (strlen($identifier)) { return $identifier; } $id = $request->getURIData('repositoryID'); if (strlen($id)) { return (int)$id; } return null; } 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, + 'commit' => null, + 'tags' => null, + 'branches' => null, + 'view' => null, ); $crumb_list = array(); // On the home page, we don't have a DiffusionRequest. if ($this->hasDiffusionRequest()) { $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); } else { $drequest = null; $repository = null; } if (!$repository) { return $crumb_list; } $repository_name = $repository->getName(); if (!$spec['commit'] && !$spec['tags'] && !$spec['branches']) { $branch_name = $drequest->getBranch(); if ($branch_name) { $repository_name .= ' ('.$branch_name.')'; } } $crumb = id(new PHUICrumbView()) ->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; $stable_commit = $drequest->getStableCommit(); $commit_name = $repository->formatCommitName($stable_commit, $local = true); $commit_uri = $repository->getCommitURI($stable_commit); if ($spec['tags']) { $crumb = new PHUICrumbView(); if ($spec['commit']) { $crumb->setName(pht('Tags for %s', $commit_name)); $crumb->setHref($commit_uri); } else { $crumb->setName(pht('Tags')); } $crumb_list[] = $crumb; return $crumb_list; } if ($spec['branches']) { $crumb = id(new PHUICrumbView()) ->setName(pht('Branches')); $crumb_list[] = $crumb; return $crumb_list; } if ($spec['commit']) { $crumb = id(new PHUICrumbView()) ->setName($commit_name); $crumb_list[] = $crumb; return $crumb_list; } $crumb = new PHUICrumbView(); $view = $spec['view']; switch ($view) { case 'history': $view_name = pht('History'); break; case 'graph': $view_name = pht('Graph'); break; case 'browse': $view_name = pht('Browse'); break; case 'lint': $view_name = pht('Lint'); break; case 'change': $view_name = pht('Change'); break; case 'compare': $view_name = pht('Compare'); break; } $crumb = id(new PHUICrumbView()) ->setName($view_name); $crumb_list[] = $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 callConduitMethod($method, array $params = array()) { $user = $this->getViewer(); $drequest = $this->getDiffusionRequest(); return DiffusionQuery::callConduitWithDiffusionRequest( $user, $drequest, $method, $params, true); } protected function getRepositoryControllerURI( PhabricatorRepository $repository, $path) { return $repository->getPathURI($path); } protected function renderPathLinks(DiffusionRequest $drequest, $action) { $path = $drequest->getPath(); $path_parts = array_filter(explode('/', trim($path, '/'))); $divider = phutil_tag( 'span', array( 'class' => 'phui-header-divider', ), '/'); $links = array(); if ($path_parts) { $links[] = phutil_tag( 'a', array( 'href' => $drequest->generateURI( array( 'action' => $action, 'path' => '', )), ), $drequest->getRepository()->getDisplayName()); $links[] = $divider; $accum = ''; $last_key = last_key($path_parts); foreach ($path_parts as $key => $part) { $accum .= '/'.$part; if ($key === $last_key) { $links[] = $part; } else { $links[] = phutil_tag( 'a', array( 'href' => $drequest->generateURI( array( 'action' => $action, 'path' => $accum.'/', )), ), $part); $links[] = $divider; } } } else { $links[] = $drequest->getRepository()->getDisplayName(); $links[] = $divider; } return $links; } protected function renderStatusMessage($title, $body) { return id(new PHUIInfoView()) - ->setSeverity(PHUIInfoView::SEVERITY_WARNING) + ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) ->setTitle($title) ->setFlush(true) ->appendChild($body); } protected function renderCommitHashTag(DiffusionRequest $drequest) { $stable_commit = $drequest->getStableCommit(); $commit = phutil_tag( 'a', array( 'href' => $drequest->generateURI( array( 'action' => 'commit', 'commit' => $stable_commit, )), ), $drequest->getRepository()->formatCommitName($stable_commit, true)); $tag = id(new PHUITagView()) ->setName($commit) ->setColor(PHUITagView::COLOR_INDIGO) ->setBorder(PHUITagView::BORDER_NONE) ->setType(PHUITagView::TYPE_SHADE); return $tag; } protected function renderDirectoryReadme(DiffusionBrowseResultSet $browse) { $readme_path = $browse->getReadmePath(); if ($readme_path === null) { return null; } $drequest = $this->getDiffusionRequest(); $viewer = $this->getViewer(); $repository = $drequest->getRepository(); $repository_phid = $repository->getPHID(); $stable_commit = $drequest->getStableCommit(); $stable_commit_hash = PhabricatorHash::digestForIndex($stable_commit); $readme_path_hash = PhabricatorHash::digestForIndex($readme_path); $cache = PhabricatorCaches::getMutableStructureCache(); $cache_key = "diffusion". ".repository({$repository_phid})". ".commit({$stable_commit_hash})". ".readme({$readme_path_hash})"; $readme_cache = $cache->getKey($cache_key); if (!$readme_cache) { try { $result = $this->callConduitWithDiffusionRequest( 'diffusion.filecontentquery', array( 'path' => $readme_path, 'commit' => $drequest->getStableCommit(), )); } catch (Exception $ex) { return null; } $file_phid = $result['filePHID']; if (!$file_phid) { return null; } $file = id(new PhabricatorFileQuery()) ->setViewer($viewer) ->withPHIDs(array($file_phid)) ->executeOne(); if (!$file) { return null; } $corpus = $file->loadFileData(); $readme_cache = array( 'corpus' => $corpus, ); $cache->setKey($cache_key, $readme_cache); } $readme_corpus = $readme_cache['corpus']; if (!strlen($readme_corpus)) { return null; } return id(new DiffusionReadmeView()) ->setUser($this->getViewer()) ->setPath($readme_path) ->setContent($readme_corpus); } + protected function buildTabsView($key) { + $drequest = $this->getDiffusionRequest(); + $repository = $drequest->getRepository(); + + $view = new PHUIListView(); + + $view->addMenuItem( + id(new PHUIListItemView()) + ->setKey('home') + ->setName(pht('Home')) + ->setIcon('fa-home') + ->setHref($drequest->generateURI( + array( + 'action' => 'branch', + 'path' => '/', + ))) + ->setSelected($key == 'home')); + + if (!$repository->isSVN()) { + $view->addMenuItem( + id(new PHUIListItemView()) + ->setKey('branch') + ->setName(pht('Branches')) + ->setIcon('fa-code-fork') + ->setHref($drequest->generateURI( + array( + 'action' => 'branches', + ))) + ->setSelected($key == 'branch')); + } + + if (!$repository->isSVN()) { + $view->addMenuItem( + id(new PHUIListItemView()) + ->setKey('tags') + ->setName(pht('Tags')) + ->setIcon('fa-tags') + ->setHref($drequest->generateURI( + array( + 'action' => 'tags', + ))) + ->setSelected($key == 'tags')); + } + + $view->addMenuItem( + id(new PHUIListItemView()) + ->setKey('history') + ->setName(pht('History')) + ->setIcon('fa-history') + ->setHref($drequest->generateURI( + array( + 'action' => 'history', + ))) + ->setSelected($key == 'history')); + + $view->addMenuItem( + id(new PHUIListItemView()) + ->setKey('graph') + ->setName(pht('Graph')) + ->setIcon('fa-code-fork') + ->setHref($drequest->generateURI( + array( + 'action' => 'graph', + ))) + ->setSelected($key == 'graph')); + + return $view; + + } + } diff --git a/src/applications/diffusion/controller/DiffusionGraphController.php b/src/applications/diffusion/controller/DiffusionGraphController.php index 8428a8152d..8ec909139a 100644 --- a/src/applications/diffusion/controller/DiffusionGraphController.php +++ b/src/applications/diffusion/controller/DiffusionGraphController.php @@ -1,108 +1,103 @@ loadDiffusionContext(); if ($response) { return $response; } $viewer = $this->getViewer(); $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); $pager = id(new PHUIPagerView()) ->readFromRequest($request); $params = array( 'commit' => $drequest->getCommit(), 'path' => $drequest->getPath(), 'offset' => $pager->getOffset(), 'limit' => $pager->getPageSize() + 1, ); $history_results = $this->callConduitWithDiffusionRequest( 'diffusion.historyquery', $params); $history = DiffusionPathChange::newFromConduit( $history_results['pathChanges']); $history = $pager->sliceResults($history); $graph = id(new DiffusionHistoryTableView()) ->setViewer($viewer) ->setDiffusionRequest($drequest) ->setHistory($history); $graph->loadRevisions(); $show_graph = !strlen($drequest->getPath()); if ($show_graph) { $graph->setParents($history_results['parents']); $graph->setIsHead(!$pager->getOffset()); $graph->setIsTail(!$pager->getHasMorePages()); } $header = $this->buildHeader($drequest); $crumbs = $this->buildCrumbs( array( 'branch' => true, 'path' => true, 'view' => 'graph', )); $crumbs->setBorder(true); $title = array( pht('Graph'), $repository->getDisplayName(), ); $graph_view = id(new PHUIObjectBoxView()) ->setHeaderText(pht('History Graph')) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setTable($graph) ->setPager($pager); + $tabs = $this->buildTabsView('graph'); + $view = id(new PHUITwoColumnView()) ->setHeader($header) + ->setTabs($tabs) ->setFooter($graph_view); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->appendChild($view); } private function buildHeader(DiffusionRequest $drequest) { $viewer = $this->getViewer(); - $tag = $this->renderCommitHashTag($drequest); - $history_uri = $drequest->generateURI( - array( - 'action' => 'history', - )); - - $history_button = id(new PHUIButtonView()) - ->setTag('a') - ->setText(pht('History')) - ->setHref($history_uri) - ->setIcon('fa-history'); + $no_path = !strlen($drequest->getPath()); + if ($no_path) { + $header_text = pht('Graph'); + } else { + $header_text = $this->renderPathLinks($drequest, $mode = 'history'); + } $header = id(new PHUIHeaderView()) ->setUser($viewer) - ->setPolicyObject($drequest->getRepository()) - ->addTag($tag) - ->setHeader($this->renderPathLinks($drequest, $mode = 'history')) - ->setHeaderIcon('fa-code-fork') - ->addActionLink($history_button); + ->setHeader($header_text) + ->setHeaderIcon('fa-code-fork'); return $header; } } diff --git a/src/applications/diffusion/controller/DiffusionHistoryController.php b/src/applications/diffusion/controller/DiffusionHistoryController.php index c2f718f11e..fde35133cc 100644 --- a/src/applications/diffusion/controller/DiffusionHistoryController.php +++ b/src/applications/diffusion/controller/DiffusionHistoryController.php @@ -1,107 +1,98 @@ loadDiffusionContext(); if ($response) { return $response; } $viewer = $this->getViewer(); $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); $pager = id(new PHUIPagerView()) ->readFromRequest($request); $params = array( 'commit' => $drequest->getCommit(), 'path' => $drequest->getPath(), 'offset' => $pager->getOffset(), 'limit' => $pager->getPageSize() + 1, ); $history_results = $this->callConduitWithDiffusionRequest( 'diffusion.historyquery', $params); $history = DiffusionPathChange::newFromConduit( $history_results['pathChanges']); $history = $pager->sliceResults($history); $history_list = id(new DiffusionHistoryListView()) ->setViewer($viewer) ->setDiffusionRequest($drequest) ->setHistory($history); $history_list->loadRevisions(); $header = $this->buildHeader($drequest); $crumbs = $this->buildCrumbs( array( 'branch' => true, 'path' => true, 'view' => 'history', )); $crumbs->setBorder(true); $title = array( pht('History'), $repository->getDisplayName(), ); $pager = id(new PHUIBoxView()) ->addClass('mlb') ->appendChild($pager); + $tabs = $this->buildTabsView('history'); + $view = id(new PHUITwoColumnView()) ->setHeader($header) + ->setTabs($tabs) ->setFooter(array( $history_list, $pager, )); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->appendChild($view) ->addClass('diffusion-history-view'); } private function buildHeader(DiffusionRequest $drequest) { $viewer = $this->getViewer(); - $tag = $this->renderCommitHashTag($drequest); - $show_graph = !strlen($drequest->getPath()); + $no_path = !strlen($drequest->getPath()); + if ($no_path) { + $header_text = pht('History'); + } else { + $header_text = $this->renderPathLinks($drequest, $mode = 'history'); + } $header = id(new PHUIHeaderView()) ->setUser($viewer) - ->setPolicyObject($drequest->getRepository()) - ->addTag($tag) - ->setHeader($this->renderPathLinks($drequest, $mode = 'history')) + ->setHeader($header_text) ->setHeaderIcon('fa-clock-o'); - if ($show_graph) { - $graph_uri = $drequest->generateURI( - array( - 'action' => 'graph', - )); - - $graph_button = id(new PHUIButtonView()) - ->setTag('a') - ->setText(pht('Graph')) - ->setHref($graph_uri) - ->setIcon('fa-code-fork'); - $header->addActionLink($graph_button); - } - return $header; } } diff --git a/src/applications/diffusion/controller/DiffusionRepositoryController.php b/src/applications/diffusion/controller/DiffusionRepositoryController.php index 362f78bd3f..d8451db2db 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryController.php @@ -1,755 +1,557 @@ loadDiffusionContext(); if ($response) { return $response; } $viewer = $this->getViewer(); $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); $crumbs = $this->buildCrumbs(); $crumbs->setBorder(true); $header = $this->buildHeaderView($repository); $curtain = $this->buildCurtain($repository); $property_table = $this->buildPropertiesTable($repository); $description = $this->buildDescriptionView($repository); $locate_file = $this->buildLocateFile(); // Before we do any work, make sure we're looking at a some content: we're // on a valid branch, and the repository is not empty. $page_has_content = false; $empty_title = null; $empty_message = null; // If this VCS supports branches, check that the selected branch actually // exists. if ($drequest->supportsBranches()) { // NOTE: Mercurial may have multiple branch heads with the same name. $ref_cursors = id(new PhabricatorRepositoryRefCursorQuery()) ->setViewer($viewer) ->withRepositoryPHIDs(array($repository->getPHID())) ->withRefTypes(array(PhabricatorRepositoryRefCursor::TYPE_BRANCH)) ->withRefNames(array($drequest->getBranch())) ->execute(); if ($ref_cursors) { // This is a valid branch, so we necessarily have some content. $page_has_content = true; } else { $empty_title = pht('No Such Branch'); $empty_message = pht( 'There is no branch named "%s" in this repository.', $drequest->getBranch()); } } // If we didn't find any branches, check if there are any commits at all. // This can tailor the message for empty repositories. if (!$page_has_content) { $any_commit = id(new DiffusionCommitQuery()) ->setViewer($viewer) ->withRepository($repository) ->setLimit(1) ->execute(); if ($any_commit) { if (!$drequest->supportsBranches()) { $page_has_content = true; } } else { $empty_title = pht('Empty Repository'); $empty_message = pht('This repository does not have any commits yet.'); } } if ($page_has_content) { $content = $this->buildNormalContent($drequest); } else { $content = id(new PHUIInfoView()) ->setTitle($empty_title) ->setSeverity(PHUIInfoView::SEVERITY_WARNING) ->setErrors(array($empty_message)); } + $tabs = $this->buildTabsView('home'); + $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setCurtain($curtain) + ->setTabs($tabs) ->setMainColumn(array( $property_table, $description, $locate_file, )) ->setFooter($content); return $this->newPage() ->setTitle( array( $repository->getName(), $repository->getDisplayName(), )) ->setCrumbs($crumbs) ->appendChild(array( $view, )); } private function buildNormalContent(DiffusionRequest $drequest) { $request = $this->getRequest(); $repository = $drequest->getRepository(); $commit = $drequest->getCommit(); $path = $drequest->getPath(); $this->historyFuture = $this->callConduitMethod( 'diffusion.historyquery', array( 'commit' => $commit, 'path' => $path, 'offset' => 0, 'limit' => 15, )); $browse_pager = id(new PHUIPagerView()) ->readFromRequest($request); $this->browseFuture = $this->callConduitMethod( 'diffusion.browsequery', array( 'commit' => $commit, 'path' => $path, 'limit' => $browse_pager->getPageSize() + 1, )); - if ($this->needTagFuture()) { - $tag_limit = $this->getTagLimit(); - $this->tagFuture = $this->callConduitMethod( - 'diffusion.tagsquery', - array( - // On the home page, we want to find tags on any branch. - 'commit' => null, - 'limit' => $tag_limit + 1, - )); - } - - if ($this->needBranchFuture()) { - $branch_limit = $this->getBranchLimit(); - $this->branchFuture = $this->callConduitMethod( - 'diffusion.branchquery', - array( - 'closed' => false, - 'limit' => $branch_limit + 1, - )); - } - $futures = array( $this->historyFuture, $this->browseFuture, - $this->tagFuture, - $this->branchFuture, ); $futures = array_filter($futures); $futures = new FutureIterator($futures); foreach ($futures as $future) { // Just resolve all the futures before continuing. } $phids = array(); $content = array(); try { $history_results = $this->historyFuture->resolve(); $history = DiffusionPathChange::newFromConduit( $history_results['pathChanges']); foreach ($history as $item) { $data = $item->getCommitData(); if ($data) { if ($data->getCommitDetail('authorPHID')) { $phids[$data->getCommitDetail('authorPHID')] = true; } if ($data->getCommitDetail('committerPHID')) { $phids[$data->getCommitDetail('committerPHID')] = true; } } } $history_exception = null; } catch (Exception $ex) { $history_results = null; $history = null; $history_exception = $ex; } try { $browse_results = $this->browseFuture->resolve(); $browse_results = DiffusionBrowseResultSet::newFromConduit( $browse_results); $browse_paths = $browse_results->getPaths(); $browse_paths = $browse_pager->sliceResults($browse_paths); foreach ($browse_paths as $item) { $data = $item->getLastCommitData(); if ($data) { if ($data->getCommitDetail('authorPHID')) { $phids[$data->getCommitDetail('authorPHID')] = true; } if ($data->getCommitDetail('committerPHID')) { $phids[$data->getCommitDetail('committerPHID')] = true; } } } $browse_exception = null; } catch (Exception $ex) { $browse_results = null; $browse_paths = null; $browse_exception = $ex; } $phids = array_keys($phids); $handles = $this->loadViewerHandles($phids); if ($browse_results) { $readme = $this->renderDirectoryReadme($browse_results); } else { $readme = null; } $content[] = $this->buildBrowseTable( $browse_results, $browse_paths, $browse_exception, $handles, $browse_pager); $content[] = $this->buildHistoryTable( $history_results, $history, $history_exception); - try { - $content[] = $this->buildTagListTable($drequest); - } catch (Exception $ex) { - if (!$repository->isImporting()) { - $content[] = $this->renderStatusMessage( - pht('Unable to Load Tags'), - $ex->getMessage()); - } - } - - try { - $content[] = $this->buildBranchListTable($drequest); - } catch (Exception $ex) { - if (!$repository->isImporting()) { - $content[] = $this->renderStatusMessage( - pht('Unable to Load Branches'), - $ex->getMessage()); - } - } - if ($readme) { $content[] = $readme; } return $content; } private function buildHeaderView(PhabricatorRepository $repository) { $viewer = $this->getViewer(); $header = id(new PHUIHeaderView()) ->setHeader($repository->getName()) ->setUser($viewer) ->setPolicyObject($repository) ->setProfileHeader(true) ->setImage($repository->getProfileImageURI()) ->setImageEditURL('/diffusion/picture/'.$repository->getID().'/'); if (!$repository->isTracked()) { $header->setStatus('fa-ban', 'dark', pht('Inactive')); } else if ($repository->isImporting()) { $ratio = $repository->loadImportProgress(); $percentage = sprintf('%.2f%%', 100 * $ratio); $header->setStatus( 'fa-clock-o', 'indigo', pht('Importing (%s)...', $percentage)); } else { $header->setStatus('fa-check', 'bluegrey', pht('Active')); } return $header; } private function buildCurtain(PhabricatorRepository $repository) { $viewer = $this->getViewer(); $edit_uri = $repository->getPathURI('manage/'); $curtain = $this->newCurtainView($repository); $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Manage Repository')) ->setIcon('fa-cogs') ->setHref($edit_uri)); if ($repository->isHosted()) { $push_uri = $this->getApplicationURI( 'pushlog/?repositories='.$repository->getMonogram()); $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('View Push Logs')) ->setIcon('fa-list-alt') ->setHref($push_uri)); } return $curtain; } private function buildDescriptionView(PhabricatorRepository $repository) { $viewer = $this->getViewer(); $view = id(new PHUIPropertyListView()) ->setUser($viewer); $description = $repository->getDetail('description'); if (strlen($description)) { $description = new PHUIRemarkupView($viewer, $description); $view->addTextContent($description); return id(new PHUIObjectBoxView()) ->setHeaderText(pht('Description')) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->appendChild($view); } return null; } private function buildPropertiesTable(PhabricatorRepository $repository) { $viewer = $this->getViewer(); $view = id(new PHUIPropertyListView()) ->setUser($viewer); $display_never = PhabricatorRepositoryURI::DISPLAY_NEVER; $uris = $repository->getURIs(); foreach ($uris as $uri) { if ($uri->getIsDisabled()) { continue; } if ($uri->getEffectiveDisplayType() == $display_never) { continue; } if ($repository->isSVN()) { $label = phutil_tag_div('diffusion-clone-label', pht('Checkout')); } else { $label = phutil_tag_div('diffusion-clone-label', pht('Clone')); } $view->addProperty( $label, $this->renderCloneURI($repository, $uri)); } + if (!$view->hasAnyProperties()) { + $view = id(new PHUIInfoView()) + ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) + ->appendChild(pht('Repository has no URIs set.')); + } + $box = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Details')) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->appendChild($view); $info = null; $drequest = $this->getDiffusionRequest(); // Try to load alternatives. This may fail for repositories which have not // cloned yet. If it does, just ignore it and continue. try { $alternatives = $drequest->getRefAlternatives(); } catch (ConduitClientException $ex) { $alternatives = array(); } if ($alternatives) { $message = array( pht( 'The ref "%s" is ambiguous in this repository.', $drequest->getBranch()), ' ', phutil_tag( 'a', array( 'href' => $drequest->generateURI( array( 'action' => 'refs', )), ), pht('View Alternatives')), ); $messages = array($message); $info = id(new PHUIInfoView()) ->setSeverity(PHUIInfoView::SEVERITY_WARNING) ->setErrors(array($message)); $box->setInfoView($info); } return $box; } - private function buildBranchListTable(DiffusionRequest $drequest) { - $viewer = $this->getViewer(); - - if (!$this->needBranchFuture()) { - return null; - } - - $branches = $this->branchFuture->resolve(); - if (!$branches) { - return null; - } - - $limit = $this->getBranchLimit(); - $more_branches = (count($branches) > $limit); - $branches = array_slice($branches, 0, $limit); - - $branches = DiffusionRepositoryRef::loadAllFromDictionaries($branches); - - $commits = id(new DiffusionCommitQuery()) - ->setViewer($viewer) - ->withIdentifiers(mpull($branches, 'getCommitIdentifier')) - ->withRepository($drequest->getRepository()) - ->execute(); - - $table = id(new DiffusionBranchTableView()) - ->setUser($viewer) - ->setDiffusionRequest($drequest) - ->setBranches($branches) - ->setCommits($commits); - - $panel = id(new PHUIObjectBoxView()) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY); - $header = new PHUIHeaderView(); - $header->setHeader(pht('Branches')); - - if ($more_branches) { - $header->setSubheader(pht('Showing %d branches.', $limit)); - } - - $button = id(new PHUIButtonView()) - ->setText(pht('Show All')) - ->setTag('a') - ->setIcon('fa-code-fork') - ->setHref($drequest->generateURI( - array( - 'action' => 'branches', - ))); - - $header->addActionLink($button); - $panel->setHeader($header); - $panel->setTable($table); - - return $panel; - } - - private function buildTagListTable(DiffusionRequest $drequest) { - $viewer = $this->getViewer(); - $repository = $drequest->getRepository(); - - if (!$this->needTagFuture()) { - return null; - } - - $tags = $this->tagFuture->resolve(); - $tags = DiffusionRepositoryTag::newFromConduit($tags); - if (!$tags) { - return null; - } - - $tag_limit = $this->getTagLimit(); - $more_tags = (count($tags) > $tag_limit); - $tags = array_slice($tags, 0, $tag_limit); - - $commits = id(new DiffusionCommitQuery()) - ->setViewer($viewer) - ->withIdentifiers(mpull($tags, 'getCommitIdentifier')) - ->withRepository($repository) - ->needCommitData(true) - ->execute(); - - $view = id(new DiffusionTagTableView()) - ->setUser($viewer) - ->setDiffusionRequest($drequest) - ->setTags($tags) - ->setCommits($commits); - - $phids = $view->getRequiredHandlePHIDs(); - $handles = $this->loadViewerHandles($phids); - $view->setHandles($handles); - - $panel = new PHUIObjectBoxView(); - $header = new PHUIHeaderView(); - $header->setHeader(pht('Tags')); - - if ($more_tags) { - $header->setSubheader( - pht('Showing the %d most recent tags.', $tag_limit)); - } - - $button = id(new PHUIButtonView()) - ->setText(pht('Show All Tags')) - ->setTag('a') - ->setIcon('fa-tag') - ->setHref($drequest->generateURI( - array( - 'action' => 'tags', - ))); - - $header->addActionLink($button); - - $panel->setHeader($header); - $panel->setTable($view); - $panel->setBackground(PHUIObjectBoxView::BLUE_PROPERTY); - - return $panel; - } - private function buildHistoryTable( $history_results, $history, $history_exception) { $request = $this->getRequest(); $viewer = $request->getUser(); $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); if ($history_exception) { if ($repository->isImporting()) { return $this->renderStatusMessage( pht('Still Importing...'), pht( 'This repository is still importing. History is not yet '. 'available.')); } else { return $this->renderStatusMessage( pht('Unable to Retrieve History'), $history_exception->getMessage()); } } $history_table = id(new DiffusionHistoryTableView()) ->setUser($viewer) ->setDiffusionRequest($drequest) ->setHistory($history); // TODO: Super sketchy. $history_table->loadRevisions(); if ($history_results) { $history_table->setParents($history_results['parents']); } $history_table->setIsHead(true); - $history = id(new PHUIButtonView()) - ->setText(pht('History')) - ->setHref($drequest->generateURI( - array( - 'action' => 'history', - ))) - ->setTag('a') - ->setIcon('fa-history'); - - $graph = id(new PHUIButtonView()) - ->setText(pht('Graph')) - ->setHref($drequest->generateURI( - array( - 'action' => 'graph', - ))) - ->setTag('a') - ->setIcon('fa-code-fork'); - $panel = id(new PHUIObjectBoxView()) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY); $header = id(new PHUIHeaderView()) - ->setHeader(pht('Recent Commits')) - ->addActionLink($graph) - ->addActionLink($history); + ->setHeader(pht('Recent Commits')); $panel->setHeader($header); $panel->setTable($history_table); return $panel; } private function buildLocateFile() { $request = $this->getRequest(); $viewer = $request->getUser(); $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); $locate_panel = null; if ($repository->canUsePathTree()) { Javelin::initBehavior( 'diffusion-locate-file', array( 'controlID' => 'locate-control', 'inputID' => 'locate-input', 'browseBaseURI' => (string)$drequest->generateURI( array( 'action' => 'browse', )), 'uri' => (string)$drequest->generateURI( array( 'action' => 'pathtree', )), )); $form = id(new AphrontFormView()) ->setUser($viewer) ->appendChild( id(new AphrontFormTypeaheadControl()) ->setHardpointID('locate-control') ->setID('locate-input') ->setLabel(pht('Locate File'))); $form_box = id(new PHUIBoxView()) ->appendChild($form->buildLayoutView()); $locate_panel = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Locate File')) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->appendChild($form_box); } return $locate_panel; } private function buildBrowseTable( $browse_results, $browse_paths, $browse_exception, array $handles, PHUIPagerView $pager) { require_celerity_resource('diffusion-icons-css'); $request = $this->getRequest(); $viewer = $request->getUser(); $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); if ($browse_exception) { if ($repository->isImporting()) { // The history table renders a useful message. return null; } else { return $this->renderStatusMessage( pht('Unable to Retrieve Paths'), $browse_exception->getMessage()); } } $browse_table = id(new DiffusionBrowseTableView()) ->setUser($viewer) ->setDiffusionRequest($drequest) ->setHandles($handles); if ($browse_paths) { $browse_table->setPaths($browse_paths); } else { $browse_table->setPaths(array()); } $browse_uri = $drequest->generateURI(array('action' => 'browse')); $browse_panel = id(new PHUIObjectBoxView()) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY); $header = id(new PHUIHeaderView()) ->setHeader($repository->getName()); $button = id(new PHUIButtonView()) ->setText(pht('Browse')) ->setTag('a') ->setIcon('fa-code') ->setHref($browse_uri); $header->addActionLink($button); $browse_panel->setHeader($header); $browse_panel->setTable($browse_table); $pager->setURI($browse_uri, 'offset'); if ($pager->willShowPagingControls()) { $browse_panel->setPager($pager); } return $browse_panel; } private function renderCloneURI( PhabricatorRepository $repository, PhabricatorRepositoryURI $uri) { if ($repository->isSVN()) { $display = csprintf( 'svn checkout %R %R', (string)$uri->getDisplayURI(), $repository->getCloneName()); } else { $display = csprintf('%R', (string)$uri->getDisplayURI()); } $display = (string)$display; $viewer = $this->getViewer(); return id(new DiffusionCloneURIView()) ->setViewer($viewer) ->setRepository($repository) ->setRepositoryURI($uri) ->setDisplayURI($display); } - private function needTagFuture() { - $drequest = $this->getDiffusionRequest(); - $repository = $drequest->getRepository(); - - switch ($repository->getVersionControlSystem()) { - case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: - // No tags in SVN. - return false; - } - - return true; - } - private function getTagLimit() { return 15; } - private function needBranchFuture() { - $drequest = $this->getDiffusionRequest(); - - if ($drequest->getBranch() === null) { - return false; - } - - return true; - } - - private function getBranchLimit() { - return 15; - } - } diff --git a/src/applications/diffusion/controller/DiffusionTagListController.php b/src/applications/diffusion/controller/DiffusionTagListController.php index 5e765ddcb6..f7cd032e1a 100644 --- a/src/applications/diffusion/controller/DiffusionTagListController.php +++ b/src/applications/diffusion/controller/DiffusionTagListController.php @@ -1,106 +1,109 @@ loadDiffusionContext(); if ($response) { return $response; } $viewer = $this->getViewer(); $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); $pager = id(new PHUIPagerView()) ->readFromRequest($request); $params = array( 'limit' => $pager->getPageSize() + 1, 'offset' => $pager->getOffset(), ); if (strlen($drequest->getSymbolicCommit())) { $is_commit = true; $params['commit'] = $drequest->getSymbolicCommit(); } else { $is_commit = false; } switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $tags = array(); break; default: $conduit_result = $this->callConduitWithDiffusionRequest( 'diffusion.tagsquery', $params); $tags = DiffusionRepositoryTag::newFromConduit($conduit_result); break; } $tags = $pager->sliceResults($tags); $content = null; $header = id(new PHUIHeaderView()) ->setHeader(pht('Tags')) ->setHeaderIcon('fa-tags'); if (!$tags) { $content = $this->renderStatusMessage( pht('No Tags'), $is_commit ? pht('This commit has no tags.') : pht('This repository has no tags.')); } else { $commits = id(new DiffusionCommitQuery()) ->setViewer($viewer) ->withRepository($repository) ->withIdentifiers(mpull($tags, 'getCommitIdentifier')) ->needCommitData(true) ->execute(); $tag_list = id(new DiffusionTagListView()) ->setTags($tags) ->setUser($viewer) ->setCommits($commits) ->setDiffusionRequest($drequest); $phids = $tag_list->getRequiredHandlePHIDs(); $handles = $this->loadViewerHandles($phids); $tag_list->setHandles($handles); $content = id(new PHUIObjectBoxView()) ->setHeaderText($repository->getDisplayName()) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setTable($tag_list) ->setPager($pager); } $crumbs = $this->buildCrumbs( array( 'tags' => true, 'commit' => $drequest->getSymbolicCommit(), )); $crumbs->setBorder(true); + $tabs = $this->buildTabsView('tags'); + $view = id(new PHUITwoColumnView()) ->setHeader($header) + ->setTabs($tabs) ->setFooter($content); return $this->newPage() ->setTitle( array( pht('Tags'), $repository->getDisplayName(), )) ->setCrumbs($crumbs) ->appendChild($view) ->addClass('diffusion-history-view'); } }