mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-22 05:20:56 +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:
parent
093a625698
commit
f8080ce931
12 changed files with 233 additions and 40 deletions
25
resources/sql/autopatches/20150910.owners.custom.1.sql
Normal file
25
resources/sql/autopatches/20150910.owners.custom.1.sql
Normal 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};
|
|
@ -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',
|
||||
|
|
|
@ -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')),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOwnersCustomFieldNumericIndex
|
||||
extends PhabricatorCustomFieldNumericIndexStorage {
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'owners';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOwnersCustomFieldStorage
|
||||
extends PhabricatorCustomFieldStorage {
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'owners';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOwnersCustomFieldStringIndex
|
||||
extends PhabricatorCustomFieldStringIndexStorage {
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'owners';
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue