diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index e5de177302..c7d05a603f 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -1980,6 +1980,20 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/js/application/owners/owners-path-editor.js', ), + 'javelin-behavior-passphrase-credential-control' => + array( + 'uri' => '/res/b599c028/rsrc/js/application/passphrase/phame-credential-control.js', + 'type' => 'js', + 'requires' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-dom', + 2 => 'javelin-stratcom', + 3 => 'javelin-workflow', + 4 => 'javelin-util', + ), + 'disk' => '/rsrc/js/application/passphrase/phame-credential-control.js', + ), 'javelin-behavior-persona-login' => array( 'uri' => '/res/128fdf56/rsrc/js/application/auth/behavior-persona-login.js', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index b73bc4e28e..82bbb6263a 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -946,6 +946,7 @@ phutil_register_library_map(array( 'PackageModifyMail' => 'applications/owners/mail/PackageModifyMail.php', 'PassphraseController' => 'applications/passphrase/controller/PassphraseController.php', 'PassphraseCredential' => 'applications/passphrase/storage/PassphraseCredential.php', + 'PassphraseCredentialControl' => 'applications/passphrase/view/PassphraseCredentialControl.php', 'PassphraseCredentialCreateController' => 'applications/passphrase/controller/PassphraseCredentialCreateController.php', 'PassphraseCredentialDestroyController' => 'applications/passphrase/controller/PassphraseCredentialDestroyController.php', 'PassphraseCredentialEditController' => 'applications/passphrase/controller/PassphraseCredentialEditController.php', @@ -3329,6 +3330,7 @@ phutil_register_library_map(array( 0 => 'PassphraseDAO', 1 => 'PhabricatorPolicyInterface', ), + 'PassphraseCredentialControl' => 'AphrontFormControl', 'PassphraseCredentialCreateController' => 'PassphraseController', 'PassphraseCredentialDestroyController' => 'PassphraseController', 'PassphraseCredentialEditController' => 'PassphraseController', diff --git a/src/applications/passphrase/controller/PassphraseCredentialEditController.php b/src/applications/passphrase/controller/PassphraseCredentialEditController.php index 4b319dd94c..52206225d7 100644 --- a/src/applications/passphrase/controller/PassphraseCredentialEditController.php +++ b/src/applications/passphrase/controller/PassphraseCredentialEditController.php @@ -129,8 +129,16 @@ final class PassphraseCredentialEditController extends PassphraseController { $credential->saveTransaction(); - return id(new AphrontRedirectResponse()) - ->setURI('/K'.$credential->getID()); + if ($request->isAjax()) { + return id(new AphrontAjaxResponse())->setContent( + array( + 'phid' => $credential->getPHID(), + 'name' => 'K'.$credential->getID().' '.$credential->getName(), + )); + } else { + return id(new AphrontRedirectResponse()) + ->setURI('/K'.$credential->getID()); + } } catch (PhabricatorApplicationTransactionValidationException $ex) { $credential->killTransaction(); @@ -151,8 +159,14 @@ final class PassphraseCredentialEditController extends PassphraseController { $secret_control = $type->newSecretControl(); - $form = id(new AphrontFormView()) - ->setUser($viewer) + if ($request->isAjax()) { + $form = new PHUIFormLayoutView(); + } else { + $form = id(new AphrontFormView()) + ->setUser($viewer); + } + + $form ->appendChild( id(new AphrontFormTextControl()) ->setName('name') @@ -197,11 +211,6 @@ final class PassphraseCredentialEditController extends PassphraseController { ->setLabel($type->getSecretLabel()) ->setValue($v_secret)); - $form->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue(pht('Save')) - ->addCancelButton($this->getApplicationURI())); - $crumbs = $this->buildApplicationCrumbs(); if ($is_new) { @@ -222,6 +231,23 @@ final class PassphraseCredentialEditController extends PassphraseController { ->setName(pht('Edit'))); } + if ($request->isAjax()) { + $dialog = id(new AphrontDialogView()) + ->setUser($viewer) + ->setWidth(AphrontDialogView::WIDTH_FORM) + ->setTitle($title) + ->appendChild($form) + ->addSubmitButton(pht('Create Credential')) + ->addCancelButton($this->getApplicationURI()); + + return id(new AphrontDialogResponse())->setDialog($dialog); + } + + $form->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue(pht('Save')) + ->addCancelButton($this->getApplicationURI())); + $box = id(new PHUIObjectBoxView()) ->setHeaderText($header) ->setValidationException($validation_exception) diff --git a/src/applications/passphrase/view/PassphraseCredentialControl.php b/src/applications/passphrase/view/PassphraseCredentialControl.php new file mode 100644 index 0000000000..fd07e5df06 --- /dev/null +++ b/src/applications/passphrase/view/PassphraseCredentialControl.php @@ -0,0 +1,79 @@ +credentialType = $credential_type; + return $this; + } + + public function getCredentialType() { + return $this->credentialType; + } + + public function setOptions(array $options) { + assert_instances_of($options, 'PassphraseCredential'); + $this->options = $options; + return $this; + } + + protected function getCustomControlClass() { + return 'passphrase-credential-control'; + } + + protected function renderInput() { + + $options_map = array(); + foreach ($this->options as $option) { + $options_map[$option->getPHID()] = pht( + "%s %s", + 'K'.$option->getID(), + $option->getName()); + } + + $disabled = $this->getDisabled(); + if (!$options_map) { + $options_map[''] = pht('(No Existing Credentials)'); + $disabled = true; + } + + Javelin::initBehavior('passphrase-credential-control'); + + $options = AphrontFormSelectControl::renderSelectTag( + $this->getValue(), + $options_map, + array( + 'id' => $this->getControlID(), + 'name' => $this->getName(), + 'disabled' => $disabled ? 'disabled' : null, + 'sigil' => 'passphrase-credential-select', + )); + + $button = javelin_tag( + 'a', + array( + 'href' => '#', + 'class' => 'button grey', + 'sigil' => 'passphrase-credential-add', + 'mustcapture' => true, + ), + pht('Add Credential')); + + return javelin_tag( + 'div', + array( + 'sigil' => 'passphrase-credential-control', + 'meta' => array( + 'type' => $this->getCredentialType(), + ), + ), + array( + $options, + $button, + )); + } + +} diff --git a/src/applications/uiexample/examples/PhabricatorFormExample.php b/src/applications/uiexample/examples/PhabricatorFormExample.php index 8956f4387b..2c9e006f71 100644 --- a/src/applications/uiexample/examples/PhabricatorFormExample.php +++ b/src/applications/uiexample/examples/PhabricatorFormExample.php @@ -38,11 +38,22 @@ final class PhabricatorFormExample extends PhabricatorUIExample { $null_value = $null_time->readValueFromRequest($request); } + $divider_control = new AphrontFormDividerControl(); + + $credentials = array(); + $password_control = id(new PassphraseCredentialControl()) + ->setName('credentialPHID') + ->setLabel(pht('Password')) + ->setCredentialType('password') + ->setOptions($credentials); + $form = id(new AphrontFormView()) ->setUser($user) ->appendChild($start_time) ->appendChild($end_time) ->appendChild($null_time) + ->appendChild($divider_control) + ->appendChild($password_control) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Submit')); diff --git a/webroot/rsrc/js/application/passphrase/phame-credential-control.js b/webroot/rsrc/js/application/passphrase/phame-credential-control.js new file mode 100644 index 0000000000..42c2d90fd9 --- /dev/null +++ b/webroot/rsrc/js/application/passphrase/phame-credential-control.js @@ -0,0 +1,44 @@ +/** + * @provides javelin-behavior-passphrase-credential-control + * @requires javelin-behavior + * javelin-dom + * javelin-stratcom + * javelin-workflow + * javelin-util + */ + +JX.behavior('passphrase-credential-control', function(config) { + + JX.Stratcom.listen( + 'click', + 'passphrase-credential-add', + function(e) { + var control = e.getNode('passphrase-credential-control'); + var data = e.getNodeData('passphrase-credential-control'); + + new JX.Workflow('/passphrase/edit/?type=' + data.type) + .setHandler(JX.bind(null, onadd, control)) + .start(); + + e.kill(); + }); + + function onadd(control, response) { + var select = JX.DOM.find(control, 'select', 'passphrase-credential-select'); + + for (var ii = 0; ii < select.options.length; ii++) { + if (!select.options[ii].value) { + select.remove(ii); + break; + } + } + + select.add( + JX.$N('option', {value: response.phid}, response.name), + select.options[0] || null); + + select.value = response.phid; + select.disabled = null; + } + +});