1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-19 13:22:42 +01:00

Implement "Repository" as a new-style CustomField in Differential

Summary:
Ref T3886. Ref T418.

  - Adds new capabilities for CustomField:
    - Controls can now bulk-load PHIDs (e.g., for tokenizers).
    - Transactions can now bulk-load PHIDs (e.g., for relationship changes).
  - Implements "Repository" control.
  - Improves tokenizer StandardCustomField controls.

Test Plan:
{F115942}

{F115943}

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T418, T3886

Differential Revision: https://secure.phabricator.com/D8286
This commit is contained in:
epriestley 2014-02-21 11:53:37 -08:00
parent 05f2ab32d8
commit 01572d9d93
25 changed files with 303 additions and 68 deletions

View file

@ -431,6 +431,7 @@ phutil_register_library_map(array(
'DifferentialReleephRequestFieldSpecification' => 'applications/releeph/differential/DifferentialReleephRequestFieldSpecification.php',
'DifferentialRemarkupRule' => 'applications/differential/remarkup/DifferentialRemarkupRule.php',
'DifferentialReplyHandler' => 'applications/differential/mail/DifferentialReplyHandler.php',
'DifferentialRepositoryField' => 'applications/differential/customfield/DifferentialRepositoryField.php',
'DifferentialRepositoryFieldSpecification' => 'applications/differential/field/specification/DifferentialRepositoryFieldSpecification.php',
'DifferentialRepositoryLookup' => 'applications/differential/query/DifferentialRepositoryLookup.php',
'DifferentialResultsTableView' => 'applications/differential/view/DifferentialResultsTableView.php',
@ -2967,6 +2968,7 @@ phutil_register_library_map(array(
'DifferentialReleephRequestFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialRemarkupRule' => 'PhabricatorRemarkupRuleObject',
'DifferentialReplyHandler' => 'PhabricatorMailReplyHandler',
'DifferentialRepositoryField' => 'DifferentialCoreCustomField',
'DifferentialRepositoryFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialRepositoryLookup' => 'Phobject',
'DifferentialResultsTableView' => 'AphrontView',

View file

@ -0,0 +1,128 @@
<?php
final class DifferentialRepositoryField
extends DifferentialCoreCustomField {
public function getFieldKey() {
return 'differential:repository';
}
public function getFieldName() {
return pht('Repository');
}
public function getFieldDescription() {
return pht('Associates a revision with a repository.');
}
protected function readValueFromRevision(
DifferentialRevision $revision) {
return $revision->getRepositoryPHID();
}
protected function writeValueToRevision(
DifferentialRevision $revision,
$value) {
$revision->setRepositoryPHID($value);
}
public function readValueFromRequest(AphrontRequest $request) {
$phids = $request->getArr($this->getFieldKey());
$first = head($phids);
$this->setValue(coalesce($first, null));
}
public function getRequiredHandlePHIDsForEdit() {
$phids = array();
if ($this->getValue()) {
$phids[] = $this->getValue();
}
return $phids;
}
public function renderEditControl(array $handles) {
if ($this->getValue()) {
$control_value = array_select_keys($handles, array($this->getValue()));
} else {
$control_value = array();
}
return id(new AphrontFormTokenizerControl())
->setName($this->getFieldKey())
->setDatasource('/typeahead/common/repositories/')
->setValue($control_value)
->setError($this->getFieldError())
->setLabel($this->getFieldName())
->setLimit(1);
}
public function getApplicationTransactionRequiredHandlePHIDs(
PhabricatorApplicationTransaction $xaction) {
$old = $xaction->getOldValue();
$new = $xaction->getNewValue();
$phids = array();
if ($old) {
$phids[] = $old;
}
if ($new) {
$phids[] = $new;
}
return $phids;
}
public function getApplicationTransactionTitle(
PhabricatorApplicationTransaction $xaction) {
$author_phid = $xaction->getAuthorPHID();
$old = $xaction->getOldValue();
$new = $xaction->getNewValue();
if ($old && $new) {
return pht(
'%s changed the repository for this revision from %s to %s.',
$xaction->renderHandleLink($author_phid),
$xaction->renderHandleLink($old),
$xaction->renderHandleLink($new));
} else if ($new) {
return pht(
'%s set the repository for this revision to %s.',
$xaction->renderHandleLink($author_phid),
$xaction->renderHandleLink($new));
} else {
return pht(
'%s removed %s as the repository for this revision.',
$xaction->renderHandleLink($author_phid),
$xaction->renderHandleLink($old));
}
}
public function getApplicationTransactionTitleForFeed(
PhabricatorApplicationTransaction $xaction,
PhabricatorFeedStory $story) {
$object_phid = $xaction->getObjectPHID();
$author_phid = $xaction->getAuthorPHID();
$old = $xaction->getOldValue();
$new = $xaction->getNewValue();
if ($old) {
return pht(
'%s updated the repository for %s from %s to %s.',
$xaction->renderHandleLink($author_phid),
$xaction->renderHandleLink($object_phid),
$xaction->renderHandleLink($old),
$xaction->renderHandleLink($new));
} else {
return pht(
'%s set the repository for %s to %s.',
$xaction->renderHandleLink($author_phid),
$xaction->renderHandleLink($object_phid),
$xaction->renderHandleLink($new));
}
}
}

View file

@ -30,7 +30,7 @@ final class DifferentialSummaryField
$this->setValue($request->getStr($this->getFieldKey()));
}
public function renderEditControl() {
public function renderEditControl(array $handles) {
return id(new PhabricatorRemarkupControl())
->setName($this->getFieldKey())
->setValue($this->getValue())

View file

@ -44,7 +44,7 @@ final class DifferentialTestPlanField
$this->setValue($request->getStr($this->getFieldKey()));
}
public function renderEditControl() {
public function renderEditControl(array $handles) {
return id(new PhabricatorRemarkupControl())
->setName($this->getFieldKey())
->setValue($this->getValue())

View file

@ -38,7 +38,7 @@ final class DifferentialTitleField
return true;
}
public function renderEditControl() {
public function renderEditControl(array $handles) {
return id(new AphrontFormTextAreaControl())
->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT)
->setName($this->getFieldKey())

View file

@ -468,6 +468,8 @@ final class DifferentialRevision extends DifferentialDAO
$fields = array(
new DifferentialTitleField(),
new DifferentialSummaryField(),
new DifferentialTestPlanField(),
new DifferentialRepositoryField(),
);
return array_fill_keys(

View file

@ -157,10 +157,10 @@ final class ManiphestTaskEditController extends ManiphestController {
$field_list = PhabricatorCustomField::getObjectFields(
$task,
PhabricatorCustomField::ROLE_EDIT);
$field_list->setViewer($user);
foreach ($field_list->getFields() as $field) {
$field->setObject($task);
$field->setViewer($user);
}
$field_list->readFieldsFromStorage($task);
@ -577,10 +577,7 @@ final class ManiphestTaskEditController extends ManiphestController {
->setDatasource('/typeahead/common/projects/'));
}
foreach ($aux_fields as $aux_field) {
$aux_control = $aux_field->renderEditControl();
$form->appendChild($aux_control);
}
$field_list->appendFieldsToForm($form);
require_celerity_resource('aphront-error-view-css');

View file

@ -50,7 +50,7 @@ final class PhabricatorUserBlurbField
$this->value = $request->getStr($this->getFieldKey());
}
public function renderEditControl() {
public function renderEditControl(array $handles) {
return id(new PhabricatorRemarkupControl())
->setName($this->getFieldKey())
->setValue($this->value)

View file

@ -53,7 +53,7 @@ final class PhabricatorUserRealNameField
$this->value = $request->getStr($this->getFieldKey());
}
public function renderEditControl() {
public function renderEditControl(array $handles) {
return id(new AphrontFormTextControl())
->setName($this->getFieldKey())
->setValue($this->value)

View file

@ -50,7 +50,7 @@ final class PhabricatorUserTitleField
$this->value = $request->getStr($this->getFieldKey());
}
public function renderEditControl() {
public function renderEditControl(array $handles) {
return id(new AphrontFormTextControl())
->setName($this->getFieldKey())
->setValue($this->value)

View file

@ -27,7 +27,7 @@ abstract class ReleephLevelFieldSpecification
return $this->getNameForLevel($this->getValue());
}
public function renderEditControl() {
public function renderEditControl(array $handles) {
$control_name = $this->getRequiredStorageKey();
$all_levels = $this->getLevels();

View file

@ -35,7 +35,7 @@ final class ReleephReasonFieldSpecification
private $error = true;
public function renderEditControl() {
public function renderEditControl(array $handles) {
return id(new AphrontFormTextAreaControl())
->setLabel('Reason')
->setName('reason')

View file

@ -19,7 +19,7 @@ final class ReleephSummaryFieldSpecification
private $error = false;
public function renderEditControl() {
public function renderEditControl(array $handles) {
return id(new AphrontFormTextControl())
->setLabel('Summary')
->setName('summary')

View file

@ -96,27 +96,6 @@ abstract class PhabricatorApplicationTransactionQuery
}
}
if ($this->needHandles) {
$phids = array();
foreach ($xactions as $xaction) {
$phids[$xaction->getPHID()] = $xaction->getRequiredHandlePHIDs();
}
$handles = array();
$merged = array_mergev($phids);
if ($merged) {
$handles = id(new PhabricatorHandleQuery())
->setViewer($this->getViewer())
->withPHIDs($merged)
->execute();
}
foreach ($xactions as $xaction) {
$xaction->setHandles(
array_select_keys(
$handles,
$phids[$xaction->getPHID()]));
}
}
return $xactions;
}
@ -138,6 +117,31 @@ abstract class PhabricatorApplicationTransactionQuery
$xaction->attachObject($objects[$object_phid]);
}
// NOTE: We have to do this after loading objects, because the objects
// may help determine which handles are required (for example, in the case
// of custom fields.
if ($this->needHandles) {
$phids = array();
foreach ($xactions as $xaction) {
$phids[$xaction->getPHID()] = $xaction->getRequiredHandlePHIDs();
}
$handles = array();
$merged = array_mergev($phids);
if ($merged) {
$handles = id(new PhabricatorHandleQuery())
->setViewer($this->getViewer())
->withPHIDs($merged)
->execute();
}
foreach ($xactions as $xaction) {
$xaction->setHandles(
array_select_keys(
$handles,
$phids[$xaction->getPHID()]));
}
}
return $xactions;
}

View file

@ -148,6 +148,13 @@ abstract class PhabricatorApplicationTransaction
$phids[] = array($this->getAuthorPHID());
switch ($this->getTransactionType()) {
case PhabricatorTransactions::TYPE_CUSTOMFIELD:
$field = $this->getTransactionCustomField();
if ($field) {
$phids[] = $field->getApplicationTransactionRequiredHandlePHIDs(
$this);
}
break;
case PhabricatorTransactions::TYPE_SUBSCRIBERS:
$phids[] = $old;
$phids[] = $new;

View file

@ -924,6 +924,15 @@ abstract class PhabricatorCustomField {
return null;
}
public function getApplicationTransactionRequiredHandlePHIDs(
PhabricatorApplicationTransaction $xaction) {
if ($this->proxy) {
return $this->proxy->getApplicationTransactionRequiredHandlePHIDs(
$xaction);
}
return array();
}
/* -( Edit View )---------------------------------------------------------- */
@ -953,9 +962,20 @@ abstract class PhabricatorCustomField {
/**
* @task edit
*/
public function renderEditControl() {
public function getRequiredHandlePHIDsForEdit() {
if ($this->proxy) {
return $this->proxy->renderEditControl();
return $this->proxy->getRequiredHandlePHIDsForEdit();
}
return array();
}
/**
* @task edit
*/
public function renderEditControl(array $handles) {
if ($this->proxy) {
return $this->proxy->renderEditControl($handles);
}
throw new PhabricatorCustomFieldImplementationIncompleteException($this);
}

View file

@ -10,6 +10,7 @@
final class PhabricatorCustomFieldList extends Phobject {
private $fields;
private $viewer;
public function __construct(array $fields) {
assert_instances_of($fields, 'PhabricatorCustomField');
@ -21,6 +22,7 @@ final class PhabricatorCustomFieldList extends Phobject {
}
public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
foreach ($this->getFields() as $field) {
$field->setViewer($viewer);
}
@ -75,11 +77,32 @@ final class PhabricatorCustomFieldList extends Phobject {
}
public function appendFieldsToForm(AphrontFormView $form) {
$enabled = array();
foreach ($this->fields as $field) {
if ($field->shouldEnableForRole(PhabricatorCustomField::ROLE_EDIT)) {
$form->appendChild($field->renderEditControl());
$enabled[] = $field;
}
}
$phids = array();
foreach ($enabled as $field_key => $field) {
$phids[$field_key] = $field->getRequiredHandlePHIDsForEdit();
}
$all_phids = array_mergev($phids);
if ($all_phids) {
$handles = id(new PhabricatorHandleQuery())
->setViewer($this->viewer)
->withPHIDs($all_phids)
->execute();
} else {
$handles = array();
}
foreach ($enabled as $field_key => $field) {
$field_handles = array_select_keys($handles, $phids[$field_key]);
$form->appendChild($field->renderEditControl($field_handles));
}
}
public function appendFieldsToPropertyList(

View file

@ -200,7 +200,7 @@ abstract class PhabricatorStandardCustomField
$this->setFieldValue($value);
}
public function renderEditControl() {
public function renderEditControl(array $handles) {
return id(new AphrontFormTextControl())
->setName($this->getFieldKey())
->setCaption($this->getCaption())

View file

@ -72,7 +72,7 @@ final class PhabricatorStandardCustomFieldBool
)));
}
public function renderEditControl() {
public function renderEditControl(array $handles) {
return id(new AphrontFormCheckboxControl())
->setLabel($this->getFieldName())
->setCaption($this->getCaption())

View file

@ -36,7 +36,7 @@ final class PhabricatorStandardCustomFieldDate
return $this->setFieldValue($value);
}
public function renderEditControl() {
public function renderEditControl(array $handles) {
return $this->newDateControl();
}

View file

@ -7,7 +7,7 @@ final class PhabricatorStandardCustomFieldHeader
return 'header';
}
public function renderEditControl() {
public function renderEditControl(array $handles) {
$header = phutil_tag(
'div',
array(

View file

@ -86,4 +86,75 @@ abstract class PhabricatorStandardCustomFieldPHIDs
return $handles;
}
public function getRequiredHandlePHIDsForEdit() {
$value = $this->getFieldValue();
if ($value) {
return $value;
} else {
return array();
}
}
public function getApplicationTransactionRequiredHandlePHIDs(
PhabricatorApplicationTransaction $xaction) {
$old = json_decode($xaction->getOldValue());
if (!is_array($old)) {
$old = array();
}
$new = json_decode($xaction->getNewValue());
if (!is_array($new)) {
$new = array();
}
$add = array_diff($new, $old);
$rem = array_diff($old, $new);
return array_merge($add, $rem);
}
public function getApplicationTransactionTitle(
PhabricatorApplicationTransaction $xaction) {
$author_phid = $xaction->getAuthorPHID();
$old = json_decode($xaction->getOldValue());
if (!is_array($old)) {
$old = array();
}
$new = json_decode($xaction->getNewValue());
if (!is_array($new)) {
$new = array();
}
$add = array_diff($new, $old);
$rem = array_diff($old, $new);
if ($add && !$rem) {
return pht(
'%s updated %s, added %d: %s.',
$xaction->renderHandleLink($author_phid),
$this->getFieldName(),
new PhutilNumber(count($add)),
$xaction->renderHandleList($add));
} else if ($rem && !$add) {
return pht(
'%s updated %s, removed %d: %s.',
$xaction->renderHandleLink($author_phid),
$this->getFieldName(),
new PhutilNumber(count($rem)),
$xaction->renderHandleList($rem));
} else {
return pht(
'%s updated %s, added %d: %s; removed %d: %s.',
$xaction->renderHandleLink($author_phid),
$this->getFieldName(),
new PhutilNumber(count($add)),
$xaction->renderHandleList($add),
new PhutilNumber(count($rem)),
$xaction->renderHandleList($rem));
}
}
}

View file

@ -7,7 +7,7 @@ final class PhabricatorStandardCustomFieldRemarkup
return 'remarkup';
}
public function renderEditControl() {
public function renderEditControl(array $handles) {
return id(new PhabricatorRemarkupControl())
->setLabel($this->getFieldName())
->setName($this->getFieldKey())

View file

@ -64,7 +64,7 @@ final class PhabricatorStandardCustomFieldSelect
return $this->getFieldConfigValue('options', array());
}
public function renderEditControl() {
public function renderEditControl(array $handles) {
return id(new AphrontFormSelectControl())
->setLabel($this->getFieldName())
->setCaption($this->getCaption())

View file

@ -7,17 +7,12 @@ final class PhabricatorStandardCustomFieldUsers
return 'users';
}
public function renderEditControl() {
$handles = array();
public function renderEditControl(array $handles) {
$value = $this->getFieldValue();
if ($value) {
// TODO: Surface and batch.
$handles = id(new PhabricatorHandleQuery())
->setViewer($this->getViewer())
->withPHIDs($value)
->execute();
$control_value = array_select_keys($handles, $value);
} else {
$control_value = array();
}
$control = id(new AphrontFormTokenizerControl())
@ -25,7 +20,7 @@ final class PhabricatorStandardCustomFieldUsers
->setName($this->getFieldKey())
->setDatasource('/typeahead/common/accounts/')
->setCaption($this->getCaption())
->setValue($handles);
->setValue($control_value);
$limit = $this->getFieldConfigValue('limit');
if ($limit) {
@ -49,18 +44,4 @@ final class PhabricatorStandardCustomFieldUsers
$form->appendChild($control);
}
public function getApplicationTransactionTitle(
PhabricatorApplicationTransaction $xaction) {
$author_phid = $xaction->getAuthorPHID();
// TODO: Show added/removed and render handles. We don't have handle
// surfacing or batching yet so this is a bit awkward right now.
return pht(
'%s updated %s.',
$xaction->renderHandleLink($author_phid),
$this->getFieldName());
}
}