Index: src/applications/drydock/application/PhabricatorApplicationDrydock.php =================================================================== --- src/applications/drydock/application/PhabricatorApplicationDrydock.php +++ src/applications/drydock/application/PhabricatorApplicationDrydock.php @@ -38,7 +38,7 @@ '(?:query/(?P[^/]+)/)?' => 'DrydockBlueprintListController', '(?P[1-9]\d*)/' => 'DrydockBlueprintViewController', 'create/' => 'DrydockBlueprintCreateController', - 'edit/(?P[1-9]\d*)/' => 'DrydockBlueprintEditController', + 'edit/(?:(?P[1-9]\d*)/)?' => 'DrydockBlueprintEditController', ), 'resource/' => array( '(?:query/(?P[^/]+)/)?' => 'DrydockResourceListController', Index: src/applications/drydock/blueprint/DrydockBlueprintImplementation.php =================================================================== --- src/applications/drydock/blueprint/DrydockBlueprintImplementation.php +++ src/applications/drydock/blueprint/DrydockBlueprintImplementation.php @@ -19,6 +19,7 @@ abstract public function isEnabled(); + abstract public function getBlueprintName(); abstract public function getDescription(); public function getBlueprintClass() { @@ -388,6 +389,10 @@ return idx($groups, $type, array()); } + public static function getNamedImplementation($class) { + return idx(self::getAllBlueprintImplementations(), $class); + } + protected function newResourceTemplate($name) { $resource = id(new DrydockResource()) ->setBlueprintPHID($this->getInstance()->getPHID()) Index: src/applications/drydock/blueprint/DrydockLocalHostBlueprintImplementation.php =================================================================== --- src/applications/drydock/blueprint/DrydockLocalHostBlueprintImplementation.php +++ src/applications/drydock/blueprint/DrydockLocalHostBlueprintImplementation.php @@ -7,8 +7,13 @@ return false; } + public function getBlueprintName() { + return pht('Local Host'); + } + public function getDescription() { - return pht('Allocates storage on the local host.'); + return pht( + 'Allows Drydock to run on the local host.'); } public function canAllocateMoreResources(array $pool) { Index: src/applications/drydock/blueprint/DrydockPreallocatedHostBlueprintImplementation.php =================================================================== --- src/applications/drydock/blueprint/DrydockPreallocatedHostBlueprintImplementation.php +++ src/applications/drydock/blueprint/DrydockPreallocatedHostBlueprintImplementation.php @@ -7,8 +7,12 @@ return true; } + public function getBlueprintName() { + return pht('Remote Host (Preallocated)'); + } + public function getDescription() { - return pht('Leases out preallocated, remote hosts.'); + return pht('Allows Drydock to run on specific remote hosts you configure.'); } public function canAllocateMoreResources(array $pool) { Index: src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php =================================================================== --- src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php +++ src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php @@ -7,8 +7,12 @@ return true; } + public function getBlueprintName() { + return pht('Working Copy'); + } + public function getDescription() { - return pht('Allocates out working copies of repositories.'); + return pht('Allows Drydock to check out working copies of repositories.'); } protected function canAllocateLease( Index: src/applications/drydock/controller/DrydockBlueprintCreateController.php =================================================================== --- src/applications/drydock/controller/DrydockBlueprintCreateController.php +++ src/applications/drydock/controller/DrydockBlueprintCreateController.php @@ -10,56 +10,75 @@ $implementations = DrydockBlueprintImplementation::getAllBlueprintImplementations(); + $errors = array(); + $e_blueprint = null; + if ($request->isFormPost()) { $class = $request->getStr('blueprint-type'); if (!isset($implementations[$class])) { - return $this->createDialog($implementations); + $e_blueprint = pht('Required'); + $errors[] = pht('You must choose a blueprint type.'); } - $blueprint = id(new DrydockBlueprint()) - ->setClassName($class) - ->setDetails(array()) - ->setViewPolicy(PhabricatorPolicies::POLICY_ADMIN) - ->setEditPolicy(PhabricatorPolicies::POLICY_ADMIN) - ->save(); - - $edit_uri = $this->getApplicationURI( - "blueprint/edit/".$blueprint->getID()."/"); - - return id(new AphrontRedirectResponse())->setURI($edit_uri); + if (!$errors) { + $edit_uri = $this->getApplicationURI('blueprint/edit/?class='.$class); + return id(new AphrontRedirectResponse())->setURI($edit_uri); + } } - return $this->createDialog($implementations); - } - - function createDialog(array $implementations) { - $request = $this->getRequest(); - $viewer = $request->getUser(); + $error_view = null; + if ($errors) { + $error_view = id(new AphrontErrorView()) + ->setErrors($errors); + } $control = id(new AphrontFormRadioButtonControl()) - ->setName('blueprint-type'); + ->setName('blueprint-type') + ->setLabel(pht('Blueprint Type')) + ->setError($e_blueprint); foreach ($implementations as $implementation_name => $implementation) { - $control - ->addButton( - $implementation_name, - $implementation->getBlueprintClass(), - $implementation->getDescription()); + $disabled = !$implementation->isEnabled(); + + $control->addButton( + $implementation_name, + $implementation->getBlueprintName(), + array( + pht('Provides: %s', $implementation->getType()), + phutil_tag('br'), + phutil_tag('br'), + $implementation->getDescription(), + ), + $disabled ? 'disabled' : null, + $disabled); } - $dialog = new AphrontDialogView(); - $dialog->setTitle(pht('Create New Blueprint')) - ->setUser($viewer) - ->addSubmitButton(pht('Create Blueprint')) - ->addCancelButton($this->getApplicationURI('blueprint/')); - $dialog->appendChild( - phutil_tag( - 'p', - array(), - pht( - 'Select what type of blueprint you want to create: '))); - $dialog->appendChild($control); - return id(new AphrontDialogResponse())->setDialog($dialog); + $title = pht('Create New Blueprint'); + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('New Blueprint')); + + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->appendChild($control) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->addCancelButton($this->getApplicationURI('blueprint/')) + ->setValue(pht('Continue'))); + + $box = id(new PHUIObjectBoxView()) + ->setFormError($error_view) + ->setHeaderText($title) + ->setForm($form); + + return $this->buildApplicationPage( + array( + $crumbs, + $box, + ), + array( + 'title' => $title, + 'device' => true, + )); } } Index: src/applications/drydock/controller/DrydockBlueprintEditController.php =================================================================== --- src/applications/drydock/controller/DrydockBlueprintEditController.php +++ src/applications/drydock/controller/DrydockBlueprintEditController.php @@ -25,10 +25,23 @@ if (!$blueprint) { return new Aphront404Response(); } + + $impl = $blueprint->getImplementation(); + $cancel_uri = $this->getApplicationURI('blueprint/'.$this->id.'/'); } else { + $class = $request->getStr('class'); + + $impl = DrydockBlueprintImplementation::getNamedImplementation($class); + if (!$impl || !$impl->isEnabled()) { + return new Aphront400Response(); + } + $blueprint = new DrydockBlueprint(); + $blueprint->setClassName($class); + $cancel_uri = $this->getApplicationURI('blueprint/'); } + if ($request->isFormPost()) { $v_view_policy = $request->getStr('viewPolicy'); $v_edit_policy = $request->getStr('editPolicy'); @@ -39,8 +52,10 @@ $blueprint->save(); - return id(new AphrontRedirectResponse()) - ->setURI('/drydock/blueprint/'); + $id = $blueprint->getID(); + $save_uri = $this->getApplicationURI("blueprint/{$id}/"); + + return id(new AphrontRedirectResponse())->setURI($save_uri); } $policies = id(new PhabricatorPolicyQuery()) @@ -48,21 +63,13 @@ ->setObject($blueprint) ->execute(); - if ($request->isAjax()) { - $form = id(new PHUIFormLayoutView()) - ->setUser($viewer); - } else { - $form = id(new AphrontFormView()) - ->setUser($viewer); - } - - $form + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->addHiddenInput('class', $request->getStr('class')) ->appendChild( - id(new AphrontFormTextControl()) - ->setName('className') - ->setLabel(pht('Implementation')) - ->setValue($blueprint->getClassName()) - ->setDisabled(true)) + id(new AphrontFormStaticControl()) + ->setLabel(pht('Blueprint Type')) + ->setValue($impl->getBlueprintName())) ->appendChild( id(new AphrontFormPolicyControl()) ->setName('viewPolicy') @@ -78,27 +85,23 @@ $crumbs = $this->buildApplicationCrumbs(); - $title = pht('Edit Blueprint'); - $header = pht('Edit Blueprint %d', $blueprint->getID()); - $crumbs->addTextCrumb(pht('Blueprint %d', $blueprint->getID())); - $crumbs->addTextCrumb(pht('Edit')); - - if ($request->isAjax()) { - $dialog = id(new AphrontDialogView()) - ->setUser($viewer) - ->setWidth(AphrontDialogView::WIDTH_FORM) - ->setTitle($title) - ->appendChild($form) - ->addSubmitButton(pht('Edit Blueprint')) - ->addCancelButton($this->getApplicationURI()); - - return id(new AphrontDialogResponse())->setDialog($dialog); + if ($blueprint->getID()) { + $title = pht('Edit Blueprint'); + $header = pht('Edit Blueprint %d', $blueprint->getID()); + $crumbs->addTextCrumb(pht('Blueprint %d', $blueprint->getID())); + $crumbs->addTextCrumb(pht('Edit')); + $submit = pht('Save Blueprint'); + } else { + $title = pht('New Blueprint'); + $header = pht('New Blueprint'); + $crumbs->addTextCrumb(pht('New Blueprint')); + $submit = pht('Create Blueprint'); } $form->appendChild( id(new AphrontFormSubmitControl()) - ->setValue(pht('Save')) - ->addCancelButton($this->getApplicationURI())); + ->setValue($submit) + ->addCancelButton($cancel_uri)); $box = id(new PHUIObjectBoxView()) ->setHeaderText($header) Index: src/applications/drydock/controller/DrydockBlueprintViewController.php =================================================================== --- src/applications/drydock/controller/DrydockBlueprintViewController.php +++ src/applications/drydock/controller/DrydockBlueprintViewController.php @@ -65,21 +65,28 @@ } private function buildActionListView(DrydockBlueprint $blueprint) { + $viewer = $this->getRequest()->getUser(); + $view = id(new PhabricatorActionListView()) - ->setUser($this->getRequest()->getUser()) + ->setUser($viewer) ->setObjectURI($this->getRequest()->getRequestURI()) ->setObject($blueprint); $uri = '/blueprint/edit/'.$blueprint->getID().'/'; $uri = $this->getApplicationURI($uri); + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $blueprint, + PhabricatorPolicyCapability::CAN_EDIT); + $view->addAction( id(new PhabricatorActionView()) ->setHref($uri) - ->setName(pht('Edit Blueprint Policies')) + ->setName(pht('Edit Blueprint')) ->setIcon('edit') - ->setWorkflow(true) - ->setDisabled(false)); + ->setWorkflow(!$can_edit) + ->setDisabled(!$can_edit)); return $view; } Index: src/applications/harbormaster/controller/HarbormasterStepAddController.php =================================================================== --- src/applications/harbormaster/controller/HarbormasterStepAddController.php +++ src/applications/harbormaster/controller/HarbormasterStepAddController.php @@ -33,7 +33,7 @@ if ($request->isDialogFormPost()) { $class = $request->getStr('step-type'); if (!in_array($class, $implementations)) { - return $this->createDialog($implementations); + return $this->createDialog($implementations, $cancel_uri); } $steps = $plan->loadOrderedBuildSteps();