diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -8,7 +8,7 @@ 'names' => array( 'core.pkg.css' => '4d72eb6e', - 'core.pkg.js' => '264721e1', + 'core.pkg.js' => 'dfe8b1da', 'darkconsole.pkg.js' => 'ca8671ce', 'differential.pkg.css' => 'cb97e095', 'differential.pkg.js' => '11a5b750', @@ -476,7 +476,7 @@ 'rsrc/js/core/behavior-tokenizer.js' => 'b3a4b884', 'rsrc/js/core/behavior-tooltip.js' => '48db4145', 'rsrc/js/core/behavior-watch-anchor.js' => '06e05112', - 'rsrc/js/core/behavior-workflow.js' => '82947dda', + 'rsrc/js/core/behavior-workflow.js' => 'fddc396f', 'rsrc/js/core/phtize.js' => 'd254d646', 'rsrc/js/phui/behavior-phui-object-box-tabs.js' => 'a3e2244e', 'rsrc/swf/aphlict.swf' => 'abac967d', @@ -628,7 +628,7 @@ 'javelin-behavior-test-payment-form' => 'b3e5ee60', 'javelin-behavior-toggle-class' => 'a82a7769', 'javelin-behavior-view-placeholder' => '2fa810fc', - 'javelin-behavior-workflow' => '82947dda', + 'javelin-behavior-workflow' => 'fddc396f', 'javelin-color' => '7e41274a', 'javelin-cookie' => '6b3dcf44', 'javelin-dom' => '5054855f', @@ -1332,13 +1332,6 @@ 0 => 'javelin-behavior', 1 => 'javelin-history', ), - '82947dda' => - array( - 0 => 'javelin-behavior', - 1 => 'javelin-stratcom', - 2 => 'javelin-workflow', - 3 => 'javelin-dom', - ), '82f568cd' => array( 0 => 'javelin-install', @@ -1947,6 +1940,13 @@ 0 => 'phabricator-busy', 1 => 'javelin-behavior', ), + 'fddc396f' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-stratcom', + 2 => 'javelin-workflow', + 3 => 'javelin-dom', + ), 'fe2e0ba4' => array( 0 => 'javelin-behavior', diff --git a/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php b/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php --- a/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php +++ b/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php @@ -149,8 +149,9 @@ - `default` This is the default status for newly created tasks. You must designate one status as default, and it must be an open status. - `closed` This is the default status for closed tasks (for example, tasks - closed via the "!close" action in email). You must designate one status - as the default closed status, and it must be a closed status. + closed via the "!close" action in email or via the quick close button in + Maniphest). You must designate one status as the default closed status, + and it must be a closed status. - `duplicate` This is the status used when tasks are merged into one another as duplicates. You must designate one status for duplicates, and it must be a closed status. diff --git a/src/applications/maniphest/controller/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/ManiphestTaskDetailController.php --- a/src/applications/maniphest/controller/ManiphestTaskDetailController.php +++ b/src/applications/maniphest/controller/ManiphestTaskDetailController.php @@ -208,6 +208,20 @@ $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); + $submit_text = $is_serious + ? pht('Submit') + : pht('Avast!'); + + $close_text = $is_serious + ? pht('Close Task') + : pht('Scuttle Task'); + + $submit_control = id(new PHUIFormMultiSubmitControl()); + if (!$task->isClosed()) { + $submit_control->addButton('scuttle', $close_text, 'grey'); + } + $submit_control->addSubmitButton($submit_text); + $comment_form = new AphrontFormView(); $comment_form ->setUser($user) @@ -273,9 +287,7 @@ ->setValue($draft_text) ->setID('transaction-comments') ->setUser($user)) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue($is_serious ? pht('Submit') : pht('Avast!'))); + ->appendChild($submit_control); $control_map = array( ManiphestTransaction::TYPE_STATUS => 'resolution', diff --git a/src/applications/maniphest/controller/ManiphestTransactionSaveController.php b/src/applications/maniphest/controller/ManiphestTransactionSaveController.php --- a/src/applications/maniphest/controller/ManiphestTransactionSaveController.php +++ b/src/applications/maniphest/controller/ManiphestTransactionSaveController.php @@ -130,6 +130,18 @@ $transactions[] = $transaction; } + $resolution = $request->getStr('resolution'); + $did_scuttle = false; + if ($action !== ManiphestTransaction::TYPE_STATUS) { + if ($request->getStr('scuttle')) { + $transactions[] = id(new ManiphestTransaction()) + ->setTransactionType(ManiphestTransaction::TYPE_STATUS) + ->setNewValue(ManiphestTaskStatus::getDefaultClosedStatus()); + $did_scuttle = true; + $resolution = ManiphestTaskStatus::getDefaultClosedStatus(); + } + } + // When you interact with a task, we add you to the CC list so you get // further updates, and possibly assign the task to you if you took an // ownership action (closing it) but it's currently unowned. We also move @@ -137,31 +149,28 @@ // and create side-effect transactions for them. $implicitly_claimed = false; - switch ($action) { - case ManiphestTransaction::TYPE_OWNER: - if ($task->getOwnerPHID() == $transaction->getNewValue()) { - // If this is actually no-op, don't generate the side effect. - break; - } - // Otherwise, when a task is reassigned, move the previous owner to CC. - $added_ccs[] = $task->getOwnerPHID(); - break; - case ManiphestTransaction::TYPE_STATUS: - $resolution = $request->getStr('resolution'); - if (!$task->getOwnerPHID() && - ManiphestTaskStatus::isClosedStatus($resolution)) { - // Closing an unassigned task. Assign the user as the owner of - // this task. - $assign = new ManiphestTransaction(); - $assign->setTransactionType(ManiphestTransaction::TYPE_OWNER); - $assign->setNewValue($user->getPHID()); - $transactions[] = $assign; - - $implicitly_claimed = true; - } + if ($action == ManiphestTransaction::TYPE_OWNER) { + if ($task->getOwnerPHID() == $transaction->getNewValue()) { + // If this is actually no-op, don't generate the side effect. break; + } + // Otherwise, when a task is reassigned, move the previous owner to CC. + $added_ccs[] = $task->getOwnerPHID(); } + if ($did_scuttle || ($action == ManiphestTransaction::TYPE_STATUS)) { + if (!$task->getOwnerPHID() && + ManiphestTaskStatus::isClosedStatus($resolution)) { + // Closing an unassigned task. Assign the user as the owner of + // this task. + $assign = new ManiphestTransaction(); + $assign->setTransactionType(ManiphestTransaction::TYPE_OWNER); + $assign->setNewValue($user->getPHID()); + $transactions[] = $assign; + + $implicitly_claimed = true; + } + } $user_owns_task = false; if ($implicitly_claimed) { diff --git a/src/view/form/control/AphrontFormSubmitControl.php b/src/view/form/control/AphrontFormSubmitControl.php --- a/src/view/form/control/AphrontFormSubmitControl.php +++ b/src/view/form/control/AphrontFormSubmitControl.php @@ -2,7 +2,7 @@ final class AphrontFormSubmitControl extends AphrontFormControl { - protected $cancelButton; + private $cancelButton; public function addCancelButton($href, $label = null) { if (!$label) { @@ -35,7 +35,11 @@ ), $this->getValue()); } - return hsprintf('%s%s', $submit_button, $this->cancelButton); + + return array( + $submit_button, + $this->cancelButton, + ); } } diff --git a/src/view/form/control/PHUIFormMultiSubmitControl.php b/src/view/form/control/PHUIFormMultiSubmitControl.php --- a/src/view/form/control/PHUIFormMultiSubmitControl.php +++ b/src/view/form/control/PHUIFormMultiSubmitControl.php @@ -32,13 +32,14 @@ } public function addButton($name, $label, $class = null) { - $this->buttons[] = phutil_tag( + $this->buttons[] = javelin_tag( 'input', array( 'type' => 'submit', 'name' => $name, 'value' => $label, 'class' => $class, + 'sigil' => 'alternate-submit-button', 'disabled' => $this->getDisabled() ? 'disabled' : null, )); return $this; diff --git a/webroot/rsrc/js/core/behavior-workflow.js b/webroot/rsrc/js/core/behavior-workflow.js --- a/webroot/rsrc/js/core/behavior-workflow.js +++ b/webroot/rsrc/js/core/behavior-workflow.js @@ -8,6 +8,22 @@ JX.behavior('workflow', function() { + // If a user clicks an alternate submit button, make sure it gets marshalled + // into the workflow. + JX.Stratcom.listen( + 'click', + ['workflow', 'tag:form', 'alternate-submit-button'], + function(e) { + e.prevent(); + + var target = e.getTarget(); + var form = e.getNode('tag:form'); + var button = {}; + button[target.name] = target.value || true; + + JX.DOM.invoke(form, 'didSyntheticSubmit', {extra: button}); + }); + // Listen for both real and synthetic submit events. JX.Stratcom.listen( ['submit', 'didSyntheticSubmit'], @@ -17,11 +33,14 @@ return; } + var data = e.getData(); + var extra = (data && data.extra) || {}; + // NOTE: We activate workflow if any parent node has the "workflow" sigil, // not just the
itself. e.prevent(); - JX.Workflow.newFromForm(e.getNode('tag:form')).start(); + JX.Workflow.newFromForm(e.getNode('tag:form'), extra).start(); }); JX.Stratcom.listen(