1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-18 19:40:55 +01:00

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
This commit is contained in:
epriestley 2015-12-26 12:20:21 -08:00
parent 55373030df
commit 367955f3fd
10 changed files with 137 additions and 17 deletions

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_drydock.drydock_repositoryoperation
ADD isDismissed BOOL NOT NULL;

View file

@ -911,6 +911,7 @@ phutil_register_library_map(array(
'DrydockObjectAuthorizationView' => 'applications/drydock/view/DrydockObjectAuthorizationView.php',
'DrydockQuery' => 'applications/drydock/query/DrydockQuery.php',
'DrydockRepositoryOperation' => 'applications/drydock/storage/DrydockRepositoryOperation.php',
'DrydockRepositoryOperationDismissController' => 'applications/drydock/controller/DrydockRepositoryOperationDismissController.php',
'DrydockRepositoryOperationListController' => 'applications/drydock/controller/DrydockRepositoryOperationListController.php',
'DrydockRepositoryOperationPHIDType' => 'applications/drydock/phid/DrydockRepositoryOperationPHIDType.php',
'DrydockRepositoryOperationQuery' => 'applications/drydock/query/DrydockRepositoryOperationQuery.php',
@ -4900,6 +4901,7 @@ phutil_register_library_map(array(
'DrydockDAO',
'PhabricatorPolicyInterface',
),
'DrydockRepositoryOperationDismissController' => 'DrydockController',
'DrydockRepositoryOperationListController' => 'DrydockController',
'DrydockRepositoryOperationPHIDType' => 'PhabricatorPHIDType',
'DrydockRepositoryOperationQuery' => 'DrydockQuery',

View file

@ -94,8 +94,7 @@ final class DifferentialRevisionOperationController
->setUser($viewer)
->appendRemarkupInstructions(
pht(
'In theory, this will do approximately what `arc land` would do. '.
'In practice, you will have a riveting adventure instead.'))
'(NOTE) This feature is new and experimental.'))
->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Onto Branch'))
@ -103,11 +102,7 @@ final class DifferentialRevisionOperationController
->setLimit(1)
->setError($e_ref)
->setValue($v_ref)
->setDatasource($ref_datasource))
->appendRemarkupInstructions(
pht(
'(WARNING) THIS FEATURE IS EXPERIMENTAL AND DANGEROUS! USE IT AT '.
'YOUR OWN RISK!'));
->setDatasource($ref_datasource));
return $this->newDialog()
->setWidth(AphrontDialogView::WIDTH_FORM)
@ -115,7 +110,7 @@ final class DifferentialRevisionOperationController
->setErrors($errors)
->appendForm($form)
->addCancelButton($detail_uri)
->addSubmitButton(pht('Mutate Repository Unpredictably'));
->addSubmitButton(pht('Land Revision'));
}
private function newRefQuery(PhabricatorRepository $repository) {

View file

@ -1047,6 +1047,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
$operations = id(new DrydockRepositoryOperationQuery())
->setViewer($viewer)
->withObjectPHIDs(array($revision->getPHID()))
->withIsDismissed(false)
->withOperationTypes(
array(
DrydockLandRepositoryOperation::OPCONST,

View file

@ -96,6 +96,7 @@ final class PhabricatorDrydockApplication extends PhabricatorApplication {
'(?P<id>[1-9]\d*)/' => array(
'' => 'DrydockRepositoryOperationViewController',
'status/' => 'DrydockRepositoryOperationStatusController',
'dismiss/' => 'DrydockRepositoryOperationDismissController',
),
),
),

View file

@ -0,0 +1,56 @@
<?php
final class DrydockRepositoryOperationDismissController
extends DrydockController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$operation = id(new DrydockRepositoryOperationQuery())
->setViewer($viewer)
->withIDs(array($id))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$operation) {
return new Aphront404Response();
}
$object_phid = $operation->getObjectPHID();
$handles = $viewer->loadHandles(array($object_phid));
$done_uri = $handles[$object_phid]->getURI();
if ($operation->getIsDismissed()) {
return $this->newDialog()
->setTitle(pht('Already Dismissed'))
->appendParagraph(
pht(
'This operation has already been dismissed, and can not be '.
'dismissed any further.'))
->addCancelButton($done_uri);
}
if ($request->isFormPost()) {
$operation
->setIsDismissed(1)
->save();
return id(new AphrontRedirectResponse())->setURI($done_uri);
}
return $this->newDialog()
->setTitle(pht('Dismiss Operation'))
->appendParagraph(
pht(
'Dismiss this operation? It will no longer be shown, but logs '.
'can be found in Drydock.'))
->addSubmitButton(pht('Dismiss'))
->addCancelButton($done_uri);
}
}

View file

@ -235,12 +235,29 @@ final class DrydockLandRepositoryOperation
$status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED;
if ($revision->getStatus() != $status_accepted) {
return array(
'title' => pht('Revision Not Accepted'),
'body' => pht(
'This revision is still under review. Only revisions which have '.
'been accepted may land.'),
);
switch ($revision->getStatus()) {
case ArcanistDifferentialRevisionStatus::CLOSED:
return array(
'title' => pht('Revision Closed'),
'body' => pht(
'This revision has already been closed. Only open, accepted '.
'revisions may land.'),
);
case ArcanistDifferentialRevisionStatus::ABANDONED:
return array(
'title' => pht('Revision Abandoned'),
'body' => pht(
'This revision has been abandoned. Only accepted revisions '.
'may land.'),
);
default:
return array(
'title' => pht('Revision Not Accepted'),
'body' => pht(
'This revision is still under review. Only revisions which '.
'have been accepted may land.'),
);
}
}
// Check for other operations. Eventually this should probably be more

View file

@ -8,6 +8,7 @@ final class DrydockRepositoryOperationQuery extends DrydockQuery {
private $repositoryPHIDs;
private $operationStates;
private $operationTypes;
private $isDismissed;
public function withIDs(array $ids) {
$this->ids = $ids;
@ -39,6 +40,11 @@ final class DrydockRepositoryOperationQuery extends DrydockQuery {
return $this;
}
public function withIsDismissed($dismissed) {
$this->isDismissed = $dismissed;
return $this;
}
public function newResultObject() {
return new DrydockRepositoryOperation();
}
@ -152,6 +158,13 @@ final class DrydockRepositoryOperationQuery extends DrydockQuery {
$this->operationTypes);
}
if ($this->isDismissed !== null) {
$where[] = qsprintf(
$conn,
'isDismissed = %d',
(int)$this->isDismissed);
}
return $where;
}

View file

@ -20,6 +20,7 @@ final class DrydockRepositoryOperation extends DrydockDAO
protected $operationType;
protected $operationState;
protected $properties = array();
protected $isDismissed;
private $repository = self::ATTACHABLE;
private $object = self::ATTACHABLE;
@ -30,7 +31,8 @@ final class DrydockRepositoryOperation extends DrydockDAO
return id(new DrydockRepositoryOperation())
->setOperationState(self::STATE_WAIT)
->setOperationType($op->getOperationConstant());
->setOperationType($op->getOperationConstant())
->setIsDismissed(0);
}
protected function getConfiguration() {
@ -43,6 +45,7 @@ final class DrydockRepositoryOperation extends DrydockDAO
'repositoryTarget' => 'bytes',
'operationType' => 'text32',
'operationState' => 'text32',
'isDismissed' => 'bool',
),
self::CONFIG_KEY_SCHEMA => array(
'key_object' => array(
@ -196,11 +199,17 @@ final class DrydockRepositoryOperation extends DrydockDAO
}
public function getPolicy($capability) {
return $this->getRepository()->getPolicy($capability);
$need_capability = $this->getRequiredRepositoryCapability($capability);
return $this->getRepository()
->getPolicy($need_capability);
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return $this->getRepository()->hasAutomaticCapability($capability, $viewer);
$need_capability = $this->getRequiredRepositoryCapability($capability);
return $this->getRepository()
->hasAutomaticCapability($need_capability, $viewer);
}
public function describeAutomaticCapability($capability) {
@ -209,4 +218,17 @@ final class DrydockRepositoryOperation extends DrydockDAO
'affects.');
}
private function getRequiredRepositoryCapability($capability) {
// To edit a RepositoryOperation, require that the user be able to push
// to the repository.
$map = array(
PhabricatorPolicyCapability::CAN_EDIT =>
DiffusionPushCapability::CAPABILITY,
);
return idx($map, $capability, $capability);
}
}

View file

@ -67,6 +67,7 @@ final class DrydockRepositoryOperationStatusView
$item = id(new PHUIObjectItemView())
->setHref("/drydock/operation/{$id}/")
->setObjectName(pht('Operation %d', $id))
->setHeader($operation->getOperationDescription($viewer))
->setStatusIcon($icon, $name);
@ -98,6 +99,16 @@ final class DrydockRepositoryOperationStatusView
} else {
$item->addAttribute(pht('Operation encountered an error.'));
}
$is_dismissed = $operation->getIsDismissed();
$item->addAction(
id(new PHUIListItemView())
->setName('Dismiss')
->setIcon('fa-times')
->setDisabled($is_dismissed)
->setWorkflow(true)
->setHref("/drydock/operation/{$id}/dismiss/"));
}
return id(new PHUIObjectItemListView())