Skip to content

Commit 367955f

Browse files
author
epriestley
committedDec 27, 2015
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
1 parent 5537303 commit 367955f

10 files changed

+137
-17
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ALTER TABLE {$NAMESPACE}_drydock.drydock_repositoryoperation
2+
ADD isDismissed BOOL NOT NULL;

‎src/__phutil_library_map__.php

+2
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,7 @@
911911
'DrydockObjectAuthorizationView' => 'applications/drydock/view/DrydockObjectAuthorizationView.php',
912912
'DrydockQuery' => 'applications/drydock/query/DrydockQuery.php',
913913
'DrydockRepositoryOperation' => 'applications/drydock/storage/DrydockRepositoryOperation.php',
914+
'DrydockRepositoryOperationDismissController' => 'applications/drydock/controller/DrydockRepositoryOperationDismissController.php',
914915
'DrydockRepositoryOperationListController' => 'applications/drydock/controller/DrydockRepositoryOperationListController.php',
915916
'DrydockRepositoryOperationPHIDType' => 'applications/drydock/phid/DrydockRepositoryOperationPHIDType.php',
916917
'DrydockRepositoryOperationQuery' => 'applications/drydock/query/DrydockRepositoryOperationQuery.php',
@@ -4900,6 +4901,7 @@
49004901
'DrydockDAO',
49014902
'PhabricatorPolicyInterface',
49024903
),
4904+
'DrydockRepositoryOperationDismissController' => 'DrydockController',
49034905
'DrydockRepositoryOperationListController' => 'DrydockController',
49044906
'DrydockRepositoryOperationPHIDType' => 'PhabricatorPHIDType',
49054907
'DrydockRepositoryOperationQuery' => 'DrydockQuery',

‎src/applications/differential/controller/DifferentialRevisionOperationController.php

+3-8
Original file line numberDiff line numberDiff line change
@@ -94,28 +94,23 @@ public function handleRequest(AphrontRequest $request) {
9494
->setUser($viewer)
9595
->appendRemarkupInstructions(
9696
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.'))
9998
->appendControl(
10099
id(new AphrontFormTokenizerControl())
101100
->setLabel(pht('Onto Branch'))
102101
->setName('refPHIDs')
103102
->setLimit(1)
104103
->setError($e_ref)
105104
->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));
111106

112107
return $this->newDialog()
113108
->setWidth(AphrontDialogView::WIDTH_FORM)
114109
->setTitle(pht('Land Revision'))
115110
->setErrors($errors)
116111
->appendForm($form)
117112
->addCancelButton($detail_uri)
118-
->addSubmitButton(pht('Mutate Repository Unpredictably'));
113+
->addSubmitButton(pht('Land Revision'));
119114
}
120115

121116
private function newRefQuery(PhabricatorRepository $repository) {

‎src/applications/differential/controller/DifferentialRevisionViewController.php

+1
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,7 @@ private function buildOperationsBox(DifferentialRevision $revision) {
10471047
$operations = id(new DrydockRepositoryOperationQuery())
10481048
->setViewer($viewer)
10491049
->withObjectPHIDs(array($revision->getPHID()))
1050+
->withIsDismissed(false)
10501051
->withOperationTypes(
10511052
array(
10521053
DrydockLandRepositoryOperation::OPCONST,

‎src/applications/drydock/application/PhabricatorDrydockApplication.php

+1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ public function getRoutes() {
9696
'(?P<id>[1-9]\d*)/' => array(
9797
'' => 'DrydockRepositoryOperationViewController',
9898
'status/' => 'DrydockRepositoryOperationStatusController',
99+
'dismiss/' => 'DrydockRepositoryOperationDismissController',
99100
),
100101
),
101102
),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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+
}

‎src/applications/drydock/operation/DrydockLandRepositoryOperation.php

+23-6
Original file line numberDiff line numberDiff line change
@@ -235,12 +235,29 @@ public function getBarrierToLanding(
235235

236236
$status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED;
237237
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+
}
244261
}
245262

246263
// Check for other operations. Eventually this should probably be more

‎src/applications/drydock/query/DrydockRepositoryOperationQuery.php

+13
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ final class DrydockRepositoryOperationQuery extends DrydockQuery {
88
private $repositoryPHIDs;
99
private $operationStates;
1010
private $operationTypes;
11+
private $isDismissed;
1112

1213
public function withIDs(array $ids) {
1314
$this->ids = $ids;
@@ -39,6 +40,11 @@ public function withOperationTypes(array $types) {
3940
return $this;
4041
}
4142

43+
public function withIsDismissed($dismissed) {
44+
$this->isDismissed = $dismissed;
45+
return $this;
46+
}
47+
4248
public function newResultObject() {
4349
return new DrydockRepositoryOperation();
4450
}
@@ -152,6 +158,13 @@ protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
152158
$this->operationTypes);
153159
}
154160

161+
if ($this->isDismissed !== null) {
162+
$where[] = qsprintf(
163+
$conn,
164+
'isDismissed = %d',
165+
(int)$this->isDismissed);
166+
}
167+
155168
return $where;
156169
}
157170

‎src/applications/drydock/storage/DrydockRepositoryOperation.php

+25-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ final class DrydockRepositoryOperation extends DrydockDAO
2020
protected $operationType;
2121
protected $operationState;
2222
protected $properties = array();
23+
protected $isDismissed;
2324

2425
private $repository = self::ATTACHABLE;
2526
private $object = self::ATTACHABLE;
@@ -30,7 +31,8 @@ public static function initializeNewOperation(
3031

3132
return id(new DrydockRepositoryOperation())
3233
->setOperationState(self::STATE_WAIT)
33-
->setOperationType($op->getOperationConstant());
34+
->setOperationType($op->getOperationConstant())
35+
->setIsDismissed(0);
3436
}
3537

3638
protected function getConfiguration() {
@@ -43,6 +45,7 @@ protected function getConfiguration() {
4345
'repositoryTarget' => 'bytes',
4446
'operationType' => 'text32',
4547
'operationState' => 'text32',
48+
'isDismissed' => 'bool',
4649
),
4750
self::CONFIG_KEY_SCHEMA => array(
4851
'key_object' => array(
@@ -196,11 +199,17 @@ public function getCapabilities() {
196199
}
197200

198201
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);
200206
}
201207

202208
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);
204213
}
205214

206215
public function describeAutomaticCapability($capability) {
@@ -209,4 +218,17 @@ public function describeAutomaticCapability($capability) {
209218
'affects.');
210219
}
211220

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+
233+
212234
}

‎src/applications/drydock/view/DrydockRepositoryOperationStatusView.php

+11
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ public function renderUnderwayState() {
6767

6868
$item = id(new PHUIObjectItemView())
6969
->setHref("/drydock/operation/{$id}/")
70+
->setObjectName(pht('Operation %d', $id))
7071
->setHeader($operation->getOperationDescription($viewer))
7172
->setStatusIcon($icon, $name);
7273

@@ -98,6 +99,16 @@ public function renderUnderwayState() {
9899
} else {
99100
$item->addAttribute(pht('Operation encountered an error.'));
100101
}
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/"));
101112
}
102113

103114
return id(new PHUIObjectItemListView())

0 commit comments

Comments
 (0)
Failed to load comments.