diff --git a/src/applications/maniphest/controller/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/ManiphestTaskDetailController.php --- a/src/applications/maniphest/controller/ManiphestTaskDetailController.php +++ b/src/applications/maniphest/controller/ManiphestTaskDetailController.php @@ -179,11 +179,14 @@ ->addTabGroup($tab_group); } + $changes_view = $this->newChangesView($task, $edges); + $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setCurtain($curtain) ->setMainColumn( array( + $changes_view, $tab_view, $timeline, $comment_view, @@ -395,56 +398,6 @@ $source)); } - $edge_types = array( - ManiphestTaskHasRevisionEdgeType::EDGECONST - => pht('Differential Revisions'), - ); - - $revisions_commits = array(); - - $commit_phids = array_keys( - $edges[ManiphestTaskHasCommitEdgeType::EDGECONST]); - if ($commit_phids) { - $commit_drev = DiffusionCommitHasRevisionEdgeType::EDGECONST; - $drev_edges = id(new PhabricatorEdgeQuery()) - ->withSourcePHIDs($commit_phids) - ->withEdgeTypes(array($commit_drev)) - ->execute(); - - foreach ($commit_phids as $phid) { - $revisions_commits[$phid] = $handles->renderHandle($phid) - ->setShowHovercard(true); - $revision_phid = key($drev_edges[$phid][$commit_drev]); - $revision_handle = $handles->getHandleIfExists($revision_phid); - if ($revision_handle) { - $task_drev = ManiphestTaskHasRevisionEdgeType::EDGECONST; - unset($edges[$task_drev][$revision_phid]); - $revisions_commits[$phid] = hsprintf( - '%s / %s', - $revision_handle->renderHovercardLink($revision_handle->getName()), - $revisions_commits[$phid]); - } - } - } - - foreach ($edge_types as $edge_type => $edge_name) { - if (!$edges[$edge_type]) { - continue; - } - - $edge_handles = $viewer->loadHandles(array_keys($edges[$edge_type])); - - $edge_list = $edge_handles->renderList(); - - $view->addProperty($edge_name, $edge_list); - } - - if ($revisions_commits) { - $view->addProperty( - pht('Commits'), - phutil_implode_html(phutil_tag('br'), $revisions_commits)); - } - $field_list->appendFieldsToPropertyList( $task, $viewer, @@ -594,5 +547,275 @@ return $handles->newSublist($phids); } + private function newChangesView(ManiphestTask $task, array $edges) { + $viewer = $this->getViewer(); + + $revision_type = ManiphestTaskHasRevisionEdgeType::EDGECONST; + $commit_type = ManiphestTaskHasCommitEdgeType::EDGECONST; + + $revision_phids = idx($edges, $revision_type, array()); + $revision_phids = array_keys($revision_phids); + $revision_phids = array_fuse($revision_phids); + + $commit_phids = idx($edges, $commit_type, array()); + $commit_phids = array_keys($commit_phids); + $commit_phids = array_fuse($commit_phids); + + if (!$revision_phids && !$commit_phids) { + return null; + } + + if ($commit_phids) { + $link_type = DiffusionCommitHasRevisionEdgeType::EDGECONST; + $link_query = id(new PhabricatorEdgeQuery()) + ->withSourcePHIDs($commit_phids) + ->withEdgeTypes(array($link_type)); + $link_query->execute(); + + $commits = id(new DiffusionCommitQuery()) + ->setViewer($viewer) + ->withPHIDs($commit_phids) + ->execute(); + $commits = mpull($commits, null, 'getPHID'); + } else { + $commits = array(); + } + + if ($revision_phids) { + $revisions = id(new DifferentialRevisionQuery()) + ->setViewer($viewer) + ->withPHIDs($revision_phids) + ->execute(); + $revisions = mpull($revisions, null, 'getPHID'); + } else { + $revisions = array(); + } + + $handle_phids = array(); + $any_linked = false; + + $tail = array(); + foreach ($commit_phids as $commit_phid) { + $handle_phids[] = $commit_phid; + + $link_phids = $link_query->getDestinationPHIDs(array($commit_phid)); + foreach ($link_phids as $link_phid) { + $handle_phids[] = $link_phid; + unset($revision_phids[$link_phid]); + $any_linked = true; + } + + $commit = idx($commits, $commit_phid); + if ($commit) { + $repository_phid = $commit->getRepository()->getPHID(); + $handle_phids[] = $repository_phid; + } else { + $repository_phid = null; + } + + $status_view = null; + if ($commit) { + $status = $commit->getAuditStatusObject(); + if (!$status->isNoAudit()) { + $status_view = id(new PHUITagView()) + ->setType(PHUITagView::TYPE_SHADE) + ->setIcon($status->getIcon()) + ->setColor($status->getColor()) + ->setName($status->getName()); + + } + } + + $object_link = null; + if ($commit) { + $commit_monogram = $commit->getDisplayName(); + $commit_monogram = phutil_tag( + 'span', + array( + 'class' => 'object-name', + ), + $commit_monogram); + + $commit_link = javelin_tag( + 'a', + array( + 'href' => $commit->getURI(), + 'sigil' => 'hovercard', + 'meta' => array( + 'hoverPHID' => $commit->getPHID(), + ), + ), + $commit->getSummary()); + + $object_link = array( + $commit_monogram, + ' ', + $commit_link, + ); + } + + $tail[] = array( + 'objectPHID' => $commit_phid, + 'objectLink' => $object_link, + 'repositoryPHID' => $repository_phid, + 'revisionPHIDs' => $link_phids, + 'status' => $status_view, + ); + } + + $head = array(); + foreach ($revision_phids as $revision_phid) { + $handle_phids[] = $revision_phid; + + $revision = idx($revisions, $revision_phid); + if ($revision) { + $repository_phid = $revision->getRepositoryPHID(); + $handle_phids[] = $repository_phid; + } else { + $repository_phid = null; + } + + if ($revision) { + $icon = $revision->getStatusIcon(); + $color = $revision->getStatusIconColor(); + $name = $revision->getStatusDisplayName(); + + $status_view = id(new PHUITagView()) + ->setType(PHUITagView::TYPE_SHADE) + ->setIcon($icon) + ->setColor($color) + ->setName($name); + } else { + $status_view = null; + } + + $object_link = null; + if ($revision) { + $revision_monogram = $revision->getMonogram(); + $revision_monogram = phutil_tag( + 'span', + array( + 'class' => 'object-name', + ), + $revision_monogram); + + $revision_link = javelin_tag( + 'a', + array( + 'href' => $revision->getURI(), + 'sigil' => 'hovercard', + 'meta' => array( + 'hoverPHID' => $revision->getPHID(), + ), + ), + $revision->getTitle()); + + $object_link = array( + $revision_monogram, + ' ', + $revision_link, + ); + } + + $head[] = array( + 'objectPHID' => $revision_phid, + 'objectLink' => $object_link, + 'repositoryPHID' => $repository_phid, + 'revisionPHIDs' => array(), + 'status' => $status_view, + ); + } + + $objects = array_merge($head, $tail); + $handles = $viewer->loadHandles($handle_phids); + + $rows = array(); + foreach ($objects as $object) { + $object_phid = $object['objectPHID']; + $handle = $handles[$object_phid]; + + $object_link = $object['objectLink']; + if ($object_link === null) { + $object_link = $handle->renderLink(); + } + + $object_icon = id(new PHUIIconView()) + ->setIcon($handle->getIcon()); + + $repository_link = null; + $repository_phid = $object['repositoryPHID']; + if ($repository_phid) { + $repository_link = $handles[$repository_phid]->renderLink(); + } + + $status_view = $object['status']; + + $revision_tags = array(); + foreach ($object['revisionPHIDs'] as $link_phid) { + $revision_handle = $handles[$link_phid]; + + $revision_name = $revision_handle->getName(); + $revision_tags[] = $revision_handle + ->renderHovercardLink($revision_name); + } + $revision_tags = phutil_implode_html( + phutil_tag('br'), + $revision_tags); + + $rows[] = array( + $object_icon, + $status_view, + $repository_link, + $revision_tags, + $object_link, + ); + } + + $changes_table = id(new AphrontTableView($rows)) + ->setNoDataString(pht('This task has no related commits or revisions.')) + ->setHeaders( + array( + null, + null, + pht('Repository'), + null, + pht('Revision/Commit'), + )) + ->setColumnClasses( + array( + 'center', + null, + null, + null, + 'wide pri object-link', + )) + ->setColumnVisibility( + array( + true, + true, + true, + $any_linked, + true, + )) + ->setDeviceVisibility( + array( + false, + true, + false, + false, + true, + )); + + $changes_header = id(new PHUIHeaderView()) + ->setHeader(pht('Revisions and Commits')); + + $changes_view = id(new PHUIObjectBoxView()) + ->setHeader($changes_header) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setTable($changes_table); + + return $changes_view; + } + }