diff --git a/src/applications/diffusion/controller/DiffusionLastModifiedController.php b/src/applications/diffusion/controller/DiffusionLastModifiedController.php index 3487733c8b..b23abf1903 100644 --- a/src/applications/diffusion/controller/DiffusionLastModifiedController.php +++ b/src/applications/diffusion/controller/DiffusionLastModifiedController.php @@ -1,166 +1,163 @@ getDiffusionRequest(); $viewer = $request->getUser(); $paths = $request->getStr('paths'); try { $paths = phutil_json_decode($paths); } catch (PhutilJSONParserException $ex) { return new Aphront400Response(); } $modified_map = $this->callConduitWithDiffusionRequest( 'diffusion.lastmodifiedquery', array( 'paths' => array_fill_keys($paths, $drequest->getCommit()), )); if ($modified_map) { $commit_map = id(new DiffusionCommitQuery()) ->setViewer($viewer) ->withRepository($drequest->getRepository()) ->withIdentifiers(array_values($modified_map)) ->needCommitData(true) ->execute(); $commit_map = mpull($commit_map, null, 'getCommitIdentifier'); } else { $commit_map = array(); } $commits = array(); foreach ($paths as $path) { $modified_at = idx($modified_map, $path); if ($modified_at) { $commit = idx($commit_map, $modified_at); if ($commit) { $commits[$path] = $commit; } } } $phids = array(); foreach ($commits as $commit) { $data = $commit->getCommitData(); $phids[] = $data->getCommitDetail('authorPHID'); $phids[] = $data->getCommitDetail('committerPHID'); } $phids = array_filter($phids); $handles = $this->loadViewerHandles($phids); $branch = $drequest->loadBranch(); if ($branch && $commits) { $lint_query = id(new DiffusionLintCountQuery()) ->withBranchIDs(array($branch->getID())) ->withPaths(array_keys($commits)); if ($drequest->getLint()) { $lint_query->withCodes(array($drequest->getLint())); } $lint = $lint_query->execute(); } else { $lint = array(); } $output = array(); foreach ($commits as $path => $commit) { $prequest = clone $drequest; $prequest->setPath($path); $output[$path] = $this->renderColumns( $prequest, $handles, $commit, idx($lint, $path)); } return id(new AphrontAjaxResponse())->setContent($output); } private function renderColumns( DiffusionRequest $drequest, array $handles, PhabricatorRepositoryCommit $commit = null, $lint = null) { assert_instances_of($handles, 'PhabricatorObjectHandle'); $viewer = $this->getRequest()->getUser(); if ($commit) { $epoch = $commit->getEpoch(); $modified = DiffusionView::linkCommit( $drequest->getRepository(), $commit->getCommitIdentifier()); - $date = phabricator_date($epoch, $viewer); - $time = phabricator_time($epoch, $viewer); + $date = phabricator_datetime($epoch, $viewer); } else { $modified = ''; $date = ''; - $time = ''; } $data = $commit->getCommitData(); if ($data) { $author_phid = $data->getCommitDetail('authorPHID'); if ($author_phid && isset($handles[$author_phid])) { $author = $handles[$author_phid]->renderLink(); } else { $author = DiffusionView::renderName($data->getAuthorName()); } $committer = $data->getCommitDetail('committer'); if ($committer) { $committer_phid = $data->getCommitDetail('committerPHID'); if ($committer_phid && isset($handles[$committer_phid])) { $committer = $handles[$committer_phid]->renderLink(); } else { $committer = DiffusionView::renderName($committer); } if ($author != $committer) { $author = hsprintf('%s/%s', $author, $committer); } } $details = AphrontTableView::renderSingleDisplayLine($data->getSummary()); } else { $author = ''; $details = ''; } $return = array( 'commit' => $modified, 'date' => $date, - 'time' => $time, 'author' => $author, 'details' => $details, ); if ($lint !== null) { $return['lint'] = phutil_tag( 'a', array( 'href' => $drequest->generateURI(array( 'action' => 'lint', 'lint' => null, )), ), number_format($lint)); } // The client treats these results as markup, so make sure they have been // escaped correctly. foreach ($return as $key => $value) { $return[$key] = hsprintf('%s', $value); } return $return; } } diff --git a/src/applications/diffusion/view/DiffusionBranchTableView.php b/src/applications/diffusion/view/DiffusionBranchTableView.php index d053d5bb33..0f4594e576 100644 --- a/src/applications/diffusion/view/DiffusionBranchTableView.php +++ b/src/applications/diffusion/view/DiffusionBranchTableView.php @@ -1,156 +1,165 @@ branches = $branches; return $this; } public function setCommits(array $commits) { assert_instances_of($commits, 'PhabricatorRepositoryCommit'); $this->commits = mpull($commits, null, 'getCommitIdentifier'); return $this; } public function render() { $drequest = $this->getDiffusionRequest(); $current_branch = $drequest->getBranch(); $repository = $drequest->getRepository(); + $commits = $this->commits; + $viewer = $this->getUser(); + + $buildables = $this->loadBuildables($commits); + $have_builds = false; $can_close_branches = ($repository->isHg()); Javelin::initBehavior('phabricator-tooltips'); $doc_href = PhabricatorEnv::getDoclink('Diffusion User Guide: Autoclose'); $rows = array(); $rowc = array(); foreach ($this->branches as $branch) { - $commit = idx($this->commits, $branch->getCommitIdentifier()); + $commit = idx($commits, $branch->getCommitIdentifier()); if ($commit) { $details = $commit->getSummary(); - $datetime = phabricator_datetime($commit->getEpoch(), $this->user); + $datetime = phabricator_datetime($commit->getEpoch(), $viewer); + $buildable = idx($buildables, $commit->getPHID()); + if ($buildable) { + $build_status = $this->renderBuildable($buildable); + $have_builds = true; + } else { + $build_status = null; + } } else { $datetime = null; $details = null; + $build_status = null; } switch ($repository->shouldSkipAutocloseBranch($branch->getShortName())) { case PhabricatorRepository::BECAUSE_REPOSITORY_IMPORTING: $icon = 'fa-times bluegrey'; $tip = pht('Repository Importing'); break; case PhabricatorRepository::BECAUSE_AUTOCLOSE_DISABLED: $icon = 'fa-times bluegrey'; $tip = pht('Repository Autoclose Disabled'); break; case PhabricatorRepository::BECAUSE_BRANCH_UNTRACKED: $icon = 'fa-times bluegrey'; $tip = pht('Branch Untracked'); break; case PhabricatorRepository::BECAUSE_BRANCH_NOT_AUTOCLOSE: $icon = 'fa-times bluegrey'; $tip = pht('Branch Autoclose Disabled'); break; case null: $icon = 'fa-check bluegrey'; $tip = pht('Autoclose Enabled'); break; default: $icon = 'fa-question'; $tip = pht('Status Unknown'); break; } $status_icon = id(new PHUIIconView()) ->setIconFont($icon) ->addSigil('has-tooltip') ->setHref($doc_href) ->setMetadata( array( 'tip' => $tip, 'size' => 200, )); $fields = $branch->getRawFields(); $closed = idx($fields, 'closed'); if ($closed) { $status = pht('Closed'); } else { $status = pht('Open'); } $rows[] = array( - phutil_tag( - 'a', - array( - 'href' => $drequest->generateURI( - array( - 'action' => 'history', - 'branch' => $branch->getShortName(), - )), - ), - pht('History')), + $this->linkBranchHistory($branch->getShortName()), phutil_tag( 'a', array( 'href' => $drequest->generateURI( array( 'action' => 'browse', 'branch' => $branch->getShortName(), )), ), $branch->getShortName()), self::linkCommit( $drequest->getRepository(), $branch->getCommitIdentifier()), + $build_status, $status, + AphrontTableView::renderSingleDisplayLine($details), $status_icon, $datetime, - AphrontTableView::renderSingleDisplayLine($details), ); if ($branch->getShortName() == $current_branch) { $rowc[] = 'highlighted'; } else { $rowc[] = null; } } $view = new AphrontTableView($rows); $view->setHeaders( array( - pht('History'), + null, pht('Branch'), pht('Head'), + null, pht('State'), - pht(''), - pht('Modified'), pht('Details'), + null, + pht('Committed'), )); $view->setColumnClasses( array( '', 'pri', '', + 'icon', '', + 'wide', '', '', - 'wide', )); $view->setColumnVisibility( array( true, true, true, + $have_builds, $can_close_branches, )); $view->setRowClasses($rowc); return $view->render(); } + } diff --git a/src/applications/diffusion/view/DiffusionBrowseTableView.php b/src/applications/diffusion/view/DiffusionBrowseTableView.php index a8eb745fe4..71cc659897 100644 --- a/src/applications/diffusion/view/DiffusionBrowseTableView.php +++ b/src/applications/diffusion/view/DiffusionBrowseTableView.php @@ -1,155 +1,156 @@ paths = $paths; return $this; } public function setHandles(array $handles) { assert_instances_of($handles, 'PhabricatorObjectHandle'); $this->handles = $handles; return $this; } public function render() { $request = $this->getDiffusionRequest(); $repository = $request->getRepository(); $base_path = trim($request->getPath(), '/'); if ($base_path) { $base_path = $base_path.'/'; } $need_pull = array(); $rows = array(); $show_edit = false; foreach ($this->paths as $path) { + $history_link = $this->linkHistory($path->getPath()); + $dir_slash = null; $file_type = $path->getFileType(); if ($file_type == DifferentialChangeType::FILE_DIRECTORY) { $browse_text = $path->getPath().'/'; $dir_slash = '/'; $browse_link = phutil_tag('strong', array(), $this->linkBrowse( $base_path.$path->getPath().$dir_slash, array( 'type' => $file_type, 'name' => $browse_text, ))); } else if ($file_type == DifferentialChangeType::FILE_SUBMODULE) { $browse_text = $path->getPath().'/'; $browse_link = phutil_tag('strong', array(), $this->linkBrowse( null, array( 'type' => $file_type, 'name' => $browse_text, 'hash' => $path->getHash(), 'external' => $path->getExternalURI(), ))); } else { $browse_text = $path->getPath(); $browse_link = $this->linkBrowse( $base_path.$path->getPath(), array( 'type' => $file_type, 'name' => $browse_text, )); } $dict = array( 'lint' => celerity_generate_unique_node_id(), 'commit' => celerity_generate_unique_node_id(), 'date' => celerity_generate_unique_node_id(), - 'time' => celerity_generate_unique_node_id(), 'author' => celerity_generate_unique_node_id(), 'details' => celerity_generate_unique_node_id(), ); $need_pull[$base_path.$path->getPath().$dir_slash] = $dict; foreach ($dict as $k => $uniq) { $dict[$k] = phutil_tag('span', array('id' => $uniq), ''); } $rows[] = array( + $history_link, $browse_link, idx($dict, 'lint'), $dict['commit'], $dict['author'], $dict['details'], $dict['date'], - $dict['time'], ); } if ($need_pull) { Javelin::initBehavior( 'diffusion-pull-lastmodified', array( 'uri' => (string)$request->generateURI( array( 'action' => 'lastmodified', 'stable' => true, )), 'map' => $need_pull, )); } $branch = $this->getDiffusionRequest()->loadBranch(); $show_lint = ($branch && $branch->getLintCommit()); $lint = $request->getLint(); $view = new AphrontTableView($rows); $view->setHeaders( array( + null, pht('Path'), ($lint ? $lint : pht('Lint')), pht('Modified'), pht('Author/Committer'), pht('Details'), - pht('Date'), - pht('Time'), + pht('Committed'), )); $view->setColumnClasses( array( + 'nudgeright', + '', + '', '', - 'n', - 'n', '', 'wide', '', - 'right', )); $view->setColumnVisibility( array( true, - $show_lint, true, + $show_lint, true, true, true, true, )); $view->setDeviceVisibility( array( true, - false, true, false, true, false, + true, false, )); return $view->render(); } } diff --git a/src/applications/diffusion/view/DiffusionHistoryTableView.php b/src/applications/diffusion/view/DiffusionHistoryTableView.php index 80989efdf2..314bfb435c 100644 --- a/src/applications/diffusion/view/DiffusionHistoryTableView.php +++ b/src/applications/diffusion/view/DiffusionHistoryTableView.php @@ -1,422 +1,368 @@ history = $history; - $this->buildCache = null; return $this; } public function loadRevisions() { $commit_phids = array(); foreach ($this->history as $item) { if ($item->getCommit()) { $commit_phids[] = $item->getCommit()->getPHID(); } } // TODO: Get rid of this. $this->revisions = id(new DifferentialRevision()) ->loadIDsByCommitPHIDs($commit_phids); return $this; } public function setHandles(array $handles) { assert_instances_of($handles, 'PhabricatorObjectHandle'); $this->handles = $handles; return $this; } private function getRequiredHandlePHIDs() { $phids = array(); foreach ($this->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; } } } return array_keys($phids); } public function setParents(array $parents) { $this->parents = $parents; return $this; } public function setIsHead($is_head) { $this->isHead = $is_head; return $this; } - public function loadBuildablesOnDemand() { - if ($this->buildCache !== null) { - return $this->buildCache; - } - - $commits_to_builds = array(); - - $commits = mpull($this->history, 'getCommit'); - - $commit_phids = mpull($commits, 'getPHID'); - - $buildables = id(new HarbormasterBuildableQuery()) - ->setViewer($this->getUser()) - ->withBuildablePHIDs($commit_phids) - ->withManualBuildables(false) - ->execute(); - - $this->buildCache = mpull($buildables, null, 'getBuildablePHID'); - - return $this->buildCache; - } - public function render() { $drequest = $this->getDiffusionRequest(); $viewer = $this->getUser(); + $buildables = $this->loadBuildables(mpull($this->history, 'getCommit')); + $has_any_build = false; + $show_revisions = PhabricatorApplication::isClassInstalledForViewer( 'PhabricatorDifferentialApplication', $viewer); $handles = $viewer->loadHandles($this->getRequiredHandlePHIDs()); $graph = null; if ($this->parents) { $graph = $this->renderGraph(); } $show_builds = PhabricatorApplication::isClassInstalledForViewer( 'PhabricatorHarbormasterApplication', $this->getUser()); $rows = array(); $ii = 0; foreach ($this->history as $history) { $epoch = $history->getEpoch(); if ($epoch) { - $date = phabricator_date($epoch, $this->user); - $time = phabricator_time($epoch, $this->user); + $committed = phabricator_datetime($epoch, $viewer); } else { - $date = null; - $time = null; + $committed = null; } $data = $history->getCommitData(); $author_phid = $committer = $committer_phid = null; if ($data) { $author_phid = $data->getCommitDetail('authorPHID'); $committer_phid = $data->getCommitDetail('committerPHID'); $committer = $data->getCommitDetail('committer'); } if ($author_phid && isset($handles[$author_phid])) { $author = $handles[$author_phid]->renderLink(); } else { $author = self::renderName($history->getAuthorName()); } $different_committer = false; if ($committer_phid) { $different_committer = ($committer_phid != $author_phid); } else if ($committer != '') { $different_committer = ($committer != $history->getAuthorName()); } if ($different_committer) { if ($committer_phid && isset($handles[$committer_phid])) { $committer = $handles[$committer_phid]->renderLink(); } else { $committer = self::renderName($committer); } $author = hsprintf('%s/%s', $author, $committer); } // We can show details once the message and change have been imported. $partial_import = PhabricatorRepositoryCommit::IMPORTED_MESSAGE | PhabricatorRepositoryCommit::IMPORTED_CHANGE; $commit = $history->getCommit(); if ($commit && $commit->isPartiallyImported($partial_import) && $data) { $summary = AphrontTableView::renderSingleDisplayLine( $history->getSummary()); } else { $summary = phutil_tag('em', array(), pht("Importing\xE2\x80\xA6")); } $build = null; if ($show_builds) { - $buildable_lookup = $this->loadBuildablesOnDemand(); - $buildable = idx($buildable_lookup, $commit->getPHID()); + $buildable = idx($buildables, $commit->getPHID()); if ($buildable !== null) { - $icon = HarbormasterBuildable::getBuildableStatusIcon( - $buildable->getBuildableStatus()); - $color = HarbormasterBuildable::getBuildableStatusColor( - $buildable->getBuildableStatus()); - $name = HarbormasterBuildable::getBuildableStatusName( - $buildable->getBuildableStatus()); - - $icon_view = id(new PHUIIconView()) - ->setIconFont($icon.' '.$color); - - $tooltip_view = javelin_tag( - 'span', - array( - 'sigil' => 'has-tooltip', - 'meta' => array('tip' => $name), - ), - $icon_view); - - Javelin::initBehavior('phabricator-tooltips'); - - $href_view = phutil_tag( - 'a', - array('href' => '/'.$buildable->getMonogram()), - $tooltip_view); - - $build = $href_view; - + $build = $this->renderBuildable($buildable); $has_any_build = true; } } $browse = $this->linkBrowse( $history->getPath(), array( 'commit' => $history->getCommitIdentifier(), 'branch' => $drequest->getBranch(), 'type' => $history->getFileType(), )); $rows[] = array( $graph ? $graph[$ii++] : null, $browse, self::linkCommit( $drequest->getRepository(), $history->getCommitIdentifier()), $build, ($commit ? self::linkRevision(idx($this->revisions, $commit->getPHID())) : null), $author, $summary, - $date, - $time, + $committed, ); } $view = new AphrontTableView($rows); $view->setHeaders( array( null, null, pht('Commit'), null, - pht('Revision'), + null, pht('Author/Committer'), pht('Details'), - pht('Date'), - pht('Time'), + pht('Committed'), )); $view->setColumnClasses( array( 'threads', 'nudgeright', - 'n', + '', 'icon', - 'n', + '', '', 'wide', '', - 'right', )); $view->setColumnVisibility( array( $graph ? true : false, true, true, - true, + $has_any_build, $show_revisions, )); $view->setDeviceVisibility( array( $graph ? true : false, true, true, true, true, false, true, false, - false, )); return $view->render(); } /** * Draw a merge/branch graph from the parent revision data. We're basically * building up a bunch of strings like this: * * ^ * |^ * o| * |o * o * * ...which form an ASCII representation of the graph we eventually want to * draw. * * NOTE: The actual implementation is black magic. */ private function renderGraph() { // This keeps our accumulated information about each line of the // merge/branch graph. $graph = array(); // This holds the next commit we're looking for in each column of the // graph. $threads = array(); // This is the largest number of columns any row has, i.e. the width of // the graph. $count = 0; foreach ($this->history as $key => $history) { $joins = array(); $splits = array(); $parent_list = $this->parents[$history->getCommitIdentifier()]; // Look for some thread which has this commit as the next commit. If // we find one, this commit goes on that thread. Otherwise, this commit // goes on a new thread. $line = ''; $found = false; $pos = count($threads); for ($n = 0; $n < $count; $n++) { if (empty($threads[$n])) { $line .= ' '; continue; } if ($threads[$n] == $history->getCommitIdentifier()) { if ($found) { $line .= ' '; $joins[] = $n; unset($threads[$n]); } else { $line .= 'o'; $found = true; $pos = $n; } } else { // We render a "|" for any threads which have a commit that we haven't // seen yet, this is later drawn as a vertical line. $line .= '|'; } } // If we didn't find the thread this commit goes on, start a new thread. // We use "o" to mark the commit for the rendering engine, or "^" to // indicate that there's nothing after it so the line from the commit // upward should not be drawn. if (!$found) { if ($this->isHead) { $line .= '^'; } else { $line .= 'o'; foreach ($graph as $k => $meta) { // Go back across all the lines we've already drawn and add a // "|" to the end, since this is connected to some future commit // we don't know about. for ($jj = strlen($meta['line']); $jj <= $count; $jj++) { $graph[$k]['line'] .= '|'; } } } } // Update the next commit on this thread to the commit's first parent. // This might have the effect of making a new thread. $threads[$pos] = head($parent_list); // If we made a new thread, increase the thread count. $count = max($pos + 1, $count); // Now, deal with splits (merges). I picked this terms opposite to the // underlying repository term to confuse you. foreach (array_slice($parent_list, 1) as $parent) { $found = false; // Try to find the other parent(s) in our existing threads. If we find // them, split to that thread. foreach ($threads as $idx => $thread_commit) { if ($thread_commit == $parent) { $found = true; $splits[] = $idx; } } // If we didn't find the parent, we don't know about it yet. Find the // first free thread and add it as the "next" commit in that thread. // This might create a new thread. if (!$found) { for ($n = 0; $n < $count; $n++) { if (empty($threads[$n])) { break; } } $threads[$n] = $parent; $splits[] = $n; $count = max($n + 1, $count); } } $graph[] = array( 'line' => $line, 'split' => $splits, 'join' => $joins, ); } // Render into tags for the behavior. foreach ($graph as $k => $meta) { $graph[$k] = javelin_tag( 'div', array( 'sigil' => 'commit-graph', 'meta' => $meta, ), ''); } Javelin::initBehavior( 'diffusion-commit-graph', array( 'count' => $count, )); return $graph; } } diff --git a/src/applications/diffusion/view/DiffusionTagListView.php b/src/applications/diffusion/view/DiffusionTagListView.php index 668453f88e..3b27284f5e 100644 --- a/src/applications/diffusion/view/DiffusionTagListView.php +++ b/src/applications/diffusion/view/DiffusionTagListView.php @@ -1,110 +1,138 @@ tags = $tags; return $this; } public function setCommits(array $commits) { $this->commits = mpull($commits, null, 'getCommitIdentifier'); return $this; } public function setHandles(array $handles) { $this->handles = $handles; return $this; } public function getRequiredHandlePHIDs() { return array_filter(mpull($this->commits, 'getAuthorPHID')); } public function render() { $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); + $buildables = $this->loadBuildables($this->commits); + $has_builds = false; $rows = array(); foreach ($this->tags as $tag) { $commit = idx($this->commits, $tag->getCommitIdentifier()); $tag_link = phutil_tag( 'a', array( 'href' => $drequest->generateURI( array( 'action' => 'browse', 'commit' => $tag->getName(), )), ), $tag->getName()); $commit_link = phutil_tag( 'a', array( 'href' => $drequest->generateURI( array( 'action' => 'commit', 'commit' => $tag->getCommitIdentifier(), )), ), $repository->formatCommitName( $tag->getCommitIdentifier())); $author = null; if ($commit && $commit->getAuthorPHID()) { $author = $this->handles[$commit->getAuthorPHID()]->renderLink(); } else if ($commit && $commit->getCommitData()) { $author = self::renderName($commit->getCommitData()->getAuthorName()); } else { $author = self::renderName($tag->getAuthor()); } $description = null; if ($tag->getType() == 'git/tag') { // In Git, a tag may be a "real" tag, or just a reference to a commit. // If it's a real tag, use the message on the tag, since this may be // unique data which isn't otherwise available. $description = $tag->getDescription(); } else { if ($commit) { $description = $commit->getSummary(); } else { $description = $tag->getDescription(); } } + $build = null; + if ($commit) { + $buildable = idx($buildables, $commit->getPHID()); + if ($buildable) { + $build = $this->renderBuildable($buildable); + $has_builds = true; + } + } + + $history = $this->linkTagHistory($tag->getName()); + $rows[] = array( + $history, $tag_link, $commit_link, - $description, + $build, $author, + $description, phabricator_datetime($tag->getEpoch(), $this->user), ); } - $table = new AphrontTableView($rows); - $table->setHeaders( - array( - pht('Tag'), - pht('Commit'), - pht('Description'), - pht('Author'), - pht('Created'), - )); - $table->setColumnClasses( - array( - 'pri', - '', - 'wide', - )); + $table = id(new AphrontTableView($rows)) + ->setHeaders( + array( + null, + pht('Tag'), + pht('Commit'), + null, + pht('Author'), + pht('Description'), + pht('Created'), + )) + ->setColumnClasses( + array( + 'nudgeright', + 'pri', + '', + '', + '', + 'wide', + )) + ->setColumnVisibility( + array( + true, + true, + true, + $has_builds, + )); + return $table->render(); } } diff --git a/src/applications/diffusion/view/DiffusionView.php b/src/applications/diffusion/view/DiffusionView.php index b7b3599a2d..83fdc1f7e5 100644 --- a/src/applications/diffusion/view/DiffusionView.php +++ b/src/applications/diffusion/view/DiffusionView.php @@ -1,173 +1,251 @@ diffusionRequest = $request; return $this; } final public function getDiffusionRequest() { return $this->diffusionRequest; } final public function linkHistory($path) { $href = $this->getDiffusionRequest()->generateURI( array( 'action' => 'history', 'path' => $path, )); + return $this->renderHistoryLink($href); + } + + final public function linkBranchHistory($branch) { + $href = $this->getDiffusionRequest()->generateURI( + array( + 'action' => 'history', + 'branch' => $branch, + )); + + return $this->renderHistoryLink($href); + } + + final public function linkTagHistory($tag) { + $href = $this->getDiffusionRequest()->generateURI( + array( + 'action' => 'history', + 'commit' => $tag, + )); + + return $this->renderHistoryLink($href); + } + + private function renderHistoryLink($href) { return javelin_tag( 'a', array( 'href' => $href, 'class' => 'diffusion-link-icon', 'sigil' => 'has-tooltip', 'meta' => array( 'tip' => pht('History'), 'align' => 'E', ), ), - id(new PHUIIconView())->setIconFont('fa-list-ul blue')); + id(new PHUIIconView())->setIconFont('fa-history bluegrey')); } final public function linkBrowse($path, array $details = array()) { require_celerity_resource('diffusion-icons-css'); Javelin::initBehavior('phabricator-tooltips'); $file_type = idx($details, 'type'); unset($details['type']); $display_name = idx($details, 'name'); unset($details['name']); if (strlen($display_name)) { $display_name = phutil_tag( 'span', array( 'class' => 'diffusion-browse-name', ), $display_name); } if (isset($details['external'])) { $href = id(new PhutilURI('/diffusion/external/')) ->setQueryParams( array( 'uri' => idx($details, 'external'), 'id' => idx($details, 'hash'), )); $tip = pht('Browse External'); } else { $href = $this->getDiffusionRequest()->generateURI( $details + array( 'action' => 'browse', 'path' => $path, )); $tip = pht('Browse'); } $icon = DifferentialChangeType::getIconForFileType($file_type); $icon_view = id(new PHUIIconView())->setIconFont("{$icon} blue"); // If we're rendering a file or directory name, don't show the tooltip. if ($display_name !== null) { $sigil = null; $meta = null; } else { $sigil = 'has-tooltip'; $meta = array( 'tip' => $tip, 'align' => 'E', ); } return javelin_tag( 'a', array( 'href' => $href, 'class' => 'diffusion-link-icon', 'sigil' => $sigil, 'meta' => $meta, ), array( $icon_view, $display_name, )); } final public static function nameCommit( PhabricatorRepository $repository, $commit) { switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $commit_name = substr($commit, 0, 12); break; default: $commit_name = $commit; break; } $callsign = $repository->getCallsign(); return "r{$callsign}{$commit_name}"; } final public static function linkCommit( PhabricatorRepository $repository, $commit, $summary = '') { $commit_name = self::nameCommit($repository, $commit); $callsign = $repository->getCallsign(); if (strlen($summary)) { $commit_name .= ': '.$summary; } return phutil_tag( 'a', array( 'href' => "/r{$callsign}{$commit}", ), $commit_name); } final public static function linkRevision($id) { if (!$id) { return null; } return phutil_tag( 'a', array( 'href' => "/D{$id}", ), "D{$id}"); } final public static function renderName($name) { $email = new PhutilEmailAddress($name); if ($email->getDisplayName() && $email->getDomainName()) { Javelin::initBehavior('phabricator-tooltips', array()); require_celerity_resource('aphront-tooltip-css'); return javelin_tag( 'span', array( 'sigil' => 'has-tooltip', 'meta' => array( 'tip' => $email->getAddress(), 'align' => 'E', 'size' => 'auto', ), ), $email->getDisplayName()); } return hsprintf('%s', $name); } + final protected function renderBuildable(HarbormasterBuildable $buildable) { + $status = $buildable->getBuildableStatus(); + + $icon = HarbormasterBuildable::getBuildableStatusIcon($status); + $color = HarbormasterBuildable::getBuildableStatusColor($status); + $name = HarbormasterBuildable::getBuildableStatusName($status); + + $icon_view = id(new PHUIIconView()) + ->setIconFont($icon.' '.$color); + + $tooltip_view = javelin_tag( + 'span', + array( + 'sigil' => 'has-tooltip', + 'meta' => array('tip' => $name), + ), + $icon_view); + + Javelin::initBehavior('phabricator-tooltips'); + + return phutil_tag( + 'a', + array('href' => '/'.$buildable->getMonogram()), + $tooltip_view); + } + + final protected function loadBuildables(array $commits) { + assert_instances_of($commits, 'PhabricatorRepositoryCommit'); + + if (!$commits) { + return array(); + } + + $viewer = $this->getUser(); + + $harbormaster_app = 'PhabricatorHarbormasterApplication'; + $have_harbormaster = PhabricatorApplication::isClassInstalledForViewer( + $harbormaster_app, + $viewer); + + if ($have_harbormaster) { + $buildables = id(new HarbormasterBuildableQuery()) + ->setViewer($viewer) + ->withBuildablePHIDs(mpull($commits, 'getPHID')) + ->withManualBuildables(false) + ->execute(); + $buildables = mpull($buildables, null, 'getBuildablePHID'); + } else { + $buildables = array(); + } + + return $buildables; + } + }