From b57b72368c3c99fb5836309ba06da9f37a9a4f60 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 25 Oct 2013 13:59:02 -0700 Subject: [PATCH] Move "Remote URI" to modern repository editor thing Summary: Ref T2231. Allows you to edit the remote URI and credentials. This is a little bit funky because I'm reusing some of the pages on the new (not-yet-hooked-up) create form. Specifically, it had pages like this: - Repo Type - Name/Callsign/Remote - Auth - Done I split "Name/Callsign/Remote" into "Name/Callsign" and "Remote", then when editing the remote I just take you through "Remote" and "Auth" and then back. This lets us reuse the giant pile of protocol/URI sanity checking logic and ends up being pretty clean, although it's a little weird that the "Create" controller does both full-create and edit-remote. Test Plan: See screenshots. Reviewers: btrahan, chad Reviewed By: btrahan CC: chad, aran Maniphest Tasks: T2231 Differential Revision: https://secure.phabricator.com/D7405 --- src/__celerity_resource_map__.php | 94 +++---- .../PhabricatorApplicationDiffusion.php | 1 + .../DiffusionRepositoryCreateController.php | 265 ++++++++++++++---- .../DiffusionRepositoryEditController.php | 47 ++++ .../editor/PhabricatorRepositoryEditor.php | 43 +++ .../PhabricatorRepositoryTransaction.php | 45 ++- src/view/form/PHUIFormPageView.php | 4 + src/view/form/PHUIPagedFormView.php | 22 +- src/view/form/control/AphrontFormControl.php | 5 + .../control/PHUIFormMultiSubmitControl.php | 16 ++ webroot/rsrc/css/phui/phui-form-view.css | 3 +- 11 files changed, 432 insertions(+), 113 deletions(-) diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index a19bbfbe19..9b22c44bde 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -3858,7 +3858,7 @@ celerity_register_resource_map(array( ), 'phui-form-view-css' => array( - 'uri' => '/res/157ddd8b/rsrc/css/phui/phui-form-view.css', + 'uri' => '/res/3621b05d/rsrc/css/phui/phui-form-view.css', 'type' => 'css', 'requires' => array( @@ -3885,7 +3885,7 @@ celerity_register_resource_map(array( ), 'phui-info-panel-css' => array( - 'uri' => '/res/0a9c55c3/rsrc/css/phui/phui-info-panel.css', + 'uri' => '/res/e0ba8d04/rsrc/css/phui/phui-info-panel.css', 'type' => 'css', 'requires' => array( @@ -4318,7 +4318,7 @@ celerity_register_resource_map(array( ), array( 'packages' => array( - '8486b05c' => + '3b488eea' => array( 'name' => 'core.pkg.css', 'symbols' => @@ -4367,7 +4367,7 @@ celerity_register_resource_map(array( 41 => 'phabricator-tag-view-css', 42 => 'phui-list-view-css', ), - 'uri' => '/res/pkg/8486b05c/core.pkg.css', + 'uri' => '/res/pkg/3b488eea/core.pkg.css', 'type' => 'css', ), '2c1dba03' => @@ -4559,15 +4559,15 @@ celerity_register_resource_map(array( ), 'reverse' => array( - 'aphront-dialog-view-css' => '8486b05c', - 'aphront-error-view-css' => '8486b05c', - 'aphront-list-filter-view-css' => '8486b05c', - 'aphront-pager-view-css' => '8486b05c', - 'aphront-panel-view-css' => '8486b05c', - 'aphront-table-view-css' => '8486b05c', - 'aphront-tokenizer-control-css' => '8486b05c', - 'aphront-tooltip-css' => '8486b05c', - 'aphront-typeahead-control-css' => '8486b05c', + 'aphront-dialog-view-css' => '3b488eea', + 'aphront-error-view-css' => '3b488eea', + 'aphront-list-filter-view-css' => '3b488eea', + 'aphront-pager-view-css' => '3b488eea', + 'aphront-panel-view-css' => '3b488eea', + 'aphront-table-view-css' => '3b488eea', + 'aphront-tokenizer-control-css' => '3b488eea', + 'aphront-tooltip-css' => '3b488eea', + 'aphront-typeahead-control-css' => '3b488eea', 'differential-changeset-view-css' => 'f87db3d0', 'differential-core-view-css' => 'f87db3d0', 'differential-inline-comment-editor' => '5e9e5c4e', @@ -4581,7 +4581,7 @@ celerity_register_resource_map(array( 'differential-table-of-contents-css' => 'f87db3d0', 'diffusion-commit-view-css' => '270f4eb4', 'diffusion-icons-css' => '270f4eb4', - 'global-drag-and-drop-css' => '8486b05c', + 'global-drag-and-drop-css' => '3b488eea', 'inline-comment-summary-css' => 'f87db3d0', 'javelin-aphlict' => '2c1dba03', 'javelin-behavior' => '3e3be199', @@ -4656,56 +4656,56 @@ celerity_register_resource_map(array( 'javelin-util' => '3e3be199', 'javelin-vector' => '3e3be199', 'javelin-workflow' => '3e3be199', - 'lightbox-attachment-css' => '8486b05c', + 'lightbox-attachment-css' => '3b488eea', 'maniphest-task-summary-css' => '49898640', - 'phabricator-action-list-view-css' => '8486b05c', - 'phabricator-application-launch-view-css' => '8486b05c', + 'phabricator-action-list-view-css' => '3b488eea', + 'phabricator-application-launch-view-css' => '3b488eea', 'phabricator-busy' => '2c1dba03', 'phabricator-content-source-view-css' => 'f87db3d0', - 'phabricator-core-css' => '8486b05c', - 'phabricator-crumbs-view-css' => '8486b05c', + 'phabricator-core-css' => '3b488eea', + 'phabricator-crumbs-view-css' => '3b488eea', 'phabricator-drag-and-drop-file-upload' => '5e9e5c4e', 'phabricator-dropdown-menu' => '2c1dba03', 'phabricator-file-upload' => '2c1dba03', - 'phabricator-filetree-view-css' => '8486b05c', - 'phabricator-flag-css' => '8486b05c', + 'phabricator-filetree-view-css' => '3b488eea', + 'phabricator-flag-css' => '3b488eea', 'phabricator-hovercard' => '2c1dba03', - 'phabricator-jump-nav' => '8486b05c', + 'phabricator-jump-nav' => '3b488eea', 'phabricator-keyboard-shortcut' => '2c1dba03', 'phabricator-keyboard-shortcut-manager' => '2c1dba03', - 'phabricator-main-menu-view' => '8486b05c', + 'phabricator-main-menu-view' => '3b488eea', 'phabricator-menu-item' => '2c1dba03', - 'phabricator-nav-view-css' => '8486b05c', + 'phabricator-nav-view-css' => '3b488eea', 'phabricator-notification' => '2c1dba03', - 'phabricator-notification-css' => '8486b05c', - 'phabricator-notification-menu-css' => '8486b05c', + 'phabricator-notification-css' => '3b488eea', + 'phabricator-notification-menu-css' => '3b488eea', 'phabricator-object-selector-css' => 'f87db3d0', 'phabricator-phtize' => '2c1dba03', 'phabricator-prefab' => '2c1dba03', 'phabricator-project-tag-css' => '49898640', - 'phabricator-remarkup-css' => '8486b05c', + 'phabricator-remarkup-css' => '3b488eea', 'phabricator-shaped-request' => '5e9e5c4e', - 'phabricator-side-menu-view-css' => '8486b05c', - 'phabricator-standard-page-view' => '8486b05c', - 'phabricator-tag-view-css' => '8486b05c', + 'phabricator-side-menu-view-css' => '3b488eea', + 'phabricator-standard-page-view' => '3b488eea', + 'phabricator-tag-view-css' => '3b488eea', 'phabricator-textareautils' => '2c1dba03', 'phabricator-tooltip' => '2c1dba03', - 'phabricator-transaction-view-css' => '8486b05c', - 'phabricator-zindex-css' => '8486b05c', - 'phui-button-css' => '8486b05c', - 'phui-form-css' => '8486b05c', - 'phui-form-view-css' => '8486b05c', - 'phui-header-view-css' => '8486b05c', - 'phui-icon-view-css' => '8486b05c', - 'phui-list-view-css' => '8486b05c', - 'phui-object-item-list-view-css' => '8486b05c', - 'phui-property-list-view-css' => '8486b05c', - 'phui-spacing-css' => '8486b05c', - 'sprite-apps-large-css' => '8486b05c', - 'sprite-gradient-css' => '8486b05c', - 'sprite-icons-css' => '8486b05c', - 'sprite-menu-css' => '8486b05c', - 'sprite-status-css' => '8486b05c', - 'syntax-highlighting-css' => '8486b05c', + 'phabricator-transaction-view-css' => '3b488eea', + 'phabricator-zindex-css' => '3b488eea', + 'phui-button-css' => '3b488eea', + 'phui-form-css' => '3b488eea', + 'phui-form-view-css' => '3b488eea', + 'phui-header-view-css' => '3b488eea', + 'phui-icon-view-css' => '3b488eea', + 'phui-list-view-css' => '3b488eea', + 'phui-object-item-list-view-css' => '3b488eea', + 'phui-property-list-view-css' => '3b488eea', + 'phui-spacing-css' => '3b488eea', + 'sprite-apps-large-css' => '3b488eea', + 'sprite-gradient-css' => '3b488eea', + 'sprite-icons-css' => '3b488eea', + 'sprite-menu-css' => '3b488eea', + 'sprite-status-css' => '3b488eea', + 'syntax-highlighting-css' => '3b488eea', ), )); diff --git a/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php b/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php index 8bf0ada033..1cf6101732 100644 --- a/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php +++ b/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php @@ -72,6 +72,7 @@ final class PhabricatorApplicationDiffusion extends PhabricatorApplication { 'branches/' => 'DiffusionRepositoryEditBranchesController', 'subversion/' => 'DiffusionRepositoryEditSubversionController', 'actions/' => 'DiffusionRepositoryEditActionsController', + '(?Premote)/' => 'DiffusionRepositoryCreateController', ), ), 'inline/' => array( diff --git a/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php b/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php index f395b72567..22f56674c2 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php @@ -2,30 +2,140 @@ final class DiffusionRepositoryCreateController extends DiffusionController { + private $edit; + private $repository; + + public function willProcessRequest(array $data) { + parent::willProcessRequest($data); + $this->edit = idx($data, 'edit'); + } + public function processRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); + // NOTE: We can end up here via either "Create Repository" or via + // "Edit Remote". In the latter case, we show only a few of the pages. + + $repository = null; + if ($this->edit) { + $repository = $this->getDiffusionRequest()->getRepository(); + + // Make sure we have CAN_EDIT. + id(new PhabricatorRepositoryQuery()) + ->setViewer($viewer) + ->withIDs(array($repository->getID())) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + + $this->setRepository($repository); + + $cancel_uri = $this->getRepositoryControllerURI($repository, 'edit/'); + } else { + $cancel_uri = $this->getApplicationURI(); + } + $form = id(new PHUIPagedFormView()) ->setUser($viewer) - ->addPage('vcs', $this->buildVCSPage()) - ->addPage('name', $this->buildNamePage()) - ->addPage('auth', $this->buildAuthPage()) - ->addPage('done', $this->buildDonePage()); + ->setCancelURI($cancel_uri); + + switch ($this->edit) { + case 'remote': + $title = pht('Edit Remote'); + $form + ->addPage('remote-uri', $this->buildRemoteURIPage()) + ->addPage('auth', $this->buildAuthPage()); + break; + default: + $title = pht('Import Repository'); + $form + ->addPage('vcs', $this->buildVCSPage()) + ->addPage('name', $this->buildNamePage()) + ->addPage('remote-uri', $this->buildRemoteURIPage()) + ->addPage('auth', $this->buildAuthPage()) + ->addPage('done', $this->buildDonePage()); + break; + } if ($request->isFormPost()) { $form->readFromRequest($request); if ($form->isComplete()) { - // TODO: This exception is heartwarming but should probably take more - // substantive actions. - throw new Exception("GOOD JOB AT FORM"); + + if ($this->edit != 'remote') { + // TODO: This exception is heartwarming but should probably take more + // substantive actions. + throw new Exception("GOOD JOB AT FORM"); + } + + $template = id(new PhabricatorRepositoryTransaction()); + + $type_remote_uri = PhabricatorRepositoryTransaction::TYPE_REMOTE_URI; + $type_ssh_login = PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN; + $type_ssh_key = PhabricatorRepositoryTransaction::TYPE_SSH_KEY; + $type_ssh_keyfile = PhabricatorRepositoryTransaction::TYPE_SSH_KEYFILE; + $type_http_login = PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN; + $type_http_pass = PhabricatorRepositoryTransaction::TYPE_HTTP_PASS; + + $xactions = array(); + + $xactions[] = id(clone $template) + ->setTransactionType($type_remote_uri) + ->setNewValue( + $form->getPage('remote-uri')->getControl('remoteURI')->getValue()); + + $xactions[] = id(clone $template) + ->setTransactionType($type_ssh_login) + ->setNewValue( + $form->getPage('auth')->getControl('ssh-login')->getValue()); + + $xactions[] = id(clone $template) + ->setTransactionType($type_ssh_key) + ->setNewValue( + $form->getPage('auth')->getControl('ssh-key')->getValue()); + + $xactions[] = id(clone $template) + ->setTransactionType($type_ssh_keyfile) + ->setNewValue( + $form->getPage('auth')->getControl('ssh-keyfile')->getValue()); + + $xactions[] = id(clone $template) + ->setTransactionType($type_http_login) + ->setNewValue( + $form->getPage('auth')->getControl('http-login')->getValue()); + + $xactions[] = id(clone $template) + ->setTransactionType($type_http_pass) + ->setNewValue( + $form->getPage('auth')->getControl('http-pass')->getValue()); + + id(new PhabricatorRepositoryEditor()) + ->setContinueOnNoEffect(true) + ->setContentSourceFromRequest($request) + ->setActor($viewer) + ->applyTransactions($repository, $xactions); + + $repo_uri = $this->getRepositoryControllerURI($repository, 'edit/'); + return id(new AphrontRedirectResponse())->setURI($repo_uri); } } else { - $form->readFromObject(null); + $dict = array(); + if ($repository) { + $dict = array( + 'remoteURI' => $repository->getRemoteURI(), + 'ssh-login' => $repository->getDetail('ssh-login'), + 'ssh-key' => $repository->getDetail('ssh-key'), + 'ssh-keyfile' => $repository->getDetail('ssh-keyfile'), + 'http-login' => $repository->getDetail('http-login'), + 'http-pass' => $repository->getDetail('http-pass'), + ); + } + $form->readFromObject($dict); } - $title = pht('Import Repository'); - $crumbs = $this->buildCrumbs(); $crumbs->addCrumb( id(new PhabricatorCrumbView()) @@ -120,7 +230,6 @@ final class DiffusionRepositoryCreateController extends DiffusionController { ->setUser($this->getRequest()->getUser()) ->setPageName(pht('Repository Name and Location')) ->setValidateFormPageCallback(array($this, 'validateNamePage')) - ->setAdjustFormPageCallback(array($this, 'adjustNamePage')) ->addRemarkupInstructions( pht( '**Choose a human-readable name for this repository**, like '. @@ -145,20 +254,81 @@ final class DiffusionRepositoryCreateController extends DiffusionController { id(new AphrontFormTextControl()) ->setName('callsign') ->setLabel(pht('Callsign')) - ->setCaption(pht('Short UPPERCASE identifier.'))) + ->setCaption(pht('Short UPPERCASE identifier.'))); + } + + public function validateNamePage(PHUIFormPageView $page) { + $c_name = $page->getControl('name'); + $v_name = $c_name->getValue(); + if (!strlen($v_name)) { + $c_name->setError(pht('Required')); + $page->addPageError( + pht('You must choose a name for this repository.')); + } + + $c_call = $page->getControl('callsign'); + $v_call = $c_call->getValue(); + if (!strlen($v_call)) { + $c_call->setError(pht('Required')); + $page->addPageError( + pht('You must choose a callsign for this repository.')); + } else if (!preg_match('/^[A-Z]+$/', $v_call)) { + $c_call->setError(pht('Invalid')); + $page->addPageError( + pht('The callsign must contain only UPPERCASE letters.')); + } else { + $exists = false; + try { + $repo = id(new PhabricatorRepositoryQuery()) + ->setViewer($this->getRequest()->getUser()) + ->withCallsigns(array($v_call)) + ->executeOne(); + $exists = (bool)$repo; + } catch (PhabricatorPolicyException $ex) { + $exists = true; + } + if ($exists) { + $c_call->setError(pht('Not Unique')); + $page->addPageError( + pht( + 'Another repository already uses that callsign. You must choose '. + 'a unique callsign.')); + } + } + + return $c_name->isValid() && + $c_call->isValid(); + } + + +/* -( Page: Remote URI )--------------------------------------------------- */ + + + private function buildRemoteURIPage() { + return id(new PHUIFormPageView()) + ->setUser($this->getRequest()->getUser()) + ->setPageName(pht('Repository Remote URI')) + ->setValidateFormPageCallback(array($this, 'validateRemoteURIPage')) + ->setAdjustFormPageCallback(array($this, 'adjustRemoteURIPage')) ->addControl( id(new AphrontFormTextControl()) ->setName('remoteURI')); } - public function adjustNamePage(PHUIFormPageView $page) { + public function adjustRemoteURIPage(PHUIFormPageView $page) { $form = $page->getForm(); $is_git = false; $is_svn = false; $is_mercurial = false; - switch ($form->getPage('vcs')->getControl('vcs')->getValue()) { + if ($this->getRepository()) { + $vcs = $this->getRepository()->getVersionControlSystem(); + } else { + $vcs = $form->getPage('vcs')->getControl('vcs')->getValue(); + } + + switch ($vcs) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $is_git = true; break; @@ -220,45 +390,7 @@ final class DiffusionRepositoryCreateController extends DiffusionController { $page->getControl('remoteURI')->setLabel($uri_label); } - public function validateNamePage(PHUIFormPageView $page) { - $c_name = $page->getControl('name'); - $v_name = $c_name->getValue(); - if (!strlen($v_name)) { - $c_name->setError(pht('Required')); - $page->addPageError( - pht('You must choose a name for this repository.')); - } - - $c_call = $page->getControl('callsign'); - $v_call = $c_call->getValue(); - if (!strlen($v_call)) { - $c_call->setError(pht('Required')); - $page->addPageError( - pht('You must choose a callsign for this repository.')); - } else if (!preg_match('/^[A-Z]+$/', $v_call)) { - $c_call->setError(pht('Invalid')); - $page->addPageError( - pht('The callsign must contain only UPPERCASE letters.')); - } else { - $exists = false; - try { - $repo = id(new PhabricatorRepositoryQuery()) - ->setViewer($this->getRequest()->getUser()) - ->withCallsigns(array($v_call)) - ->executeOne(); - $exists = (bool)$repo; - } catch (PhabricatorPolicyException $ex) { - $exists = true; - } - if ($exists) { - $c_call->setError(pht('Not Unique')); - $page->addPageError( - pht( - 'Another repository already uses that callsign. You must choose '. - 'a unique callsign.')); - } - } - + public function validateRemoteURIPage(PHUIFormPageView $page) { $c_remote = $page->getControl('remoteURI'); $v_remote = $c_remote->getValue(); @@ -301,9 +433,7 @@ final class DiffusionRepositoryCreateController extends DiffusionController { } } - return $c_name->isValid() && - $c_call->isValid() && - $c_remote->isValid(); + return $c_remote->isValid(); } @@ -346,8 +476,17 @@ final class DiffusionRepositoryCreateController extends DiffusionController { public function adjustAuthPage($page) { $form = $page->getForm(); - $remote_uri = $form->getPage('name')->getControl('remoteURI')->getValue(); - $vcs = $form->getPage('vcs')->getControl('vcs')->getValue(); + + $remote_uri = $form->getPage('remote-uri') + ->getControl('remoteURI') + ->getValue(); + + if ($this->getRepository()) { + $vcs = $this->getRepository()->getVersionControlSystem(); + } else { + $vcs = $form->getPage('vcs')->getControl('vcs')->getValue(); + } + $proto = $this->getRemoteURIProtocol($remote_uri); $remote_user = $this->getRemoteURIUser($remote_uri); @@ -541,4 +680,14 @@ final class DiffusionRepositoryCreateController extends DiffusionController { return ($proto == 'http' || $proto == 'https' || $proto == 'svn'); } + private function setRepository(PhabricatorRepository $repository) { + $this->repository = $repository; + return $this; + } + + private function getRepository() { + return $this->repository; + } + + } diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditController.php index fdbd5cf777..c3b5a9c12b 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryEditController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryEditController.php @@ -50,6 +50,10 @@ final class DiffusionRepositoryEditController extends DiffusionController { $policy_properties = $this->buildPolicyProperties($repository, $policy_actions); + $remote_properties = $this->buildRemoteProperties( + $repository, + $this->buildRemoteActions($repository)); + $encoding_actions = $this->buildEncodingActions($repository); $encoding_properties = $this->buildEncodingProperties($repository, $encoding_actions); @@ -98,6 +102,7 @@ final class DiffusionRepositoryEditController extends DiffusionController { ->setHeader($header) ->addPropertyList($basic_properties) ->addPropertyList($policy_properties) + ->addPropertyList($remote_properties) ->addPropertyList($encoding_properties); if ($branches_properties) { @@ -445,4 +450,46 @@ final class DiffusionRepositoryEditController extends DiffusionController { return $view; } + private function buildRemoteActions(PhabricatorRepository $repository) { + $viewer = $this->getRequest()->getUser(); + + $view = id(new PhabricatorActionListView()) + ->setObjectURI($this->getRequest()->getRequestURI()) + ->setUser($viewer); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $repository, + PhabricatorPolicyCapability::CAN_EDIT); + + $edit = id(new PhabricatorActionView()) + ->setIcon('edit') + ->setName(pht('Edit Remote')) + ->setHref( + $this->getRepositoryControllerURI($repository, 'edit/remote/')) + ->setWorkflow(!$can_edit) + ->setDisabled(!$can_edit); + $view->addAction($edit); + + return $view; + } + + private function buildRemoteProperties( + PhabricatorRepository $repository, + PhabricatorActionListView $actions) { + + $viewer = $this->getRequest()->getUser(); + + $view = id(new PHUIPropertyListView()) + ->setUser($viewer) + ->setActionList($actions) + ->addSectionHeader(pht('Remote')); + + $view->addProperty( + pht('Remote URI'), + $repository->getDetail('remote-uri')); + + return $view; + } + } diff --git a/src/applications/repository/editor/PhabricatorRepositoryEditor.php b/src/applications/repository/editor/PhabricatorRepositoryEditor.php index 4c813467c7..52684c41e3 100644 --- a/src/applications/repository/editor/PhabricatorRepositoryEditor.php +++ b/src/applications/repository/editor/PhabricatorRepositoryEditor.php @@ -17,6 +17,13 @@ final class PhabricatorRepositoryEditor $types[] = PhabricatorRepositoryTransaction::TYPE_SVN_SUBPATH; $types[] = PhabricatorRepositoryTransaction::TYPE_NOTIFY; $types[] = PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE; + $types[] = PhabricatorRepositoryTransaction::TYPE_REMOTE_URI; + $types[] = PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN; + $types[] = PhabricatorRepositoryTransaction::TYPE_SSH_KEY; + $types[] = PhabricatorRepositoryTransaction::TYPE_SSH_KEYFILE; + $types[] = PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN; + $types[] = PhabricatorRepositoryTransaction::TYPE_HTTP_PASS; + $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; @@ -50,6 +57,18 @@ final class PhabricatorRepositoryEditor return (int)!$object->getDetail('herald-disabled'); case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE: return (int)!$object->getDetail('disable-autoclose'); + case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI: + return $object->getDetail('remote-uri'); + case PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN: + return $object->getDetail('ssh-login'); + case PhabricatorRepositoryTransaction::TYPE_SSH_KEY: + return $object->getDetail('ssh-key'); + case PhabricatorRepositoryTransaction::TYPE_SSH_KEYFILE: + return $object->getDetail('ssh-keyfile'); + case PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN: + return $object->getDetail('http-login'); + case PhabricatorRepositoryTransaction::TYPE_HTTP_PASS: + return $object->getDetail('http-pass'); } } @@ -67,6 +86,12 @@ final class PhabricatorRepositoryEditor case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE_ONLY: case PhabricatorRepositoryTransaction::TYPE_UUID: case PhabricatorRepositoryTransaction::TYPE_SVN_SUBPATH: + case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI: + case PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN: + case PhabricatorRepositoryTransaction::TYPE_SSH_KEY: + case PhabricatorRepositoryTransaction::TYPE_SSH_KEYFILE: + case PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN: + case PhabricatorRepositoryTransaction::TYPE_HTTP_PASS: return $xaction->getNewValue(); case PhabricatorRepositoryTransaction::TYPE_NOTIFY: case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE: @@ -113,6 +138,24 @@ final class PhabricatorRepositoryEditor case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE: $object->setDetail('disable-autoclose', (int)!$xaction->getNewValue()); break; + case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI: + $object->setDetail('remote-uri', $xaction->getNewValue()); + break; + case PhabricatorRepositoryTransaction::TYPE_SSH_LOGIN: + $object->setDetail('ssh-login', $xaction->getNewValue()); + break; + case PhabricatorRepositoryTransaction::TYPE_SSH_KEY: + $object->setDetail('ssh-key', $xaction->getNewValue()); + break; + case PhabricatorRepositoryTransaction::TYPE_SSH_KEYFILE: + $object->setDetail('ssh-keyfile', $xaction->getNewValue()); + break; + case PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN: + $object->setDetail('http-login', $xaction->getNewValue()); + break; + case PhabricatorRepositoryTransaction::TYPE_HTTP_PASS: + $object->setDetail('http-pass', $xaction->getNewValue()); + break; case PhabricatorRepositoryTransaction::TYPE_ENCODING: // Make sure the encoding is valid by converting to UTF-8. This tests // that the user has mbstring installed, and also that they didn't type diff --git a/src/applications/repository/storage/PhabricatorRepositoryTransaction.php b/src/applications/repository/storage/PhabricatorRepositoryTransaction.php index a3a4cb54ef..c66885af57 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryTransaction.php +++ b/src/applications/repository/storage/PhabricatorRepositoryTransaction.php @@ -14,6 +14,12 @@ final class PhabricatorRepositoryTransaction const TYPE_UUID = 'repo:uuid'; const TYPE_NOTIFY = 'repo:notify'; const TYPE_AUTOCLOSE = 'repo:autoclose'; + const TYPE_REMOTE_URI = 'repo:remote-uri'; + const TYPE_SSH_LOGIN = 'repo:ssh-login'; + const TYPE_SSH_KEY = 'repo:ssh-key'; + const TYPE_SSH_KEYFILE = 'repo:ssh-keyfile'; + const TYPE_HTTP_LOGIN = 'repo:http-login'; + const TYPE_HTTP_PASS = 'repo:http-pass'; public function getApplicationName() { return 'repository'; @@ -187,7 +193,44 @@ final class PhabricatorRepositoryTransaction $this->renderHandleLink($author_phid)); } break; - + case self::TYPE_REMOTE_URI: + if (!strlen($old)) { + return pht( + '%s set the remote URI for this repository to "%s".', + $this->renderHandleLink($author_phid), + $new); + } else if (!strlen($new)) { + return pht( + '%s removed the remote URI for this repository.', + $this->renderHandleLink($author_phid)); + } else { + return pht( + '%s changed the remote URI for this repository from "%s" to "%s".', + $this->renderHandleLink($author_phid), + $old, + $new); + } + break; + case self::TYPE_SSH_LOGIN: + return pht( + '%s updated the SSH login for this repository.', + $this->renderHandleLink($author_phid)); + case self::TYPE_SSH_KEY: + return pht( + '%s updated the SSH key for this repository.', + $this->renderHandleLink($author_phid)); + case self::TYPE_SSH_KEYFILE: + return pht( + '%s updated the SSH keyfile for this repository.', + $this->renderHandleLink($author_phid)); + case self::TYPE_HTTP_LOGIN: + return pht( + '%s updated the HTTP login for this repository.', + $this->renderHandleLink($author_phid)); + case self::TYPE_HTTP_PASS: + return pht( + '%s updated the HTTP password for this repository.', + $this->renderHandleLink($author_phid)); } return parent::getTitle(); diff --git a/src/view/form/PHUIFormPageView.php b/src/view/form/PHUIFormPageView.php index 110094c8d5..ae17e08bd8 100644 --- a/src/view/form/PHUIFormPageView.php +++ b/src/view/form/PHUIFormPageView.php @@ -190,6 +190,10 @@ class PHUIFormPageView extends AphrontView { } public function readFromObject($object) { + foreach ($this->getControls() as $name => $control) { + $control->readValueFromDictionary($object); + } + return $this; } diff --git a/src/view/form/PHUIPagedFormView.php b/src/view/form/PHUIPagedFormView.php index 53d8c0308f..a088980275 100644 --- a/src/view/form/PHUIPagedFormView.php +++ b/src/view/form/PHUIPagedFormView.php @@ -1,7 +1,6 @@ name.':'.$key; } + public function setCancelURI($cancel_uri) { + $this->cancelURI = $cancel_uri; + return $this; + } + + public function getCancelURI() { + return $this->cancelURI; + } + public function getTagContent() { $form = id(new AphrontFormView()) ->setUser($this->getUser()); @@ -240,6 +249,8 @@ final class PHUIPagedFormView extends AphrontTagView { if (!$this->isFirstPage($selected_page)) { $submit->addBackButton(); + } else if ($this->getCancelURI()) { + $submit->addCancelButton($this->getCancelURI()); } if ($this->isLastPage($selected_page)) { @@ -261,11 +272,10 @@ final class PHUIPagedFormView extends AphrontTagView { ->setHeader($selected_page->getPageName()); } - return array( - $header, - $errors, - $form, - ); + return id(new PHUIObjectBoxView()) + ->setHeader($header) + ->setFormError($errors) + ->setForm($form); } } diff --git a/src/view/form/control/AphrontFormControl.php b/src/view/form/control/AphrontFormControl.php index 5a480179d9..a955916fb3 100644 --- a/src/view/form/control/AphrontFormControl.php +++ b/src/view/form/control/AphrontFormControl.php @@ -126,6 +126,11 @@ abstract class AphrontFormControl extends AphrontView { return $this; } + public function readValueFromDictionary(array $dictionary) { + $this->setValue(idx($dictionary, $this->getName())); + return $this; + } + public function setFormPage(PHUIFormPageView $page) { if ($this->formPage) { throw new Exception("This control is already a member of a page!"); diff --git a/src/view/form/control/PHUIFormMultiSubmitControl.php b/src/view/form/control/PHUIFormMultiSubmitControl.php index 17b12376ae..ae632c549c 100644 --- a/src/view/form/control/PHUIFormMultiSubmitControl.php +++ b/src/view/form/control/PHUIFormMultiSubmitControl.php @@ -15,6 +15,22 @@ final class PHUIFormMultiSubmitControl extends AphrontFormControl { return $this->addButton('__submit__', $label); } + public function addCancelButton($uri, $label = null) { + if ($label === null) { + $label = pht('Cancel'); + } + + $this->buttons[] = phutil_tag( + 'a', + array( + 'class' => 'grey button', + 'href' => $uri, + ), + $label); + + return $this; + } + public function addButton($name, $label, $class = null) { $this->buttons[] = phutil_tag( 'input', diff --git a/webroot/rsrc/css/phui/phui-form-view.css b/webroot/rsrc/css/phui/phui-form-view.css index c2937d3b60..004af717fe 100644 --- a/webroot/rsrc/css/phui/phui-form-view.css +++ b/webroot/rsrc/css/phui/phui-form-view.css @@ -108,7 +108,8 @@ margin: 4px 0 0 8px; } -.phui-form-control-multi-submit input { +.phui-form-control-multi-submit input, +.phui-form-control-multi-submit a { float: right; margin: 0.5em 0 0em 2%; width: auto;