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

Rough in EditEngine for Maniphest

Summary:
Ref T9132. I'm going hold this until after the release cut since it isn't going to land completely smoothly, but I think I can prep it today/tomorrow and hopefully get it close enough to working to put in HEAD on Saturday after the push.

This adds the basics: new EditEngine, new EditController, and new `maniphest.edit` API endpoint.

I put the new stuff at `editpro/` for now until it works a little better.

Some notes on stuff this is dropping/changing/not-working-yet:

- Preview for the description. I'd rather solve this by putting a "Preview" button on every Remarkup area if we want to retain it. Particularly, it does not generalize to adding custom remarkup fields in its current form. See also T3967.
- Per-field policies are no longer enforced. They were never truly enforced anyway (for example, any user who can edit a task has always been able to edit every field via Conduit or email actions or Herald, where Herald supports things), and only really served as a hint to users. I think we can obsolete this by having installs hide/lock these fields instead. This is a desirable outcome for me, since I don't like retaining these policies and the idea of truly enforcing them properly is worrisome. These were originally added for Uber as an onboarding sort of thing. I'll prepare users for this in greater detail in the documentation.
- Couple of minor bugs with ordering / defaults / only-one-owner-allowed in this diff that I'll clean up in future diffs before this stuff lands.
- I don't have a concrete plan on "Create Similar Task" / "Clone" yet (do you have thoughts? Is this worth trying to do in every application?). I'll probably just mostly mimic the current behavior.

Test Plan: I'll vet this more thoroughly in followups, just banged around some tasks for now and created/edited via the API.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T9132

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

+180
+6
src/__phutil_library_map__.php
··· 1260 1260 'ManiphestDefaultEditCapability' => 'applications/maniphest/capability/ManiphestDefaultEditCapability.php', 1261 1261 'ManiphestDefaultViewCapability' => 'applications/maniphest/capability/ManiphestDefaultViewCapability.php', 1262 1262 'ManiphestEditAssignCapability' => 'applications/maniphest/capability/ManiphestEditAssignCapability.php', 1263 + 'ManiphestEditConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestEditConduitAPIMethod.php', 1264 + 'ManiphestEditEngine' => 'applications/maniphest/editor/ManiphestEditEngine.php', 1263 1265 'ManiphestEditPoliciesCapability' => 'applications/maniphest/capability/ManiphestEditPoliciesCapability.php', 1264 1266 'ManiphestEditPriorityCapability' => 'applications/maniphest/capability/ManiphestEditPriorityCapability.php', 1265 1267 'ManiphestEditProjectsCapability' => 'applications/maniphest/capability/ManiphestEditProjectsCapability.php', ··· 1299 1301 'ManiphestTaskDetailController' => 'applications/maniphest/controller/ManiphestTaskDetailController.php', 1300 1302 'ManiphestTaskEditBulkJobType' => 'applications/maniphest/bulk/ManiphestTaskEditBulkJobType.php', 1301 1303 'ManiphestTaskEditController' => 'applications/maniphest/controller/ManiphestTaskEditController.php', 1304 + 'ManiphestTaskEditProController' => 'applications/maniphest/controller/ManiphestTaskEditProController.php', 1302 1305 'ManiphestTaskHasCommitEdgeType' => 'applications/maniphest/edge/ManiphestTaskHasCommitEdgeType.php', 1303 1306 'ManiphestTaskHasMockEdgeType' => 'applications/maniphest/edge/ManiphestTaskHasMockEdgeType.php', 1304 1307 'ManiphestTaskHasRevisionEdgeType' => 'applications/maniphest/edge/ManiphestTaskHasRevisionEdgeType.php', ··· 5235 5238 'ManiphestDefaultEditCapability' => 'PhabricatorPolicyCapability', 5236 5239 'ManiphestDefaultViewCapability' => 'PhabricatorPolicyCapability', 5237 5240 'ManiphestEditAssignCapability' => 'PhabricatorPolicyCapability', 5241 + 'ManiphestEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 5242 + 'ManiphestEditEngine' => 'PhabricatorEditEngine', 5238 5243 'ManiphestEditPoliciesCapability' => 'PhabricatorPolicyCapability', 5239 5244 'ManiphestEditPriorityCapability' => 'PhabricatorPolicyCapability', 5240 5245 'ManiphestEditProjectsCapability' => 'PhabricatorPolicyCapability', ··· 5288 5293 'ManiphestTaskDetailController' => 'ManiphestController', 5289 5294 'ManiphestTaskEditBulkJobType' => 'PhabricatorWorkerBulkJobType', 5290 5295 'ManiphestTaskEditController' => 'ManiphestController', 5296 + 'ManiphestTaskEditProController' => 'ManiphestController', 5291 5297 'ManiphestTaskHasCommitEdgeType' => 'PhabricatorEdgeType', 5292 5298 'ManiphestTaskHasMockEdgeType' => 'PhabricatorEdgeType', 5293 5299 'ManiphestTaskHasRevisionEdgeType' => 'PhabricatorEdgeType',
+2
src/applications/maniphest/application/PhabricatorManiphestApplication.php
··· 69 69 ), 70 70 'export/(?P<key>[^/]+)/' => 'ManiphestExportController', 71 71 'subpriority/' => 'ManiphestSubpriorityController', 72 + $this->getEditRoutePattern('editpro/') 73 + => 'ManiphestTaskEditProController', 72 74 ), 73 75 ); 74 76 }
+19
src/applications/maniphest/conduit/ManiphestEditConduitAPIMethod.php
··· 1 + <?php 2 + 3 + final class ManiphestEditConduitAPIMethod 4 + extends PhabricatorEditEngineAPIMethod { 5 + 6 + public function getAPIMethodName() { 7 + return 'maniphest.edit'; 8 + } 9 + 10 + public function newEditEngine() { 11 + return new ManiphestEditEngine(); 12 + } 13 + 14 + public function getMethodSummary() { 15 + return pht( 16 + 'Apply transactions to create a new task or edit an existing one.'); 17 + } 18 + 19 + }
+11
src/applications/maniphest/controller/ManiphestTaskEditProController.php
··· 1 + <?php 2 + 3 + final class ManiphestTaskEditProController extends ManiphestController { 4 + 5 + public function handleRequest(AphrontRequest $request) { 6 + return id(new ManiphestEditEngine()) 7 + ->setController($this) 8 + ->buildResponse(); 9 + } 10 + 11 + }
+113
src/applications/maniphest/editor/ManiphestEditEngine.php
··· 1 + <?php 2 + 3 + final class ManiphestEditEngine 4 + extends PhabricatorEditEngine { 5 + 6 + const ENGINECONST = 'maniphest.task'; 7 + 8 + public function getEngineName() { 9 + return pht('Maniphest Tasks'); 10 + } 11 + 12 + public function getEngineApplicationClass() { 13 + return 'PhabricatorManiphestApplication'; 14 + } 15 + 16 + protected function newEditableObject() { 17 + return ManiphestTask::initializeNewTask($this->getViewer()); 18 + } 19 + 20 + protected function newObjectQuery() { 21 + return id(new ManiphestTaskQuery()); 22 + } 23 + 24 + protected function getObjectCreateTitleText($object) { 25 + return pht('Create New Task'); 26 + } 27 + 28 + protected function getObjectEditTitleText($object) { 29 + return pht('Edit %s %s', $object->getMonogram(), $object->getTitle()); 30 + } 31 + 32 + protected function getObjectEditShortText($object) { 33 + return $object->getMonogram(); 34 + } 35 + 36 + protected function getObjectCreateShortText() { 37 + return pht('Create Task'); 38 + } 39 + 40 + protected function getCommentViewHeaderText($object) { 41 + $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); 42 + if (!$is_serious) { 43 + return pht('Weigh In'); 44 + } 45 + 46 + return parent::getCommentViewHeaderText($object); 47 + } 48 + 49 + protected function getObjectViewURI($object) { 50 + return '/'.$object->getMonogram(); 51 + } 52 + 53 + protected function buildCustomEditFields($object) { 54 + // See T4819. 55 + $status_map = ManiphestTaskStatus::getTaskStatusMap(); 56 + $dup_status = ManiphestTaskStatus::getDuplicateStatus(); 57 + if ($object->getStatus() != $dup_status) { 58 + unset($status_map[$dup_status]); 59 + } 60 + 61 + $owner_phid = $object->getOwnerPHID(); 62 + if ($owner_phid) { 63 + $owner_value = array($owner_phid); 64 + } else { 65 + $owner_value = array(); 66 + } 67 + 68 + $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); 69 + 70 + return array( 71 + id(new PhabricatorTextEditField()) 72 + ->setKey('title') 73 + ->setLabel(pht('Title')) 74 + ->setDescription(pht('Name of the paste.')) 75 + ->setTransactionType(ManiphestTransaction::TYPE_TITLE) 76 + ->setIsRequired(true) 77 + ->setValue($object->getTitle()), 78 + id(new PhabricatorSelectEditField()) 79 + ->setKey('status') 80 + ->setLabel(pht('Status')) 81 + ->setDescription(pht('Status of the task.')) 82 + ->setTransactionType(ManiphestTransaction::TYPE_STATUS) 83 + ->setValue($object->getStatus()) 84 + ->setOptions($status_map), 85 + id(new PhabricatorUsersEditField()) 86 + ->setKey('assigned') 87 + ->setAliases(array('assign', 'assignee')) 88 + ->setLabel(pht('Assigned To')) 89 + ->setDescription(pht('User who is responsible for the task.')) 90 + ->setTransactionType(ManiphestTransaction::TYPE_OWNER) 91 + ->setValue($owner_value), 92 + id(new PhabricatorSelectEditField()) 93 + ->setKey('priority') 94 + ->setLabel(pht('Priority')) 95 + ->setDescription(pht('Priority of the task.')) 96 + ->setTransactionType(ManiphestTransaction::TYPE_PRIORITY) 97 + ->setValue($object->getPriority()) 98 + ->setOptions($priority_map), 99 + id(new PhabricatorRemarkupEditField()) 100 + ->setKey('description') 101 + ->setLabel(pht('Description')) 102 + ->setDescription(pht('Task description.')) 103 + ->setTransactionType(ManiphestTransaction::TYPE_DESCRIPTION) 104 + ->setValue($object->getDescription()), 105 + ); 106 + } 107 + 108 + protected function getEditorURI() { 109 + // TODO: Remove when cutting over. 110 + return $this->getApplication()->getApplicationURI('editpro/'); 111 + } 112 + 113 + }
+29
src/applications/maniphest/editor/ManiphestTransactionEditor.php
··· 716 716 return array($dst->getPriority(), $sub); 717 717 } 718 718 719 + protected function validateTransaction( 720 + PhabricatorLiskDAO $object, 721 + $type, 722 + array $xactions) { 723 + 724 + $errors = parent::validateTransaction($object, $type, $xactions); 725 + 726 + switch ($type) { 727 + case ManiphestTransaction::TYPE_TITLE: 728 + $missing = $this->validateIsEmptyTextField( 729 + $object->getTitle(), 730 + $xactions); 731 + 732 + if ($missing) { 733 + $error = new PhabricatorApplicationTransactionValidationError( 734 + $type, 735 + pht('Required'), 736 + pht('Task title is required.'), 737 + nonempty(last($xactions), null)); 738 + 739 + $error->setIsMissingFieldError(true); 740 + $errors[] = $error; 741 + } 742 + break; 743 + } 744 + 745 + return $errors; 746 + } 747 + 719 748 720 749 }