@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Projects - merge create + edit interface code paths

Summary:
Fixes T6145, T4016.

Filed T6287 and T6288 for some polish on this.

Test Plan: Made new projects from Maniphest - great success. Made new projects from project / create - also great success.

Reviewers: chad, epriestley

Reviewed By: epriestley

Subscribers: Korvin, epriestley

Maniphest Tasks: T4016, T6145

Differential Revision: https://secure.phabricator.com/D10679

+130 -162
-2
src/__phutil_library_map__.php
··· 2029 2029 'PhabricatorProjectConfiguredCustomField' => 'applications/project/customfield/PhabricatorProjectConfiguredCustomField.php', 2030 2030 'PhabricatorProjectConstants' => 'applications/project/constants/PhabricatorProjectConstants.php', 2031 2031 'PhabricatorProjectController' => 'applications/project/controller/PhabricatorProjectController.php', 2032 - 'PhabricatorProjectCreateController' => 'applications/project/controller/PhabricatorProjectCreateController.php', 2033 2032 'PhabricatorProjectCustomField' => 'applications/project/customfield/PhabricatorProjectCustomField.php', 2034 2033 'PhabricatorProjectCustomFieldNumericIndex' => 'applications/project/storage/PhabricatorProjectCustomFieldNumericIndex.php', 2035 2034 'PhabricatorProjectCustomFieldStorage' => 'applications/project/storage/PhabricatorProjectCustomFieldStorage.php', ··· 5030 5029 'PhabricatorStandardCustomFieldInterface', 5031 5030 ), 5032 5031 'PhabricatorProjectController' => 'PhabricatorController', 5033 - 'PhabricatorProjectCreateController' => 'PhabricatorProjectController', 5034 5032 'PhabricatorProjectCustomField' => 'PhabricatorCustomField', 5035 5033 'PhabricatorProjectCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage', 5036 5034 'PhabricatorProjectCustomFieldStorage' => 'PhabricatorCustomFieldStorage',
+3 -1
src/applications/project/application/PhabricatorProjectApplication.php
··· 58 58 => 'PhabricatorProjectEditPictureController', 59 59 'icon/(?P<id>[1-9]\d*)/' 60 60 => 'PhabricatorProjectEditIconController', 61 - 'create/' => 'PhabricatorProjectCreateController', 61 + 'icon/' 62 + => 'PhabricatorProjectEditIconController', 63 + 'create/' => 'PhabricatorProjectEditDetailsController', 62 64 'board/(?P<id>[1-9]\d*)/'. 63 65 '(?P<filter>filter/)?'. 64 66 '(?:query/(?P<queryKey>[^/]+)/)?'
-115
src/applications/project/controller/PhabricatorProjectCreateController.php
··· 1 - <?php 2 - 3 - final class PhabricatorProjectCreateController 4 - extends PhabricatorProjectController { 5 - 6 - public function processRequest() { 7 - $request = $this->getRequest(); 8 - $user = $request->getUser(); 9 - 10 - $this->requireApplicationCapability( 11 - ProjectCreateProjectsCapability::CAPABILITY); 12 - 13 - $project = PhabricatorProject::initializeNewProject($user); 14 - 15 - $e_name = true; 16 - $type_name = PhabricatorProjectTransaction::TYPE_NAME; 17 - $v_name = $project->getName(); 18 - $validation_exception = null; 19 - if ($request->isFormPost()) { 20 - $xactions = array(); 21 - $v_name = $request->getStr('name'); 22 - 23 - $xactions[] = id(new PhabricatorProjectTransaction()) 24 - ->setTransactionType($type_name) 25 - ->setNewValue($v_name); 26 - 27 - $xactions[] = id(new PhabricatorProjectTransaction()) 28 - ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 29 - ->setMetadataValue('edge:type', PhabricatorEdgeConfig::TYPE_PROJ_MEMBER) 30 - ->setNewValue( 31 - array( 32 - '+' => array($user->getPHID() => $user->getPHID()), 33 - )); 34 - 35 - $editor = id(new PhabricatorProjectTransactionEditor()) 36 - ->setActor($user) 37 - ->setContinueOnNoEffect(true) 38 - ->setContentSourceFromRequest($request); 39 - try { 40 - $editor->applyTransactions($project, $xactions); 41 - if ($request->isAjax()) { 42 - return id(new AphrontAjaxResponse()) 43 - ->setContent(array( 44 - 'phid' => $project->getPHID(), 45 - 'name' => $project->getName(), 46 - )); 47 - } else { 48 - return id(new AphrontRedirectResponse()) 49 - ->setURI('/project/view/'.$project->getID().'/'); 50 - } 51 - } catch (PhabricatorApplicationTransactionValidationException $ex) { 52 - $validation_exception = $ex; 53 - $e_name = $ex->getShortMessage($type_name); 54 - } 55 - } 56 - 57 - if ($request->isAjax()) { 58 - $form = new PHUIFormLayoutView(); 59 - } else { 60 - $form = new AphrontFormView(); 61 - $form->setUser($user); 62 - } 63 - 64 - $form 65 - ->appendChild( 66 - id(new AphrontFormTextControl()) 67 - ->setLabel(pht('Name')) 68 - ->setName('name') 69 - ->setValue($v_name) 70 - ->setError($e_name)); 71 - 72 - if ($request->isAjax()) { 73 - $errors = array(); 74 - if ($validation_exception) { 75 - $errors = mpull($ex->getErrors(), 'getMessage'); 76 - } 77 - $dialog = id(new AphrontDialogView()) 78 - ->setUser($user) 79 - ->setWidth(AphrontDialogView::WIDTH_FORM) 80 - ->setTitle(pht('Create a New Project')) 81 - ->setErrors($errors) 82 - ->appendChild($form) 83 - ->addSubmitButton(pht('Create Project')) 84 - ->addCancelButton('/project/'); 85 - 86 - return id(new AphrontDialogResponse())->setDialog($dialog); 87 - } else { 88 - $form 89 - ->appendChild( 90 - id(new AphrontFormSubmitControl()) 91 - ->setValue(pht('Create')) 92 - ->addCancelButton('/project/')); 93 - 94 - $crumbs = $this->buildApplicationCrumbs($this->buildSideNavView()); 95 - $crumbs->addTextCrumb( 96 - pht('Create Project'), 97 - $this->getApplicationURI().'create/'); 98 - 99 - $form_box = id(new PHUIObjectBoxView()) 100 - ->setHeaderText(pht('Create New Project')) 101 - ->setValidationException($validation_exception) 102 - ->setForm($form); 103 - 104 - return $this->buildApplicationPage( 105 - array( 106 - $crumbs, 107 - $form_box, 108 - ), 109 - array( 110 - 'title' => pht('Create New Project'), 111 - )); 112 - } 113 - } 114 - 115 - }
+97 -28
src/applications/project/controller/PhabricatorProjectEditDetailsController.php
··· 6 6 private $id; 7 7 8 8 public function willProcessRequest(array $data) { 9 - $this->id = $data['id']; 9 + $this->id = idx($data, 'id'); 10 10 } 11 11 12 12 public function processRequest() { 13 13 $request = $this->getRequest(); 14 14 $viewer = $request->getUser(); 15 15 16 - $project = id(new PhabricatorProjectQuery()) 17 - ->setViewer($viewer) 18 - ->withIDs(array($this->id)) 19 - ->needSlugs(true) 20 - ->requireCapabilities( 21 - array( 22 - PhabricatorPolicyCapability::CAN_VIEW, 23 - PhabricatorPolicyCapability::CAN_EDIT, 24 - )) 25 - ->executeOne(); 26 - if (!$project) { 27 - return new Aphront404Response(); 16 + if ($this->id) { 17 + $is_new = false; 18 + 19 + $project = id(new PhabricatorProjectQuery()) 20 + ->setViewer($viewer) 21 + ->withIDs(array($this->id)) 22 + ->needSlugs(true) 23 + ->requireCapabilities( 24 + array( 25 + PhabricatorPolicyCapability::CAN_VIEW, 26 + PhabricatorPolicyCapability::CAN_EDIT, 27 + )) 28 + ->executeOne(); 29 + if (!$project) { 30 + return new Aphront404Response(); 31 + } 32 + 33 + } else { 34 + $is_new = true; 35 + 36 + $this->requireApplicationCapability( 37 + ProjectCreateProjectsCapability::CAPABILITY); 38 + 39 + $project = PhabricatorProject::initializeNewProject($viewer); 28 40 } 29 41 30 42 $field_list = PhabricatorCustomField::getObjectFields( ··· 114 126 ->setContentSourceFromRequest($request) 115 127 ->setContinueOnNoEffect(true); 116 128 129 + if ($is_new) { 130 + $xactions[] = id(new PhabricatorProjectTransaction()) 131 + ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 132 + ->setMetadataValue( 133 + 'edge:type', 134 + PhabricatorEdgeConfig::TYPE_PROJ_MEMBER) 135 + ->setNewValue( 136 + array( 137 + '+' => array($viewer->getPHID() => $viewer->getPHID()), 138 + )); 139 + } 140 + 117 141 try { 142 + 118 143 $editor->applyTransactions($project, $xactions); 119 144 120 - return id(new AphrontRedirectResponse())->setURI($edit_uri); 145 + if ($request->isAjax()) { 146 + return id(new AphrontAjaxResponse()) 147 + ->setContent(array( 148 + 'phid' => $project->getPHID(), 149 + 'name' => $project->getName(), 150 + )); 151 + } 152 + 153 + if ($is_new) { 154 + $redirect_uri = $view_uri; 155 + } else { 156 + $redirect_uri = $edit_uri; 157 + } 158 + 159 + return id(new AphrontRedirectResponse())->setURI($redirect_uri); 121 160 } catch (PhabricatorApplicationTransactionValidationException $ex) { 122 161 $validation_exception = $ex; 123 162 ··· 131 170 } 132 171 } 133 172 134 - $header_name = pht('Edit Project'); 135 - $title = pht('Edit Project'); 173 + if ($is_new) { 174 + $header_name = pht('Create a New Project'); 175 + $title = pht('Create Project'); 176 + } else { 177 + $header_name = pht('Edit Project'); 178 + $title = pht('Edit Project'); 179 + } 136 180 137 181 $policies = id(new PhabricatorPolicyQuery()) 138 182 ->setViewer($viewer) ··· 140 184 ->execute(); 141 185 $v_slugs = implode(', ', $v_slugs); 142 186 143 - $form = new AphrontFormView(); 144 - $form 187 + $form = id(new AphrontFormView()) 145 188 ->setUser($viewer) 146 189 ->appendChild( 147 190 id(new AphrontFormTextControl()) ··· 153 196 154 197 $shades = PhabricatorProjectIcon::getColorMap(); 155 198 156 - $icon_uri = $this->getApplicationURI('icon/'.$project->getID().'/'); 199 + if ($is_new) { 200 + $icon_uri = $this->getApplicationURI('icon/'); 201 + } else { 202 + $icon_uri = $this->getApplicationURI('icon/'.$project->getID().'/'); 203 + } 157 204 $icon_display = PhabricatorProjectIcon::renderIconForChooser($v_icon); 158 205 list($can_lock, $lock_message) = $this->explainApplicationCapability( 159 206 ProjectCanLockProjectsCapability::CAPABILITY, ··· 221 268 1, 222 269 pht('Prevent members from leaving this project.'), 223 270 $v_locked) 224 - ->setCaption($lock_message)) 225 - ->appendChild( 226 - id(new AphrontFormSubmitControl()) 227 - ->addCancelButton($edit_uri) 228 - ->setValue(pht('Save'))); 271 + ->setCaption($lock_message)); 272 + 273 + if ($request->isAjax()) { 274 + $errors = array(); 275 + if ($validation_exception) { 276 + $errors = mpull($ex->getErrors(), 'getMessage'); 277 + } 278 + $dialog = id(new AphrontDialogView()) 279 + ->setUser($viewer) 280 + ->setWidth(AphrontDialogView::WIDTH_FULL) 281 + ->setTitle($header_name) 282 + ->setErrors($errors) 283 + ->appendForm($form) 284 + ->addSubmitButton($title) 285 + ->addCancelButton('/project/'); 286 + return id(new AphrontDialogResponse())->setDialog($dialog); 287 + } 288 + 289 + $form->appendChild( 290 + id(new AphrontFormSubmitControl()) 291 + ->addCancelButton($edit_uri) 292 + ->setValue(pht('Save'))); 229 293 230 294 $form_box = id(new PHUIObjectBoxView()) 231 295 ->setHeaderText($title) 232 296 ->setValidationException($validation_exception) 233 297 ->setForm($form); 234 298 235 - $crumbs = $this->buildApplicationCrumbs($this->buildSideNavView()) 236 - ->addTextCrumb($project->getName(), $view_uri) 237 - ->addTextCrumb(pht('Edit'), $edit_uri) 238 - ->addTextCrumb(pht('Details')); 299 + $crumbs = $this->buildApplicationCrumbs($this->buildSideNavView()); 300 + if ($is_new) { 301 + $crumbs->addTextCrumb($title); 302 + } else { 303 + $crumbs 304 + ->addTextCrumb($project->getName(), $view_uri) 305 + ->addTextCrumb(pht('Edit'), $edit_uri) 306 + ->addTextCrumb(pht('Details')); 307 + } 239 308 240 309 return $this->buildApplicationPage( 241 310 array(
+24 -15
src/applications/project/controller/PhabricatorProjectEditIconController.php
··· 6 6 private $id; 7 7 8 8 public function willProcessRequest(array $data) { 9 - $this->id = $data['id']; 9 + $this->id = idx($data, 'id'); 10 10 } 11 11 12 12 public function processRequest() { 13 13 $request = $this->getRequest(); 14 14 $viewer = $request->getUser(); 15 15 16 - $project = id(new PhabricatorProjectQuery()) 17 - ->setViewer($viewer) 18 - ->withIDs(array($this->id)) 19 - ->requireCapabilities( 20 - array( 21 - PhabricatorPolicyCapability::CAN_VIEW, 22 - PhabricatorPolicyCapability::CAN_EDIT, 23 - )) 24 - ->executeOne(); 25 - if (!$project) { 26 - return new Aphront404Response(); 16 + if ($this->id) { 17 + $project = id(new PhabricatorProjectQuery()) 18 + ->setViewer($viewer) 19 + ->withIDs(array($this->id)) 20 + ->requireCapabilities( 21 + array( 22 + PhabricatorPolicyCapability::CAN_VIEW, 23 + PhabricatorPolicyCapability::CAN_EDIT, 24 + )) 25 + ->executeOne(); 26 + if (!$project) { 27 + return new Aphront404Response(); 28 + } 29 + $cancel_uri = $this->getApplicationURI('edit/'.$project->getID().'/'); 30 + $project_icon = $project->getIcon(); 31 + } else { 32 + $this->requireApplicationCapability( 33 + ProjectCreateProjectsCapability::CAPABILITY); 34 + 35 + $cancel_uri = '/project/'; 36 + $project_icon = $request->getStr('value'); 27 37 } 28 38 29 - $edit_uri = $this->getApplicationURI('edit/'.$project->getID().'/'); 30 39 require_celerity_resource('project-icon-css'); 31 40 Javelin::initBehavior('phabricator-tooltips'); 32 41 ··· 55 64 ), 56 65 pht('Choose "%s" Icon', $label)); 57 66 58 - if ($icon == $project->getIcon()) { 67 + if ($icon == $project_icon) { 59 68 $class_extra = ' selected'; 60 69 } else { 61 70 $class_extra = null; ··· 92 101 return $this->newDialog() 93 102 ->setTitle(pht('Choose Project Icon')) 94 103 ->appendChild($buttons) 95 - ->addCancelButton($edit_uri); 104 + ->addCancelButton($cancel_uri); 96 105 } 97 106 }
+2 -1
src/applications/project/storage/PhabricatorProject.php
··· 45 45 ->setEditPolicy(PhabricatorPolicies::POLICY_USER) 46 46 ->setJoinPolicy(PhabricatorPolicies::POLICY_USER) 47 47 ->setIsMembershipLocked(0) 48 - ->attachMemberPHIDs(array()); 48 + ->attachMemberPHIDs(array()) 49 + ->attachSlugs(array()); 49 50 } 50 51 51 52 public function getCapabilities() {
+4
src/view/AphrontDialogView.php
··· 146 146 $paragraph)); 147 147 } 148 148 149 + public function appendForm(AphrontFormView $form) { 150 + return $this->appendChild($form->buildLayoutView()); 151 + } 152 + 149 153 public function setDisableWorkflowOnSubmit($disable_workflow_on_submit) { 150 154 $this->disableWorkflowOnSubmit = $disable_workflow_on_submit; 151 155 return $this;