diff --git a/src/applications/releeph/controller/ReleephController.php b/src/applications/releeph/controller/ReleephController.php index 83c94debe9..f48d2858e8 100644 --- a/src/applications/releeph/controller/ReleephController.php +++ b/src/applications/releeph/controller/ReleephController.php @@ -1,50 +1,37 @@ buildStandardPageView(); - - $page->setApplicationName(pht('Releeph')); - $page->setBaseURI('/releeph/'); - $page->setTitle(idx($data, 'title')); - $page->setGlyph("\xD3\x82"); - $page->appendChild($view); - - $response = new AphrontWebpageResponse(); - return $response->setContent($page->render()); - } - public function buildSideNavView($for_app = false) { $user = $this->getRequest()->getUser(); $nav = new AphrontSideNavFilterView(); $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); if ($for_app) { $nav->addFilter('project/create/', pht('Create Product')); } id(new ReleephProductSearchEngine()) ->setViewer($user) ->addNavigationItems($nav->getMenu()); $nav->selectFilter(null); return $nav; } public function buildApplicationMenu() { return $this->buildSideNavView(true)->getMenu(); } protected function getProductViewURI(ReleephProject $product) { return $this->getApplicationURI('project/'.$product->getID().'/'); } protected function getBranchViewURI(ReleephBranch $branch) { return $this->getApplicationURI('branch/'.$branch->getID().'/'); } } diff --git a/src/applications/releeph/controller/branch/ReleephBranchCreateController.php b/src/applications/releeph/controller/branch/ReleephBranchCreateController.php index d13383cc3b..e03e432d1f 100644 --- a/src/applications/releeph/controller/branch/ReleephBranchCreateController.php +++ b/src/applications/releeph/controller/branch/ReleephBranchCreateController.php @@ -1,124 +1,133 @@ getViewer(); $id = $request->getURIData('projectID'); $product = id(new ReleephProductQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$product) { return new Aphront404Response(); } $this->setProduct($product); $cut_point = $request->getStr('cutPoint'); $symbolic_name = $request->getStr('symbolicName'); if (!$cut_point) { $repository = $product->getRepository(); switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: break; case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $cut_point = $product->getTrunkBranch(); break; } } $e_cut = true; $errors = array(); $branch_date_control = id(new AphrontFormDateControl()) ->setUser($request->getUser()) ->setName('templateDate') ->setLabel(pht('Date')) ->setCaption(pht('The date used for filling out the branch template.')) ->setInitialTime(AphrontFormDateControl::TIME_START_OF_DAY); $branch_date = $branch_date_control->readValueFromRequest($request); if ($request->isFormPost()) { $cut_commit = null; if (!$cut_point) { $e_cut = pht('Required'); $errors[] = pht('You must give a branch cut point'); } else { try { $finder = id(new ReleephCommitFinder()) ->setUser($request->getUser()) ->setReleephProject($product); $cut_commit = $finder->fromPartial($cut_point); } catch (Exception $e) { $e_cut = pht('Invalid'); $errors[] = $e->getMessage(); } } if (!$errors) { $branch = id(new ReleephBranchEditor()) ->setReleephProject($product) ->setActor($request->getUser()) ->newBranchFromCommit( $cut_commit, $branch_date, $symbolic_name); $branch_uri = $this->getApplicationURI('branch/'.$branch->getID()); return id(new AphrontRedirectResponse()) ->setURI($branch_uri); } } $product_uri = $this->getProductViewURI($product); $form = id(new AphrontFormView()) ->setUser($request->getUser()) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Symbolic Name')) ->setName('symbolicName') ->setValue($symbolic_name) ->setCaption(pht( 'Mutable alternate name, for easy reference, (e.g. "LATEST")'))) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Cut point')) ->setName('cutPoint') ->setValue($cut_point) ->setError($e_cut) ->setCaption(pht( 'A commit ID for your repo type, or a Diffusion ID like "rE123"'))) ->appendChild($branch_date_control) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue(pht('Cut Branch')) ->addCancelButton($product_uri)); $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('New Branch')) + ->setHeaderText(pht('Branch')) ->setFormErrors($errors) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->appendChild($form); + $title = pht('New Branch'); + $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb(pht('New Branch')); - - return $this->buildApplicationPage( - array( - $crumbs, - $box, - ), - array( - 'title' => pht('New Branch'), - )); + $crumbs->addTextCrumb($title); + $crumbs->setBorder(true); + + $header = id(new PHUIHeaderView()) + ->setHeader($title) + ->setHeaderIcon('fa-plus-square'); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter($box); + + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->appendChild($view); + } } diff --git a/src/applications/releeph/controller/branch/ReleephBranchEditController.php b/src/applications/releeph/controller/branch/ReleephBranchEditController.php index 6d66f5d9d5..9d34e78668 100644 --- a/src/applications/releeph/controller/branch/ReleephBranchEditController.php +++ b/src/applications/releeph/controller/branch/ReleephBranchEditController.php @@ -1,108 +1,114 @@ getViewer(); $id = $request->getURIData('branchID'); $branch = id(new ReleephBranchQuery()) ->setViewer($viewer) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->withIDs(array($id)) ->executeOne(); if (!$branch) { return new Aphront404Response(); } $this->setBranch($branch); $symbolic_name = $request->getStr( 'symbolicName', $branch->getSymbolicName()); if ($request->isFormPost()) { $existing_with_same_symbolic_name = id(new ReleephBranch()) ->loadOneWhere( 'id != %d AND releephProjectID = %d AND symbolicName = %s', $branch->getID(), $branch->getReleephProjectID(), $symbolic_name); $branch->openTransaction(); $branch->setSymbolicName($symbolic_name); if ($existing_with_same_symbolic_name) { $existing_with_same_symbolic_name ->setSymbolicName(null) ->save(); } $branch->save(); $branch->saveTransaction(); return id(new AphrontRedirectResponse()) ->setURI($this->getBranchViewURI($branch)); } $phids = array(); $phids[] = $creator_phid = $branch->getCreatedByUserPHID(); $phids[] = $cut_commit_phid = $branch->getCutPointCommitPHID(); $handles = id(new PhabricatorHandleQuery()) ->setViewer($request->getUser()) ->withPHIDs($phids) ->execute(); $form = id(new AphrontFormView()) ->setUser($request->getUser()) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel(pht('Branch Name')) ->setValue($branch->getName())) ->appendChild( id(new AphrontFormMarkupControl()) ->setLabel(pht('Cut Point')) ->setValue($handles[$cut_commit_phid]->renderLink())) ->appendChild( id(new AphrontFormMarkupControl()) ->setLabel(pht('Created By')) ->setValue($handles[$creator_phid]->renderLink())) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Symbolic Name')) ->setName('symbolicName') ->setValue($symbolic_name) ->setCaption(pht( 'Mutable alternate name, for easy reference, (e.g. "LATEST")'))) ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($this->getBranchViewURI($branch)) ->setValue(pht('Save Branch'))); $title = pht( - 'Edit Branch %s', + 'Edit Branch: %s', $branch->getDisplayNameWithDetail()); + $box = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Branch')) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->appendChild($form); + $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Edit')); + $crumbs->setBorder(true); - $box = id(new PHUIObjectBoxView()) - ->setHeaderText($title) - ->appendChild($form); + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Edit Branch')) + ->setHeaderIcon('fa-pencil'); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter($box); - return $this->buildApplicationPage( - array( - $crumbs, - $box, - ), - array( - 'title' => $title, - )); + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->appendChild($view); } } diff --git a/src/applications/releeph/controller/branch/ReleephBranchHistoryController.php b/src/applications/releeph/controller/branch/ReleephBranchHistoryController.php index a77cdf8fb3..5a07a5c879 100644 --- a/src/applications/releeph/controller/branch/ReleephBranchHistoryController.php +++ b/src/applications/releeph/controller/branch/ReleephBranchHistoryController.php @@ -1,41 +1,41 @@ getViewer(); $id = $request->getURIData('branchID'); $branch = id(new ReleephBranchQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->executeOne(); if (!$branch) { return new Aphront404Response(); } $this->setBranch($branch); $timeline = $this->buildTransactionTimeline( $branch, new ReleephBranchTransactionQuery()); $timeline ->setShouldTerminate(true); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('History')); + $crumbs->setBorder(true); + + $title = pht('Branch History'); + + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->appendChild($timeline); - return $this->buildApplicationPage( - array( - $crumbs, - $timeline, - ), - array( - 'title' => pht('Branch History'), - )); } } diff --git a/src/applications/releeph/controller/product/ReleephProductCreateController.php b/src/applications/releeph/controller/product/ReleephProductCreateController.php index 2aedf8cdf1..12da2ea3f4 100644 --- a/src/applications/releeph/controller/product/ReleephProductCreateController.php +++ b/src/applications/releeph/controller/product/ReleephProductCreateController.php @@ -1,132 +1,140 @@ getStr('name')); $trunk_branch = trim($request->getStr('trunkBranch')); $repository_phid = $request->getStr('repositoryPHID'); $e_name = true; $e_trunk_branch = true; $errors = array(); if ($request->isFormPost()) { if (!$name) { $e_name = pht('Required'); $errors[] = pht( 'Your product should have a simple, descriptive name.'); } if (!$trunk_branch) { $e_trunk_branch = pht('Required'); $errors[] = pht( 'You must specify which branch you will be picking from.'); } $pr_repository = id(new PhabricatorRepositoryQuery()) ->setViewer($request->getUser()) ->withPHIDs(array($repository_phid)) ->executeOne(); if (!$errors) { $releeph_product = id(new ReleephProject()) ->setName($name) ->setTrunkBranch($trunk_branch) ->setRepositoryPHID($pr_repository->getPHID()) ->setCreatedByUserPHID($request->getUser()->getPHID()) ->setIsActive(1); try { $releeph_product->save(); return id(new AphrontRedirectResponse()) ->setURI($releeph_product->getURI()); } catch (AphrontDuplicateKeyQueryException $ex) { $e_name = pht('Not Unique'); $errors[] = pht('Another product already uses this name.'); } } } $repo_options = $this->getRepositorySelectOptions(); $product_name_input = id(new AphrontFormTextControl()) ->setLabel(pht('Name')) ->setDisableAutocomplete(true) ->setName('name') ->setValue($name) ->setError($e_name) ->setCaption(pht('A name like "Thrift" but not "Thrift releases".')); $repository_input = id(new AphrontFormSelectControl()) ->setLabel(pht('Repository')) ->setName('repositoryPHID') ->setValue($repository_phid) ->setOptions($repo_options); $branch_name_preview = id(new ReleephBranchPreviewView()) ->setLabel(pht('Example Branch')) ->addControl('projectName', $product_name_input) ->addControl('repositoryPHID', $repository_input) ->addStatic('template', '') ->addStatic('isSymbolic', false); $form = id(new AphrontFormView()) ->setUser($request->getUser()) ->appendChild($product_name_input) ->appendChild($repository_input) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Trunk')) ->setName('trunkBranch') ->setValue($trunk_branch) ->setError($e_trunk_branch) ->setCaption(pht( 'The development branch, from which requests will be picked.'))) ->appendChild($branch_name_preview) ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton('/releeph/project/') ->setValue(pht('Create Release Product'))); - $form_box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Create New Product')) + $box = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Product')) ->setFormErrors($errors) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setForm($form); + $title = pht('Create New Product'); + $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('New Product')); + $crumbs->setBorder(true); + + $header = id(new PHUIHeaderView()) + ->setHeader($title) + ->setHeaderIcon('fa-plus-square'); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter($box); - return $this->buildApplicationPage( - array( - $crumbs, - $form_box, - ), - array( - 'title' => pht('Create New Product'), - )); + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->appendChild($view); } private function getRepositorySelectOptions() { $repos = id(new PhabricatorRepositoryQuery()) ->setViewer($this->getRequest()->getUser()) ->execute(); $repos = msort($repos, 'getName'); $repos = mpull($repos, null, 'getID'); $choices = array(); foreach ($repos as $repo_id => $repo) { $repo_name = $repo->getName(); $display = $repo->getDisplayName(); $choices[$repo->getPHID()] = "{$display} ({$repo_name})"; } asort($choices); return $choices; } } diff --git a/src/applications/releeph/controller/product/ReleephProductEditController.php b/src/applications/releeph/controller/product/ReleephProductEditController.php index 6a58a39bd9..7938f0d930 100644 --- a/src/applications/releeph/controller/product/ReleephProductEditController.php +++ b/src/applications/releeph/controller/product/ReleephProductEditController.php @@ -1,267 +1,275 @@ getViewer(); $id = $request->getURIData('projectID'); $product = id(new ReleephProductQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$product) { return new Aphront404Response(); } $this->setProduct($product); $e_name = true; $e_trunk_branch = true; $e_branch_template = false; $errors = array(); $product_name = $request->getStr('name', $product->getName()); $trunk_branch = $request->getStr('trunkBranch', $product->getTrunkBranch()); $branch_template = $request->getStr('branchTemplate'); if ($branch_template === null) { $branch_template = $product->getDetail('branchTemplate'); } $pick_failure_instructions = $request->getStr('pickFailureInstructions', $product->getDetail('pick_failure_instructions')); $test_paths = $request->getStr('testPaths'); if ($test_paths !== null) { $test_paths = array_filter(explode("\n", $test_paths)); } else { $test_paths = $product->getDetail('testPaths', array()); } $repository_phid = $product->getRepositoryPHID(); if ($request->isFormPost()) { $pusher_phids = $request->getArr('pushers'); if (!$product_name) { $e_name = pht('Required'); $errors[] = pht('Your Releeph product should have a simple descriptive name.'); } if (!$trunk_branch) { $e_trunk_branch = pht('Required'); $errors[] = pht('You must specify which branch you will be picking from.'); } $other_releeph_products = id(new ReleephProject()) ->loadAllWhere('id != %d', $product->getID()); $other_releeph_product_names = mpull($other_releeph_products, 'getName', 'getID'); if (in_array($product_name, $other_releeph_product_names)) { $errors[] = pht('Releeph product name %s is already taken', $product_name); } foreach ($test_paths as $test_path) { $result = @preg_match($test_path, ''); $is_a_valid_regexp = $result !== false; if (!$is_a_valid_regexp) { $errors[] = pht('Please provide a valid regular expression: '. '%s is not valid', $test_path); } } $product ->setName($product_name) ->setTrunkBranch($trunk_branch) ->setDetail('pushers', $pusher_phids) ->setDetail('pick_failure_instructions', $pick_failure_instructions) ->setDetail('branchTemplate', $branch_template) ->setDetail('testPaths', $test_paths); $fake_commit_handle = ReleephBranchTemplate::getFakeCommitHandleFor( $repository_phid, $viewer); if ($branch_template) { list($branch_name, $template_errors) = id(new ReleephBranchTemplate()) ->setCommitHandle($fake_commit_handle) ->setReleephProjectName($product_name) ->interpolate($branch_template); if ($template_errors) { $e_branch_template = pht('Whoopsies!'); foreach ($template_errors as $template_error) { $errors[] = pht('Template error: %s', $template_error); } } } if (!$errors) { $product->save(); return id(new AphrontRedirectResponse())->setURI($product->getURI()); } } $pusher_phids = $request->getArr( 'pushers', $product->getDetail('pushers', array())); $form = id(new AphrontFormView()) ->setUser($request->getUser()) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Name')) ->setName('name') ->setValue($product_name) ->setError($e_name) ->setCaption(pht('A name like "Thrift" but not "Thrift releases".'))) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel(pht('Repository')) ->setValue( $product->getRepository()->getName())) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel(pht('Repository')) ->setValue( $product->getRepository()->getName())) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel(pht('Releeph Project PHID')) ->setValue( $product->getPHID())) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Trunk')) ->setValue($trunk_branch) ->setName('trunkBranch') ->setError($e_trunk_branch)) ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel(pht('Pick Instructions')) ->setValue($pick_failure_instructions) ->setName('pickFailureInstructions') ->setCaption( pht('Instructions for pick failures, which will be used '. 'in emails generated by failed picks'))) ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel(pht('Tests paths')) ->setValue(implode("\n", $test_paths)) ->setName('testPaths') ->setCaption( pht('List of strings that all test files contain in their path '. 'in this project. One string per line. '. 'Examples: \'__tests__\', \'/javatests/\'...'))); $branch_template_input = id(new AphrontFormTextControl()) ->setName('branchTemplate') ->setValue($branch_template) ->setLabel(pht('Branch Template')) ->setError($e_branch_template) ->setCaption( pht("Leave this blank to use your installation's default.")); $branch_template_preview = id(new ReleephBranchPreviewView()) ->setLabel(pht('Preview')) ->addControl('template', $branch_template_input) ->addStatic('repositoryPHID', $repository_phid) ->addStatic('isSymbolic', false) ->addStatic('projectName', $product->getName()); $form ->appendControl( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Pushers')) ->setName('pushers') ->setDatasource(new PhabricatorPeopleDatasource()) ->setValue($pusher_phids)) ->appendChild($branch_template_input) ->appendChild($branch_template_preview) ->appendRemarkupInstructions($this->getBranchHelpText()); $form ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton('/releeph/product/') ->setValue(pht('Save'))); $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Edit Releeph Product')) + ->setHeaderText(pht('Product')) ->setFormErrors($errors) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->appendChild($form); + $title = pht('Edit Product'); + $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Edit Product')); + $crumbs->setBorder(true); + + $header = id(new PHUIHeaderView()) + ->setHeader($title) + ->setHeaderIcon('fa-pencil'); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter($box); + + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->appendChild($view); - return $this->buildStandardPageResponse( - array( - $crumbs, - $box, - ), - array( - 'title' => pht('Edit Releeph Product'), - 'device' => true, - )); } private function getBranchHelpText() { return << releases/2012-30-16-rHERGE32cd512a52b7 Include a second hierarchy if you share your repository with other products: lang=none releases/%P/%p-release-%Y%m%d-%V => releases/Tintin/tintin-release-20121116-32cd512a52b7 Keep your branch names simple, avoiding strange punctuation, most of which is forbidden or escaped anyway: lang=none, counterexample releases//..clown-releases..//`date --iso=seconds`-$(sudo halt) Include the date early in your template, in an order which sorts properly: lang=none releases/%Y%m%d-%v => releases/20121116-rHERGE32cd512a52b7 (good!) releases/%V-%m.%d.%Y => releases/32cd512a52b7-11.16.2012 (awful!) EOTEXT; } } diff --git a/src/applications/releeph/controller/product/ReleephProductHistoryController.php b/src/applications/releeph/controller/product/ReleephProductHistoryController.php index ebe9f15725..12d0d0b5c1 100644 --- a/src/applications/releeph/controller/product/ReleephProductHistoryController.php +++ b/src/applications/releeph/controller/product/ReleephProductHistoryController.php @@ -1,41 +1,39 @@ getViewer(); $id = $request->getURIData('projectID'); $product = id(new ReleephProductQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->executeOne(); if (!$product) { return new Aphront404Response(); } $this->setProduct($product); $timeline = $this->buildTransactionTimeline( $product, new ReleephProductTransactionQuery()); $timeline->setShouldTerminate(true); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('History')); $crumbs->setBorder(true); - return $this->buildApplicationPage( - array( - $crumbs, - $timeline, - ), - array( - 'title' => pht('Product History'), - )); + $title = pht('Product History'); + + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->appendChild($timeline); } } diff --git a/src/applications/releeph/controller/request/ReleephRequestEditController.php b/src/applications/releeph/controller/request/ReleephRequestEditController.php index d5f5187349..af7adc2c83 100644 --- a/src/applications/releeph/controller/request/ReleephRequestEditController.php +++ b/src/applications/releeph/controller/request/ReleephRequestEditController.php @@ -1,308 +1,320 @@ getURIData('action'); $request_id = $request->getURIData('requestID'); $branch_id = $request->getURIData('branchID'); $viewer = $request->getViewer(); if ($request_id) { $pull = id(new ReleephRequestQuery()) ->setViewer($viewer) ->withIDs(array($request_id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$pull) { return new Aphront404Response(); } $branch = $pull->getBranch(); $is_edit = true; } else { $branch = id(new ReleephBranchQuery()) ->setViewer($viewer) ->withIDs(array($branch_id)) ->executeOne(); if (!$branch) { return new Aphront404Response(); } $pull = id(new ReleephRequest()) ->setRequestUserPHID($viewer->getPHID()) ->setBranchID($branch->getID()) ->setInBranch(0) ->attachBranch($branch); $is_edit = false; } $this->setBranch($branch); $product = $branch->getProduct(); $request_identifier = $request->getStr('requestIdentifierRaw'); $e_request_identifier = true; // Load all the ReleephFieldSpecifications $selector = $branch->getProduct()->getReleephFieldSelector(); $fields = $selector->getFieldSpecifications(); foreach ($fields as $field) { $field ->setReleephProject($product) ->setReleephBranch($branch) ->setReleephRequest($pull); } $field_list = PhabricatorCustomField::getObjectFields( $pull, PhabricatorCustomField::ROLE_EDIT); foreach ($field_list->getFields() as $field) { $field ->setReleephProject($product) ->setReleephBranch($branch) ->setReleephRequest($pull); } $field_list->readFieldsFromStorage($pull); if ($branch_id) { $cancel_uri = $this->getApplicationURI('branch/'.$branch_id.'/'); } else { $cancel_uri = '/'.$pull->getMonogram(); } // Make edits $errors = array(); if ($request->isFormPost()) { $xactions = array(); // The commit-identifier being requested... if (!$is_edit) { if ($request_identifier === ReleephRequestTypeaheadControl::PLACEHOLDER) { $errors[] = pht('No commit ID was provided.'); $e_request_identifier = pht('Required'); } else { $pr_commit = null; $finder = id(new ReleephCommitFinder()) ->setUser($viewer) ->setReleephProject($product); try { $pr_commit = $finder->fromPartial($request_identifier); } catch (Exception $e) { $e_request_identifier = pht('Invalid'); $errors[] = pht( 'Request %s is probably not a valid commit.', $request_identifier); $errors[] = $e->getMessage(); } if (!$errors) { $object_phid = $finder->getRequestedObjectPHID(); if (!$object_phid) { $object_phid = $pr_commit->getPHID(); } $pull->setRequestedObjectPHID($object_phid); } } if (!$errors) { $existing = id(new ReleephRequest()) ->loadOneWhere('requestCommitPHID = %s AND branchID = %d', $pr_commit->getPHID(), $branch->getID()); if ($existing) { return id(new AphrontRedirectResponse()) ->setURI('/releeph/request/edit/'.$existing->getID(). '?existing=1'); } $xactions[] = id(new ReleephRequestTransaction()) ->setTransactionType(ReleephRequestTransaction::TYPE_REQUEST) ->setNewValue($pr_commit->getPHID()); $xactions[] = id(new ReleephRequestTransaction()) ->setTransactionType(ReleephRequestTransaction::TYPE_USER_INTENT) // To help hide these implicit intents... ->setMetadataValue('isRQCreate', true) ->setMetadataValue('userPHID', $viewer->getPHID()) ->setMetadataValue( 'isAuthoritative', $product->isAuthoritative($viewer)) ->setNewValue(ReleephRequest::INTENT_WANT); } } // TODO: This should happen implicitly while building transactions // instead. foreach ($field_list->getFields() as $field) { $field->readValueFromRequest($request); } if (!$errors) { foreach ($fields as $field) { if ($field->isEditable()) { try { $data = $request->getRequestData(); $value = idx($data, $field->getRequiredStorageKey()); $field->validate($value); $xactions[] = id(new ReleephRequestTransaction()) ->setTransactionType(ReleephRequestTransaction::TYPE_EDIT_FIELD) ->setMetadataValue('fieldClass', get_class($field)) ->setNewValue($value); } catch (ReleephFieldParseException $ex) { $errors[] = $ex->getMessage(); } } } } if (!$errors) { $editor = id(new ReleephRequestTransactionalEditor()) ->setActor($viewer) ->setContinueOnNoEffect(true) ->setContentSourceFromRequest($request); $editor->applyTransactions($pull, $xactions); return id(new AphrontRedirectResponse())->setURI($cancel_uri); } } $handle_phids = array( $pull->getRequestUserPHID(), $pull->getRequestCommitPHID(), ); $handle_phids = array_filter($handle_phids); if ($handle_phids) { $handles = id(new PhabricatorHandleQuery()) ->setViewer($viewer) ->withPHIDs($handle_phids) ->execute(); } else { $handles = array(); } $age_string = ''; if ($is_edit) { $age_string = phutil_format_relative_time( time() - $pull->getDateCreated()).' ago'; } // Warn the user if we've been redirected here because we tried to // re-request something. $notice_view = null; if ($request->getInt('existing')) { $notice_messages = array( pht('You are editing an existing pick request!'), pht( 'Requested %s by %s', $age_string, $handles[$pull->getRequestUserPHID()]->renderLink()), ); $notice_view = id(new PHUIInfoView()) ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) ->setErrors($notice_messages); } $form = id(new AphrontFormView()) ->setUser($viewer); if ($is_edit) { $form ->appendChild( id(new AphrontFormMarkupControl()) ->setLabel(pht('Original Commit')) ->setValue( $handles[$pull->getRequestCommitPHID()]->renderLink())) ->appendChild( id(new AphrontFormMarkupControl()) ->setLabel(pht('Requestor')) ->setValue(hsprintf( '%s %s', $handles[$pull->getRequestUserPHID()]->renderLink(), $age_string))); } else { $origin = null; $diff_rev_id = $request->getStr('D'); if ($diff_rev_id) { $diff_rev = id(new DifferentialRevisionQuery()) ->setViewer($viewer) ->withIDs(array($diff_rev_id)) ->executeOne(); $origin = '/D'.$diff_rev->getID(); $title = sprintf( 'D%d: %s', $diff_rev_id, $diff_rev->getTitle()); $form ->addHiddenInput('requestIdentifierRaw', 'D'.$diff_rev_id) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel(pht('Diff')) ->setValue($title)); } else { $origin = $branch->getURI(); $repo = $product->getRepository(); $branch_cut_point = id(new PhabricatorRepositoryCommit()) ->loadOneWhere( 'phid = %s', $branch->getCutPointCommitPHID()); $form->appendChild( id(new ReleephRequestTypeaheadControl()) ->setName('requestIdentifierRaw') ->setLabel(pht('Commit ID')) ->setRepo($repo) ->setValue($request_identifier) ->setError($e_request_identifier) ->setStartTime($branch_cut_point->getEpoch()) ->setCaption( pht( 'Start typing to autocomplete on commit title, '. 'or give a Phabricator commit identifier like rFOO1234.'))); } } $field_list->appendFieldsToForm($form); $crumbs = $this->buildApplicationCrumbs(); if ($is_edit) { $title = pht('Edit Pull Request'); $submit_name = pht('Save'); + $header_icon = 'fa-pencil'; $crumbs->addTextCrumb($pull->getMonogram(), '/'.$pull->getMonogram()); $crumbs->addTextCrumb(pht('Edit')); } else { $title = pht('Create Pull Request'); $submit_name = pht('Create Pull Request'); + $header_icon = 'fa-plus-square'; $crumbs->addTextCrumb(pht('New Pull Request')); } $form->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($cancel_uri, pht('Cancel')) ->setValue($submit_name)); $box = id(new PHUIObjectBoxView()) - ->setHeaderText($title) + ->setHeaderText(pht('Request')) ->setFormErrors($errors) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->appendChild($form); - return $this->buildApplicationPage( - array( - $crumbs, + $crumbs->setBorder(true); + + $header = id(new PHUIHeaderView()) + ->setHeader($title) + ->setHeaderIcon($header_icon); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter(array( $notice_view, $box, - ), - array( - 'title' => $title, )); + + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->appendChild($view); + } } diff --git a/src/applications/releeph/controller/request/ReleephRequestViewController.php b/src/applications/releeph/controller/request/ReleephRequestViewController.php index 694505cd20..c404e31579 100644 --- a/src/applications/releeph/controller/request/ReleephRequestViewController.php +++ b/src/applications/releeph/controller/request/ReleephRequestViewController.php @@ -1,93 +1,101 @@ getURIData('requestID'); $viewer = $request->getViewer(); $pull = id(new ReleephRequestQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->executeOne(); if (!$pull) { return new Aphront404Response(); } $this->setBranch($pull->getBranch()); // Redirect older URIs to new "Y" URIs. // TODO: Get rid of this eventually. $actual_path = $request->getRequestURI()->getPath(); $expect_path = '/'.$pull->getMonogram(); if ($actual_path != $expect_path) { return id(new AphrontRedirectResponse())->setURI($expect_path); } // TODO: Break this 1:1 stuff? $branch = $pull->getBranch(); $field_list = PhabricatorCustomField::getObjectFields( $pull, PhabricatorCustomField::ROLE_VIEW); $field_list ->setViewer($viewer) ->readFieldsFromStorage($pull); // TODO: This should be more modern and general. $engine = id(new PhabricatorMarkupEngine()) ->setViewer($viewer); foreach ($field_list->getFields() as $field) { if ($field->shouldMarkup()) { $field->setMarkupEngine($engine); } } $engine->process(); $pull_box = id(new ReleephRequestView()) ->setUser($viewer) ->setCustomFields($field_list) ->setPullRequest($pull); $timeline = $this->buildTransactionTimeline( $pull, new ReleephRequestTransactionQuery()); $add_comment_header = pht('Plea or Yield'); $draft = PhabricatorDraft::newFromUserAndKey( $viewer, $pull->getPHID()); $title = hsprintf( '%s %s', $pull->getMonogram(), $pull->getSummaryForDisplay()); $add_comment_form = id(new PhabricatorApplicationTransactionCommentView()) ->setUser($viewer) ->setObjectPHID($pull->getPHID()) ->setDraft($draft) ->setHeaderText($add_comment_header) ->setAction($this->getApplicationURI( '/request/comment/'.$pull->getID().'/')) ->setSubmitButtonName(pht('Comment')); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($pull->getMonogram(), '/'.$pull->getMonogram()); + $crumbs->setBorder(true); - return $this->buildStandardPageResponse( - array( - $crumbs, + $header = id(new PHUIHeaderView()) + ->setHeader($title) + ->setHeaderIcon('fa-flag-checkered'); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter(array( $pull_box, $timeline, $add_comment_form, - ), - array( - 'title' => $title, )); + + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->appendChild($view); + } }