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 @@ -2114,7 +2114,9 @@ 'PhabricatorEditEngine' => 'applications/transactions/editengine/PhabricatorEditEngine.php', 'PhabricatorEditEngineAPIMethod' => 'applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php', 'PhabricatorEditEngineConfiguration' => 'applications/transactions/storage/PhabricatorEditEngineConfiguration.php', + 'PhabricatorEditEngineConfigurationDefaultCreateController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationDefaultCreateController.php', 'PhabricatorEditEngineConfigurationDefaultsController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationDefaultsController.php', + 'PhabricatorEditEngineConfigurationDisableController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationDisableController.php', 'PhabricatorEditEngineConfigurationEditController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationEditController.php', 'PhabricatorEditEngineConfigurationEditEngine' => 'applications/transactions/editor/PhabricatorEditEngineConfigurationEditEngine.php', 'PhabricatorEditEngineConfigurationEditor' => 'applications/transactions/editor/PhabricatorEditEngineConfigurationEditor.php', @@ -6210,7 +6212,9 @@ 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', ), + 'PhabricatorEditEngineConfigurationDefaultCreateController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineConfigurationDefaultsController' => 'PhabricatorEditEngineController', + 'PhabricatorEditEngineConfigurationDisableController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineConfigurationEditController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineConfigurationEditEngine' => 'PhabricatorEditEngine', 'PhabricatorEditEngineConfigurationEditor' => 'PhabricatorApplicationTransactionEditor', diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -640,7 +640,7 @@ '(?P[0-9]\d*)/)?'. '(?:'. '(?:'. - '(?Pparameters)'. + '(?Pparameters|nodefault)'. '|'. '(?:form/(?P[^/]+))'. ')'. diff --git a/src/applications/paste/controller/PhabricatorPasteListController.php b/src/applications/paste/controller/PhabricatorPasteListController.php --- a/src/applications/paste/controller/PhabricatorPasteListController.php +++ b/src/applications/paste/controller/PhabricatorPasteListController.php @@ -15,11 +15,9 @@ protected function buildApplicationCrumbs() { $crumbs = parent::buildApplicationCrumbs(); - $crumbs->addAction( - id(new PHUIListItemView()) - ->setName(pht('Create Paste')) - ->setHref($this->getApplicationURI('edit/')) - ->setIcon('fa-plus-square')); + id(new PhabricatorPasteEditEngine()) + ->setViewer($this->getViewer()) + ->addActionToCrumbs($crumbs); return $crumbs; } diff --git a/src/applications/transactions/application/PhabricatorTransactionsApplication.php b/src/applications/transactions/application/PhabricatorTransactionsApplication.php --- a/src/applications/transactions/application/PhabricatorTransactionsApplication.php +++ b/src/applications/transactions/application/PhabricatorTransactionsApplication.php @@ -51,6 +51,10 @@ 'PhabricatorEditEngineConfigurationDefaultsController', 'lock/(?P[^/]+)/' => 'PhabricatorEditEngineConfigurationLockController', + 'defaultcreate/(?P[^/]+)/' => + 'PhabricatorEditEngineConfigurationDefaultCreateController', + 'disable/(?P[^/]+)/' => + 'PhabricatorEditEngineConfigurationDisableController', ), ), ), diff --git a/src/applications/transactions/controller/PhabricatorEditEngineConfigurationDefaultCreateController.php b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationDefaultCreateController.php new file mode 100644 --- /dev/null +++ b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationDefaultCreateController.php @@ -0,0 +1,61 @@ +getViewer(); + + $config = $this->loadConfigForEdit(); + if (!$config) { + return id(new Aphront404Response()); + } + + $engine_key = $config->getEngineKey(); + $key = $config->getIdentifier(); + $cancel_uri = "/transactions/editengine/{$engine_key}/view/{$key}/"; + + $type = PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE; + + if ($request->isFormPost()) { + $xactions = array(); + + $xactions[] = id(new PhabricatorEditEngineConfigurationTransaction()) + ->setTransactionType($type) + ->setNewValue(!$config->getIsDefault()); + + $editor = id(new PhabricatorEditEngineConfigurationEditor()) + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnMissingFields(true) + ->setContinueOnNoEffect(true); + + $editor->applyTransactions($config, $xactions); + + return id(new AphrontRedirectResponse()) + ->setURI($cancel_uri); + } + + if ($config->getIsDefault()) { + $title = pht('Remove From "Create" Menu'); + $body = pht( + 'Remove this form from the application "Create" menu? It will still '. + 'function properly, but no longer be reachable directly from the '. + 'application.'); + $button = pht('Remove From Menu'); + } else { + $title = pht('Add To "Create" Menu'); + $body = pht( + 'Add this form to the application "Create" menu? Users will '. + 'be able to choose it when creating new objects.'); + $button = pht('Add To Menu'); + } + + return $this->newDialog() + ->setTitle($title) + ->appendParagraph($body) + ->addSubmitButton($button) + ->addCancelbutton($cancel_uri); + } + +} diff --git a/src/applications/transactions/controller/PhabricatorEditEngineConfigurationDisableController.php b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationDisableController.php new file mode 100644 --- /dev/null +++ b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationDisableController.php @@ -0,0 +1,59 @@ +getViewer(); + + $config = $this->loadConfigForEdit(); + if (!$config) { + return id(new Aphront404Response()); + } + + $engine_key = $config->getEngineKey(); + $key = $config->getIdentifier(); + $cancel_uri = "/transactions/editengine/{$engine_key}/view/{$key}/"; + + $type = PhabricatorEditEngineConfigurationTransaction::TYPE_DISABLE; + + if ($request->isFormPost()) { + $xactions = array(); + + $xactions[] = id(new PhabricatorEditEngineConfigurationTransaction()) + ->setTransactionType($type) + ->setNewValue(!$config->getIsDisabled()); + + $editor = id(new PhabricatorEditEngineConfigurationEditor()) + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnMissingFields(true) + ->setContinueOnNoEffect(true); + + $editor->applyTransactions($config, $xactions); + + return id(new AphrontRedirectResponse()) + ->setURI($cancel_uri); + } + + if ($config->getIsDisabled()) { + $title = pht('Enable Form'); + $body = pht( + 'Enable this form? Users who can see it will be able to use it to '. + 'create objects.'); + $button = pht('Enable Form'); + } else { + $title = pht('Disable Form'); + $body = pht( + 'Disable this form? Users will no longer be able to use it.'); + $button = pht('Disable Form'); + } + + return $this->newDialog() + ->setTitle($title) + ->appendParagraph($body) + ->addSubmitButton($button) + ->addCancelbutton($cancel_uri); + } + +} diff --git a/src/applications/transactions/controller/PhabricatorEditEngineConfigurationListController.php b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationListController.php --- a/src/applications/transactions/controller/PhabricatorEditEngineConfigurationListController.php +++ b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationListController.php @@ -17,16 +17,16 @@ } protected function buildApplicationCrumbs() { + $viewer = $this->getViewer(); $crumbs = parent::buildApplicationCrumbs(); - $engine_key = $this->getEngineKey(); - $edit_uri = "/transactions/editengine/{$engine_key}/edit/"; + $target_key = $this->getEngineKey(); + $target_engine = PhabricatorEditEngine::getByKey($viewer, $target_key); - $crumbs->addAction( - id(new PHUIListItemView()) - ->setName(pht('New Form')) - ->setHref($edit_uri) - ->setIcon('fa-plus-square')); + id(new PhabricatorEditEngineConfigurationEditEngine()) + ->setTargetEngine($target_engine) + ->setViewer($viewer) + ->addActionToCrumbs($crumbs); return $crumbs; } diff --git a/src/applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php --- a/src/applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php +++ b/src/applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php @@ -8,17 +8,9 @@ } public function handleRequest(AphrontRequest $request) { - $engine_key = $request->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)) - ->executeOne(); + $config = $this->loadConfigForEdit(); if (!$config) { return id(new Aphront404Response()); } @@ -149,6 +141,42 @@ ->setWorkflow(true) ->setDisabled(!$can_edit)); + $disable_uri = "{$base_uri}/disable/{$form_key}/"; + + if ($config->getIsDisabled()) { + $disable_name = pht('Enable Form'); + $disable_icon = 'fa-check'; + } else { + $disable_name = pht('Disable Form'); + $disable_icon = 'fa-ban'; + } + + $view->addAction( + id(new PhabricatorActionView()) + ->setName($disable_name) + ->setIcon($disable_icon) + ->setHref($disable_uri) + ->setWorkflow(true) + ->setDisabled(!$can_edit)); + + $defaultcreate_uri = "{$base_uri}/defaultcreate/{$form_key}/"; + + if ($config->getIsDefault()) { + $defaultcreate_name = pht('Remove from "Create" Menu'); + $defaultcreate_icon = 'fa-minus'; + } else { + $defaultcreate_name = pht('Add to "Create" Menu'); + $defaultcreate_icon = 'fa-plus'; + } + + $view->addAction( + id(new PhabricatorActionView()) + ->setName($defaultcreate_name) + ->setIcon($defaultcreate_icon) + ->setHref($defaultcreate_uri) + ->setWorkflow(true) + ->setDisabled(!$can_edit)); + return $view; } diff --git a/src/applications/transactions/controller/PhabricatorEditEngineController.php b/src/applications/transactions/controller/PhabricatorEditEngineController.php --- a/src/applications/transactions/controller/PhabricatorEditEngineController.php +++ b/src/applications/transactions/controller/PhabricatorEditEngineController.php @@ -34,4 +34,39 @@ return $crumbs; } + protected function loadConfigForEdit() { + $request = $this->getRequest(); + $viewer = $this->getViewer(); + + $engine_key = $request->getURIData('engineKey'); + $this->setEngineKey($engine_key); + + $key = $request->getURIData('key'); + + $config = id(new PhabricatorEditEngineConfigurationQuery()) + ->setViewer($viewer) + ->withEngineKeys(array($engine_key)) + ->withIdentifiers(array($key)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + + if ($config) { + $engine = $config->getEngine(); + + // TODO: When we're editing the meta-engine, we need to set the engine + // itself as its own target. This is hacky and it would be nice to find + // a cleaner approach later. + if ($engine instanceof PhabricatorEditEngineConfigurationEditEngine) { + $engine->setTargetEngine($engine); + } + } + + return $config; + } + + } diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php --- a/src/applications/transactions/editengine/PhabricatorEditEngine.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php @@ -352,7 +352,9 @@ if (!$has_default) { $first = head($configurations); if (!$first->getBuiltinKey()) { - $first->setBuiltinKey(self::EDITENGINECONFIG_DEFAULT); + $first + ->setBuiltinKey(self::EDITENGINECONFIG_DEFAULT) + ->setIsDefault(true); if (!strlen($first->getName())) { $first->setName($this->getObjectCreateShortText()); @@ -629,6 +631,8 @@ switch ($action) { case 'parameters': return $this->buildParametersResponse($object); + case 'nodefault': + return $this->buildNoDefaultResponse($object); default: return $this->buildEditResponse($object); } @@ -820,6 +824,74 @@ return $actions; } + final public function addActionToCrumbs(PHUICrumbsView $crumbs) { + $viewer = $this->getViewer(); + + $configs = id(new PhabricatorEditEngineConfigurationQuery()) + ->setViewer($viewer) + ->withEngineKeys(array($this->getEngineKey())) + ->withIsDefault(true) + ->withIsDisabled(false) + ->execute(); + + $dropdown = null; + $disabled = false; + $workflow = false; + + $menu_icon = 'fa-plus-square'; + + if (!$configs) { + if ($viewer->isLoggedIn()) { + $disabled = true; + } else { + // If the viewer isn't logged in, assume they'll get hit with a login + // dialog and are likely able to create objects after they log in. + $disabled = false; + } + $workflow = true; + $create_uri = $this->getEditURI(null, 'nodefault/'); + } else { + $config = head($configs); + $form_key = $config->getIdentifier(); + $create_uri = $this->getEditURI(null, "form/{$form_key}/"); + + if (count($configs) > 1) { + $configs = msort($configs, 'getDisplayName'); + + $menu_icon = 'fa-caret-square-o-down'; + + $dropdown = id(new PhabricatorActionListView()) + ->setUser($viewer); + + foreach ($configs as $config) { + $form_key = $config->getIdentifier(); + $config_uri = $this->getEditURI(null, "form/{$form_key}/"); + + $item_icon = 'fa-plus'; + + $dropdown->addAction( + id(new PhabricatorActionView()) + ->setName($config->getDisplayName()) + ->setIcon($item_icon) + ->setHref($config_uri)); + } + } + } + + $action = id(new PHUIListItemView()) + ->setName($this->getObjectCreateShortText()) + ->setHref($create_uri) + ->setIcon($menu_icon) + ->setWorkflow($workflow) + ->setDisabled($disabled); + + if ($dropdown) { + $action->setDropdownMenu($dropdown); + } + + $crumbs->addAction($action); + } + /* -( Responding to HTTP Parameter Requests )------------------------------ */ @@ -864,6 +936,19 @@ } + private function buildNoDefaultResponse($object) { + $cancel_uri = $this->getObjectCreateCancelURI($object); + + return $this->getController() + ->newDialog() + ->setTitle(pht('No Default Create Forms')) + ->appendParagraph( + pht( + 'This application is not configured with any visible, enabled '. + 'forms for creating objects.')) + ->addCancelButton($cancel_uri); + } + /* -( Conduit )------------------------------------------------------------ */ diff --git a/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditEngine.php b/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditEngine.php --- a/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditEngine.php +++ b/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditEngine.php @@ -13,6 +13,9 @@ } public function getTargetEngine() { + if (!$this->targetEngine) { + throw new PhutilInvalidStateException('setTargetEngine'); + } return $this->targetEngine; } diff --git a/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditor.php b/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditor.php --- a/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditor.php +++ b/src/applications/transactions/editor/PhabricatorEditEngineConfigurationEditor.php @@ -22,6 +22,10 @@ $types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_ORDER; $types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULT; $types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_LOCKS; + $types[] = + PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE; + $types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_DISABLE; + return $types; } @@ -70,6 +74,10 @@ return $object->getFieldDefault($field_key); case PhabricatorEditEngineConfigurationTransaction::TYPE_LOCKS: return $object->getFieldLocks(); + case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE: + return (int)$object->getIsDefault(); + case PhabricatorEditEngineConfigurationTransaction::TYPE_DISABLE: + return (int)$object->getIsDisabled(); } } @@ -84,6 +92,9 @@ case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULT: case PhabricatorEditEngineConfigurationTransaction::TYPE_LOCKS: return $xaction->getNewValue(); + case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE: + case PhabricatorEditEngineConfigurationTransaction::TYPE_DISABLE: + return (int)$xaction->getNewValue(); } } @@ -108,6 +119,12 @@ case PhabricatorEditEngineConfigurationTransaction::TYPE_LOCKS: $object->setFieldLocks($xaction->getNewValue()); return; + case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE: + $object->setIsDefault($xaction->getNewValue()); + return; + case PhabricatorEditEngineConfigurationTransaction::TYPE_DISABLE: + $object->setIsDisabled($xaction->getNewValue()); + return; } return parent::applyCustomInternalTransaction($object, $xaction); @@ -123,6 +140,8 @@ case PhabricatorEditEngineConfigurationTransaction::TYPE_ORDER; case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULT: case PhabricatorEditEngineConfigurationTransaction::TYPE_LOCKS: + case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE: + case PhabricatorEditEngineConfigurationTransaction::TYPE_DISABLE: return; } diff --git a/src/applications/transactions/query/PhabricatorEditEngineConfigurationQuery.php b/src/applications/transactions/query/PhabricatorEditEngineConfigurationQuery.php --- a/src/applications/transactions/query/PhabricatorEditEngineConfigurationQuery.php +++ b/src/applications/transactions/query/PhabricatorEditEngineConfigurationQuery.php @@ -8,6 +8,8 @@ private $engineKeys; private $builtinKeys; private $identifiers; + private $default; + private $disabled; public function withIDs(array $ids) { $this->ids = $ids; @@ -34,6 +36,16 @@ return $this; } + public function withIsDefault($default) { + $this->default = $default; + return $this; + } + + public function withIsDisabled($disabled) { + $this->disabled = $disabled; + return $this; + } + public function newResultObject() { return new PhabricatorEditEngineConfiguration(); } @@ -118,6 +130,22 @@ } } + if ($this->default !== null) { + foreach ($page as $key => $config) { + if ($config->getIsDefault() != $this->default) { + unset($page[$key]); + } + } + } + + if ($this->disabled !== null) { + foreach ($page as $key => $config) { + if ($config->getIsDisabled() != $this->disabled) { + unset($page[$key]); + } + } + } + if ($this->identifiers !== null) { $identifiers = array_fuse($this->identifiers); foreach ($page as $key => $config) { diff --git a/src/applications/transactions/query/PhabricatorEditEngineConfigurationSearchEngine.php b/src/applications/transactions/query/PhabricatorEditEngineConfigurationSearchEngine.php --- a/src/applications/transactions/query/PhabricatorEditEngineConfigurationSearchEngine.php +++ b/src/applications/transactions/query/PhabricatorEditEngineConfigurationSearchEngine.php @@ -92,6 +92,13 @@ } $item->setHref("/transactions/editengine/{$engine_key}/view/{$key}/"); + if ($config->getIsDefault()) { + $item->addIcon('fa-plus', pht('Default')); + } + + if ($config->getIsDisabled()) { + $item->addIcon('fa-ban', pht('Disabled')); + } $list->addItem($item); } diff --git a/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php b/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php --- a/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php +++ b/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php @@ -29,7 +29,7 @@ PhabricatorUser $actor, PhabricatorEditEngine $engine) { - // TODO: This should probably be controlled by a new defualt capability. + // TODO: This should probably be controlled by a new default capability. $edit_policy = PhabricatorPolicies::POLICY_ADMIN; return id(new PhabricatorEditEngineConfiguration()) diff --git a/src/applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php b/src/applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php --- a/src/applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php +++ b/src/applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php @@ -8,6 +8,8 @@ const TYPE_ORDER = 'editengine.config.order'; const TYPE_DEFAULT = 'editengine.config.default'; const TYPE_LOCKS = 'editengine.config.locks'; + const TYPE_DEFAULTCREATE = 'editengine.config.default.create'; + const TYPE_DISABLE = 'editengine.config.disable'; public function getApplicationName() { return 'search'; @@ -60,6 +62,26 @@ return pht( '%s changed locked and hidden fields.', $this->renderHandleLink($author_phid)); + case self::TYPE_DEFAULTCREATE: + if ($new) { + return pht( + '%s added this form to the "Create" menu.', + $this->renderHandleLink($author_phid)); + } else { + return pht( + '%s removed this form from the "Create" menu.', + $this->renderHandleLink($author_phid)); + } + case self::TYPE_DISABLE: + if ($new) { + return pht( + '%s disabled this form.', + $this->renderHandleLink($author_phid)); + } else { + return pht( + '%s enabled this form.', + $this->renderHandleLink($author_phid)); + } } return parent::getTitle();