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

Improve UX and messaging for certain errors when landing revisions

Summary:
Ref T9994.

- Allow errors to be dismissed.
- Tailor messaging for closed/abandoned revisions.
- Reduce scare messaging on land dialog, since it's not really that scary anymore.

Test Plan:
- Dismissed errors.
- Hit new warnings.
- Wasn't as scared when landing.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T9994

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

+137 -17
+2
resources/sql/autopatches/20151226.reop.1.sql
··· 1 + ALTER TABLE {$NAMESPACE}_drydock.drydock_repositoryoperation 2 + ADD isDismissed BOOL NOT NULL;
+2
src/__phutil_library_map__.php
··· 911 911 'DrydockObjectAuthorizationView' => 'applications/drydock/view/DrydockObjectAuthorizationView.php', 912 912 'DrydockQuery' => 'applications/drydock/query/DrydockQuery.php', 913 913 'DrydockRepositoryOperation' => 'applications/drydock/storage/DrydockRepositoryOperation.php', 914 + 'DrydockRepositoryOperationDismissController' => 'applications/drydock/controller/DrydockRepositoryOperationDismissController.php', 914 915 'DrydockRepositoryOperationListController' => 'applications/drydock/controller/DrydockRepositoryOperationListController.php', 915 916 'DrydockRepositoryOperationPHIDType' => 'applications/drydock/phid/DrydockRepositoryOperationPHIDType.php', 916 917 'DrydockRepositoryOperationQuery' => 'applications/drydock/query/DrydockRepositoryOperationQuery.php', ··· 4900 4901 'DrydockDAO', 4901 4902 'PhabricatorPolicyInterface', 4902 4903 ), 4904 + 'DrydockRepositoryOperationDismissController' => 'DrydockController', 4903 4905 'DrydockRepositoryOperationListController' => 'DrydockController', 4904 4906 'DrydockRepositoryOperationPHIDType' => 'PhabricatorPHIDType', 4905 4907 'DrydockRepositoryOperationQuery' => 'DrydockQuery',
+3 -8
src/applications/differential/controller/DifferentialRevisionOperationController.php
··· 94 94 ->setUser($viewer) 95 95 ->appendRemarkupInstructions( 96 96 pht( 97 - 'In theory, this will do approximately what `arc land` would do. '. 98 - 'In practice, you will have a riveting adventure instead.')) 97 + '(NOTE) This feature is new and experimental.')) 99 98 ->appendControl( 100 99 id(new AphrontFormTokenizerControl()) 101 100 ->setLabel(pht('Onto Branch')) ··· 103 102 ->setLimit(1) 104 103 ->setError($e_ref) 105 104 ->setValue($v_ref) 106 - ->setDatasource($ref_datasource)) 107 - ->appendRemarkupInstructions( 108 - pht( 109 - '(WARNING) THIS FEATURE IS EXPERIMENTAL AND DANGEROUS! USE IT AT '. 110 - 'YOUR OWN RISK!')); 105 + ->setDatasource($ref_datasource)); 111 106 112 107 return $this->newDialog() 113 108 ->setWidth(AphrontDialogView::WIDTH_FORM) ··· 115 110 ->setErrors($errors) 116 111 ->appendForm($form) 117 112 ->addCancelButton($detail_uri) 118 - ->addSubmitButton(pht('Mutate Repository Unpredictably')); 113 + ->addSubmitButton(pht('Land Revision')); 119 114 } 120 115 121 116 private function newRefQuery(PhabricatorRepository $repository) {
+1
src/applications/differential/controller/DifferentialRevisionViewController.php
··· 1047 1047 $operations = id(new DrydockRepositoryOperationQuery()) 1048 1048 ->setViewer($viewer) 1049 1049 ->withObjectPHIDs(array($revision->getPHID())) 1050 + ->withIsDismissed(false) 1050 1051 ->withOperationTypes( 1051 1052 array( 1052 1053 DrydockLandRepositoryOperation::OPCONST,
+1
src/applications/drydock/application/PhabricatorDrydockApplication.php
··· 96 96 '(?P<id>[1-9]\d*)/' => array( 97 97 '' => 'DrydockRepositoryOperationViewController', 98 98 'status/' => 'DrydockRepositoryOperationStatusController', 99 + 'dismiss/' => 'DrydockRepositoryOperationDismissController', 99 100 ), 100 101 ), 101 102 ),
+56
src/applications/drydock/controller/DrydockRepositoryOperationDismissController.php
··· 1 + <?php 2 + 3 + final class DrydockRepositoryOperationDismissController 4 + extends DrydockController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $request->getViewer(); 8 + $id = $request->getURIData('id'); 9 + 10 + $operation = id(new DrydockRepositoryOperationQuery()) 11 + ->setViewer($viewer) 12 + ->withIDs(array($id)) 13 + ->requireCapabilities( 14 + array( 15 + PhabricatorPolicyCapability::CAN_VIEW, 16 + PhabricatorPolicyCapability::CAN_EDIT, 17 + )) 18 + ->executeOne(); 19 + if (!$operation) { 20 + return new Aphront404Response(); 21 + } 22 + 23 + $object_phid = $operation->getObjectPHID(); 24 + $handles = $viewer->loadHandles(array($object_phid)); 25 + $done_uri = $handles[$object_phid]->getURI(); 26 + 27 + if ($operation->getIsDismissed()) { 28 + return $this->newDialog() 29 + ->setTitle(pht('Already Dismissed')) 30 + ->appendParagraph( 31 + pht( 32 + 'This operation has already been dismissed, and can not be '. 33 + 'dismissed any further.')) 34 + ->addCancelButton($done_uri); 35 + } 36 + 37 + 38 + if ($request->isFormPost()) { 39 + $operation 40 + ->setIsDismissed(1) 41 + ->save(); 42 + 43 + return id(new AphrontRedirectResponse())->setURI($done_uri); 44 + } 45 + 46 + return $this->newDialog() 47 + ->setTitle(pht('Dismiss Operation')) 48 + ->appendParagraph( 49 + pht( 50 + 'Dismiss this operation? It will no longer be shown, but logs '. 51 + 'can be found in Drydock.')) 52 + ->addSubmitButton(pht('Dismiss')) 53 + ->addCancelButton($done_uri); 54 + } 55 + 56 + }
+23 -6
src/applications/drydock/operation/DrydockLandRepositoryOperation.php
··· 235 235 236 236 $status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED; 237 237 if ($revision->getStatus() != $status_accepted) { 238 - return array( 239 - 'title' => pht('Revision Not Accepted'), 240 - 'body' => pht( 241 - 'This revision is still under review. Only revisions which have '. 242 - 'been accepted may land.'), 243 - ); 238 + switch ($revision->getStatus()) { 239 + case ArcanistDifferentialRevisionStatus::CLOSED: 240 + return array( 241 + 'title' => pht('Revision Closed'), 242 + 'body' => pht( 243 + 'This revision has already been closed. Only open, accepted '. 244 + 'revisions may land.'), 245 + ); 246 + case ArcanistDifferentialRevisionStatus::ABANDONED: 247 + return array( 248 + 'title' => pht('Revision Abandoned'), 249 + 'body' => pht( 250 + 'This revision has been abandoned. Only accepted revisions '. 251 + 'may land.'), 252 + ); 253 + default: 254 + return array( 255 + 'title' => pht('Revision Not Accepted'), 256 + 'body' => pht( 257 + 'This revision is still under review. Only revisions which '. 258 + 'have been accepted may land.'), 259 + ); 260 + } 244 261 } 245 262 246 263 // Check for other operations. Eventually this should probably be more
+13
src/applications/drydock/query/DrydockRepositoryOperationQuery.php
··· 8 8 private $repositoryPHIDs; 9 9 private $operationStates; 10 10 private $operationTypes; 11 + private $isDismissed; 11 12 12 13 public function withIDs(array $ids) { 13 14 $this->ids = $ids; ··· 36 37 37 38 public function withOperationTypes(array $types) { 38 39 $this->operationTypes = $types; 40 + return $this; 41 + } 42 + 43 + public function withIsDismissed($dismissed) { 44 + $this->isDismissed = $dismissed; 39 45 return $this; 40 46 } 41 47 ··· 150 156 $conn, 151 157 'operationType IN (%Ls)', 152 158 $this->operationTypes); 159 + } 160 + 161 + if ($this->isDismissed !== null) { 162 + $where[] = qsprintf( 163 + $conn, 164 + 'isDismissed = %d', 165 + (int)$this->isDismissed); 153 166 } 154 167 155 168 return $where;
+25 -3
src/applications/drydock/storage/DrydockRepositoryOperation.php
··· 20 20 protected $operationType; 21 21 protected $operationState; 22 22 protected $properties = array(); 23 + protected $isDismissed; 23 24 24 25 private $repository = self::ATTACHABLE; 25 26 private $object = self::ATTACHABLE; ··· 30 31 31 32 return id(new DrydockRepositoryOperation()) 32 33 ->setOperationState(self::STATE_WAIT) 33 - ->setOperationType($op->getOperationConstant()); 34 + ->setOperationType($op->getOperationConstant()) 35 + ->setIsDismissed(0); 34 36 } 35 37 36 38 protected function getConfiguration() { ··· 43 45 'repositoryTarget' => 'bytes', 44 46 'operationType' => 'text32', 45 47 'operationState' => 'text32', 48 + 'isDismissed' => 'bool', 46 49 ), 47 50 self::CONFIG_KEY_SCHEMA => array( 48 51 'key_object' => array( ··· 196 199 } 197 200 198 201 public function getPolicy($capability) { 199 - return $this->getRepository()->getPolicy($capability); 202 + $need_capability = $this->getRequiredRepositoryCapability($capability); 203 + 204 + return $this->getRepository() 205 + ->getPolicy($need_capability); 200 206 } 201 207 202 208 public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 203 - return $this->getRepository()->hasAutomaticCapability($capability, $viewer); 209 + $need_capability = $this->getRequiredRepositoryCapability($capability); 210 + 211 + return $this->getRepository() 212 + ->hasAutomaticCapability($need_capability, $viewer); 204 213 } 205 214 206 215 public function describeAutomaticCapability($capability) { ··· 208 217 'A repository operation inherits the policies of the repository it '. 209 218 'affects.'); 210 219 } 220 + 221 + private function getRequiredRepositoryCapability($capability) { 222 + // To edit a RepositoryOperation, require that the user be able to push 223 + // to the repository. 224 + 225 + $map = array( 226 + PhabricatorPolicyCapability::CAN_EDIT => 227 + DiffusionPushCapability::CAPABILITY, 228 + ); 229 + 230 + return idx($map, $capability, $capability); 231 + } 232 + 211 233 212 234 }
+11
src/applications/drydock/view/DrydockRepositoryOperationStatusView.php
··· 67 67 68 68 $item = id(new PHUIObjectItemView()) 69 69 ->setHref("/drydock/operation/{$id}/") 70 + ->setObjectName(pht('Operation %d', $id)) 70 71 ->setHeader($operation->getOperationDescription($viewer)) 71 72 ->setStatusIcon($icon, $name); 72 73 ··· 98 99 } else { 99 100 $item->addAttribute(pht('Operation encountered an error.')); 100 101 } 102 + 103 + $is_dismissed = $operation->getIsDismissed(); 104 + 105 + $item->addAction( 106 + id(new PHUIListItemView()) 107 + ->setName('Dismiss') 108 + ->setIcon('fa-times') 109 + ->setDisabled($is_dismissed) 110 + ->setWorkflow(true) 111 + ->setHref("/drydock/operation/{$id}/dismiss/")); 101 112 } 102 113 103 114 return id(new PHUIObjectItemListView())