@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.

Allow comment actions to be grouped; group Differential "Review" and "Revision" actions

Summary:
Ref T11114. Differential has more actions than it once did, and may have further actions in the future.

Make this dropdown a little easier to parse by grouping similar types of actions, like "Accept" and "Reject".

(The action order still needs to be tweaked a bit.)

Test Plan: {F2274526}

Reviewers: chad

Reviewed By: chad

Subscribers: eadler

Maniphest Tasks: T11114

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

+262 -122
+7 -3
src/__phutil_library_map__.php
··· 557 557 'DifferentialRevisionRequiredActionResultBucket' => 'applications/differential/query/DifferentialRevisionRequiredActionResultBucket.php', 558 558 'DifferentialRevisionResignTransaction' => 'applications/differential/xaction/DifferentialRevisionResignTransaction.php', 559 559 'DifferentialRevisionResultBucket' => 'applications/differential/query/DifferentialRevisionResultBucket.php', 560 + 'DifferentialRevisionReviewTransaction' => 'applications/differential/xaction/DifferentialRevisionReviewTransaction.php', 560 561 'DifferentialRevisionReviewersHeraldField' => 'applications/differential/herald/DifferentialRevisionReviewersHeraldField.php', 561 562 'DifferentialRevisionReviewersTransaction' => 'applications/differential/xaction/DifferentialRevisionReviewersTransaction.php', 562 563 'DifferentialRevisionSearchConduitAPIMethod' => 'applications/differential/conduit/DifferentialRevisionSearchConduitAPIMethod.php', ··· 2554 2555 'PhabricatorEditEngineAPIMethod' => 'applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php', 2555 2556 'PhabricatorEditEngineColumnsCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineColumnsCommentAction.php', 2556 2557 'PhabricatorEditEngineCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineCommentAction.php', 2558 + 'PhabricatorEditEngineCommentActionGroup' => 'applications/transactions/commentaction/PhabricatorEditEngineCommentActionGroup.php', 2557 2559 'PhabricatorEditEngineConfiguration' => 'applications/transactions/storage/PhabricatorEditEngineConfiguration.php', 2558 2560 'PhabricatorEditEngineConfigurationDefaultCreateController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationDefaultCreateController.php', 2559 2561 'PhabricatorEditEngineConfigurationDefaultsController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationDefaultsController.php', ··· 5183 5185 'PhabricatorConduitResultInterface', 5184 5186 ), 5185 5187 'DifferentialRevisionAbandonTransaction' => 'DifferentialRevisionActionTransaction', 5186 - 'DifferentialRevisionAcceptTransaction' => 'DifferentialRevisionActionTransaction', 5188 + 'DifferentialRevisionAcceptTransaction' => 'DifferentialRevisionReviewTransaction', 5187 5189 'DifferentialRevisionActionTransaction' => 'DifferentialRevisionTransactionType', 5188 5190 'DifferentialRevisionAffectedFilesHeraldField' => 'DifferentialRevisionHeraldField', 5189 5191 'DifferentialRevisionAuthorHeraldField' => 'DifferentialRevisionHeraldField', ··· 5223 5225 'DifferentialRevisionPlanChangesTransaction' => 'DifferentialRevisionActionTransaction', 5224 5226 'DifferentialRevisionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 5225 5227 'DifferentialRevisionReclaimTransaction' => 'DifferentialRevisionActionTransaction', 5226 - 'DifferentialRevisionRejectTransaction' => 'DifferentialRevisionActionTransaction', 5228 + 'DifferentialRevisionRejectTransaction' => 'DifferentialRevisionReviewTransaction', 5227 5229 'DifferentialRevisionRelationship' => 'PhabricatorObjectRelationship', 5228 5230 'DifferentialRevisionRelationshipSource' => 'PhabricatorObjectRelationshipSource', 5229 5231 'DifferentialRevisionReopenTransaction' => 'DifferentialRevisionActionTransaction', ··· 5232 5234 'DifferentialRevisionRepositoryTransaction' => 'DifferentialRevisionTransactionType', 5233 5235 'DifferentialRevisionRequestReviewTransaction' => 'DifferentialRevisionActionTransaction', 5234 5236 'DifferentialRevisionRequiredActionResultBucket' => 'DifferentialRevisionResultBucket', 5235 - 'DifferentialRevisionResignTransaction' => 'DifferentialRevisionActionTransaction', 5237 + 'DifferentialRevisionResignTransaction' => 'DifferentialRevisionReviewTransaction', 5236 5238 'DifferentialRevisionResultBucket' => 'PhabricatorSearchResultBucket', 5239 + 'DifferentialRevisionReviewTransaction' => 'DifferentialRevisionActionTransaction', 5237 5240 'DifferentialRevisionReviewersHeraldField' => 'DifferentialRevisionHeraldField', 5238 5241 'DifferentialRevisionReviewersTransaction' => 'DifferentialRevisionTransactionType', 5239 5242 'DifferentialRevisionSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', ··· 7536 7539 'PhabricatorEditEngineAPIMethod' => 'ConduitAPIMethod', 7537 7540 'PhabricatorEditEngineColumnsCommentAction' => 'PhabricatorEditEngineCommentAction', 7538 7541 'PhabricatorEditEngineCommentAction' => 'Phobject', 7542 + 'PhabricatorEditEngineCommentActionGroup' => 'Phobject', 7539 7543 'PhabricatorEditEngineConfiguration' => array( 7540 7544 'PhabricatorSearchDAO', 7541 7545 'PhabricatorApplicationTransactionInterface',
+14
src/applications/differential/editor/DifferentialRevisionEditEngine.php
··· 9 9 10 10 const KEY_UPDATE = 'update'; 11 11 12 + const ACTIONGROUP_REVIEW = 'review'; 13 + const ACTIONGROUP_REVISION = 'revision'; 14 + 12 15 public function getEngineName() { 13 16 return pht('Revisions'); 14 17 } ··· 85 88 86 89 public function getDiff() { 87 90 return $this->diff; 91 + } 92 + 93 + protected function newCommentActionGroups() { 94 + return array( 95 + id(new PhabricatorEditEngineCommentActionGroup()) 96 + ->setKey(self::ACTIONGROUP_REVIEW) 97 + ->setLabel(pht('Review Actions')), 98 + id(new PhabricatorEditEngineCommentActionGroup()) 99 + ->setKey(self::ACTIONGROUP_REVISION) 100 + ->setLabel(pht('Revision Actions')), 101 + ); 88 102 } 89 103 90 104 protected function buildCustomEditFields($object) {
+1 -1
src/applications/differential/xaction/DifferentialRevisionAcceptTransaction.php
··· 1 1 <?php 2 2 3 3 final class DifferentialRevisionAcceptTransaction 4 - extends DifferentialRevisionActionTransaction { 4 + extends DifferentialRevisionReviewTransaction { 5 5 6 6 const TRANSACTIONTYPE = 'differential.revision.accept'; 7 7 const ACTIONKEY = 'accept';
+7 -110
src/applications/differential/xaction/DifferentialRevisionActionTransaction.php
··· 19 19 abstract protected function validateAction($object, PhabricatorUser $viewer); 20 20 abstract protected function getRevisionActionLabel(); 21 21 22 + protected function getRevisionActionGroupKey() { 23 + return DifferentialRevisionEditEngine::ACTIONGROUP_REVISION; 24 + } 25 + 22 26 protected function getRevisionActionDescription() { 23 27 return null; 24 28 } ··· 41 45 return ($viewer->getPHID() === $revision->getAuthorPHID()); 42 46 } 43 47 44 - protected function isViewerAnyReviewer( 45 - DifferentialRevision $revision, 46 - PhabricatorUser $viewer) { 47 - return ($this->getViewerReviewerStatus($revision, $viewer) !== null); 48 - } 49 - 50 - protected function isViewerAcceptingReviewer( 51 - DifferentialRevision $revision, 52 - PhabricatorUser $viewer) { 53 - return $this->isViewerReviewerStatusAmong( 54 - $revision, 55 - $viewer, 56 - array( 57 - DifferentialReviewerStatus::STATUS_ACCEPTED, 58 - )); 59 - } 60 - 61 - protected function isViewerRejectingReviewer( 62 - DifferentialRevision $revision, 63 - PhabricatorUser $viewer) { 64 - return $this->isViewerReviewerStatusAmong( 65 - $revision, 66 - $viewer, 67 - array( 68 - DifferentialReviewerStatus::STATUS_REJECTED, 69 - )); 70 - } 71 - 72 - protected function getViewerReviewerStatus( 73 - DifferentialRevision $revision, 74 - PhabricatorUser $viewer) { 75 - 76 - if (!$viewer->getPHID()) { 77 - return null; 78 - } 79 - 80 - foreach ($revision->getReviewerStatus() as $reviewer) { 81 - if ($reviewer->getReviewerPHID() != $viewer->getPHID()) { 82 - continue; 83 - } 84 - 85 - return $reviewer->getStatus(); 86 - } 87 - 88 - return null; 89 - } 90 - 91 - protected function isViewerReviewerStatusAmong( 92 - DifferentialRevision $revision, 93 - PhabricatorUser $viewer, 94 - array $status_list) { 95 - 96 - $status = $this->getViewerReviewerStatus($revision, $viewer); 97 - if ($status === null) { 98 - return false; 99 - } 100 - 101 - $status_map = array_fuse($status_list); 102 - return isset($status_map[$status]); 103 - } 104 - 105 - protected function applyReviewerEffect( 106 - DifferentialRevision $revision, 107 - PhabricatorUser $viewer, 108 - $value, 109 - $status) { 110 - 111 - $map = array(); 112 - 113 - // When you accept or reject, you may accept or reject on behalf of all 114 - // reviewers you have authority for. When you resign, you only affect 115 - // yourself. 116 - $with_authority = ($status != DifferentialReviewerStatus::STATUS_RESIGNED); 117 - if ($with_authority) { 118 - foreach ($revision->getReviewerStatus() as $reviewer) { 119 - if ($reviewer->hasAuthority($viewer)) { 120 - $map[$reviewer->getReviewerPHID()] = $status; 121 - } 122 - } 123 - } 124 - 125 - // In all cases, you affect yourself. 126 - $map[$viewer->getPHID()] = $status; 127 - 128 - // Convert reviewer statuses into edge data. 129 - foreach ($map as $reviewer_phid => $reviewer_status) { 130 - $map[$reviewer_phid] = array( 131 - 'data' => array( 132 - 'status' => $reviewer_status, 133 - ), 134 - ); 135 - } 136 - 137 - $src_phid = $revision->getPHID(); 138 - $edge_type = DifferentialRevisionHasReviewerEdgeType::EDGECONST; 139 - 140 - $editor = new PhabricatorEdgeEditor(); 141 - foreach ($map as $dst_phid => $edge_data) { 142 - if ($status == DifferentialReviewerStatus::STATUS_RESIGNED) { 143 - // TODO: For now, we just remove these reviewers. In the future, we will 144 - // store resignations explicitly. 145 - $editor->removeEdge($src_phid, $edge_type, $dst_phid); 146 - } else { 147 - $editor->addEdge($src_phid, $edge_type, $dst_phid, $edge_data); 148 - } 149 - } 150 - 151 - $editor->save(); 152 - } 153 - 154 48 public function newEditField( 155 49 DifferentialRevision $revision, 156 50 PhabricatorUser $viewer) { ··· 167 61 168 62 $description = $this->getRevisionActionDescription(); 169 63 $field->setActionDescription($description); 64 + 65 + $group_key = $this->getRevisionActionGroupKey(); 66 + $field->setCommentActionGroupKey($group_key); 170 67 } 171 68 } 172 69
+1 -1
src/applications/differential/xaction/DifferentialRevisionRejectTransaction.php
··· 1 1 <?php 2 2 3 3 final class DifferentialRevisionRejectTransaction 4 - extends DifferentialRevisionActionTransaction { 4 + extends DifferentialRevisionReviewTransaction { 5 5 6 6 const TRANSACTIONTYPE = 'differential.revision.reject'; 7 7 const ACTIONKEY = 'reject';
+1 -1
src/applications/differential/xaction/DifferentialRevisionResignTransaction.php
··· 1 1 <?php 2 2 3 3 final class DifferentialRevisionResignTransaction 4 - extends DifferentialRevisionActionTransaction { 4 + extends DifferentialRevisionReviewTransaction { 5 5 6 6 const TRANSACTIONTYPE = 'differential.revision.resign'; 7 7 const ACTIONKEY = 'resign';
+120
src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php
··· 1 + <?php 2 + 3 + abstract class DifferentialRevisionReviewTransaction 4 + extends DifferentialRevisionActionTransaction { 5 + 6 + protected function getRevisionActionGroupKey() { 7 + return DifferentialRevisionEditEngine::ACTIONGROUP_REVIEW; 8 + } 9 + 10 + protected function isViewerAnyReviewer( 11 + DifferentialRevision $revision, 12 + PhabricatorUser $viewer) { 13 + return ($this->getViewerReviewerStatus($revision, $viewer) !== null); 14 + } 15 + 16 + protected function isViewerAcceptingReviewer( 17 + DifferentialRevision $revision, 18 + PhabricatorUser $viewer) { 19 + return $this->isViewerReviewerStatusAmong( 20 + $revision, 21 + $viewer, 22 + array( 23 + DifferentialReviewerStatus::STATUS_ACCEPTED, 24 + )); 25 + } 26 + 27 + protected function isViewerRejectingReviewer( 28 + DifferentialRevision $revision, 29 + PhabricatorUser $viewer) { 30 + return $this->isViewerReviewerStatusAmong( 31 + $revision, 32 + $viewer, 33 + array( 34 + DifferentialReviewerStatus::STATUS_REJECTED, 35 + )); 36 + } 37 + 38 + protected function getViewerReviewerStatus( 39 + DifferentialRevision $revision, 40 + PhabricatorUser $viewer) { 41 + 42 + if (!$viewer->getPHID()) { 43 + return null; 44 + } 45 + 46 + foreach ($revision->getReviewerStatus() as $reviewer) { 47 + if ($reviewer->getReviewerPHID() != $viewer->getPHID()) { 48 + continue; 49 + } 50 + 51 + return $reviewer->getStatus(); 52 + } 53 + 54 + return null; 55 + } 56 + 57 + protected function isViewerReviewerStatusAmong( 58 + DifferentialRevision $revision, 59 + PhabricatorUser $viewer, 60 + array $status_list) { 61 + 62 + $status = $this->getViewerReviewerStatus($revision, $viewer); 63 + if ($status === null) { 64 + return false; 65 + } 66 + 67 + $status_map = array_fuse($status_list); 68 + return isset($status_map[$status]); 69 + } 70 + 71 + protected function applyReviewerEffect( 72 + DifferentialRevision $revision, 73 + PhabricatorUser $viewer, 74 + $value, 75 + $status) { 76 + 77 + $map = array(); 78 + 79 + // When you accept or reject, you may accept or reject on behalf of all 80 + // reviewers you have authority for. When you resign, you only affect 81 + // yourself. 82 + $with_authority = ($status != DifferentialReviewerStatus::STATUS_RESIGNED); 83 + if ($with_authority) { 84 + foreach ($revision->getReviewerStatus() as $reviewer) { 85 + if ($reviewer->hasAuthority($viewer)) { 86 + $map[$reviewer->getReviewerPHID()] = $status; 87 + } 88 + } 89 + } 90 + 91 + // In all cases, you affect yourself. 92 + $map[$viewer->getPHID()] = $status; 93 + 94 + // Convert reviewer statuses into edge data. 95 + foreach ($map as $reviewer_phid => $reviewer_status) { 96 + $map[$reviewer_phid] = array( 97 + 'data' => array( 98 + 'status' => $reviewer_status, 99 + ), 100 + ); 101 + } 102 + 103 + $src_phid = $revision->getPHID(); 104 + $edge_type = DifferentialRevisionHasReviewerEdgeType::EDGECONST; 105 + 106 + $editor = new PhabricatorEdgeEditor(); 107 + foreach ($map as $dst_phid => $edge_data) { 108 + if ($status == DifferentialReviewerStatus::STATUS_RESIGNED) { 109 + // TODO: For now, we just remove these reviewers. In the future, we will 110 + // store resignations explicitly. 111 + $editor->removeEdge($src_phid, $edge_type, $dst_phid); 112 + } else { 113 + $editor->addEdge($src_phid, $edge_type, $dst_phid, $edge_data); 114 + } 115 + } 116 + 117 + $editor->save(); 118 + } 119 + 120 + }
+10
src/applications/transactions/commentaction/PhabricatorEditEngineCommentAction.php
··· 7 7 private $value; 8 8 private $initialValue; 9 9 private $order; 10 + private $groupKey; 10 11 11 12 abstract public function getPHUIXControlType(); 12 13 abstract public function getPHUIXControlSpecification(); ··· 18 19 19 20 public function getKey() { 20 21 return $this->key; 22 + } 23 + 24 + public function setGroupKey($group_key) { 25 + $this->groupKey = $group_key; 26 + return $this; 27 + } 28 + 29 + public function getGroupKey() { 30 + return $this->groupKey; 21 31 } 22 32 23 33 public function setLabel($label) {
+27
src/applications/transactions/commentaction/PhabricatorEditEngineCommentActionGroup.php
··· 1 + <?php 2 + 3 + final class PhabricatorEditEngineCommentActionGroup 4 + extends Phobject { 5 + 6 + private $key; 7 + private $label; 8 + 9 + public function setKey($key) { 10 + $this->key = $key; 11 + return $this; 12 + } 13 + 14 + public function getKey() { 15 + return $this->key; 16 + } 17 + 18 + public function setLabel($label) { 19 + $this->label = $label; 20 + return $this; 21 + } 22 + 23 + public function getLabel() { 24 + return $this->label; 25 + } 26 + 27 + }
+7
src/applications/transactions/editengine/PhabricatorEditEngine.php
··· 1549 1549 1550 1550 $view->setCommentActions($comment_actions); 1551 1551 1552 + $comment_groups = $this->newCommentActionGroups(); 1553 + $view->setCommentActionGroups($comment_groups); 1554 + 1552 1555 return $view; 1553 1556 } 1554 1557 ··· 2155 2158 $controller = $this->getController(); 2156 2159 $request = $controller->getRequest(); 2157 2160 return $request->getURIData('editAction'); 2161 + } 2162 + 2163 + protected function newCommentActionGroups() { 2164 + return array(); 2158 2165 } 2159 2166 2160 2167
+12 -1
src/applications/transactions/editfield/PhabricatorEditField.php
··· 25 25 26 26 private $commentActionLabel; 27 27 private $commentActionValue; 28 + private $commentActionGroupKey; 28 29 private $commentActionOrder = 1000; 29 30 private $hasCommentActionValue; 30 31 ··· 243 244 244 245 public function getCommentActionLabel() { 245 246 return $this->commentActionLabel; 247 + } 248 + 249 + public function setCommentActionGroupKey($key) { 250 + $this->commentActionGroupKey = $key; 251 + return $this; 252 + } 253 + 254 + public function getCommentActionGroupKey() { 255 + return $this->commentActionGroupKey; 246 256 } 247 257 248 258 public function setCommentActionOrder($order) { ··· 719 729 ->setKey($this->getKey()) 720 730 ->setLabel($label) 721 731 ->setValue($this->getValueForCommentAction($value)) 722 - ->setOrder($this->getCommentActionOrder()); 732 + ->setOrder($this->getCommentActionOrder()) 733 + ->setGroupKey($this->getCommentActionGroupKey()); 723 734 724 735 return $action; 725 736 }
+55 -5
src/applications/transactions/view/PhabricatorApplicationTransactionCommentView.php
··· 24 24 private $currentVersion; 25 25 private $versionedDraft; 26 26 private $commentActions; 27 + private $commentActionGroups = array(); 27 28 private $transactionTimeline; 28 29 29 30 public function setObjectPHID($object_phid) { ··· 116 117 117 118 public function getCommentActions() { 118 119 return $this->commentActions; 120 + } 121 + 122 + public function setCommentActionGroups(array $groups) { 123 + assert_instances_of($groups, 'PhabricatorEditEngineCommentActionGroup'); 124 + $this->commentActionGroups = $groups; 125 + return $this; 126 + } 127 + 128 + public function getCommentActionGroups() { 129 + return $this->commentActionGroups; 119 130 } 120 131 121 132 public function setNoPermission($no_permission) { ··· 279 290 'type' => $comment_action->getPHUIXControlType(), 280 291 'spec' => $comment_action->getPHUIXControlSpecification(), 281 292 'initialValue' => $comment_action->getInitialValue(), 293 + 'groupKey' => $comment_action->getGroupKey(), 282 294 ); 283 295 284 296 $type_map[$key] = $comment_action; 285 297 } 286 298 287 - $options = array(); 288 - $options['+'] = pht('Add Action...'); 289 - foreach ($action_map as $key => $item) { 290 - $options[$key] = $item['label']; 291 - } 299 + $options = $this->newCommentActionOptions($action_map); 292 300 293 301 $action_id = celerity_generate_unique_node_id(); 294 302 $input_id = celerity_generate_unique_node_id(); ··· 422 430 $this->commentID = celerity_generate_unique_node_id(); 423 431 } 424 432 return $this->commentID; 433 + } 434 + 435 + private function newCommentActionOptions(array $action_map) { 436 + $options = array(); 437 + $options['+'] = pht('Add Action...'); 438 + 439 + // Merge options into groups. 440 + $groups = array(); 441 + foreach ($action_map as $key => $item) { 442 + $group_key = $item['groupKey']; 443 + if (!isset($groups[$group_key])) { 444 + $groups[$group_key] = array(); 445 + } 446 + $groups[$group_key][$key] = $item; 447 + } 448 + 449 + $group_specs = $this->getCommentActionGroups(); 450 + $group_labels = mpull($group_specs, 'getLabel', 'getKey'); 451 + 452 + // Reorder groups to put them in the same order as the recognized 453 + // group definitions. 454 + $groups = array_select_keys($groups, array_keys($group_labels)) + $groups; 455 + 456 + // Move options with no group to the end. 457 + $default_group = idx($groups, ''); 458 + if ($default_group) { 459 + unset($groups['']); 460 + $groups[''] = $default_group; 461 + } 462 + 463 + foreach ($groups as $group_key => $group_items) { 464 + if (strlen($group_key)) { 465 + $group_label = idx($group_labels, $group_key, $group_key); 466 + $options[$group_label] = ipull($group_items, 'label'); 467 + } else { 468 + foreach ($group_items as $key => $item) { 469 + $options[$key] = $item['label']; 470 + } 471 + } 472 + } 473 + 474 + return $options; 425 475 } 426 476 427 477 }