@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Build a page for viewing all inline comments

Summary: Adds a very basic list of all inline comments, threaded, and their status. Kept this a little simpler than the mock, mostly because sorting here feels a little strange given threads would be all over the place. Not sure sorted is needed in practice anyways. I'd probably lean towards just adding a JS checkbox to hide certain rows if needed in the future.

Test Plan:
Test various commenting structures:

- Leave Comment
- Update Diff
- Leave new comment
- Reply to comment
- Reply to comment as revision author
- Mark items as done
- Update diff again

{F4996915}

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: Korvin, epriestley

Differential Revision: https://secure.phabricator.com/D18112

+292 -65
+4
src/__phutil_library_map__.php
··· 547 547 'DifferentialRevisionHeraldField' => 'applications/differential/herald/DifferentialRevisionHeraldField.php', 548 548 'DifferentialRevisionHeraldFieldGroup' => 'applications/differential/herald/DifferentialRevisionHeraldFieldGroup.php', 549 549 'DifferentialRevisionIDCommitMessageField' => 'applications/differential/field/DifferentialRevisionIDCommitMessageField.php', 550 + 'DifferentialRevisionInlinesController' => 'applications/differential/controller/DifferentialRevisionInlinesController.php', 550 551 'DifferentialRevisionLandController' => 'applications/differential/controller/DifferentialRevisionLandController.php', 551 552 'DifferentialRevisionListController' => 'applications/differential/controller/DifferentialRevisionListController.php', 552 553 'DifferentialRevisionListView' => 'applications/differential/view/DifferentialRevisionListView.php', ··· 1738 1739 'PHUIDiffInlineCommentTableScaffold' => 'infrastructure/diff/view/PHUIDiffInlineCommentTableScaffold.php', 1739 1740 'PHUIDiffInlineCommentUndoView' => 'infrastructure/diff/view/PHUIDiffInlineCommentUndoView.php', 1740 1741 'PHUIDiffInlineCommentView' => 'infrastructure/diff/view/PHUIDiffInlineCommentView.php', 1742 + 'PHUIDiffInlineThreader' => 'infrastructure/diff/view/PHUIDiffInlineThreader.php', 1741 1743 'PHUIDiffOneUpInlineCommentRowScaffold' => 'infrastructure/diff/view/PHUIDiffOneUpInlineCommentRowScaffold.php', 1742 1744 'PHUIDiffRevealIconView' => 'infrastructure/diff/view/PHUIDiffRevealIconView.php', 1743 1745 'PHUIDiffTableOfContentsItemView' => 'infrastructure/diff/view/PHUIDiffTableOfContentsItemView.php', ··· 5516 5518 'DifferentialRevisionHeraldField' => 'HeraldField', 5517 5519 'DifferentialRevisionHeraldFieldGroup' => 'HeraldFieldGroup', 5518 5520 'DifferentialRevisionIDCommitMessageField' => 'DifferentialCommitMessageField', 5521 + 'DifferentialRevisionInlinesController' => 'DifferentialController', 5519 5522 'DifferentialRevisionLandController' => 'DifferentialController', 5520 5523 'DifferentialRevisionListController' => 'DifferentialController', 5521 5524 'DifferentialRevisionListView' => 'AphrontView', ··· 6872 6875 'PHUIDiffInlineCommentTableScaffold' => 'AphrontView', 6873 6876 'PHUIDiffInlineCommentUndoView' => 'PHUIDiffInlineCommentView', 6874 6877 'PHUIDiffInlineCommentView' => 'AphrontView', 6878 + 'PHUIDiffInlineThreader' => 'Phobject', 6875 6879 'PHUIDiffOneUpInlineCommentRowScaffold' => 'PHUIDiffInlineCommentRowScaffold', 6876 6880 'PHUIDiffRevealIconView' => 'AphrontView', 6877 6881 'PHUIDiffTableOfContentsItemView' => 'AphrontView',
+8
src/applications/audit/storage/PhabricatorAuditInlineComment.php
··· 331 331 return $this->isGhost; 332 332 } 333 333 334 + public function getDateModified() { 335 + return $this->proxy->getDateModified(); 336 + } 337 + 338 + public function getDateCreated() { 339 + return $this->proxy->getDateCreated(); 340 + } 341 + 334 342 335 343 /* -( PhabricatorMarkupInterface Implementation )-------------------------- */ 336 344
+4 -2
src/applications/base/controller/PhabricatorController.php
··· 483 483 // NOTE: Applications (objects of class PhabricatorApplication) can't 484 484 // currently be set here, although they don't need any of the extensions 485 485 // anyway. This should probably work differently than it does, though. 486 - if ($object instanceof PhabricatorLiskDAO) { 487 - $action_list->setObject($object); 486 + if ($object) { 487 + if ($object instanceof PhabricatorLiskDAO) { 488 + $action_list->setObject($object); 489 + } 488 490 } 489 491 490 492 $curtain = id(new PHUICurtainView())
+2
src/applications/differential/application/PhabricatorDifferentialApplication.php
··· 77 77 => 'DifferentialDiffCreateController', 78 78 'operation/(?P<id>[1-9]\d*)/' 79 79 => 'DifferentialRevisionOperationController', 80 + 'inlines/(?P<id>[1-9]\d*)/' 81 + => 'DifferentialRevisionInlinesController', 80 82 ), 81 83 'comment/' => array( 82 84 'preview/(?P<id>[1-9]\d*)/' => 'DifferentialCommentPreviewController',
+190
src/applications/differential/controller/DifferentialRevisionInlinesController.php
··· 1 + <?php 2 + 3 + final class DifferentialRevisionInlinesController 4 + extends DifferentialController { 5 + 6 + public function shouldAllowPublic() { 7 + return true; 8 + } 9 + 10 + public function handleRequest(AphrontRequest $request) { 11 + $viewer = $this->getViewer(); 12 + $id = $request->getURIData('id'); 13 + 14 + $revision = id(new DifferentialRevisionQuery()) 15 + ->withIDs(array($id)) 16 + ->setViewer($viewer) 17 + ->needDiffIDs(true) 18 + ->executeOne(); 19 + if (!$revision) { 20 + return new Aphront404Response(); 21 + } 22 + 23 + $revision_monogram = $revision->getMonogram(); 24 + $revision_uri = $revision->getURI(); 25 + $revision_title = $revision->getTitle(); 26 + 27 + $query = id(new DifferentialInlineCommentQuery()) 28 + ->setViewer($viewer) 29 + ->needHidden(true) 30 + ->withRevisionPHIDs(array($revision->getPHID())); 31 + $inlines = $query->execute(); 32 + 33 + $crumbs = $this->buildApplicationCrumbs(); 34 + $crumbs->addTextCrumb($revision_monogram, $revision_uri); 35 + $crumbs->addTextCrumb(pht('Inline Comments')); 36 + $crumbs->setBorder(true); 37 + 38 + $content = $this->renderInlineTable($revision, $inlines); 39 + $header = $this->buildHeader($revision); 40 + 41 + $view = id(new PHUITwoColumnView()) 42 + ->setHeader($header) 43 + ->setFooter($content); 44 + 45 + return $this->newPage() 46 + ->setTitle( 47 + array( 48 + "{$revision_monogram} {$revision_title}", 49 + pht('Inlines'), 50 + )) 51 + ->setCrumbs($crumbs) 52 + ->appendChild($view); 53 + } 54 + 55 + private function buildHeader(DifferentialRevision $revision) { 56 + $viewer = $this->getViewer(); 57 + 58 + $button = id(new PHUIButtonView()) 59 + ->setTag('a') 60 + ->setIcon('fa-chevron-left') 61 + ->setHref($revision->getURI()) 62 + ->setText(pht('Back to Revision')); 63 + 64 + return id(new PHUIHeaderView()) 65 + ->setHeader($revision->getTitle()) 66 + ->setUser($viewer) 67 + ->setHeaderIcon('fa-cog') 68 + ->addActionLink($button); 69 + } 70 + 71 + private function renderInlineTable( 72 + DifferentialRevision $revision, 73 + array $inlines) { 74 + 75 + $viewer = $this->getViewer(); 76 + $inlines = id(new PHUIDiffInlineThreader()) 77 + ->reorderAndThreadCommments($inlines); 78 + 79 + $handle_phids = array(); 80 + $changeset_ids = array(); 81 + foreach ($inlines as $inline) { 82 + $handle_phids[] = $inline->getAuthorPHID(); 83 + $changeset_ids[] = $inline->getChangesetID(); 84 + } 85 + $handles = $viewer->loadHandles($handle_phids); 86 + $handles = iterator_to_array($handles); 87 + 88 + if ($changeset_ids) { 89 + $changesets = id(new DifferentialChangesetQuery()) 90 + ->setViewer($viewer) 91 + ->withIDs($changeset_ids) 92 + ->execute(); 93 + $changesets = mpull($changesets, null, 'getID'); 94 + } else { 95 + $changesets = array(); 96 + } 97 + 98 + $current_changeset = head($revision->getDiffIDs()); 99 + 100 + $rows = array(); 101 + foreach ($inlines as $inline) { 102 + $status_icons = array(); 103 + 104 + $c_id = $inline->getChangesetID(); 105 + $d_id = $changesets[$c_id]->getDiffID(); 106 + 107 + if ($d_id == $current_changeset) { 108 + $diff_id = phutil_tag('strong', array(), pht('Current')); 109 + } else { 110 + $diff_id = pht('Diff %d', $d_id); 111 + } 112 + 113 + $reviewer = $handles[$inline->getAuthorPHID()]->renderLink(); 114 + $now = PhabricatorTime::getNow(); 115 + $then = $inline->getDateModified(); 116 + $datetime = phutil_format_relative_time($now - $then); 117 + 118 + $comment_href = $revision->getURI().'#inline-'.$inline->getID(); 119 + $comment = phutil_tag( 120 + 'a', 121 + array( 122 + 'href' => $comment_href, 123 + ), 124 + $inline->getContent()); 125 + 126 + $state = $inline->getFixedState(); 127 + if ($state == PhabricatorInlineCommentInterface::STATE_DONE) { 128 + $status_icons[] = id(new PHUIIconView()) 129 + ->setIcon('fa-check green') 130 + ->addClass('mmr'); 131 + } else if ($inline->getReplyToCommentPHID() && 132 + $inline->getAuthorPHID() == $revision->getAuthorPHID()) { 133 + $status_icons[] = id(new PHUIIconView()) 134 + ->setIcon('fa-commenting-o blue') 135 + ->addClass('mmr'); 136 + } else { 137 + $status_icons[] = id(new PHUIIconView()) 138 + ->setIcon('fa-circle-o grey') 139 + ->addClass('mmr'); 140 + } 141 + 142 + 143 + if ($inline->getReplyToCommentPHID()) { 144 + $reply_icon = id(new PHUIIconView()) 145 + ->setIcon('fa-reply mmr darkgrey'); 146 + $comment = array($reply_icon, $comment); 147 + } 148 + 149 + $rows[] = array( 150 + $diff_id, 151 + $status_icons, 152 + $reviewer, 153 + AphrontTableView::renderSingleDisplayLine($comment), 154 + $datetime, 155 + ); 156 + } 157 + 158 + $table = new AphrontTableView($rows); 159 + $table->setHeaders( 160 + array( 161 + pht('Diff'), 162 + pht('Status'), 163 + pht('Reviewer'), 164 + pht('Comment'), 165 + pht('Created'), 166 + )); 167 + $table->setColumnClasses( 168 + array( 169 + '', 170 + '', 171 + '', 172 + 'wide', 173 + 'right', 174 + )); 175 + $table->setColumnVisibility( 176 + array( 177 + true, 178 + true, 179 + true, 180 + true, 181 + true, 182 + )); 183 + 184 + return id(new PHUIObjectBoxView()) 185 + ->setHeaderText(pht('Inline Comments')) 186 + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 187 + ->setTable($table); 188 + } 189 + 190 + }
+6
src/applications/differential/controller/DifferentialRevisionViewController.php
··· 576 576 577 577 $curtain->addAction( 578 578 id(new PhabricatorActionView()) 579 + ->setIcon('fa-indent') 580 + ->setHref("/differential/revision/inlines/{$revision_id}/") 581 + ->setName(pht('List Inline Comments'))); 582 + 583 + $curtain->addAction( 584 + id(new PhabricatorActionView()) 579 585 ->setIcon('fa-upload') 580 586 ->setHref("/differential/revision/update/{$revision_id}/") 581 587 ->setName(pht('Update Diff'))
+2 -63
src/applications/differential/parser/DifferentialChangesetParser.php
··· 1045 1045 } 1046 1046 } 1047 1047 1048 - $this->comments = $this->reorderAndThreadComments($this->comments); 1048 + $this->comments = id(new PHUIDiffInlineThreader()) 1049 + ->reorderAndThreadCommments($this->comments); 1049 1050 1050 1051 foreach ($this->comments as $comment) { 1051 1052 $final = $comment->getLineNumber() + ··· 1615 1616 } 1616 1617 1617 1618 return array($old_back, $new_back); 1618 - } 1619 - 1620 - private function reorderAndThreadComments(array $comments) { 1621 - $comments = msort($comments, 'getID'); 1622 - 1623 - // Build an empty map of all the comments we actually have. If a comment 1624 - // is a reply but the parent has gone missing, we don't want it to vanish 1625 - // completely. 1626 - $comment_phids = mpull($comments, 'getPHID'); 1627 - $replies = array_fill_keys($comment_phids, array()); 1628 - 1629 - // Now, remove all comments which are replies, leaving only the top-level 1630 - // comments. 1631 - foreach ($comments as $key => $comment) { 1632 - $reply_phid = $comment->getReplyToCommentPHID(); 1633 - if (isset($replies[$reply_phid])) { 1634 - $replies[$reply_phid][] = $comment; 1635 - unset($comments[$key]); 1636 - } 1637 - } 1638 - 1639 - // For each top level comment, add the comment, then add any replies 1640 - // to it. Do this recursively so threads are shown in threaded order. 1641 - $results = array(); 1642 - foreach ($comments as $comment) { 1643 - $results[] = $comment; 1644 - $phid = $comment->getPHID(); 1645 - $descendants = $this->getInlineReplies($replies, $phid, 1); 1646 - foreach ($descendants as $descendant) { 1647 - $results[] = $descendant; 1648 - } 1649 - } 1650 - 1651 - // If we have anything left, they were cyclic references. Just dump 1652 - // them in a the end. This should be impossible, but users are very 1653 - // creative. 1654 - foreach ($replies as $phid => $comments) { 1655 - foreach ($comments as $comment) { 1656 - $results[] = $comment; 1657 - } 1658 - } 1659 - 1660 - return $results; 1661 - } 1662 - 1663 - private function getInlineReplies(array &$replies, $phid, $depth) { 1664 - $comments = idx($replies, $phid, array()); 1665 - unset($replies[$phid]); 1666 - 1667 - $results = array(); 1668 - foreach ($comments as $comment) { 1669 - $results[] = $comment; 1670 - $descendants = $this->getInlineReplies( 1671 - $replies, 1672 - $comment->getPHID(), 1673 - $depth + 1); 1674 - foreach ($descendants as $descendant) { 1675 - $results[] = $descendant; 1676 - } 1677 - } 1678 - 1679 - return $results; 1680 1619 } 1681 1620 1682 1621 private function getOffset(array $map, $line) {
+7
src/applications/differential/storage/DifferentialInlineComment.php
··· 255 255 return $this; 256 256 } 257 257 258 + public function getDateModified() { 259 + return $this->proxy->getDateModified(); 260 + } 261 + 262 + public function getDateCreated() { 263 + return $this->proxy->getDateCreated(); 264 + } 258 265 259 266 /* -( PhabricatorMarkupInterface Implementation )-------------------------- */ 260 267
+3
src/infrastructure/diff/interface/PhabricatorInlineCommentInterface.php
··· 60 60 public function supportsHiding(); 61 61 public function isHidden(); 62 62 63 + public function getDateModified(); 64 + public function getDateCreated(); 65 + 63 66 }
+66
src/infrastructure/diff/view/PHUIDiffInlineThreader.php
··· 1 + <?php 2 + 3 + final class PHUIDiffInlineThreader extends Phobject { 4 + 5 + public function reorderAndThreadCommments(array $comments) { 6 + $comments = msort($comments, 'getID'); 7 + 8 + // Build an empty map of all the comments we actually have. If a comment 9 + // is a reply but the parent has gone missing, we don't want it to vanish 10 + // completely. 11 + $comment_phids = mpull($comments, 'getPHID'); 12 + $replies = array_fill_keys($comment_phids, array()); 13 + 14 + // Now, remove all comments which are replies, leaving only the top-level 15 + // comments. 16 + foreach ($comments as $key => $comment) { 17 + $reply_phid = $comment->getReplyToCommentPHID(); 18 + if (isset($replies[$reply_phid])) { 19 + $replies[$reply_phid][] = $comment; 20 + unset($comments[$key]); 21 + } 22 + } 23 + 24 + // For each top level comment, add the comment, then add any replies 25 + // to it. Do this recursively so threads are shown in threaded order. 26 + $results = array(); 27 + foreach ($comments as $comment) { 28 + $results[] = $comment; 29 + $phid = $comment->getPHID(); 30 + $descendants = $this->getInlineReplies($replies, $phid, 1); 31 + foreach ($descendants as $descendant) { 32 + $results[] = $descendant; 33 + } 34 + } 35 + 36 + // If we have anything left, they were cyclic references. Just dump 37 + // them in a the end. This should be impossible, but users are very 38 + // creative. 39 + foreach ($replies as $phid => $comments) { 40 + foreach ($comments as $comment) { 41 + $results[] = $comment; 42 + } 43 + } 44 + 45 + return $results; 46 + } 47 + 48 + private function getInlineReplies(array &$replies, $phid, $depth) { 49 + $comments = idx($replies, $phid, array()); 50 + unset($replies[$phid]); 51 + 52 + $results = array(); 53 + foreach ($comments as $comment) { 54 + $results[] = $comment; 55 + $descendants = $this->getInlineReplies( 56 + $replies, 57 + $comment->getPHID(), 58 + $depth + 1); 59 + foreach ($descendants as $descendant) { 60 + $results[] = $descendant; 61 + } 62 + } 63 + 64 + return $results; 65 + } 66 + }