1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-18 12:52:42 +01:00

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
This commit is contained in:
epriestley 2015-09-10 13:32:31 -07:00
parent 093a625698
commit f8080ce931
12 changed files with 233 additions and 40 deletions

View file

@ -0,0 +1,25 @@
CREATE TABLE {$NAMESPACE}_owners.owners_customfieldstorage (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
objectPHID VARBINARY(64) NOT NULL,
fieldIndex BINARY(12) NOT NULL,
fieldValue LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
UNIQUE KEY (objectPHID, fieldIndex)
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
CREATE TABLE {$NAMESPACE}_owners.owners_customfieldstringindex (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
objectPHID VARBINARY(64) NOT NULL,
indexKey BINARY(12) NOT NULL,
indexValue LONGTEXT NOT NULL COLLATE {$COLLATE_SORT},
KEY `key_join` (objectPHID, indexKey, indexValue(64)),
KEY `key_find` (indexKey, indexValue(64))
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
CREATE TABLE {$NAMESPACE}_owners.owners_customfieldnumericindex (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
objectPHID VARBINARY(64) NOT NULL,
indexKey BINARY(12) NOT NULL,
indexValue BIGINT NOT NULL,
KEY `key_join` (objectPHID, indexKey, indexValue),
KEY `key_find` (indexKey, indexValue)
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -2437,7 +2437,12 @@ phutil_register_library_map(array(
'PhabricatorOwnerPathQuery' => 'applications/owners/query/PhabricatorOwnerPathQuery.php',
'PhabricatorOwnersApplication' => 'applications/owners/application/PhabricatorOwnersApplication.php',
'PhabricatorOwnersConfigOptions' => 'applications/owners/config/PhabricatorOwnersConfigOptions.php',
'PhabricatorOwnersConfiguredCustomField' => 'applications/owners/customfield/PhabricatorOwnersConfiguredCustomField.php',
'PhabricatorOwnersController' => 'applications/owners/controller/PhabricatorOwnersController.php',
'PhabricatorOwnersCustomField' => 'applications/owners/customfield/PhabricatorOwnersCustomField.php',
'PhabricatorOwnersCustomFieldNumericIndex' => 'applications/owners/storage/PhabricatorOwnersCustomFieldNumericIndex.php',
'PhabricatorOwnersCustomFieldStorage' => 'applications/owners/storage/PhabricatorOwnersCustomFieldStorage.php',
'PhabricatorOwnersCustomFieldStringIndex' => 'applications/owners/storage/PhabricatorOwnersCustomFieldStringIndex.php',
'PhabricatorOwnersDAO' => 'applications/owners/storage/PhabricatorOwnersDAO.php',
'PhabricatorOwnersDetailController' => 'applications/owners/controller/PhabricatorOwnersDetailController.php',
'PhabricatorOwnersEditController' => 'applications/owners/controller/PhabricatorOwnersEditController.php',
@ -6425,7 +6430,15 @@ phutil_register_library_map(array(
'PhabricatorOwnerPathQuery' => 'Phobject',
'PhabricatorOwnersApplication' => 'PhabricatorApplication',
'PhabricatorOwnersConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorOwnersConfiguredCustomField' => array(
'PhabricatorOwnersCustomField',
'PhabricatorStandardCustomFieldInterface',
),
'PhabricatorOwnersController' => 'PhabricatorController',
'PhabricatorOwnersCustomField' => 'PhabricatorCustomField',
'PhabricatorOwnersCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage',
'PhabricatorOwnersCustomFieldStorage' => 'PhabricatorCustomFieldStorage',
'PhabricatorOwnersCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage',
'PhabricatorOwnersDAO' => 'PhabricatorLiskDAO',
'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController',
'PhabricatorOwnersEditController' => 'PhabricatorOwnersController',
@ -6435,6 +6448,7 @@ phutil_register_library_map(array(
'PhabricatorOwnersDAO',
'PhabricatorPolicyInterface',
'PhabricatorApplicationTransactionInterface',
'PhabricatorCustomFieldInterface',
),
'PhabricatorOwnersPackageDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorOwnersPackageFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',

View file

@ -20,9 +20,35 @@ final class PhabricatorOwnersConfigOptions
}
public function getOptions() {
$custom_field_type = 'custom:PhabricatorCustomFieldConfigOptionType';
$default_fields = array();
$field_base_class = id(new PhabricatorOwnersPackage())
->getCustomFieldBaseClass();
$fields_example = array(
'mycompany:lore' => array(
'name' => pht('Package Lore'),
'type' => 'remarkup',
'caption' => pht('Tales of adventure for this package.'),
),
);
$fields_example = id(new PhutilJSON())->encodeFormatted($fields_example);
return array(
$this->newOption('metamta.package.subject-prefix', 'string', '[Package]')
->setDescription(pht('Subject prefix for Owners email.')),
$this->newOption('owners.fields', $custom_field_type, $default_fields)
->setCustomData($field_base_class)
->setDescription(pht('Select and reorder package fields.')),
$this->newOption('owners.custom-field-definitions', 'wild', array())
->setSummary(pht('Custom Owners fields.'))
->setDescription(
pht(
'Map of custom fields for Owners packages. For details on '.
'adding custom fields to Owners, see "Configuring Custom '.
'Fields" in the documentation.'))
->addExample($fields_example, pht('Valid Setting')),
);
}

View file

@ -37,8 +37,15 @@ final class PhabricatorOwnersDetailController
$repositories = array();
}
$field_list = PhabricatorCustomField::getObjectFields(
$package,
PhabricatorCustomField::ROLE_VIEW);
$field_list
->setViewer($viewer)
->readFieldsFromStorage($package);
$actions = $this->buildPackageActionView($package);
$properties = $this->buildPackagePropertyView($package);
$properties = $this->buildPackagePropertyView($package, $field_list);
$properties->setActionList($actions);
if ($package->isArchived()) {
@ -156,7 +163,10 @@ final class PhabricatorOwnersDetailController
}
private function buildPackagePropertyView(PhabricatorOwnersPackage $package) {
private function buildPackagePropertyView(
PhabricatorOwnersPackage $package,
PhabricatorCustomFieldList $field_list) {
$viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
@ -187,6 +197,13 @@ final class PhabricatorOwnersDetailController
$viewer));
}
$view->invokeWillRenderEvent();
$field_list->appendFieldsToPropertyList(
$package,
$viewer,
$view);
return $view;
}

View file

@ -36,6 +36,11 @@ final class PhabricatorOwnersEditController
$v_description = $package->getDescription();
$v_status = $package->getStatus();
$field_list = PhabricatorCustomField::getObjectFields(
$package,
PhabricatorCustomField::ROLE_EDIT);
$field_list->setViewer($viewer);
$field_list->readFieldsFromStorage($package);
$errors = array();
if ($request->isFormPost()) {
@ -75,6 +80,12 @@ final class PhabricatorOwnersEditController
->setNewValue($v_status);
}
$field_xactions = $field_list->buildFieldTransactionsFromRequest(
new PhabricatorOwnersPackageTransaction(),
$request);
$xactions = array_merge($xactions, $field_xactions);
$editor = id(new PhabricatorOwnersPackageTransactionEditor())
->setActor($viewer)
->setContentSourceFromRequest($request)
@ -126,41 +137,44 @@ final class PhabricatorOwnersEditController
->setName('owners')
->setValue($v_owners));
if (!$is_new) {
$form->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Status'))
->setName('status')
->setValue($v_status)
->setOptions($package->getStatusNameMap()));
}
if (!$is_new) {
$form->appendChild(
id(new AphrontFormSelectControl())
->setName('auditing')
->setLabel(pht('Auditing'))
->setCaption(
pht(
'With auditing enabled, all future commits that touch '.
'this package will be reviewed to make sure an owner '.
'of the package is involved and the commit message has '.
'a valid revision, reviewed by, and author.'))
->setOptions(
array(
'disabled' => pht('Disabled'),
'enabled' => pht('Enabled'),
))
->setValue(($v_auditing ? 'enabled' : 'disabled')))
->setLabel(pht('Status'))
->setName('status')
->setValue($v_status)
->setOptions($package->getStatusNameMap()));
}
$form->appendChild(
id(new AphrontFormSelectControl())
->setName('auditing')
->setLabel(pht('Auditing'))
->setCaption(
pht(
'With auditing enabled, all future commits that touch '.
'this package will be reviewed to make sure an owner '.
'of the package is involved and the commit message has '.
'a valid revision, reviewed by, and author.'))
->setOptions(
array(
'disabled' => pht('Disabled'),
'enabled' => pht('Enabled'),
))
->setValue(($v_auditing ? 'enabled' : 'disabled')))
->appendChild(
id(new PhabricatorRemarkupControl())
->setUser($viewer)
->setLabel(pht('Description'))
->setName('description')
->setValue($v_description))
->appendChild(
id(new AphrontFormSubmitControl())
->addCancelButton($cancel_uri)
->setValue($button_text));
->setValue($v_description));
$field_list->appendFieldsToForm($form);
$form->appendChild(
id(new AphrontFormSubmitControl())
->addCancelButton($cancel_uri)
->setValue($button_text));
$form_box = id(new PHUIObjectBoxView())
->setHeaderText($title)

View file

@ -0,0 +1,23 @@
<?php
final class PhabricatorOwnersConfiguredCustomField
extends PhabricatorOwnersCustomField
implements PhabricatorStandardCustomFieldInterface {
public function getStandardCustomFieldNamespace() {
return 'owners';
}
public function createFields($object) {
$config = PhabricatorEnv::getEnvConfig(
'owners.custom-field-definitions',
array());
$fields = PhabricatorStandardCustomField::buildStandardFields(
$this,
$config);
return $fields;
}
}

View file

@ -0,0 +1,18 @@
<?php
abstract class PhabricatorOwnersCustomField
extends PhabricatorCustomField {
public function newStorageObject() {
return new PhabricatorOwnersCustomFieldStorage();
}
protected function newStringIndexStorage() {
return new PhabricatorOwnersCustomFieldStringIndex();
}
protected function newNumericIndexStorage() {
return new PhabricatorOwnersCustomFieldNumericIndex();
}
}

View file

@ -0,0 +1,10 @@
<?php
final class PhabricatorOwnersCustomFieldNumericIndex
extends PhabricatorCustomFieldNumericIndexStorage {
public function getApplicationName() {
return 'owners';
}
}

View file

@ -0,0 +1,10 @@
<?php
final class PhabricatorOwnersCustomFieldStorage
extends PhabricatorCustomFieldStorage {
public function getApplicationName() {
return 'owners';
}
}

View file

@ -0,0 +1,10 @@
<?php
final class PhabricatorOwnersCustomFieldStringIndex
extends PhabricatorCustomFieldStringIndexStorage {
public function getApplicationName() {
return 'owners';
}
}

View file

@ -4,7 +4,8 @@ final class PhabricatorOwnersPackage
extends PhabricatorOwnersDAO
implements
PhabricatorPolicyInterface,
PhabricatorApplicationTransactionInterface {
PhabricatorApplicationTransactionInterface,
PhabricatorCustomFieldInterface {
protected $name;
protected $originalName;
@ -16,6 +17,7 @@ final class PhabricatorOwnersPackage
private $paths = self::ATTACHABLE;
private $owners = self::ATTACHABLE;
private $customFields = self::ATTACHABLE;
const STATUS_ACTIVE = 'active';
const STATUS_ARCHIVED = 'archived';
@ -304,4 +306,25 @@ final class PhabricatorOwnersPackage
return $timeline;
}
/* -( PhabricatorCustomFieldInterface )------------------------------------ */
public function getCustomFieldSpecificationForRole($role) {
return PhabricatorEnv::getEnvConfig('owners.fields');
}
public function getCustomFieldBaseClass() {
return 'PhabricatorOwnersCustomField';
}
public function getCustomFields() {
return $this->assertAttached($this->customFields);
}
public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) {
$this->customFields = $fields;
return $this;
}
}

View file

@ -16,11 +16,12 @@ These applications currently support custom fields:
| Application | Support |
|-------------|---------|
| Maniphest | Full Support |
| Projects | Full Support |
| People | Full Support |
| Differential | Partial Support |
| Diffusion | Limited Support |
| Maniphest | Full Support |
| Owners | Full Support |
| People | Full Support |
| Projects | Full Support |
Custom fields can appear in many interfaces and support search, editing, and
other features.
@ -38,11 +39,12 @@ The relevant configuration settings are:
| Application | Add Fields | Select Fields |
|-------------|------------|---------------|
| Maniphest | `maniphest.custom-field-definitions` | `maniphest.fields` |
| Projects | `projects.custom-field-definitions` | `projects.fields` |
| People | `user.custom-field-definitions` | `user.fields` |
| Differential | Planned | `differential.fields` |
| Diffusion | Planned | Planned |
| Maniphest | `maniphest.custom-field-definitions` | `maniphest.fields` |
| Owners | `owners.custom-field-definitions` | `owners.fields` |
| People | `user.custom-field-definitions` | `user.fields` |
| Projects | `projects.custom-field-definitions` | `projects.fields` |
When adding fields, you'll specify a JSON blob like this (for example, as the
value of `maniphest.custom-field-definitions`):
@ -157,11 +159,12 @@ want to add a field to:
| Application | Extend |
|-------------|---------|
| Maniphest | @{class:ManiphestCustomField} |
| Projects | @{class:PhabricatorProjectCustomField} |
| People | @{class:PhabricatorUserCustomField} |
| Differential | @{class:DifferentialCustomField} |
| Diffusion | @{class:PhabricatorCommitCustomField} |
| Maniphest | @{class:ManiphestCustomField} |
| Owners | @{class:PhabricatorOwnersCustomField} |
| People | @{class:PhabricatorUserCustomField} |
| Projects | @{class:PhabricatorProjectCustomField} |
The easiest way to get started is to drop your subclass into
`phabricator/src/extensions/`, which should make it immediately available in the