mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-25 16:22:43 +01:00
Add (Advanced) Custom Fields to Item List
Summary: Allow PHP-coded Custom Fields to show things in Lists. Also add Repository to Revision List and Flags to Maniphest lists. Closes T15133. Ref T15512, T15750 Test Plan: Look at Repository List and Task lists that have flags. Reviewers: O1 Blessed Committers, aklapper, valerio.bozzolan Reviewed By: O1 Blessed Committers, aklapper, valerio.bozzolan Subscribers: aklapper, tobiaswiese, valerio.bozzolan, Matthew, Cigaryno Maniphest Tasks: T15750, T15512, T15133 Differential Revision: https://we.phorge.it/D25548
This commit is contained in:
parent
f2a01dca39
commit
ea554af476
13 changed files with 244 additions and 6 deletions
|
@ -1802,6 +1802,7 @@ phutil_register_library_map(array(
|
|||
'ManiphestEditConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestEditConduitAPIMethod.php',
|
||||
'ManiphestEditEngine' => 'applications/maniphest/editor/ManiphestEditEngine.php',
|
||||
'ManiphestEmailCommand' => 'applications/maniphest/command/ManiphestEmailCommand.php',
|
||||
'ManiphestFlagCustomField' => 'applications/maniphest/field/ManiphestFlagCustomField.php',
|
||||
'ManiphestGetTaskTransactionsConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestGetTaskTransactionsConduitAPIMethod.php',
|
||||
'ManiphestHovercardEngineExtension' => 'applications/maniphest/engineextension/ManiphestHovercardEngineExtension.php',
|
||||
'ManiphestInfoConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestInfoConduitAPIMethod.php',
|
||||
|
@ -5388,6 +5389,8 @@ phutil_register_library_map(array(
|
|||
'PholioTransactionView' => 'applications/pholio/view/PholioTransactionView.php',
|
||||
'PholioUploadedImageView' => 'applications/pholio/view/PholioUploadedImageView.php',
|
||||
'PhorgeCodeWarningSetupCheck' => 'applications/config/check/PhorgeCodeWarningSetupCheck.php',
|
||||
'PhorgeFlagFlaggedObjectCustomField' => 'applications/flag/customfield/PhorgeFlagFlaggedObjectCustomField.php',
|
||||
'PhorgeFlagFlaggedObjectFieldStorage' => 'applications/flag/customfield/PhorgeFlagFlaggedObjectFieldStorage.php',
|
||||
'PhorgeSystemDeprecationWarningListener' => 'applications/system/events/PhorgeSystemDeprecationWarningListener.php',
|
||||
'PhortuneAccount' => 'applications/phortune/storage/PhortuneAccount.php',
|
||||
'PhortuneAccountAddManagerController' => 'applications/phortune/controller/account/PhortuneAccountAddManagerController.php',
|
||||
|
@ -8008,6 +8011,7 @@ phutil_register_library_map(array(
|
|||
'ManiphestEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
|
||||
'ManiphestEditEngine' => 'PhabricatorEditEngine',
|
||||
'ManiphestEmailCommand' => 'MetaMTAEmailTransactionCommand',
|
||||
'ManiphestFlagCustomField' => 'ManiphestCustomField',
|
||||
'ManiphestGetTaskTransactionsConduitAPIMethod' => 'ManiphestConduitAPIMethod',
|
||||
'ManiphestHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
|
||||
'ManiphestInfoConduitAPIMethod' => 'ManiphestConduitAPIMethod',
|
||||
|
@ -12212,6 +12216,8 @@ phutil_register_library_map(array(
|
|||
'PholioTransactionView' => 'PhabricatorApplicationTransactionView',
|
||||
'PholioUploadedImageView' => 'AphrontView',
|
||||
'PhorgeCodeWarningSetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhorgeFlagFlaggedObjectCustomField' => 'PhabricatorCustomField',
|
||||
'PhorgeFlagFlaggedObjectFieldStorage' => 'Phobject',
|
||||
'PhorgeSystemDeprecationWarningListener' => 'PhabricatorEventListener',
|
||||
'PhortuneAccount' => array(
|
||||
'PhortuneDAO',
|
||||
|
|
|
@ -63,4 +63,16 @@ final class DifferentialRepositoryField
|
|||
$repository->getMonogram().' '.$repository->getName());
|
||||
}
|
||||
|
||||
public function shouldAppearInListView() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function renderOnListItem(PHUIObjectItemView $view) {
|
||||
if ($this->getValue()) {
|
||||
$handle = $this->getViewer()->renderHandle($this->getValue());
|
||||
$view->addByLine(pht('Repository: %s', $handle));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -199,6 +199,10 @@ final class DifferentialRevisionSearchEngine
|
|||
|
||||
$unlanded = $this->loadUnlandedDependencies($revisions);
|
||||
|
||||
$custom_field_lists = $this->loadCustomFields(
|
||||
$revisions,
|
||||
PhabricatorCustomField::ROLE_LIST);
|
||||
|
||||
$views = array();
|
||||
if ($bucket) {
|
||||
$bucket->setViewer($viewer);
|
||||
|
@ -231,6 +235,7 @@ final class DifferentialRevisionSearchEngine
|
|||
|
||||
foreach ($views as $view) {
|
||||
$view->setUnlandedDependencies($unlanded);
|
||||
$view->setCustomFieldLists($custom_field_lists);
|
||||
}
|
||||
|
||||
if (count($views) == 1) {
|
||||
|
|
|
@ -11,6 +11,7 @@ final class DifferentialRevisionListView extends AphrontView {
|
|||
private $noBox;
|
||||
private $background = null;
|
||||
private $unlandedDependencies = array();
|
||||
private $customFieldLists = array();
|
||||
|
||||
public function setUnlandedDependencies(array $unlanded_dependencies) {
|
||||
$this->unlandedDependencies = $unlanded_dependencies;
|
||||
|
@ -47,6 +48,11 @@ final class DifferentialRevisionListView extends AphrontView {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function setCustomFieldLists(array $lists) {
|
||||
$this->customFieldLists = $lists;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
|
@ -181,6 +187,12 @@ final class DifferentialRevisionListView extends AphrontView {
|
|||
"{$icon} {$color}",
|
||||
$revision->getStatusDisplayName());
|
||||
|
||||
$field_list = idx($this->customFieldLists, $revision->getPHID());
|
||||
if ($field_list) {
|
||||
$field_list
|
||||
->addFieldsToListViewItem($revision, $viewer, $item);
|
||||
}
|
||||
|
||||
$list->addItem($item);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
final class PhorgeFlagFlaggedObjectCustomField extends PhabricatorCustomField {
|
||||
|
||||
private $flag;
|
||||
|
||||
public function getFieldKey() {
|
||||
return 'flag:flag';
|
||||
}
|
||||
public function shouldAppearInPropertyView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function shouldAppearInListView() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function renderOnListItem(PHUIObjectItemView $view) {
|
||||
if (!$this->flag) {
|
||||
return;
|
||||
}
|
||||
// I'm very open to improvements in the way a Flag is displayed
|
||||
$icon = PhabricatorFlagColor::getIcon($this->flag->getColor());
|
||||
$view->addIcon($icon);
|
||||
}
|
||||
|
||||
|
||||
public function shouldUseStorage() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function setValueFromStorage($value) {
|
||||
$this->flag = $value;
|
||||
}
|
||||
|
||||
// The parent function is defined to return a PhabricatorCustomFieldStorage,
|
||||
// but that assumes a DTO with a particular form; That doesn't apply here.
|
||||
// Maybe the function needs to be re-defined with a suitable interface.
|
||||
// For now, PhorgeFlagFlaggedObjectFieldStorage just duck-types into the
|
||||
// right shape.
|
||||
public function newStorageObject() {
|
||||
return id(new PhorgeFlagFlaggedObjectFieldStorage())
|
||||
->setViewer($this->getViewer());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
final class PhorgeFlagFlaggedObjectFieldStorage extends Phobject {
|
||||
|
||||
private $viewer;
|
||||
|
||||
public function setViewer(PhabricatorUser $viewer) {
|
||||
$this->viewer = $viewer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStorageSourceKey() {
|
||||
return 'flags/flag';
|
||||
}
|
||||
|
||||
public function loadStorageSourceData(array $fields) {
|
||||
|
||||
$objects = mpull($fields, 'getObject');
|
||||
$object_phids = mpull($objects, 'getPHID');
|
||||
$flags = (new PhabricatorFlagQuery())
|
||||
->setViewer($this->viewer)
|
||||
->withOwnerPHIDs(array($this->viewer->getPHID()))
|
||||
->withObjectPHIDs($object_phids)
|
||||
->execute();
|
||||
$flags = mpull($flags, null, 'getObjectPHID');
|
||||
|
||||
$result = array();
|
||||
foreach ($fields as $key => $field) {
|
||||
$target_phid = $field->getObject()->getPHID();
|
||||
$result[$key] = idx($flags, $target_phid);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
// I'm not sure this is the right use for the Proxy capability.
|
||||
// Probably should just use Traits for this.
|
||||
final class ManiphestFlagCustomField extends ManiphestCustomField {
|
||||
|
||||
public function __construct() {
|
||||
$this->setProxy(new PhorgeFlagFlaggedObjectCustomField());
|
||||
}
|
||||
|
||||
public function canSetProxy() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function newStorageObject() {
|
||||
return $this->getProxy()->newStorageObject();
|
||||
}
|
||||
}
|
|
@ -374,11 +374,17 @@ final class ManiphestTaskSearchEngine
|
|||
ManiphestBulkEditCapability::CAPABILITY);
|
||||
}
|
||||
|
||||
$custom_field_lists = $this->loadCustomFields(
|
||||
$tasks,
|
||||
PhabricatorCustomField::ROLE_LIST);
|
||||
|
||||
$list = id(new ManiphestTaskResultListView())
|
||||
->setUser($viewer)
|
||||
->setTasks($tasks)
|
||||
->setHandles($handles)
|
||||
->setSavedQuery($saved)
|
||||
->setCanBatchEdit($can_bulk_edit)
|
||||
->setCustomFieldLists($custom_field_lists)
|
||||
->setShowBatchControls($this->showBatchControls);
|
||||
|
||||
$result = new PhabricatorApplicationSearchResultView();
|
||||
|
@ -387,6 +393,24 @@ final class ManiphestTaskSearchEngine
|
|||
return $result;
|
||||
}
|
||||
|
||||
protected function getRequiredHandlePHIDsForResultList(
|
||||
array $objects,
|
||||
PhabricatorSavedQuery $query) {
|
||||
|
||||
$phids = array();
|
||||
foreach ($objects as $task) {
|
||||
$assigned_phid = $task->getOwnerPHID();
|
||||
if ($assigned_phid) {
|
||||
$phids[] = $assigned_phid;
|
||||
}
|
||||
foreach ($task->getProjectPHIDs() as $project_phid) {
|
||||
$phids[] = $project_phid;
|
||||
}
|
||||
}
|
||||
|
||||
return $phids;
|
||||
}
|
||||
|
||||
protected function willUseSavedQuery(PhabricatorSavedQuery $saved) {
|
||||
|
||||
// The 'withUnassigned' parameter may be present in old saved queries from
|
||||
|
|
|
@ -4,6 +4,7 @@ final class ManiphestTaskListView extends ManiphestView {
|
|||
|
||||
private $tasks;
|
||||
private $handles;
|
||||
private $customFieldLists = array();
|
||||
private $showBatchControls;
|
||||
private $noDataString;
|
||||
|
||||
|
@ -19,6 +20,11 @@ final class ManiphestTaskListView extends ManiphestView {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function setCustomFieldLists(array $lists) {
|
||||
$this->customFieldLists = $lists;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setShowBatchControls($show_batch_controls) {
|
||||
$this->showBatchControls = $show_batch_controls;
|
||||
return $this;
|
||||
|
@ -132,12 +138,21 @@ final class ManiphestTaskListView extends ManiphestView {
|
|||
->setHref($href));
|
||||
}
|
||||
|
||||
|
||||
$field_list = idx($this->customFieldLists, $task->getPHID());
|
||||
if ($field_list) {
|
||||
$field_list
|
||||
->addFieldsToListViewItem($task, $this->getViewer(), $item);
|
||||
}
|
||||
|
||||
$list->addItem($item);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
// This method should be removed, and all call-sites switch
|
||||
// to use ManiphestSearchEngine
|
||||
public static function loadTaskHandles(
|
||||
PhabricatorUser $viewer,
|
||||
array $tasks) {
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
final class ManiphestTaskResultListView extends ManiphestView {
|
||||
|
||||
private $tasks;
|
||||
private $handles;
|
||||
private $customFieldLists = array();
|
||||
private $savedQuery;
|
||||
private $canBatchEdit;
|
||||
private $showBatchControls;
|
||||
|
@ -17,6 +19,16 @@ final class ManiphestTaskResultListView extends ManiphestView {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function setHandles(array $handles) {
|
||||
$this->handles = $handles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCustomFieldLists(array $lists) {
|
||||
$this->customFieldLists = $lists;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCanBatchEdit($can_batch_edit) {
|
||||
$this->canBatchEdit = $can_batch_edit;
|
||||
return $this;
|
||||
|
@ -42,11 +54,10 @@ final class ManiphestTaskResultListView extends ManiphestView {
|
|||
$group_parameter = nonempty($query->getParameter('group'), 'priority');
|
||||
$order_parameter = nonempty($query->getParameter('order'), 'priority');
|
||||
|
||||
$handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks);
|
||||
$groups = $this->groupTasks(
|
||||
$tasks,
|
||||
$group_parameter,
|
||||
$handles);
|
||||
$this->handles);
|
||||
|
||||
$result = array();
|
||||
|
||||
|
@ -56,7 +67,8 @@ final class ManiphestTaskResultListView extends ManiphestView {
|
|||
$task_list->setShowBatchControls($this->showBatchControls);
|
||||
$task_list->setUser($viewer);
|
||||
$task_list->setTasks($list);
|
||||
$task_list->setHandles($handles);
|
||||
$task_list->setHandles($this->handles);
|
||||
$task_list->setCustomFieldLists($this->customFieldLists);
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->addSigil('task-group')
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
* @task read Reading Utilities
|
||||
* @task exec Paging and Executing Queries
|
||||
* @task render Rendering Results
|
||||
* @task custom Custom Fields
|
||||
*/
|
||||
abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||
|
||||
|
@ -1071,7 +1072,7 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
|||
if ($phids) {
|
||||
$handles = id(new PhabricatorHandleQuery())
|
||||
->setViewer($this->requireViewer())
|
||||
->witHPHIDs($phids)
|
||||
->withPHIDs($phids)
|
||||
->execute();
|
||||
} else {
|
||||
$handles = array();
|
||||
|
@ -1626,4 +1627,33 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
|||
return $supported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from object and from storage, and updates Custom Fields instances
|
||||
* that are attached to each object.
|
||||
*
|
||||
* @return map<phid->PhabricatorCustomFieldList> of loaded fields.
|
||||
* @task custom
|
||||
*/
|
||||
protected function loadCustomFields(array $objects, $role) {
|
||||
assert_instances_of($objects, 'PhabricatorCustomFieldInterface');
|
||||
|
||||
$query = new PhabricatorCustomFieldStorageQuery();
|
||||
$lists = array();
|
||||
|
||||
foreach ($objects as $object) {
|
||||
$field_list = PhabricatorCustomField::getObjectFields($object, $role);
|
||||
$field_list->readFieldsFromObject($object);
|
||||
foreach ($field_list->getFields() as $field) {
|
||||
// TODO move $viewer into PhabricatorCustomFieldStorageQuery
|
||||
$field->setViewer($this->viewer);
|
||||
}
|
||||
$lists[$object->getPHID()] = $field_list;
|
||||
$query->addFields($field_list->getFields());
|
||||
}
|
||||
// This updates the field_list objects.
|
||||
$query->execute();
|
||||
|
||||
return $lists;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -384,6 +384,7 @@ abstract class PhabricatorCustomField extends Phobject {
|
|||
*
|
||||
* @param PhabricatorCustomField Field implementation.
|
||||
* @return this
|
||||
* @task proxy
|
||||
*/
|
||||
final public function setProxy(PhabricatorCustomField $proxy) {
|
||||
if (!$this->canSetProxy()) {
|
||||
|
@ -400,12 +401,20 @@ abstract class PhabricatorCustomField extends Phobject {
|
|||
* @{method:canSetProxy}.
|
||||
*
|
||||
* @return PhabricatorCustomField|null Proxy field, if one is set.
|
||||
* @task proxy
|
||||
*/
|
||||
final public function getProxy() {
|
||||
return $this->proxy;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @task proxy
|
||||
*/
|
||||
public function __clone() {
|
||||
if ($this->proxy) {
|
||||
$this->proxy = clone $this->proxy;
|
||||
}
|
||||
}
|
||||
/* -( Contextual Data )---------------------------------------------------- */
|
||||
|
||||
|
||||
|
@ -827,7 +836,7 @@ abstract class PhabricatorCustomField extends Phobject {
|
|||
|
||||
|
||||
/**
|
||||
* Appearing in ApplicationTrasactions allows a field to be edited using
|
||||
* Appearing in ApplicationTransactions allows a field to be edited using
|
||||
* standard workflows.
|
||||
*
|
||||
* @return bool True to appear in ApplicationTransactions.
|
||||
|
|
|
@ -200,6 +200,19 @@ final class PhabricatorCustomFieldList extends Phobject {
|
|||
}
|
||||
}
|
||||
|
||||
public function addFieldsToListViewItem(
|
||||
PhabricatorCustomFieldInterface $object,
|
||||
PhabricatorUser $viewer,
|
||||
PHUIObjectItemView $view) {
|
||||
|
||||
foreach ($this->fields as $field) {
|
||||
if ($field->shouldAppearInListView()) {
|
||||
$field->setViewer($viewer);
|
||||
$field->renderOnListItem($view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function buildFieldTransactionsFromRequest(
|
||||
PhabricatorApplicationTransaction $template,
|
||||
AphrontRequest $request) {
|
||||
|
|
Loading…
Reference in a new issue