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

Add CustomField support to Owners

Summary: Fixes T9351. This is straightforward since this application is now relatively modern and doesn't have any bizarre craziness.

Test Plan:
{F787981}

{F787982}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T9351

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

+233 -40
+25
resources/sql/autopatches/20150910.owners.custom.1.sql
··· 1 + CREATE TABLE {$NAMESPACE}_owners.owners_customfieldstorage ( 2 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 + objectPHID VARBINARY(64) NOT NULL, 4 + fieldIndex BINARY(12) NOT NULL, 5 + fieldValue LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}, 6 + UNIQUE KEY (objectPHID, fieldIndex) 7 + ) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; 8 + 9 + CREATE TABLE {$NAMESPACE}_owners.owners_customfieldstringindex ( 10 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 11 + objectPHID VARBINARY(64) NOT NULL, 12 + indexKey BINARY(12) NOT NULL, 13 + indexValue LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, 14 + KEY `key_join` (objectPHID, indexKey, indexValue(64)), 15 + KEY `key_find` (indexKey, indexValue(64)) 16 + ) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; 17 + 18 + CREATE TABLE {$NAMESPACE}_owners.owners_customfieldnumericindex ( 19 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 20 + objectPHID VARBINARY(64) NOT NULL, 21 + indexKey BINARY(12) NOT NULL, 22 + indexValue BIGINT NOT NULL, 23 + KEY `key_join` (objectPHID, indexKey, indexValue), 24 + KEY `key_find` (indexKey, indexValue) 25 + ) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
+14
src/__phutil_library_map__.php
··· 2437 2437 'PhabricatorOwnerPathQuery' => 'applications/owners/query/PhabricatorOwnerPathQuery.php', 2438 2438 'PhabricatorOwnersApplication' => 'applications/owners/application/PhabricatorOwnersApplication.php', 2439 2439 'PhabricatorOwnersConfigOptions' => 'applications/owners/config/PhabricatorOwnersConfigOptions.php', 2440 + 'PhabricatorOwnersConfiguredCustomField' => 'applications/owners/customfield/PhabricatorOwnersConfiguredCustomField.php', 2440 2441 'PhabricatorOwnersController' => 'applications/owners/controller/PhabricatorOwnersController.php', 2442 + 'PhabricatorOwnersCustomField' => 'applications/owners/customfield/PhabricatorOwnersCustomField.php', 2443 + 'PhabricatorOwnersCustomFieldNumericIndex' => 'applications/owners/storage/PhabricatorOwnersCustomFieldNumericIndex.php', 2444 + 'PhabricatorOwnersCustomFieldStorage' => 'applications/owners/storage/PhabricatorOwnersCustomFieldStorage.php', 2445 + 'PhabricatorOwnersCustomFieldStringIndex' => 'applications/owners/storage/PhabricatorOwnersCustomFieldStringIndex.php', 2441 2446 'PhabricatorOwnersDAO' => 'applications/owners/storage/PhabricatorOwnersDAO.php', 2442 2447 'PhabricatorOwnersDetailController' => 'applications/owners/controller/PhabricatorOwnersDetailController.php', 2443 2448 'PhabricatorOwnersEditController' => 'applications/owners/controller/PhabricatorOwnersEditController.php', ··· 6425 6430 'PhabricatorOwnerPathQuery' => 'Phobject', 6426 6431 'PhabricatorOwnersApplication' => 'PhabricatorApplication', 6427 6432 'PhabricatorOwnersConfigOptions' => 'PhabricatorApplicationConfigOptions', 6433 + 'PhabricatorOwnersConfiguredCustomField' => array( 6434 + 'PhabricatorOwnersCustomField', 6435 + 'PhabricatorStandardCustomFieldInterface', 6436 + ), 6428 6437 'PhabricatorOwnersController' => 'PhabricatorController', 6438 + 'PhabricatorOwnersCustomField' => 'PhabricatorCustomField', 6439 + 'PhabricatorOwnersCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage', 6440 + 'PhabricatorOwnersCustomFieldStorage' => 'PhabricatorCustomFieldStorage', 6441 + 'PhabricatorOwnersCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage', 6429 6442 'PhabricatorOwnersDAO' => 'PhabricatorLiskDAO', 6430 6443 'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController', 6431 6444 'PhabricatorOwnersEditController' => 'PhabricatorOwnersController', ··· 6435 6448 'PhabricatorOwnersDAO', 6436 6449 'PhabricatorPolicyInterface', 6437 6450 'PhabricatorApplicationTransactionInterface', 6451 + 'PhabricatorCustomFieldInterface', 6438 6452 ), 6439 6453 'PhabricatorOwnersPackageDatasource' => 'PhabricatorTypeaheadDatasource', 6440 6454 'PhabricatorOwnersPackageFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
+26
src/applications/owners/config/PhabricatorOwnersConfigOptions.php
··· 20 20 } 21 21 22 22 public function getOptions() { 23 + $custom_field_type = 'custom:PhabricatorCustomFieldConfigOptionType'; 24 + $default_fields = array(); 25 + 26 + $field_base_class = id(new PhabricatorOwnersPackage()) 27 + ->getCustomFieldBaseClass(); 28 + 29 + $fields_example = array( 30 + 'mycompany:lore' => array( 31 + 'name' => pht('Package Lore'), 32 + 'type' => 'remarkup', 33 + 'caption' => pht('Tales of adventure for this package.'), 34 + ), 35 + ); 36 + $fields_example = id(new PhutilJSON())->encodeFormatted($fields_example); 37 + 23 38 return array( 24 39 $this->newOption('metamta.package.subject-prefix', 'string', '[Package]') 25 40 ->setDescription(pht('Subject prefix for Owners email.')), 41 + $this->newOption('owners.fields', $custom_field_type, $default_fields) 42 + ->setCustomData($field_base_class) 43 + ->setDescription(pht('Select and reorder package fields.')), 44 + $this->newOption('owners.custom-field-definitions', 'wild', array()) 45 + ->setSummary(pht('Custom Owners fields.')) 46 + ->setDescription( 47 + pht( 48 + 'Map of custom fields for Owners packages. For details on '. 49 + 'adding custom fields to Owners, see "Configuring Custom '. 50 + 'Fields" in the documentation.')) 51 + ->addExample($fields_example, pht('Valid Setting')), 26 52 ); 27 53 } 28 54
+19 -2
src/applications/owners/controller/PhabricatorOwnersDetailController.php
··· 37 37 $repositories = array(); 38 38 } 39 39 40 + $field_list = PhabricatorCustomField::getObjectFields( 41 + $package, 42 + PhabricatorCustomField::ROLE_VIEW); 43 + $field_list 44 + ->setViewer($viewer) 45 + ->readFieldsFromStorage($package); 46 + 40 47 $actions = $this->buildPackageActionView($package); 41 - $properties = $this->buildPackagePropertyView($package); 48 + $properties = $this->buildPackagePropertyView($package, $field_list); 42 49 $properties->setActionList($actions); 43 50 44 51 if ($package->isArchived()) { ··· 156 163 } 157 164 158 165 159 - private function buildPackagePropertyView(PhabricatorOwnersPackage $package) { 166 + private function buildPackagePropertyView( 167 + PhabricatorOwnersPackage $package, 168 + PhabricatorCustomFieldList $field_list) { 169 + 160 170 $viewer = $this->getViewer(); 161 171 162 172 $view = id(new PHUIPropertyListView()) ··· 186 196 'default', 187 197 $viewer)); 188 198 } 199 + 200 + $view->invokeWillRenderEvent(); 201 + 202 + $field_list->appendFieldsToPropertyList( 203 + $package, 204 + $viewer, 205 + $view); 189 206 190 207 return $view; 191 208 }
+42 -28
src/applications/owners/controller/PhabricatorOwnersEditController.php
··· 36 36 $v_description = $package->getDescription(); 37 37 $v_status = $package->getStatus(); 38 38 39 + $field_list = PhabricatorCustomField::getObjectFields( 40 + $package, 41 + PhabricatorCustomField::ROLE_EDIT); 42 + $field_list->setViewer($viewer); 43 + $field_list->readFieldsFromStorage($package); 39 44 40 45 $errors = array(); 41 46 if ($request->isFormPost()) { ··· 74 79 ->setTransactionType($type_status) 75 80 ->setNewValue($v_status); 76 81 } 82 + 83 + $field_xactions = $field_list->buildFieldTransactionsFromRequest( 84 + new PhabricatorOwnersPackageTransaction(), 85 + $request); 86 + 87 + $xactions = array_merge($xactions, $field_xactions); 77 88 78 89 $editor = id(new PhabricatorOwnersPackageTransactionEditor()) 79 90 ->setActor($viewer) ··· 126 137 ->setName('owners') 127 138 ->setValue($v_owners)); 128 139 129 - if (!$is_new) { 130 - $form->appendChild( 131 - id(new AphrontFormSelectControl()) 132 - ->setLabel(pht('Status')) 133 - ->setName('status') 134 - ->setValue($v_status) 135 - ->setOptions($package->getStatusNameMap())); 136 - } 137 - 140 + if (!$is_new) { 138 141 $form->appendChild( 139 142 id(new AphrontFormSelectControl()) 140 - ->setName('auditing') 141 - ->setLabel(pht('Auditing')) 142 - ->setCaption( 143 - pht( 144 - 'With auditing enabled, all future commits that touch '. 145 - 'this package will be reviewed to make sure an owner '. 146 - 'of the package is involved and the commit message has '. 147 - 'a valid revision, reviewed by, and author.')) 148 - ->setOptions( 149 - array( 150 - 'disabled' => pht('Disabled'), 151 - 'enabled' => pht('Enabled'), 152 - )) 153 - ->setValue(($v_auditing ? 'enabled' : 'disabled'))) 143 + ->setLabel(pht('Status')) 144 + ->setName('status') 145 + ->setValue($v_status) 146 + ->setOptions($package->getStatusNameMap())); 147 + } 148 + 149 + $form->appendChild( 150 + id(new AphrontFormSelectControl()) 151 + ->setName('auditing') 152 + ->setLabel(pht('Auditing')) 153 + ->setCaption( 154 + pht( 155 + 'With auditing enabled, all future commits that touch '. 156 + 'this package will be reviewed to make sure an owner '. 157 + 'of the package is involved and the commit message has '. 158 + 'a valid revision, reviewed by, and author.')) 159 + ->setOptions( 160 + array( 161 + 'disabled' => pht('Disabled'), 162 + 'enabled' => pht('Enabled'), 163 + )) 164 + ->setValue(($v_auditing ? 'enabled' : 'disabled'))) 154 165 ->appendChild( 155 166 id(new PhabricatorRemarkupControl()) 156 167 ->setUser($viewer) 157 168 ->setLabel(pht('Description')) 158 169 ->setName('description') 159 - ->setValue($v_description)) 160 - ->appendChild( 161 - id(new AphrontFormSubmitControl()) 162 - ->addCancelButton($cancel_uri) 163 - ->setValue($button_text)); 170 + ->setValue($v_description)); 171 + 172 + $field_list->appendFieldsToForm($form); 173 + 174 + $form->appendChild( 175 + id(new AphrontFormSubmitControl()) 176 + ->addCancelButton($cancel_uri) 177 + ->setValue($button_text)); 164 178 165 179 $form_box = id(new PHUIObjectBoxView()) 166 180 ->setHeaderText($title)
+23
src/applications/owners/customfield/PhabricatorOwnersConfiguredCustomField.php
··· 1 + <?php 2 + 3 + final class PhabricatorOwnersConfiguredCustomField 4 + extends PhabricatorOwnersCustomField 5 + implements PhabricatorStandardCustomFieldInterface { 6 + 7 + public function getStandardCustomFieldNamespace() { 8 + return 'owners'; 9 + } 10 + 11 + public function createFields($object) { 12 + $config = PhabricatorEnv::getEnvConfig( 13 + 'owners.custom-field-definitions', 14 + array()); 15 + 16 + $fields = PhabricatorStandardCustomField::buildStandardFields( 17 + $this, 18 + $config); 19 + 20 + return $fields; 21 + } 22 + 23 + }
+18
src/applications/owners/customfield/PhabricatorOwnersCustomField.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorOwnersCustomField 4 + extends PhabricatorCustomField { 5 + 6 + public function newStorageObject() { 7 + return new PhabricatorOwnersCustomFieldStorage(); 8 + } 9 + 10 + protected function newStringIndexStorage() { 11 + return new PhabricatorOwnersCustomFieldStringIndex(); 12 + } 13 + 14 + protected function newNumericIndexStorage() { 15 + return new PhabricatorOwnersCustomFieldNumericIndex(); 16 + } 17 + 18 + }
+10
src/applications/owners/storage/PhabricatorOwnersCustomFieldNumericIndex.php
··· 1 + <?php 2 + 3 + final class PhabricatorOwnersCustomFieldNumericIndex 4 + extends PhabricatorCustomFieldNumericIndexStorage { 5 + 6 + public function getApplicationName() { 7 + return 'owners'; 8 + } 9 + 10 + }
+10
src/applications/owners/storage/PhabricatorOwnersCustomFieldStorage.php
··· 1 + <?php 2 + 3 + final class PhabricatorOwnersCustomFieldStorage 4 + extends PhabricatorCustomFieldStorage { 5 + 6 + public function getApplicationName() { 7 + return 'owners'; 8 + } 9 + 10 + }
+10
src/applications/owners/storage/PhabricatorOwnersCustomFieldStringIndex.php
··· 1 + <?php 2 + 3 + final class PhabricatorOwnersCustomFieldStringIndex 4 + extends PhabricatorCustomFieldStringIndexStorage { 5 + 6 + public function getApplicationName() { 7 + return 'owners'; 8 + } 9 + 10 + }
+24 -1
src/applications/owners/storage/PhabricatorOwnersPackage.php
··· 4 4 extends PhabricatorOwnersDAO 5 5 implements 6 6 PhabricatorPolicyInterface, 7 - PhabricatorApplicationTransactionInterface { 7 + PhabricatorApplicationTransactionInterface, 8 + PhabricatorCustomFieldInterface { 8 9 9 10 protected $name; 10 11 protected $originalName; ··· 16 17 17 18 private $paths = self::ATTACHABLE; 18 19 private $owners = self::ATTACHABLE; 20 + private $customFields = self::ATTACHABLE; 19 21 20 22 const STATUS_ACTIVE = 'active'; 21 23 const STATUS_ARCHIVED = 'archived'; ··· 302 304 PhabricatorApplicationTransactionView $timeline, 303 305 AphrontRequest $request) { 304 306 return $timeline; 307 + } 308 + 309 + 310 + /* -( PhabricatorCustomFieldInterface )------------------------------------ */ 311 + 312 + 313 + public function getCustomFieldSpecificationForRole($role) { 314 + return PhabricatorEnv::getEnvConfig('owners.fields'); 315 + } 316 + 317 + public function getCustomFieldBaseClass() { 318 + return 'PhabricatorOwnersCustomField'; 319 + } 320 + 321 + public function getCustomFields() { 322 + return $this->assertAttached($this->customFields); 323 + } 324 + 325 + public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) { 326 + $this->customFields = $fields; 327 + return $this; 305 328 } 306 329 307 330 }
+12 -9
src/docs/user/configuration/custom_fields.diviner
··· 16 16 17 17 | Application | Support | 18 18 |-------------|---------| 19 + | Differential | Partial Support | 20 + | Diffusion | Limited Support | 19 21 | Maniphest | Full Support | 22 + | Owners | Full Support | 23 + | People | Full Support | 20 24 | Projects | Full Support | 21 - | People | Full Support | 22 - | Differential | Partial Support | 23 - | Diffusion | Limited Support | 24 25 25 26 Custom fields can appear in many interfaces and support search, editing, and 26 27 other features. ··· 38 39 39 40 | Application | Add Fields | Select Fields | 40 41 |-------------|------------|---------------| 42 + | Differential | Planned | `differential.fields` | 43 + | Diffusion | Planned | Planned | 41 44 | Maniphest | `maniphest.custom-field-definitions` | `maniphest.fields` | 45 + | Owners | `owners.custom-field-definitions` | `owners.fields` | 46 + | People | `user.custom-field-definitions` | `user.fields` | 42 47 | Projects | `projects.custom-field-definitions` | `projects.fields` | 43 - | People | `user.custom-field-definitions` | `user.fields` | 44 - | Differential | Planned | `differential.fields` | 45 - | Diffusion | Planned | Planned | 46 48 47 49 When adding fields, you'll specify a JSON blob like this (for example, as the 48 50 value of `maniphest.custom-field-definitions`): ··· 157 159 158 160 | Application | Extend | 159 161 |-------------|---------| 162 + | Differential | @{class:DifferentialCustomField} | 163 + | Diffusion | @{class:PhabricatorCommitCustomField} | 160 164 | Maniphest | @{class:ManiphestCustomField} | 165 + | Owners | @{class:PhabricatorOwnersCustomField} | 166 + | People | @{class:PhabricatorUserCustomField} | 161 167 | Projects | @{class:PhabricatorProjectCustomField} | 162 - | People | @{class:PhabricatorUserCustomField} | 163 - | Differential | @{class:DifferentialCustomField} | 164 - | Diffusion | @{class:PhabricatorCommitCustomField} | 165 168 166 169 The easiest way to get started is to drop your subclass into 167 170 `phabricator/src/extensions/`, which should make it immediately available in the