Page MenuHomePhabricator

D17107.id41146.diff
No OneTemporary

D17107.id41146.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -9,7 +9,7 @@
'names' => array(
'conpherence.pkg.css' => '0b64e988',
'conpherence.pkg.js' => '6249a1cf',
- 'core.pkg.css' => '404132bb',
+ 'core.pkg.css' => '202700e2',
'core.pkg.js' => '28e8cda8',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => 'a4ba74b5',
@@ -146,7 +146,7 @@
'rsrc/css/phui/phui-document.css' => 'c32e8dec',
'rsrc/css/phui/phui-feed-story.css' => '44a9c8e9',
'rsrc/css/phui/phui-fontkit.css' => '9cda225e',
- 'rsrc/css/phui/phui-form-view.css' => 'cd79ff6a',
+ 'rsrc/css/phui/phui-form-view.css' => '04cc4771',
'rsrc/css/phui/phui-form.css' => '2342b0e5',
'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f',
'rsrc/css/phui/phui-header-view.css' => '6ec8f155',
@@ -542,7 +542,7 @@
'rsrc/js/phuix/PHUIXActionView.js' => '8cf6d262',
'rsrc/js/phuix/PHUIXAutocomplete.js' => '6d86ce8b',
'rsrc/js/phuix/PHUIXDropdownMenu.js' => '82e270da',
- 'rsrc/js/phuix/PHUIXFormControl.js' => '301b7812',
+ 'rsrc/js/phuix/PHUIXFormControl.js' => 'bbece68d',
'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b',
),
'symbols' => array(
@@ -860,7 +860,7 @@
'phui-font-icon-base-css' => '870a7360',
'phui-fontkit-css' => '9cda225e',
'phui-form-css' => '2342b0e5',
- 'phui-form-view-css' => 'cd79ff6a',
+ 'phui-form-view-css' => '04cc4771',
'phui-head-thing-view-css' => 'fd311e5f',
'phui-header-view-css' => '6ec8f155',
'phui-hovercard' => '1bd28176',
@@ -901,7 +901,7 @@
'phuix-action-view' => '8cf6d262',
'phuix-autocomplete' => '6d86ce8b',
'phuix-dropdown-menu' => '82e270da',
- 'phuix-form-control-view' => '301b7812',
+ 'phuix-form-control-view' => 'bbece68d',
'phuix-icon-view' => 'bff6884b',
'policy-css' => '957ea14c',
'policy-edit-css' => '815c66f7',
@@ -1159,10 +1159,6 @@
'2ee659ce' => array(
'javelin-install',
),
- '301b7812' => array(
- 'javelin-install',
- 'javelin-dom',
- ),
'320810c8' => array(
'javelin-install',
'javelin-dom',
@@ -1916,6 +1912,10 @@
'javelin-vector',
'javelin-install',
),
+ 'bbece68d' => array(
+ 'javelin-install',
+ 'javelin-dom',
+ ),
'bcaccd64' => array(
'javelin-behavior',
'javelin-behavior-device',
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -505,6 +505,8 @@
'DifferentialReviewersHeraldAction' => 'applications/differential/herald/DifferentialReviewersHeraldAction.php',
'DifferentialReviewersView' => 'applications/differential/view/DifferentialReviewersView.php',
'DifferentialRevision' => 'applications/differential/storage/DifferentialRevision.php',
+ 'DifferentialRevisionAbandonTransaction' => 'applications/differential/xaction/DifferentialRevisionAbandonTransaction.php',
+ 'DifferentialRevisionActionTransaction' => 'applications/differential/xaction/DifferentialRevisionActionTransaction.php',
'DifferentialRevisionAffectedFilesHeraldField' => 'applications/differential/herald/DifferentialRevisionAffectedFilesHeraldField.php',
'DifferentialRevisionAuthorHeraldField' => 'applications/differential/herald/DifferentialRevisionAuthorHeraldField.php',
'DifferentialRevisionAuthorProjectsHeraldField' => 'applications/differential/herald/DifferentialRevisionAuthorProjectsHeraldField.php',
@@ -539,6 +541,7 @@
'DifferentialRevisionPackageHeraldField' => 'applications/differential/herald/DifferentialRevisionPackageHeraldField.php',
'DifferentialRevisionPackageOwnerHeraldField' => 'applications/differential/herald/DifferentialRevisionPackageOwnerHeraldField.php',
'DifferentialRevisionQuery' => 'applications/differential/query/DifferentialRevisionQuery.php',
+ 'DifferentialRevisionReclaimTransaction' => 'applications/differential/xaction/DifferentialRevisionReclaimTransaction.php',
'DifferentialRevisionRelationship' => 'applications/differential/relationships/DifferentialRevisionRelationship.php',
'DifferentialRevisionRelationshipSource' => 'applications/search/relationship/DifferentialRevisionRelationshipSource.php',
'DifferentialRevisionRepositoryHeraldField' => 'applications/differential/herald/DifferentialRevisionRepositoryHeraldField.php',
@@ -1840,6 +1843,7 @@
'PhabricatorApplicationsApplication' => 'applications/meta/application/PhabricatorApplicationsApplication.php',
'PhabricatorApplicationsController' => 'applications/meta/controller/PhabricatorApplicationsController.php',
'PhabricatorApplicationsListController' => 'applications/meta/controller/PhabricatorApplicationsListController.php',
+ 'PhabricatorApplyEditField' => 'applications/transactions/editfield/PhabricatorApplyEditField.php',
'PhabricatorAsanaAuthProvider' => 'applications/auth/provider/PhabricatorAsanaAuthProvider.php',
'PhabricatorAsanaConfigOptions' => 'applications/doorkeeper/option/PhabricatorAsanaConfigOptions.php',
'PhabricatorAsanaSubtaskHasObjectEdgeType' => 'applications/doorkeeper/edge/PhabricatorAsanaSubtaskHasObjectEdgeType.php',
@@ -2572,6 +2576,7 @@
'PhabricatorEditEngineSearchEngine' => 'applications/transactions/query/PhabricatorEditEngineSearchEngine.php',
'PhabricatorEditEngineSelectCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineSelectCommentAction.php',
'PhabricatorEditEngineSettingsPanel' => 'applications/settings/panel/PhabricatorEditEngineSettingsPanel.php',
+ 'PhabricatorEditEngineStaticCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineStaticCommentAction.php',
'PhabricatorEditEngineTokenizerCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineTokenizerCommentAction.php',
'PhabricatorEditField' => 'applications/transactions/editfield/PhabricatorEditField.php',
'PhabricatorEditPage' => 'applications/transactions/editengine/PhabricatorEditPage.php',
@@ -5169,6 +5174,8 @@
'PhabricatorFulltextInterface',
'PhabricatorConduitResultInterface',
),
+ 'DifferentialRevisionAbandonTransaction' => 'DifferentialRevisionActionTransaction',
+ 'DifferentialRevisionActionTransaction' => 'DifferentialRevisionTransactionType',
'DifferentialRevisionAffectedFilesHeraldField' => 'DifferentialRevisionHeraldField',
'DifferentialRevisionAuthorHeraldField' => 'DifferentialRevisionHeraldField',
'DifferentialRevisionAuthorProjectsHeraldField' => 'DifferentialRevisionHeraldField',
@@ -5203,6 +5210,7 @@
'DifferentialRevisionPackageHeraldField' => 'DifferentialRevisionHeraldField',
'DifferentialRevisionPackageOwnerHeraldField' => 'DifferentialRevisionHeraldField',
'DifferentialRevisionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'DifferentialRevisionReclaimTransaction' => 'DifferentialRevisionActionTransaction',
'DifferentialRevisionRelationship' => 'PhabricatorObjectRelationship',
'DifferentialRevisionRelationshipSource' => 'PhabricatorObjectRelationshipSource',
'DifferentialRevisionRepositoryHeraldField' => 'DifferentialRevisionHeraldField',
@@ -6688,6 +6696,7 @@
'PhabricatorApplicationsApplication' => 'PhabricatorApplication',
'PhabricatorApplicationsController' => 'PhabricatorController',
'PhabricatorApplicationsListController' => 'PhabricatorApplicationsController',
+ 'PhabricatorApplyEditField' => 'PhabricatorEditField',
'PhabricatorAsanaAuthProvider' => 'PhabricatorOAuth2AuthProvider',
'PhabricatorAsanaConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorAsanaSubtaskHasObjectEdgeType' => 'PhabricatorEdgeType',
@@ -7545,6 +7554,7 @@
'PhabricatorEditEngineSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorEditEngineSelectCommentAction' => 'PhabricatorEditEngineCommentAction',
'PhabricatorEditEngineSettingsPanel' => 'PhabricatorSettingsPanel',
+ 'PhabricatorEditEngineStaticCommentAction' => 'PhabricatorEditEngineCommentAction',
'PhabricatorEditEngineTokenizerCommentAction' => 'PhabricatorEditEngineCommentAction',
'PhabricatorEditField' => 'Phobject',
'PhabricatorEditPage' => 'Phobject',
diff --git a/src/applications/differential/editor/DifferentialRevisionEditEngine.php b/src/applications/differential/editor/DifferentialRevisionEditEngine.php
--- a/src/applications/differential/editor/DifferentialRevisionEditEngine.php
+++ b/src/applications/differential/editor/DifferentialRevisionEditEngine.php
@@ -87,6 +87,7 @@
}
protected function buildCustomEditFields($object) {
+ $viewer = $this->getViewer();
$plan_required = PhabricatorEnv::getEnvConfig(
'differential.require-test-plan-field');
@@ -180,7 +181,7 @@
->setUseEdgeTransactions(true)
->setTransactionType(
DifferentialRevisionReviewersTransaction::TRANSACTIONTYPE)
- ->setCommentActionLabel(pht('Edit Reviewers'))
+ ->setCommentActionLabel(pht('Change Reviewers'))
->setDescription(pht('Reviewers for this revision.'))
->setConduitDescription(pht('Change the reviewers for this revision.'))
->setConduitTypeDescription(pht('New reviewers.'))
@@ -212,6 +213,11 @@
->setConduitTypeDescription(pht('List of tasks.'))
->setValue(array());
+ $actions = DifferentialRevisionActionTransaction::loadAllActions();
+ foreach ($actions as $key => $action) {
+ $fields[] = $action->newEditField($object, $viewer);
+ }
+
return $fields;
}
diff --git a/src/applications/differential/storage/DifferentialRevision.php b/src/applications/differential/storage/DifferentialRevision.php
--- a/src/applications/differential/storage/DifferentialRevision.php
+++ b/src/applications/differential/storage/DifferentialRevision.php
@@ -442,6 +442,11 @@
return DifferentialRevisionStatus::isClosedStatus($this->getStatus());
}
+ public function isAbandoned() {
+ $status_abandoned = ArcanistDifferentialRevisionStatus::ABANDONED;
+ return ($this->getStatus() == $status_abandoned);
+ }
+
public function getStatusIcon() {
$map = array(
ArcanistDifferentialRevisionStatus::NEEDS_REVIEW
diff --git a/src/applications/differential/xaction/DifferentialRevisionAbandonTransaction.php b/src/applications/differential/xaction/DifferentialRevisionAbandonTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/differential/xaction/DifferentialRevisionAbandonTransaction.php
@@ -0,0 +1,67 @@
+<?php
+
+final class DifferentialRevisionAbandonTransaction
+ extends DifferentialRevisionActionTransaction {
+
+ const TRANSACTIONTYPE = 'differential.revision.abandon';
+ const ACTIONKEY = 'abandon';
+
+ protected function getRevisionActionLabel() {
+ return pht('Abandon Revision');
+ }
+
+ protected function getRevisionActionDescription() {
+ return pht('This revision will be abandoned and closed.');
+ }
+
+ public function getIcon() {
+ return 'fa-plane';
+ }
+
+ public function getColor() {
+ return 'indigo';
+ }
+
+ public function generateOldValue($object) {
+ return $object->isAbandoned();
+ }
+
+ public function applyInternalEffects($object, $value) {
+ $object->setStatus(ArcanistDifferentialRevisionStatus::ABANDONED);
+ }
+
+ protected function validateAction($object, PhabricatorUser $viewer) {
+ if ($object->isClosed()) {
+ throw new Exception(
+ pht(
+ 'You can not abandon this revision because it has already been '.
+ 'closed. Only open revisions can be abandoned.'));
+ }
+
+ $config_key = 'differential.always-allow-abandon';
+ if (!PhabricatorEnv::getEnvConfig($config_key)) {
+ if (!$this->isViewerRevisionAuthor($object, $viewer)) {
+ throw new Exception(
+ pht(
+ 'You can not abandon this revision because you are not the '.
+ 'author. You can only abandon revisions you own. You can change '.
+ 'this behavior by adjusting the "%s" setting in Config',
+ $config_key));
+ }
+ }
+ }
+
+ public function getTitle() {
+ return pht(
+ '%s abandoned this revision.',
+ $this->renderAuthor());
+ }
+
+ public function getTitleForFeed() {
+ return pht(
+ '%s abandoned %s.',
+ $this->renderAuthor(),
+ $this->renderObject());
+ }
+
+}
diff --git a/src/applications/differential/xaction/DifferentialRevisionActionTransaction.php b/src/applications/differential/xaction/DifferentialRevisionActionTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/differential/xaction/DifferentialRevisionActionTransaction.php
@@ -0,0 +1,88 @@
+<?php
+
+abstract class DifferentialRevisionActionTransaction
+ extends DifferentialRevisionTransactionType {
+
+ final public function getRevisionActionKey() {
+ return $this->getPhobjectClassConstant('ACTIONKEY', 32);
+ }
+
+ public function isActionAvailable($object, PhabricatorUser $viewer) {
+ try {
+ $this->validateAction($object, $viewer);
+ return true;
+ } catch (Exception $ex) {
+ return false;
+ }
+ }
+
+ abstract protected function validateAction($object, PhabricatorUser $viewer);
+ abstract protected function getRevisionActionLabel();
+
+ protected function getRevisionActionDescription() {
+ return null;
+ }
+
+ public static function loadAllActions() {
+ return id(new PhutilClassMapQuery())
+ ->setAncestorClass(__CLASS__)
+ ->setUniqueMethod('getRevisionActionKey')
+ ->execute();
+ }
+
+ protected function isViewerRevisionAuthor(
+ DifferentialRevision $revision,
+ PhabricatorUser $viewer) {
+
+ if (!$viewer->getPHID()) {
+ return false;
+ }
+
+ return ($viewer->getPHID() === $revision->getAuthorPHID());
+ }
+
+ public function newEditField(
+ DifferentialRevision $revision,
+ PhabricatorUser $viewer) {
+
+ $field = id(new PhabricatorApplyEditField())
+ ->setKey($this->getRevisionActionKey())
+ ->setTransactionType($this->getTransactionTypeConstant())
+ ->setValue(true);
+
+ if ($this->isActionAvailable($revision, $viewer)) {
+ $label = $this->getRevisionActionLabel();
+ if ($label !== null) {
+ $field->setCommentActionLabel($label);
+
+ $description = $this->getRevisionActionDescription();
+ $field->setActionDescription($description);
+ }
+ }
+
+ return $field;
+ }
+
+ public function validateTransactions($object, array $xactions) {
+ $errors = array();
+ $actor = $this->getActor();
+
+ $action_exception = null;
+ try {
+ $this->validateAction($object, $actor);
+ } catch (Exception $ex) {
+ $action_exception = $ex;
+ }
+
+ foreach ($xactions as $xaction) {
+ if ($action_exception) {
+ $errors[] = $this->newInvalidError(
+ $action_exception->getMessage(),
+ $xaction);
+ }
+ }
+
+ return $errors;
+ }
+
+}
diff --git a/src/applications/differential/xaction/DifferentialRevisionReclaimTransaction.php b/src/applications/differential/xaction/DifferentialRevisionReclaimTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/differential/xaction/DifferentialRevisionReclaimTransaction.php
@@ -0,0 +1,62 @@
+<?php
+
+final class DifferentialRevisionReclaimTransaction
+ extends DifferentialRevisionActionTransaction {
+
+ const TRANSACTIONTYPE = 'differential.revision.reclaim';
+ const ACTIONKEY = 'reclaim';
+
+ protected function getRevisionActionLabel() {
+ return pht('Reclaim Revision');
+ }
+
+ protected function getRevisionActionDescription() {
+ return pht('This revision will be reclaimed and reopened.');
+ }
+
+ public function getIcon() {
+ return 'fa-bullhorn';
+ }
+
+ public function getColor() {
+ return 'sky';
+ }
+
+ public function generateOldValue($object) {
+ return !$object->isAbandoned();
+ }
+
+ public function applyInternalEffects($object, $value) {
+ $object->setStatus(ArcanistDifferentialRevisionStatus::NEEDS_REVIEW);
+ }
+
+ protected function validateAction($object, PhabricatorUser $viewer) {
+ if (!$object->isAbandoned()) {
+ throw new Exception(
+ pht(
+ 'You can not reclaim this revision because it has not been '.
+ 'abandoned. Only abandoned revisions can be reclaimed.'));
+ }
+
+ if (!$this->isViewerRevisionAuthor($object, $viewer)) {
+ throw new Exception(
+ pht(
+ 'You can not reclaim this revision because you are not the '.
+ 'revision author. You can only reclaim revisions you own.'));
+ }
+ }
+
+ public function getTitle() {
+ return pht(
+ '%s reclaimed this revision.',
+ $this->renderAuthor());
+ }
+
+ public function getTitleForFeed() {
+ return pht(
+ '%s reclaimed %s.',
+ $this->renderAuthor(),
+ $this->renderObject());
+ }
+
+}
diff --git a/src/applications/transactions/commentaction/PhabricatorEditEngineStaticCommentAction.php b/src/applications/transactions/commentaction/PhabricatorEditEngineStaticCommentAction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/commentaction/PhabricatorEditEngineStaticCommentAction.php
@@ -0,0 +1,28 @@
+<?php
+
+final class PhabricatorEditEngineStaticCommentAction
+ extends PhabricatorEditEngineCommentAction {
+
+ private $description;
+
+ public function setDescription($description) {
+ $this->description = $description;
+ return $this;
+ }
+
+ public function getDescription() {
+ return $this->description;
+ }
+
+ public function getPHUIXControlType() {
+ return 'static';
+ }
+
+ public function getPHUIXControlSpecification() {
+ return array(
+ 'value' => $this->getValue(),
+ 'description' => $this->getDescription(),
+ );
+ }
+
+}
diff --git a/src/applications/transactions/editfield/PhabricatorApplyEditField.php b/src/applications/transactions/editfield/PhabricatorApplyEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorApplyEditField.php
@@ -0,0 +1,40 @@
+<?php
+
+final class PhabricatorApplyEditField
+ extends PhabricatorEditField {
+
+ private $actionDescription;
+
+ protected function newControl() {
+ return null;
+ }
+
+ public function setActionDescription($action_description) {
+ $this->actionDescription = $action_description;
+ return $this;
+ }
+
+ public function getActionDescription() {
+ return $this->actionDescription;
+ }
+
+ protected function newHTTPParameterType() {
+ return new AphrontBoolHTTPParameterType();
+ }
+
+ protected function newConduitParameterType() {
+ return new ConduitBoolParameterType();
+ }
+
+ public function shouldGenerateTransactionsFromSubmit() {
+ // This type of edit field just applies a prebuilt action, like "Accept
+ // Revision", and can not be submitted as part of an "Edit Object" form.
+ return false;
+ }
+
+ protected function newCommentAction() {
+ return id(new PhabricatorEditEngineStaticCommentAction())
+ ->setDescription($this->getActionDescription());
+ }
+
+}
diff --git a/webroot/rsrc/css/phui/phui-form-view.css b/webroot/rsrc/css/phui/phui-form-view.css
--- a/webroot/rsrc/css/phui/phui-form-view.css
+++ b/webroot/rsrc/css/phui/phui-form-view.css
@@ -545,3 +545,8 @@
.device-desktop .aphront-form-error .phui-icon-view:hover {
color: {$red};
}
+
+.phui-form-static-action {
+ padding: 4px;
+ color: {$bluetext};
+}
diff --git a/webroot/rsrc/js/phuix/PHUIXFormControl.js b/webroot/rsrc/js/phuix/PHUIXFormControl.js
--- a/webroot/rsrc/js/phuix/PHUIXFormControl.js
+++ b/webroot/rsrc/js/phuix/PHUIXFormControl.js
@@ -47,6 +47,9 @@
case 'optgroups':
input = this._newOptgroups(spec);
break;
+ case 'static':
+ input = this._newStatic(spec);
+ break;
default:
// TODO: Default or better error?
JX.$E('Bad Input Type');
@@ -172,6 +175,25 @@
};
},
+ _newStatic: function(spec) {
+ var node = JX.$N(
+ 'div',
+ {
+ className: 'phui-form-static-action'
+ },
+ spec.description || '');
+
+ return {
+ node: node,
+ get: function() {
+ return true;
+ },
+ set: function() {
+ return;
+ }
+ };
+ },
+
_newPoints: function(spec) {
var attrs = {
type: 'text',

File Metadata

Mime Type
text/plain
Expires
Thu, Oct 24, 7:28 PM (3 w, 3 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6737192
Default Alt Text
D17107.id41146.diff (20 KB)

Event Timeline