@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

Allow EditEngine forms for objects which support subtyping to have a subtype configured

Summary:
Ref T12314. This adds a "Change Form Subtype" workflow to the EditEngine form configuration screen, for forms that edit/create objects which support subtyping (for now, only tasks).

For example, this allows you to switch a form from being a "task" form to a "plant" or "animal" form.

Doing this doesn't yet do anything useful or interesting. I'm also not showing it in the UI yet since I'm not sure what we should make that look like (presumably, we should just echo whatever UI we end up with on tasks).

Test Plan:
- Changed the subtype of a task form.
- Verified that the "Change Subtype" action doesn't appear on other forms (for example, those for Pastes).

{F3491374}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T12314

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

+198
+2
src/__phutil_library_map__.php
··· 2610 2610 'PhabricatorEditEngineConfigurationSaveController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationSaveController.php', 2611 2611 'PhabricatorEditEngineConfigurationSearchEngine' => 'applications/transactions/query/PhabricatorEditEngineConfigurationSearchEngine.php', 2612 2612 'PhabricatorEditEngineConfigurationSortController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationSortController.php', 2613 + 'PhabricatorEditEngineConfigurationSubtypeController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationSubtypeController.php', 2613 2614 'PhabricatorEditEngineConfigurationTransaction' => 'applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php', 2614 2615 'PhabricatorEditEngineConfigurationTransactionQuery' => 'applications/transactions/query/PhabricatorEditEngineConfigurationTransactionQuery.php', 2615 2616 'PhabricatorEditEngineConfigurationViewController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php', ··· 7669 7670 'PhabricatorEditEngineConfigurationSaveController' => 'PhabricatorEditEngineController', 7670 7671 'PhabricatorEditEngineConfigurationSearchEngine' => 'PhabricatorApplicationSearchEngine', 7671 7672 'PhabricatorEditEngineConfigurationSortController' => 'PhabricatorEditEngineController', 7673 + 'PhabricatorEditEngineConfigurationSubtypeController' => 'PhabricatorEditEngineController', 7672 7674 'PhabricatorEditEngineConfigurationTransaction' => 'PhabricatorApplicationTransaction', 7673 7675 'PhabricatorEditEngineConfigurationTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 7674 7676 'PhabricatorEditEngineConfigurationViewController' => 'PhabricatorEditEngineController',
+5
src/applications/maniphest/storage/ManiphestTask.php
··· 557 557 return $this->setSubtype($value); 558 558 } 559 559 560 + public function newEditEngineSubtypeMap() { 561 + $config = PhabricatorEnv::getEnvConfig('maniphest.subtypes'); 562 + return PhabricatorEditEngineSubtype::newSubtypeMap($config); 563 + } 564 + 560 565 }
+2
src/applications/transactions/application/PhabricatorTransactionsApplication.php
··· 55 55 'PhabricatorEditEngineConfigurationDefaultsController', 56 56 'lock/(?P<key>[^/]+)/' => 57 57 'PhabricatorEditEngineConfigurationLockController', 58 + 'subtype/(?P<key>[^/]+)/' => 59 + 'PhabricatorEditEngineConfigurationSubtypeController', 58 60 'defaultcreate/(?P<key>[^/]+)/' => 59 61 'PhabricatorEditEngineConfigurationDefaultCreateController', 60 62 'defaultedit/(?P<key>[^/]+)/' =>
+85
src/applications/transactions/controller/PhabricatorEditEngineConfigurationSubtypeController.php
··· 1 + <?php 2 + 3 + final class PhabricatorEditEngineConfigurationSubtypeController 4 + extends PhabricatorEditEngineController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $engine_key = $request->getURIData('engineKey'); 8 + $this->setEngineKey($engine_key); 9 + 10 + $key = $request->getURIData('key'); 11 + $viewer = $this->getViewer(); 12 + 13 + $config = id(new PhabricatorEditEngineConfigurationQuery()) 14 + ->setViewer($viewer) 15 + ->withEngineKeys(array($engine_key)) 16 + ->withIdentifiers(array($key)) 17 + ->requireCapabilities( 18 + array( 19 + PhabricatorPolicyCapability::CAN_VIEW, 20 + PhabricatorPolicyCapability::CAN_EDIT, 21 + )) 22 + ->executeOne(); 23 + if (!$config) { 24 + return new Aphront404Response(); 25 + } 26 + 27 + $cancel_uri = "/transactions/editengine/{$engine_key}/view/{$key}/"; 28 + 29 + $engine = $config->getEngine(); 30 + if (!$engine->supportsSubtypes()) { 31 + return new Aphront404Response(); 32 + } 33 + 34 + if ($request->isFormPost()) { 35 + $xactions = array(); 36 + 37 + $subtype = $request->getStr('subtype'); 38 + $type_subtype = 39 + PhabricatorEditEngineConfigurationTransaction::TYPE_SUBTYPE; 40 + 41 + $xactions[] = id(new PhabricatorEditEngineConfigurationTransaction()) 42 + ->setTransactionType($type_subtype) 43 + ->setNewValue($subtype); 44 + 45 + $editor = id(new PhabricatorEditEngineConfigurationEditor()) 46 + ->setActor($viewer) 47 + ->setContentSourceFromRequest($request) 48 + ->setContinueOnMissingFields(true) 49 + ->setContinueOnNoEffect(true); 50 + 51 + $editor->applyTransactions($config, $xactions); 52 + 53 + return id(new AphrontRedirectResponse()) 54 + ->setURI($cancel_uri); 55 + } 56 + 57 + $fields = $engine->getFieldsForConfig($config); 58 + 59 + $help = pht(<<<EOTEXT 60 + Choose the object **subtype** that this form should create and edit. 61 + EOTEXT 62 + ); 63 + 64 + $map = $engine->newSubtypeMap(); 65 + $map = mpull($map, 'getName'); 66 + 67 + $form = id(new AphrontFormView()) 68 + ->setUser($viewer) 69 + ->appendRemarkupInstructions($help) 70 + ->appendControl( 71 + id(new AphrontFormSelectControl()) 72 + ->setName('subtype') 73 + ->setLabel(pht('Subtype')) 74 + ->setValue($config->getSubtype()) 75 + ->setOptions($map)); 76 + 77 + return $this->newDialog() 78 + ->setTitle(pht('Change Form Subtype')) 79 + ->setWidth(AphrontDialogView::WIDTH_FORM) 80 + ->appendForm($form) 81 + ->addSubmitButton(pht('Save Changes')) 82 + ->addCancelButton($cancel_uri); 83 + } 84 + 85 + }
+21
src/applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php
··· 151 151 ->setWorkflow(true) 152 152 ->setDisabled(!$can_edit)); 153 153 154 + if ($engine->supportsSubtypes()) { 155 + $subtype_uri = "{$base_uri}/subtype/{$form_key}/"; 156 + 157 + $curtain->addAction( 158 + id(new PhabricatorActionView()) 159 + ->setName(pht('Change Form Subtype')) 160 + ->setIcon('fa-drivers-license-o') 161 + ->setHref($subtype_uri) 162 + ->setWorkflow(true) 163 + ->setDisabled(!$can_edit)); 164 + } 165 + 166 + $curtain->addAction( 167 + id(new PhabricatorActionView()) 168 + ->setName(pht('Change Default Values')) 169 + ->setIcon('fa-paint-brush') 170 + ->setHref($defaults_uri) 171 + ->setWorkflow(!$can_edit) 172 + ->setDisabled(!$can_edit)); 173 + 174 + 154 175 $disable_uri = "{$base_uri}/disable/{$form_key}/"; 155 176 156 177 if ($config->getIsDisabled()) {
+14
src/applications/transactions/editengine/PhabricatorEditEngine.php
··· 213 213 return $fields; 214 214 } 215 215 216 + final public function supportsSubtypes() { 217 + try { 218 + $object = $this->newEditableObject(); 219 + } catch (Exception $ex) { 220 + return false; 221 + } 222 + 223 + return ($object instanceof PhabricatorEditEngineSubtypeInterface); 224 + } 225 + 226 + final public function newSubtypeMap() { 227 + return $this->newEditableObject()->newEditEngineSubtypeMap(); 228 + } 229 + 216 230 217 231 /* -( Display Text )------------------------------------------------------- */ 218 232
+36
src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php
··· 6 6 7 7 const SUBTYPE_DEFAULT = 'default'; 8 8 9 + private $key; 10 + private $name; 11 + 12 + public function setKey($key) { 13 + $this->key = $key; 14 + return $this; 15 + } 16 + 17 + public function getKey() { 18 + return $this->key; 19 + } 20 + 21 + public function setName($name) { 22 + $this->name = $name; 23 + return $this; 24 + } 25 + 26 + public function getName() { 27 + return $this->name; 28 + } 29 + 9 30 public static function validateSubtypeKey($subtype) { 10 31 if (strlen($subtype) > 64) { 11 32 throw new Exception( ··· 79 100 'with key "%s". This subtype is required and must be defined.', 80 101 self::SUBTYPE_DEFAULT)); 81 102 } 103 + } 104 + 105 + public static function newSubtypeMap(array $config) { 106 + $map = array(); 107 + 108 + foreach ($config as $entry) { 109 + $key = $entry['key']; 110 + $name = $entry['name']; 111 + 112 + $map[$key] = id(new self()) 113 + ->setKey($key) 114 + ->setName($name); 115 + } 116 + 117 + return $map; 82 118 } 83 119 84 120 }
+1
src/applications/transactions/editengine/PhabricatorEditEngineSubtypeInterface.php
··· 4 4 5 5 public function getEditEngineSubtype(); 6 6 public function setEditEngineSubtype($subtype); 7 + public function newEditEngineSubtypeMap(); 7 8 8 9 }
+25
src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditor.php
··· 21 21 $types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_ORDER; 22 22 $types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULT; 23 23 $types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_LOCKS; 24 + $types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_SUBTYPE; 24 25 $types[] = 25 26 PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE; 26 27 $types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_ISEDIT; ··· 55 56 $errors[] = $error; 56 57 } 57 58 break; 59 + case PhabricatorEditEngineConfigurationTransaction::TYPE_SUBTYPE: 60 + $map = $object->getEngine()->newSubtypeMap(); 61 + foreach ($xactions as $xaction) { 62 + $new = $xaction->getNewValue(); 63 + 64 + if (isset($map[$new])) { 65 + continue; 66 + } 67 + 68 + $errors[] = new PhabricatorApplicationTransactionValidationError( 69 + $type, 70 + pht('Invalid'), 71 + pht('Subtype "%s" is not a valid subtype.', $new), 72 + $xaction); 73 + } 74 + break; 58 75 } 59 76 60 77 return $errors; ··· 76 93 return $object->getFieldDefault($field_key); 77 94 case PhabricatorEditEngineConfigurationTransaction::TYPE_LOCKS: 78 95 return $object->getFieldLocks(); 96 + case PhabricatorEditEngineConfigurationTransaction::TYPE_SUBTYPE: 97 + return $object->getSubtype(); 79 98 case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE: 80 99 return (int)$object->getIsDefault(); 81 100 case PhabricatorEditEngineConfigurationTransaction::TYPE_ISEDIT: ··· 86 105 return (int)$object->getCreateOrder(); 87 106 case PhabricatorEditEngineConfigurationTransaction::TYPE_EDITORDER: 88 107 return (int)$object->getEditOrder(); 108 + 89 109 } 90 110 } 91 111 ··· 99 119 case PhabricatorEditEngineConfigurationTransaction::TYPE_ORDER: 100 120 case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULT: 101 121 case PhabricatorEditEngineConfigurationTransaction::TYPE_LOCKS: 122 + case PhabricatorEditEngineConfigurationTransaction::TYPE_SUBTYPE: 102 123 return $xaction->getNewValue(); 103 124 case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE: 104 125 case PhabricatorEditEngineConfigurationTransaction::TYPE_ISEDIT: ··· 130 151 case PhabricatorEditEngineConfigurationTransaction::TYPE_LOCKS: 131 152 $object->setFieldLocks($xaction->getNewValue()); 132 153 return; 154 + case PhabricatorEditEngineConfigurationTransaction::TYPE_SUBTYPE: 155 + $object->setSubtype($xaction->getNewValue()); 156 + return; 133 157 case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE: 134 158 $object->setIsDefault($xaction->getNewValue()); 135 159 return; ··· 161 185 case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULT: 162 186 case PhabricatorEditEngineConfigurationTransaction::TYPE_ISEDIT: 163 187 case PhabricatorEditEngineConfigurationTransaction::TYPE_LOCKS: 188 + case PhabricatorEditEngineConfigurationTransaction::TYPE_SUBTYPE: 164 189 case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE: 165 190 case PhabricatorEditEngineConfigurationTransaction::TYPE_DISABLE: 166 191 case PhabricatorEditEngineConfigurationTransaction::TYPE_CREATEORDER:
+7
src/applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php
··· 13 13 const TYPE_DISABLE = 'editengine.config.disable'; 14 14 const TYPE_CREATEORDER = 'editengine.order.create'; 15 15 const TYPE_EDITORDER = 'editengine.order.edit'; 16 + const TYPE_SUBTYPE = 'editengine.config.subtype'; 16 17 17 18 public function getApplicationName() { 18 19 return 'search'; ··· 99 100 '%s enabled this form.', 100 101 $this->renderHandleLink($author_phid)); 101 102 } 103 + case self::TYPE_SUBTYPE: 104 + return pht( 105 + '%s changed the subtype of this form from "%s" to "%s".', 106 + $this->renderHandleLink($author_phid), 107 + $old, 108 + $new); 102 109 } 103 110 104 111 return parent::getTitle();