From b9d60d2653a3fb0fd12caa7c4dfaa4f1180b564d Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 1 Mar 2017 16:04:25 -0800 Subject: [PATCH] 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 --- src/__phutil_library_map__.php | 2 + .../maniphest/storage/ManiphestTask.php | 5 ++ .../PhabricatorTransactionsApplication.php | 2 + ...itEngineConfigurationSubtypeController.php | 85 +++++++++++++++++++ ...rEditEngineConfigurationViewController.php | 21 +++++ .../editengine/PhabricatorEditEngine.php | 14 +++ .../PhabricatorEditEngineSubtype.php | 36 ++++++++ .../PhabricatorEditEngineSubtypeInterface.php | 1 + ...abricatorEditEngineConfigurationEditor.php | 25 ++++++ ...atorEditEngineConfigurationTransaction.php | 7 ++ 10 files changed, 198 insertions(+) create mode 100644 src/applications/transactions/controller/PhabricatorEditEngineConfigurationSubtypeController.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index ca4d9978c4..cb2cfa36b5 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2610,6 +2610,7 @@ phutil_register_library_map(array( 'PhabricatorEditEngineConfigurationSaveController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationSaveController.php', 'PhabricatorEditEngineConfigurationSearchEngine' => 'applications/transactions/query/PhabricatorEditEngineConfigurationSearchEngine.php', 'PhabricatorEditEngineConfigurationSortController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationSortController.php', + 'PhabricatorEditEngineConfigurationSubtypeController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationSubtypeController.php', 'PhabricatorEditEngineConfigurationTransaction' => 'applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php', 'PhabricatorEditEngineConfigurationTransactionQuery' => 'applications/transactions/query/PhabricatorEditEngineConfigurationTransactionQuery.php', 'PhabricatorEditEngineConfigurationViewController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php', @@ -7669,6 +7670,7 @@ phutil_register_library_map(array( 'PhabricatorEditEngineConfigurationSaveController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineConfigurationSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorEditEngineConfigurationSortController' => 'PhabricatorEditEngineController', + 'PhabricatorEditEngineConfigurationSubtypeController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineConfigurationTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorEditEngineConfigurationTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorEditEngineConfigurationViewController' => 'PhabricatorEditEngineController', diff --git a/src/applications/maniphest/storage/ManiphestTask.php b/src/applications/maniphest/storage/ManiphestTask.php index aa59378e20..be540b9056 100644 --- a/src/applications/maniphest/storage/ManiphestTask.php +++ b/src/applications/maniphest/storage/ManiphestTask.php @@ -557,4 +557,9 @@ final class ManiphestTask extends ManiphestDAO return $this->setSubtype($value); } + public function newEditEngineSubtypeMap() { + $config = PhabricatorEnv::getEnvConfig('maniphest.subtypes'); + return PhabricatorEditEngineSubtype::newSubtypeMap($config); + } + } diff --git a/src/applications/transactions/application/PhabricatorTransactionsApplication.php b/src/applications/transactions/application/PhabricatorTransactionsApplication.php index 51c88e990d..f5e40671fe 100644 --- a/src/applications/transactions/application/PhabricatorTransactionsApplication.php +++ b/src/applications/transactions/application/PhabricatorTransactionsApplication.php @@ -55,6 +55,8 @@ final class PhabricatorTransactionsApplication extends PhabricatorApplication { 'PhabricatorEditEngineConfigurationDefaultsController', 'lock/(?P[^/]+)/' => 'PhabricatorEditEngineConfigurationLockController', + 'subtype/(?P[^/]+)/' => + 'PhabricatorEditEngineConfigurationSubtypeController', 'defaultcreate/(?P[^/]+)/' => 'PhabricatorEditEngineConfigurationDefaultCreateController', 'defaultedit/(?P[^/]+)/' => diff --git a/src/applications/transactions/controller/PhabricatorEditEngineConfigurationSubtypeController.php b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationSubtypeController.php new file mode 100644 index 0000000000..92bc34c72b --- /dev/null +++ b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationSubtypeController.php @@ -0,0 +1,85 @@ +getURIData('engineKey'); + $this->setEngineKey($engine_key); + + $key = $request->getURIData('key'); + $viewer = $this->getViewer(); + + $config = id(new PhabricatorEditEngineConfigurationQuery()) + ->setViewer($viewer) + ->withEngineKeys(array($engine_key)) + ->withIdentifiers(array($key)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$config) { + return new Aphront404Response(); + } + + $cancel_uri = "/transactions/editengine/{$engine_key}/view/{$key}/"; + + $engine = $config->getEngine(); + if (!$engine->supportsSubtypes()) { + return new Aphront404Response(); + } + + if ($request->isFormPost()) { + $xactions = array(); + + $subtype = $request->getStr('subtype'); + $type_subtype = + PhabricatorEditEngineConfigurationTransaction::TYPE_SUBTYPE; + + $xactions[] = id(new PhabricatorEditEngineConfigurationTransaction()) + ->setTransactionType($type_subtype) + ->setNewValue($subtype); + + $editor = id(new PhabricatorEditEngineConfigurationEditor()) + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnMissingFields(true) + ->setContinueOnNoEffect(true); + + $editor->applyTransactions($config, $xactions); + + return id(new AphrontRedirectResponse()) + ->setURI($cancel_uri); + } + + $fields = $engine->getFieldsForConfig($config); + + $help = pht(<<newSubtypeMap(); + $map = mpull($map, 'getName'); + + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->appendRemarkupInstructions($help) + ->appendControl( + id(new AphrontFormSelectControl()) + ->setName('subtype') + ->setLabel(pht('Subtype')) + ->setValue($config->getSubtype()) + ->setOptions($map)); + + return $this->newDialog() + ->setTitle(pht('Change Form Subtype')) + ->setWidth(AphrontDialogView::WIDTH_FORM) + ->appendForm($form) + ->addSubmitButton(pht('Save Changes')) + ->addCancelButton($cancel_uri); + } + +} diff --git a/src/applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php index 23ccedd04d..c07b2d5f3d 100644 --- a/src/applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php +++ b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php @@ -151,6 +151,27 @@ final class PhabricatorEditEngineConfigurationViewController ->setWorkflow(true) ->setDisabled(!$can_edit)); + if ($engine->supportsSubtypes()) { + $subtype_uri = "{$base_uri}/subtype/{$form_key}/"; + + $curtain->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Change Form Subtype')) + ->setIcon('fa-drivers-license-o') + ->setHref($subtype_uri) + ->setWorkflow(true) + ->setDisabled(!$can_edit)); + } + + $curtain->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Change Default Values')) + ->setIcon('fa-paint-brush') + ->setHref($defaults_uri) + ->setWorkflow(!$can_edit) + ->setDisabled(!$can_edit)); + + $disable_uri = "{$base_uri}/disable/{$form_key}/"; if ($config->getIsDisabled()) { diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php index 44b794bceb..88604e99bc 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngine.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php @@ -213,6 +213,20 @@ abstract class PhabricatorEditEngine return $fields; } + final public function supportsSubtypes() { + try { + $object = $this->newEditableObject(); + } catch (Exception $ex) { + return false; + } + + return ($object instanceof PhabricatorEditEngineSubtypeInterface); + } + + final public function newSubtypeMap() { + return $this->newEditableObject()->newEditEngineSubtypeMap(); + } + /* -( Display Text )------------------------------------------------------- */ diff --git a/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php b/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php index 038267834c..6c03e17ee4 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php @@ -6,6 +6,27 @@ final class PhabricatorEditEngineSubtype const SUBTYPE_DEFAULT = 'default'; + private $key; + private $name; + + public function setKey($key) { + $this->key = $key; + return $this; + } + + public function getKey() { + return $this->key; + } + + public function setName($name) { + $this->name = $name; + return $this; + } + + public function getName() { + return $this->name; + } + public static function validateSubtypeKey($subtype) { if (strlen($subtype) > 64) { throw new Exception( @@ -81,4 +102,19 @@ final class PhabricatorEditEngineSubtype } } + public static function newSubtypeMap(array $config) { + $map = array(); + + foreach ($config as $entry) { + $key = $entry['key']; + $name = $entry['name']; + + $map[$key] = id(new self()) + ->setKey($key) + ->setName($name); + } + + return $map; + } + } diff --git a/src/applications/transactions/editengine/PhabricatorEditEngineSubtypeInterface.php b/src/applications/transactions/editengine/PhabricatorEditEngineSubtypeInterface.php index 9c15232b7e..8058e0702c 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngineSubtypeInterface.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngineSubtypeInterface.php @@ -4,5 +4,6 @@ interface PhabricatorEditEngineSubtypeInterface { public function getEditEngineSubtype(); public function setEditEngineSubtype($subtype); + public function newEditEngineSubtypeMap(); } diff --git a/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditor.php b/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditor.php index b8e9d908a4..fb07d251be 100644 --- a/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditor.php +++ b/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditor.php @@ -21,6 +21,7 @@ final class PhabricatorEditEngineConfigurationEditor $types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_ORDER; $types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULT; $types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_LOCKS; + $types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_SUBTYPE; $types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE; $types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_ISEDIT; @@ -55,6 +56,22 @@ final class PhabricatorEditEngineConfigurationEditor $errors[] = $error; } break; + case PhabricatorEditEngineConfigurationTransaction::TYPE_SUBTYPE: + $map = $object->getEngine()->newSubtypeMap(); + foreach ($xactions as $xaction) { + $new = $xaction->getNewValue(); + + if (isset($map[$new])) { + continue; + } + + $errors[] = new PhabricatorApplicationTransactionValidationError( + $type, + pht('Invalid'), + pht('Subtype "%s" is not a valid subtype.', $new), + $xaction); + } + break; } return $errors; @@ -76,6 +93,8 @@ final class PhabricatorEditEngineConfigurationEditor return $object->getFieldDefault($field_key); case PhabricatorEditEngineConfigurationTransaction::TYPE_LOCKS: return $object->getFieldLocks(); + case PhabricatorEditEngineConfigurationTransaction::TYPE_SUBTYPE: + return $object->getSubtype(); case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE: return (int)$object->getIsDefault(); case PhabricatorEditEngineConfigurationTransaction::TYPE_ISEDIT: @@ -86,6 +105,7 @@ final class PhabricatorEditEngineConfigurationEditor return (int)$object->getCreateOrder(); case PhabricatorEditEngineConfigurationTransaction::TYPE_EDITORDER: return (int)$object->getEditOrder(); + } } @@ -99,6 +119,7 @@ final class PhabricatorEditEngineConfigurationEditor case PhabricatorEditEngineConfigurationTransaction::TYPE_ORDER: case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULT: case PhabricatorEditEngineConfigurationTransaction::TYPE_LOCKS: + case PhabricatorEditEngineConfigurationTransaction::TYPE_SUBTYPE: return $xaction->getNewValue(); case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE: case PhabricatorEditEngineConfigurationTransaction::TYPE_ISEDIT: @@ -130,6 +151,9 @@ final class PhabricatorEditEngineConfigurationEditor case PhabricatorEditEngineConfigurationTransaction::TYPE_LOCKS: $object->setFieldLocks($xaction->getNewValue()); return; + case PhabricatorEditEngineConfigurationTransaction::TYPE_SUBTYPE: + $object->setSubtype($xaction->getNewValue()); + return; case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE: $object->setIsDefault($xaction->getNewValue()); return; @@ -161,6 +185,7 @@ final class PhabricatorEditEngineConfigurationEditor case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULT: case PhabricatorEditEngineConfigurationTransaction::TYPE_ISEDIT: case PhabricatorEditEngineConfigurationTransaction::TYPE_LOCKS: + case PhabricatorEditEngineConfigurationTransaction::TYPE_SUBTYPE: case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE: case PhabricatorEditEngineConfigurationTransaction::TYPE_DISABLE: case PhabricatorEditEngineConfigurationTransaction::TYPE_CREATEORDER: diff --git a/src/applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php b/src/applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php index 4bae34e5eb..a1c44cc003 100644 --- a/src/applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php +++ b/src/applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php @@ -13,6 +13,7 @@ final class PhabricatorEditEngineConfigurationTransaction const TYPE_DISABLE = 'editengine.config.disable'; const TYPE_CREATEORDER = 'editengine.order.create'; const TYPE_EDITORDER = 'editengine.order.edit'; + const TYPE_SUBTYPE = 'editengine.config.subtype'; public function getApplicationName() { return 'search'; @@ -99,6 +100,12 @@ final class PhabricatorEditEngineConfigurationTransaction '%s enabled this form.', $this->renderHandleLink($author_phid)); } + case self::TYPE_SUBTYPE: + return pht( + '%s changed the subtype of this form from "%s" to "%s".', + $this->renderHandleLink($author_phid), + $old, + $new); } return parent::getTitle();