@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.

Convert projects to EditEngine

Summary: Ref T10010. This is pretty straightforward with a couple of very minor new behaviors, like the icon selector edit field.

Test Plan:
- Created projects.
- Edited projects.
- Saw "Create Project" in quick create menu.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10010

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

+288 -317
+10 -2
src/__phutil_library_map__.php
··· 2381 2381 'PhabricatorIRCProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorIRCProtocolAdapter.php', 2382 2382 'PhabricatorIconRemarkupRule' => 'applications/macro/markup/PhabricatorIconRemarkupRule.php', 2383 2383 'PhabricatorIconSet' => 'applications/files/iconset/PhabricatorIconSet.php', 2384 + 'PhabricatorIconSetEditField' => 'applications/transactions/editfield/PhabricatorIconSetEditField.php', 2384 2385 'PhabricatorIconSetIcon' => 'applications/files/iconset/PhabricatorIconSetIcon.php', 2385 2386 'PhabricatorImageMacroRemarkupRule' => 'applications/macro/markup/PhabricatorImageMacroRemarkupRule.php', 2386 2387 'PhabricatorImageTransformer' => 'applications/files/PhabricatorImageTransformer.php', ··· 2845 2846 'PhabricatorProjectDAO' => 'applications/project/storage/PhabricatorProjectDAO.php', 2846 2847 'PhabricatorProjectDatasource' => 'applications/project/typeahead/PhabricatorProjectDatasource.php', 2847 2848 'PhabricatorProjectDescriptionField' => 'applications/project/customfield/PhabricatorProjectDescriptionField.php', 2848 - 'PhabricatorProjectEditDetailsController' => 'applications/project/controller/PhabricatorProjectEditDetailsController.php', 2849 + 'PhabricatorProjectEditController' => 'applications/project/controller/PhabricatorProjectEditController.php', 2850 + 'PhabricatorProjectEditEngine' => 'applications/project/engine/PhabricatorProjectEditEngine.php', 2849 2851 'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php', 2850 2852 'PhabricatorProjectFeedController' => 'applications/project/controller/PhabricatorProjectFeedController.php', 2851 2853 'PhabricatorProjectFulltextEngine' => 'applications/project/search/PhabricatorProjectFulltextEngine.php', ··· 3187 3189 'PhabricatorStorageSchemaSpec' => 'infrastructure/storage/schema/PhabricatorStorageSchemaSpec.php', 3188 3190 'PhabricatorStorageSetupCheck' => 'applications/config/check/PhabricatorStorageSetupCheck.php', 3189 3191 'PhabricatorStreamingProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorStreamingProtocolAdapter.php', 3192 + 'PhabricatorStringListEditField' => 'applications/transactions/editfield/PhabricatorStringListEditField.php', 3190 3193 'PhabricatorSubscribableInterface' => 'applications/subscriptions/interface/PhabricatorSubscribableInterface.php', 3191 3194 'PhabricatorSubscribedToObjectEdgeType' => 'applications/transactions/edges/PhabricatorSubscribedToObjectEdgeType.php', 3192 3195 'PhabricatorSubscribersEditField' => 'applications/transactions/editfield/PhabricatorSubscribersEditField.php', ··· 3746 3749 'ProjectDefaultEditCapability' => 'applications/project/capability/ProjectDefaultEditCapability.php', 3747 3750 'ProjectDefaultJoinCapability' => 'applications/project/capability/ProjectDefaultJoinCapability.php', 3748 3751 'ProjectDefaultViewCapability' => 'applications/project/capability/ProjectDefaultViewCapability.php', 3752 + 'ProjectEditConduitAPIMethod' => 'applications/project/conduit/ProjectEditConduitAPIMethod.php', 3749 3753 'ProjectQueryConduitAPIMethod' => 'applications/project/conduit/ProjectQueryConduitAPIMethod.php', 3750 3754 'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php', 3751 3755 'ProjectRemarkupRuleTestCase' => 'applications/project/remarkup/__tests__/ProjectRemarkupRuleTestCase.php', ··· 6642 6646 'PhabricatorIRCProtocolAdapter' => 'PhabricatorProtocolAdapter', 6643 6647 'PhabricatorIconRemarkupRule' => 'PhutilRemarkupRule', 6644 6648 'PhabricatorIconSet' => 'Phobject', 6649 + 'PhabricatorIconSetEditField' => 'PhabricatorEditField', 6645 6650 'PhabricatorIconSetIcon' => 'Phobject', 6646 6651 'PhabricatorImageMacroRemarkupRule' => 'PhutilRemarkupRule', 6647 6652 'PhabricatorImageTransformer' => 'Phobject', ··· 7192 7197 'PhabricatorProjectDAO' => 'PhabricatorLiskDAO', 7193 7198 'PhabricatorProjectDatasource' => 'PhabricatorTypeaheadDatasource', 7194 7199 'PhabricatorProjectDescriptionField' => 'PhabricatorProjectStandardCustomField', 7195 - 'PhabricatorProjectEditDetailsController' => 'PhabricatorProjectController', 7200 + 'PhabricatorProjectEditController' => 'PhabricatorProjectController', 7201 + 'PhabricatorProjectEditEngine' => 'PhabricatorEditEngine', 7196 7202 'PhabricatorProjectEditPictureController' => 'PhabricatorProjectController', 7197 7203 'PhabricatorProjectFeedController' => 'PhabricatorProjectController', 7198 7204 'PhabricatorProjectFulltextEngine' => 'PhabricatorFulltextEngine', ··· 7594 7600 'PhabricatorStorageSchemaSpec' => 'PhabricatorConfigSchemaSpec', 7595 7601 'PhabricatorStorageSetupCheck' => 'PhabricatorSetupCheck', 7596 7602 'PhabricatorStreamingProtocolAdapter' => 'PhabricatorProtocolAdapter', 7603 + 'PhabricatorStringListEditField' => 'PhabricatorEditField', 7597 7604 'PhabricatorSubscribedToObjectEdgeType' => 'PhabricatorEdgeType', 7598 7605 'PhabricatorSubscribersEditField' => 'PhabricatorTokenizerEditField', 7599 7606 'PhabricatorSubscribersQuery' => 'PhabricatorQuery', ··· 8300 8307 'ProjectDefaultEditCapability' => 'PhabricatorPolicyCapability', 8301 8308 'ProjectDefaultJoinCapability' => 'PhabricatorPolicyCapability', 8302 8309 'ProjectDefaultViewCapability' => 'PhabricatorPolicyCapability', 8310 + 'ProjectEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 8303 8311 'ProjectQueryConduitAPIMethod' => 'ProjectConduitAPIMethod', 8304 8312 'ProjectRemarkupRule' => 'PhabricatorObjectRemarkupRule', 8305 8313 'ProjectRemarkupRuleTestCase' => 'PhabricatorTestCase',
+5 -18
src/applications/project/application/PhabricatorProjectApplication.php
··· 43 43 '/project/' => array( 44 44 '(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorProjectListController', 45 45 'filter/(?P<filter>[^/]+)/' => 'PhabricatorProjectListController', 46 - 'details/(?P<id>[1-9]\d*)/' 47 - => 'PhabricatorProjectEditDetailsController', 48 46 'archive/(?P<id>[1-9]\d*)/' 49 47 => 'PhabricatorProjectArchiveController', 50 48 'lock/(?P<id>[1-9]\d*)/' ··· 61 59 => 'PhabricatorProjectViewController', 62 60 'picture/(?P<id>[1-9]\d*)/' 63 61 => 'PhabricatorProjectEditPictureController', 64 - 'create/' => 'PhabricatorProjectEditDetailsController', 62 + $this->getEditRoutePattern('edit/') 63 + => 'PhabricatorProjectEditController', 65 64 'subprojects/(?P<id>[1-9]\d*)/' 66 65 => 'PhabricatorProjectSubprojectsController', 67 66 'milestones/(?P<id>[1-9]\d*)/' ··· 97 96 } 98 97 99 98 public function getQuickCreateItems(PhabricatorUser $viewer) { 100 - $can_create = PhabricatorPolicyFilter::hasCapability( 101 - $viewer, 102 - $this, 103 - ProjectCreateProjectsCapability::CAPABILITY); 104 - 105 - $items = array(); 106 - if ($can_create) { 107 - $item = id(new PHUIListItemView()) 108 - ->setName(pht('Project')) 109 - ->setIcon('fa-briefcase') 110 - ->setHref($this->getBaseURI().'create/'); 111 - $items[] = $item; 112 - } 113 - 114 - return $items; 99 + return id(new PhabricatorProjectEditEngine()) 100 + ->setViewer($viewer) 101 + ->loadQuickCreateItems(); 115 102 } 116 103 117 104 protected function getCustomCapabilities() {
+19
src/applications/project/conduit/ProjectEditConduitAPIMethod.php
··· 1 + <?php 2 + 3 + final class ProjectEditConduitAPIMethod 4 + extends PhabricatorEditEngineAPIMethod { 5 + 6 + public function getAPIMethodName() { 7 + return 'project.edit'; 8 + } 9 + 10 + public function newEditEngine() { 11 + return new PhabricatorProjectEditEngine(); 12 + } 13 + 14 + public function getMethodSummary() { 15 + return pht( 16 + 'Apply transactions to create a new project or edit an existing one.'); 17 + } 18 + 19 + }
+12
src/applications/project/controller/PhabricatorProjectEditController.php
··· 1 + <?php 2 + 3 + final class PhabricatorProjectEditController 4 + extends PhabricatorProjectController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + return id(new PhabricatorProjectEditEngine()) 8 + ->setController($this) 9 + ->buildResponse(); 10 + } 11 + 12 + }
-282
src/applications/project/controller/PhabricatorProjectEditDetailsController.php
··· 1 - <?php 2 - 3 - final class PhabricatorProjectEditDetailsController 4 - extends PhabricatorProjectController { 5 - 6 - public function handleRequest(AphrontRequest $request) { 7 - $viewer = $request->getViewer(); 8 - $id = $request->getURIData('id'); 9 - 10 - if ($id) { 11 - $id = $request->getURIData('id'); 12 - $is_new = false; 13 - 14 - $project = id(new PhabricatorProjectQuery()) 15 - ->setViewer($viewer) 16 - ->withIDs(array($id)) 17 - ->needSlugs(true) 18 - ->needImages(true) 19 - ->requireCapabilities( 20 - array( 21 - PhabricatorPolicyCapability::CAN_VIEW, 22 - PhabricatorPolicyCapability::CAN_EDIT, 23 - )) 24 - ->executeOne(); 25 - if (!$project) { 26 - return new Aphront404Response(); 27 - } 28 - 29 - } else { 30 - $is_new = true; 31 - 32 - $this->requireApplicationCapability( 33 - ProjectCreateProjectsCapability::CAPABILITY); 34 - 35 - $project = PhabricatorProject::initializeNewProject($viewer); 36 - } 37 - 38 - $field_list = PhabricatorCustomField::getObjectFields( 39 - $project, 40 - PhabricatorCustomField::ROLE_EDIT); 41 - $field_list 42 - ->setViewer($viewer) 43 - ->readFieldsFromStorage($project); 44 - 45 - $e_name = true; 46 - $e_slugs = false; 47 - $e_edit = null; 48 - 49 - $v_name = $project->getName(); 50 - $project_slugs = $project->getSlugs(); 51 - $project_slugs = mpull($project_slugs, 'getSlug', 'getSlug'); 52 - $v_primary_slug = $project->getPrimarySlug(); 53 - unset($project_slugs[$v_primary_slug]); 54 - $v_slugs = $project_slugs; 55 - $v_color = $project->getColor(); 56 - $v_icon = $project->getIcon(); 57 - 58 - $validation_exception = null; 59 - 60 - if ($request->isFormPost()) { 61 - $e_name = null; 62 - $e_slugs = null; 63 - 64 - $v_name = $request->getStr('name'); 65 - $v_slugs = $request->getStrList('slugs'); 66 - $v_view = $request->getStr('can_view'); 67 - $v_edit = $request->getStr('can_edit'); 68 - $v_join = $request->getStr('can_join'); 69 - $v_color = $request->getStr('color'); 70 - $v_icon = $request->getStr('icon'); 71 - 72 - $type_name = PhabricatorProjectTransaction::TYPE_NAME; 73 - $type_slugs = PhabricatorProjectTransaction::TYPE_SLUGS; 74 - $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; 75 - $type_icon = PhabricatorProjectTransaction::TYPE_ICON; 76 - $type_color = PhabricatorProjectTransaction::TYPE_COLOR; 77 - 78 - $xactions = array(); 79 - 80 - $xactions[] = id(new PhabricatorProjectTransaction()) 81 - ->setTransactionType($type_name) 82 - ->setNewValue($v_name); 83 - 84 - $xactions[] = id(new PhabricatorProjectTransaction()) 85 - ->setTransactionType($type_slugs) 86 - ->setNewValue($v_slugs); 87 - 88 - $xactions[] = id(new PhabricatorProjectTransaction()) 89 - ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) 90 - ->setNewValue($v_view); 91 - 92 - $xactions[] = id(new PhabricatorProjectTransaction()) 93 - ->setTransactionType($type_edit) 94 - ->setNewValue($v_edit); 95 - 96 - $xactions[] = id(new PhabricatorProjectTransaction()) 97 - ->setTransactionType(PhabricatorTransactions::TYPE_JOIN_POLICY) 98 - ->setNewValue($v_join); 99 - 100 - $xactions[] = id(new PhabricatorProjectTransaction()) 101 - ->setTransactionType($type_icon) 102 - ->setNewValue($v_icon); 103 - 104 - $xactions[] = id(new PhabricatorProjectTransaction()) 105 - ->setTransactionType($type_color) 106 - ->setNewValue($v_color); 107 - 108 - $xactions = array_merge( 109 - $xactions, 110 - $field_list->buildFieldTransactionsFromRequest( 111 - new PhabricatorProjectTransaction(), 112 - $request)); 113 - 114 - $editor = id(new PhabricatorProjectTransactionEditor()) 115 - ->setActor($viewer) 116 - ->setContentSourceFromRequest($request) 117 - ->setContinueOnNoEffect(true); 118 - 119 - if ($is_new) { 120 - $xactions[] = id(new PhabricatorProjectTransaction()) 121 - ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 122 - ->setMetadataValue( 123 - 'edge:type', 124 - PhabricatorProjectProjectHasMemberEdgeType::EDGECONST) 125 - ->setNewValue( 126 - array( 127 - '+' => array($viewer->getPHID() => $viewer->getPHID()), 128 - )); 129 - } 130 - 131 - try { 132 - 133 - $editor->applyTransactions($project, $xactions); 134 - 135 - if ($request->isAjax()) { 136 - return id(new AphrontAjaxResponse()) 137 - ->setContent(array( 138 - 'phid' => $project->getPHID(), 139 - 'name' => $project->getName(), 140 - )); 141 - } 142 - 143 - $redirect_uri = 144 - $this->getApplicationURI('profile/'.$project->getID().'/'); 145 - 146 - return id(new AphrontRedirectResponse())->setURI($redirect_uri); 147 - } catch (PhabricatorApplicationTransactionValidationException $ex) { 148 - $validation_exception = $ex; 149 - 150 - $e_name = $ex->getShortMessage($type_name); 151 - $e_slugs = $ex->getShortMessage($type_slugs); 152 - $e_edit = $ex->getShortMessage($type_edit); 153 - 154 - $project->setViewPolicy($v_view); 155 - $project->setEditPolicy($v_edit); 156 - $project->setJoinPolicy($v_join); 157 - } 158 - } 159 - 160 - if ($is_new) { 161 - $header_name = pht('Create a New Project'); 162 - $title = pht('Create Project'); 163 - } else { 164 - $header_name = pht('Edit Project'); 165 - $title = pht('Edit Project'); 166 - } 167 - 168 - $policies = id(new PhabricatorPolicyQuery()) 169 - ->setViewer($viewer) 170 - ->setObject($project) 171 - ->execute(); 172 - $v_slugs = implode(', ', $v_slugs); 173 - 174 - $form = id(new AphrontFormView()) 175 - ->setUser($viewer) 176 - ->appendChild( 177 - id(new AphrontFormTextControl()) 178 - ->setLabel(pht('Name')) 179 - ->setName('name') 180 - ->setValue($v_name) 181 - ->setError($e_name)); 182 - $field_list->appendFieldsToForm($form); 183 - 184 - $shades = PhabricatorProjectIconSet::getColorMap(); 185 - 186 - $form 187 - ->appendChild( 188 - id(new PHUIFormIconSetControl()) 189 - ->setLabel(pht('Icon')) 190 - ->setName('icon') 191 - ->setIconSet(new PhabricatorProjectIconSet()) 192 - ->setValue($v_icon)) 193 - ->appendChild( 194 - id(new AphrontFormSelectControl()) 195 - ->setLabel(pht('Color')) 196 - ->setName('color') 197 - ->setValue($v_color) 198 - ->setOptions($shades)); 199 - 200 - if (!$is_new) { 201 - $form->appendChild( 202 - id(new AphrontFormStaticControl()) 203 - ->setLabel(pht('Primary Hashtag')) 204 - ->setCaption(pht('The primary hashtag is derived from the name.')) 205 - ->setValue($v_primary_slug)); 206 - } 207 - 208 - $form 209 - ->appendChild( 210 - id(new AphrontFormTextControl()) 211 - ->setLabel(pht('Additional Hashtags')) 212 - ->setCaption(pht( 213 - 'Specify a comma-separated list of additional hashtags.')) 214 - ->setName('slugs') 215 - ->setValue($v_slugs) 216 - ->setError($e_slugs)) 217 - ->appendChild( 218 - id(new AphrontFormPolicyControl()) 219 - ->setUser($viewer) 220 - ->setName('can_view') 221 - ->setPolicyObject($project) 222 - ->setPolicies($policies) 223 - ->setCapability(PhabricatorPolicyCapability::CAN_VIEW)) 224 - ->appendChild( 225 - id(new AphrontFormPolicyControl()) 226 - ->setUser($viewer) 227 - ->setName('can_edit') 228 - ->setPolicyObject($project) 229 - ->setPolicies($policies) 230 - ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) 231 - ->setError($e_edit)) 232 - ->appendChild( 233 - id(new AphrontFormPolicyControl()) 234 - ->setUser($viewer) 235 - ->setName('can_join') 236 - ->setCaption( 237 - pht('Users who can edit a project can always join a project.')) 238 - ->setPolicyObject($project) 239 - ->setPolicies($policies) 240 - ->setCapability(PhabricatorPolicyCapability::CAN_JOIN)); 241 - 242 - if ($request->isAjax()) { 243 - $errors = array(); 244 - if ($validation_exception) { 245 - $errors = mpull($ex->getErrors(), 'getMessage'); 246 - } 247 - $dialog = id(new AphrontDialogView()) 248 - ->setUser($viewer) 249 - ->setWidth(AphrontDialogView::WIDTH_FULL) 250 - ->setTitle($header_name) 251 - ->setErrors($errors) 252 - ->appendForm($form) 253 - ->addSubmitButton($title) 254 - ->addCancelButton('/project/'); 255 - return id(new AphrontDialogResponse())->setDialog($dialog); 256 - } 257 - 258 - $form->appendChild( 259 - id(new AphrontFormSubmitControl()) 260 - ->addCancelButton($this->getApplicationURI()) 261 - ->setValue(pht('Save'))); 262 - 263 - $form_box = id(new PHUIObjectBoxView()) 264 - ->setHeaderText($title) 265 - ->setValidationException($validation_exception) 266 - ->setForm($form); 267 - 268 - if (!$is_new) { 269 - $nav = $this->buildIconNavView($project); 270 - $nav->selectFilter("details/{$id}/"); 271 - $nav->appendChild($form_box); 272 - } else { 273 - $nav = array($form_box); 274 - } 275 - 276 - return $this->buildApplicationPage( 277 - $nav, 278 - array( 279 - 'title' => $title, 280 - )); 281 - } 282 - }
+3 -10
src/applications/project/controller/PhabricatorProjectListController.php
··· 26 26 protected function buildApplicationCrumbs() { 27 27 $crumbs = parent::buildApplicationCrumbs(); 28 28 29 - $can_create = $this->hasApplicationCapability( 30 - ProjectCreateProjectsCapability::CAPABILITY); 31 - 32 - $crumbs->addAction( 33 - id(new PHUIListItemView()) 34 - ->setName(pht('Create Project')) 35 - ->setHref($this->getApplicationURI('create/')) 36 - ->setIcon('fa-plus-square') 37 - ->setWorkflow(!$can_create) 38 - ->setDisabled(!$can_create)); 29 + id(new PhabricatorProjectEditEngine()) 30 + ->setViewer($this->getViewer()) 31 + ->addActionToCrumbs($crumbs); 39 32 40 33 return $crumbs; 41 34 }
+1 -1
src/applications/project/controller/PhabricatorProjectProfileController.php
··· 76 76 id(new PhabricatorActionView()) 77 77 ->setName(pht('Edit Details')) 78 78 ->setIcon('fa-pencil') 79 - ->setHref($this->getApplicationURI("details/{$id}/")) 79 + ->setHref($this->getApplicationURI("edit/{$id}/")) 80 80 ->setDisabled(!$can_edit) 81 81 ->setWorkflow(!$can_edit)); 82 82
+2 -1
src/applications/project/customfield/PhabricatorProjectDescriptionField.php
··· 13 13 'description' => pht('Short project description.'), 14 14 'fulltext' => PhabricatorSearchDocumentFieldType::FIELD_BODY, 15 15 ), 16 - )); 16 + ), 17 + $internal = true); 17 18 } 18 19 19 20 }
+34
src/applications/project/editor/PhabricatorProjectTransactionEditor.php
··· 745 745 return $copy; 746 746 } 747 747 748 + protected function expandTransactions( 749 + PhabricatorLiskDAO $object, 750 + array $xactions) { 751 + 752 + $actor = $this->getActor(); 753 + $actor_phid = $actor->getPHID(); 754 + 755 + $results = parent::expandTransactions($object, $xactions); 756 + 757 + // Automatically add the author as a member when they create a project 758 + // if they're using the web interface. 759 + 760 + $content_source = $this->getContentSource(); 761 + $source_web = PhabricatorContentSource::SOURCE_WEB; 762 + $is_web = ($content_source->getSource() === $source_web); 763 + 764 + if ($this->getIsNewObject() && $is_web) { 765 + if ($actor_phid) { 766 + $type_member = PhabricatorProjectProjectHasMemberEdgeType::EDGECONST; 767 + 768 + $results[] = id(new PhabricatorProjectTransaction()) 769 + ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 770 + ->setMetadataValue('edge:type', $type_member) 771 + ->setNewValue( 772 + array( 773 + '+' => array($actor_phid => $actor_phid), 774 + )); 775 + } 776 + } 777 + 778 + return $results; 779 + } 780 + 781 + 748 782 }
+126
src/applications/project/engine/PhabricatorProjectEditEngine.php
··· 1 + <?php 2 + 3 + final class PhabricatorProjectEditEngine 4 + extends PhabricatorEditEngine { 5 + 6 + const ENGINECONST = 'projects.project'; 7 + 8 + public function getEngineName() { 9 + return pht('Projects'); 10 + } 11 + 12 + public function getSummaryHeader() { 13 + return pht('Configure Project Forms'); 14 + } 15 + 16 + public function getSummaryText() { 17 + return pht('Configure forms for creating projects.'); 18 + } 19 + 20 + public function getEngineApplicationClass() { 21 + return 'PhabricatorProjectApplication'; 22 + } 23 + 24 + protected function newEditableObject() { 25 + return PhabricatorProject::initializeNewProject($this->getViewer()); 26 + } 27 + 28 + protected function newObjectQuery() { 29 + return id(new PhabricatorProjectQuery()) 30 + ->needSlugs(true); 31 + } 32 + 33 + protected function getObjectCreateTitleText($object) { 34 + return pht('Create New Project'); 35 + } 36 + 37 + protected function getObjectEditTitleText($object) { 38 + return pht('Edit %s', $object->getName()); 39 + } 40 + 41 + protected function getObjectEditShortText($object) { 42 + return $object->getName(); 43 + } 44 + 45 + protected function getObjectCreateShortText() { 46 + return pht('Create Project'); 47 + } 48 + 49 + protected function getObjectViewURI($object) { 50 + return $object->getURI(); 51 + } 52 + 53 + protected function getCreateNewObjectPolicy() { 54 + return $this->getApplication()->getPolicy( 55 + ProjectCreateProjectsCapability::CAPABILITY); 56 + } 57 + 58 + protected function newBuiltinEngineConfigurations() { 59 + $configuration = head(parent::newBuiltinEngineConfigurations()); 60 + 61 + // TODO: This whole method is clumsy, and the ordering for the custom 62 + // field is especially clumsy. Maybe try to make this more natural to 63 + // express. 64 + 65 + $configuration 66 + ->setFieldOrder( 67 + array( 68 + 'name', 69 + 'std:project:internal:description', 70 + 'icon', 71 + 'color', 72 + 'slugs', 73 + 'subscriberPHIDs', 74 + )); 75 + 76 + return array( 77 + $configuration, 78 + ); 79 + } 80 + 81 + protected function buildCustomEditFields($object) { 82 + $slugs = mpull($object->getSlugs(), 'getSlug'); 83 + $slugs = array_fuse($slugs); 84 + unset($slugs[$object->getPrimarySlug()]); 85 + $slugs = array_values($slugs); 86 + 87 + return array( 88 + id(new PhabricatorTextEditField()) 89 + ->setKey('name') 90 + ->setLabel(pht('Name')) 91 + ->setTransactionType(PhabricatorProjectTransaction::TYPE_NAME) 92 + ->setIsRequired(true) 93 + ->setDescription(pht('Project name.')) 94 + ->setConduitDescription(pht('Rename the project')) 95 + ->setConduitTypeDescription(pht('New project name.')) 96 + ->setValue($object->getName()), 97 + id(new PhabricatorIconSetEditField()) 98 + ->setKey('icon') 99 + ->setLabel(pht('Icon')) 100 + ->setTransactionType(PhabricatorProjectTransaction::TYPE_ICON) 101 + ->setIconSet(new PhabricatorProjectIconSet()) 102 + ->setDescription(pht('Project icon.')) 103 + ->setConduitDescription(pht('Change the project icon.')) 104 + ->setConduitTypeDescription(pht('New project icon.')) 105 + ->setValue($object->getIcon()), 106 + id(new PhabricatorSelectEditField()) 107 + ->setKey('color') 108 + ->setLabel(pht('Color')) 109 + ->setTransactionType(PhabricatorProjectTransaction::TYPE_COLOR) 110 + ->setOptions(PhabricatorProjectIconSet::getColorMap()) 111 + ->setDescription(pht('Project tag color.')) 112 + ->setConduitDescription(pht('Change the project tag color.')) 113 + ->setConduitTypeDescription(pht('New project tag color.')) 114 + ->setValue($object->getColor()), 115 + id(new PhabricatorStringListEditField()) 116 + ->setKey('slugs') 117 + ->setLabel(pht('Additional Hashtags')) 118 + ->setTransactionType(PhabricatorProjectTransaction::TYPE_SLUGS) 119 + ->setDescription(pht('Additional project slugs.')) 120 + ->setConduitDescription(pht('Change project slugs.')) 121 + ->setConduitTypeDescription(pht('New list of slugs.')) 122 + ->setValue($slugs), 123 + ); 124 + } 125 + 126 + }
+7 -1
src/applications/project/storage/PhabricatorProjectTransaction.php
··· 99 99 public function getTitle() { 100 100 $old = $this->getOldValue(); 101 101 $new = $this->getNewValue(); 102 - $author_handle = $this->renderHandleLink($this->getAuthorPHID()); 102 + $author_phid = $this->getAuthorPHID(); 103 + $author_handle = $this->renderHandleLink($author_phid); 103 104 104 105 switch ($this->getTransactionType()) { 106 + case PhabricatorTransactions::TYPE_CREATE: 107 + return pht( 108 + '%s created this project.', 109 + $this->renderHandleLink($author_phid)); 110 + 105 111 case self::TYPE_NAME: 106 112 if ($old === null) { 107 113 return pht(
+30
src/applications/transactions/editfield/PhabricatorIconSetEditField.php
··· 1 + <?php 2 + 3 + final class PhabricatorIconSetEditField 4 + extends PhabricatorEditField { 5 + 6 + private $iconSet; 7 + 8 + public function setIconSet(PhabricatorIconSet $icon_set) { 9 + $this->iconSet = $icon_set; 10 + return $this; 11 + } 12 + 13 + public function getIconSet() { 14 + return $this->iconSet; 15 + } 16 + 17 + protected function newControl() { 18 + return id(new PHUIFormIconSetControl()) 19 + ->setIconSet($this->getIconSet()); 20 + } 21 + 22 + protected function newConduitParameterType() { 23 + return new ConduitStringParameterType(); 24 + } 25 + 26 + protected function newHTTPParameterType() { 27 + return new AphrontStringHTTPParameterType(); 28 + } 29 + 30 + }
+18
src/applications/transactions/editfield/PhabricatorStringListEditField.php
··· 1 + <?php 2 + 3 + final class PhabricatorStringListEditField 4 + extends PhabricatorEditField { 5 + 6 + protected function newControl() { 7 + return new AphrontFormTextControl(); 8 + } 9 + 10 + protected function newConduitParameterType() { 11 + return new ConduitStringListParameterType(); 12 + } 13 + 14 + protected function newHTTPParameterType() { 15 + return new AphrontStringListHTTPParameterType(); 16 + } 17 + 18 + }
+21 -2
src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php
··· 17 17 private $default; 18 18 private $isCopyable; 19 19 private $hasStorageValue; 20 + private $isBuiltin; 20 21 21 22 abstract public function getFieldType(); 22 23 23 24 public static function buildStandardFields( 24 25 PhabricatorCustomField $template, 25 - array $config) { 26 + array $config, 27 + $builtin = false) { 26 28 27 29 $types = id(new PhutilClassMapQuery()) 28 30 ->setAncestorClass(__CLASS__) ··· 47 49 ->setFieldKey($full_key) 48 50 ->setFieldConfig($value) 49 51 ->setApplicationField($template); 52 + 53 + if ($builtin) { 54 + $standard->setIsBuiltin(true); 55 + } 50 56 51 57 $field = $template->setProxy($standard); 52 58 $fields[] = $field; ··· 91 97 public function setFieldDescription($description) { 92 98 $this->fieldDescription = $description; 93 99 return $this; 100 + } 101 + 102 + public function setIsBuiltin($is_builtin) { 103 + $this->isBuiltin = $is_builtin; 104 + return $this; 105 + } 106 + 107 + public function getIsBuiltin() { 108 + return $this->isBuiltin; 94 109 } 95 110 96 111 public function setFieldConfig(array $config) { ··· 470 485 } 471 486 472 487 public function getModernFieldKey() { 473 - return 'custom.'.$this->getRawStandardFieldKey(); 488 + if ($this->getIsBuiltin()) { 489 + return $this->getRawStandardFieldKey(); 490 + } else { 491 + return 'custom.'.$this->getRawStandardFieldKey(); 492 + } 474 493 } 475 494 476 495 public function getConduitDictionaryValue() {