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

Inch toward using ApplicationSearch to power related objects

Summary:
Ref T4788. Fixes T9232. This moves the "search for stuff to attach to this object" flow away from hard-coding and legacy constants and toward something more modular and flexible.

It also adds an "Edit Commits..." action to Maniphest, resolving T9232. The behavior of the search for commits isn't great right now, but it will improve once these use real ApplicationSearch.

Test Plan: Edited a tasks' related commits, mocks, tasks, etc.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T4788, T9232

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

+249 -41
+12
src/__phutil_library_map__.php
··· 536 536 'DifferentialRevisionPackageHeraldField' => 'applications/differential/herald/DifferentialRevisionPackageHeraldField.php', 537 537 'DifferentialRevisionPackageOwnerHeraldField' => 'applications/differential/herald/DifferentialRevisionPackageOwnerHeraldField.php', 538 538 'DifferentialRevisionQuery' => 'applications/differential/query/DifferentialRevisionQuery.php', 539 + 'DifferentialRevisionRelationshipSource' => 'applications/search/relationship/DifferentialRevisionRelationshipSource.php', 539 540 'DifferentialRevisionRepositoryHeraldField' => 'applications/differential/herald/DifferentialRevisionRepositoryHeraldField.php', 540 541 'DifferentialRevisionRepositoryProjectsHeraldField' => 'applications/differential/herald/DifferentialRevisionRepositoryProjectsHeraldField.php', 541 542 'DifferentialRevisionRequiredActionResultBucket' => 'applications/differential/query/DifferentialRevisionRequiredActionResultBucket.php', ··· 614 615 'DiffusionCommitParentsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionCommitParentsQueryConduitAPIMethod.php', 615 616 'DiffusionCommitQuery' => 'applications/diffusion/query/DiffusionCommitQuery.php', 616 617 'DiffusionCommitRef' => 'applications/diffusion/data/DiffusionCommitRef.php', 618 + 'DiffusionCommitRelationshipSource' => 'applications/search/relationship/DiffusionCommitRelationshipSource.php', 617 619 'DiffusionCommitRemarkupRule' => 'applications/diffusion/remarkup/DiffusionCommitRemarkupRule.php', 618 620 'DiffusionCommitRemarkupRuleTestCase' => 'applications/diffusion/remarkup/__tests__/DiffusionCommitRemarkupRuleTestCase.php', 619 621 'DiffusionCommitRepositoryHeraldField' => 'applications/diffusion/herald/DiffusionCommitRepositoryHeraldField.php', ··· 1442 1444 'ManiphestTaskPriorityHeraldField' => 'applications/maniphest/herald/ManiphestTaskPriorityHeraldField.php', 1443 1445 'ManiphestTaskQuery' => 'applications/maniphest/query/ManiphestTaskQuery.php', 1444 1446 'ManiphestTaskRelationship' => 'applications/maniphest/relationship/ManiphestTaskRelationship.php', 1447 + 'ManiphestTaskRelationshipSource' => 'applications/search/relationship/ManiphestTaskRelationshipSource.php', 1445 1448 'ManiphestTaskResultListView' => 'applications/maniphest/view/ManiphestTaskResultListView.php', 1446 1449 'ManiphestTaskSearchEngine' => 'applications/maniphest/query/ManiphestTaskSearchEngine.php', 1447 1450 'ManiphestTaskStatus' => 'applications/maniphest/constants/ManiphestTaskStatus.php', ··· 2867 2870 'PhabricatorObjectQuery' => 'applications/phid/query/PhabricatorObjectQuery.php', 2868 2871 'PhabricatorObjectRelationship' => 'applications/search/relationship/PhabricatorObjectRelationship.php', 2869 2872 'PhabricatorObjectRelationshipList' => 'applications/search/relationship/PhabricatorObjectRelationshipList.php', 2873 + 'PhabricatorObjectRelationshipSource' => 'applications/search/relationship/PhabricatorObjectRelationshipSource.php', 2870 2874 'PhabricatorObjectRemarkupRule' => 'infrastructure/markup/rule/PhabricatorObjectRemarkupRule.php', 2871 2875 'PhabricatorObjectSelectorDialog' => 'view/control/PhabricatorObjectSelectorDialog.php', 2872 2876 'PhabricatorOffsetPagedQuery' => 'infrastructure/query/PhabricatorOffsetPagedQuery.php', ··· 3397 3401 'PhabricatorSearchOrderField' => 'applications/search/field/PhabricatorSearchOrderField.php', 3398 3402 'PhabricatorSearchRelationship' => 'applications/search/constants/PhabricatorSearchRelationship.php', 3399 3403 'PhabricatorSearchRelationshipController' => 'applications/search/controller/PhabricatorSearchRelationshipController.php', 3404 + 'PhabricatorSearchRelationshipSourceController' => 'applications/search/controller/PhabricatorSearchRelationshipSourceController.php', 3400 3405 'PhabricatorSearchResultBucket' => 'applications/search/buckets/PhabricatorSearchResultBucket.php', 3401 3406 'PhabricatorSearchResultBucketGroup' => 'applications/search/buckets/PhabricatorSearchResultBucketGroup.php', 3402 3407 'PhabricatorSearchResultView' => 'applications/search/view/PhabricatorSearchResultView.php', ··· 3870 3875 'PholioMockNameHeraldField' => 'applications/pholio/herald/PholioMockNameHeraldField.php', 3871 3876 'PholioMockPHIDType' => 'applications/pholio/phid/PholioMockPHIDType.php', 3872 3877 'PholioMockQuery' => 'applications/pholio/query/PholioMockQuery.php', 3878 + 'PholioMockRelationshipSource' => 'applications/search/relationship/PholioMockRelationshipSource.php', 3873 3879 'PholioMockSearchEngine' => 'applications/pholio/query/PholioMockSearchEngine.php', 3874 3880 'PholioMockThumbGridView' => 'applications/pholio/view/PholioMockThumbGridView.php', 3875 3881 'PholioMockViewController' => 'applications/pholio/controller/PholioMockViewController.php', ··· 4887 4893 'DifferentialRevisionPackageHeraldField' => 'DifferentialRevisionHeraldField', 4888 4894 'DifferentialRevisionPackageOwnerHeraldField' => 'DifferentialRevisionHeraldField', 4889 4895 'DifferentialRevisionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 4896 + 'DifferentialRevisionRelationshipSource' => 'PhabricatorObjectRelationshipSource', 4890 4897 'DifferentialRevisionRepositoryHeraldField' => 'DifferentialRevisionHeraldField', 4891 4898 'DifferentialRevisionRepositoryProjectsHeraldField' => 'DifferentialRevisionHeraldField', 4892 4899 'DifferentialRevisionRequiredActionResultBucket' => 'DifferentialRevisionResultBucket', ··· 4965 4972 'DiffusionCommitParentsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 4966 4973 'DiffusionCommitQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 4967 4974 'DiffusionCommitRef' => 'Phobject', 4975 + 'DiffusionCommitRelationshipSource' => 'PhabricatorObjectRelationshipSource', 4968 4976 'DiffusionCommitRemarkupRule' => 'PhabricatorObjectRemarkupRule', 4969 4977 'DiffusionCommitRemarkupRuleTestCase' => 'PhabricatorTestCase', 4970 4978 'DiffusionCommitRepositoryHeraldField' => 'DiffusionCommitHeraldField', ··· 5935 5943 'ManiphestTaskPriorityHeraldField' => 'ManiphestTaskHeraldField', 5936 5944 'ManiphestTaskQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 5937 5945 'ManiphestTaskRelationship' => 'PhabricatorObjectRelationship', 5946 + 'ManiphestTaskRelationshipSource' => 'PhabricatorObjectRelationshipSource', 5938 5947 'ManiphestTaskResultListView' => 'ManiphestView', 5939 5948 'ManiphestTaskSearchEngine' => 'PhabricatorApplicationSearchEngine', 5940 5949 'ManiphestTaskStatus' => 'ManiphestConstants', ··· 7561 7570 'PhabricatorObjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 7562 7571 'PhabricatorObjectRelationship' => 'Phobject', 7563 7572 'PhabricatorObjectRelationshipList' => 'Phobject', 7573 + 'PhabricatorObjectRelationshipSource' => 'Phobject', 7564 7574 'PhabricatorObjectRemarkupRule' => 'PhutilRemarkupRule', 7565 7575 'PhabricatorObjectSelectorDialog' => 'Phobject', 7566 7576 'PhabricatorOffsetPagedQuery' => 'PhabricatorQuery', ··· 8219 8229 'PhabricatorSearchOrderField' => 'PhabricatorSearchField', 8220 8230 'PhabricatorSearchRelationship' => 'Phobject', 8221 8231 'PhabricatorSearchRelationshipController' => 'PhabricatorSearchBaseController', 8232 + 'PhabricatorSearchRelationshipSourceController' => 'PhabricatorSearchBaseController', 8222 8233 'PhabricatorSearchResultBucket' => 'Phobject', 8223 8234 'PhabricatorSearchResultBucketGroup' => 'Phobject', 8224 8235 'PhabricatorSearchResultView' => 'AphrontView', ··· 8790 8801 'PholioMockNameHeraldField' => 'PholioMockHeraldField', 8791 8802 'PholioMockPHIDType' => 'PhabricatorPHIDType', 8792 8803 'PholioMockQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 8804 + 'PholioMockRelationshipSource' => 'PhabricatorObjectRelationshipSource', 8793 8805 'PholioMockSearchEngine' => 'PhabricatorApplicationSearchEngine', 8794 8806 'PholioMockThumbGridView' => 'AphrontView', 8795 8807 'PholioMockViewController' => 'PholioController',
+4 -7
src/applications/maniphest/relationship/ManiphestTaskHasCommitRelationship.php
··· 17 17 return 'fa-code'; 18 18 } 19 19 20 - public function shouldAppearInActionMenu() { 21 - // TODO: For now, the default search for commits is not very good, so 22 - // it is hard to find objects to link to. Until that works better, just 23 - // hide this item. 24 - return false; 25 - } 26 - 27 20 public function canRelateObjects($src, $dst) { 28 21 return ($dst instanceof PhabricatorRepositoryCommit); 29 22 } ··· 38 31 39 32 public function getDialogButtonText() { 40 33 return pht('Save Related Commits'); 34 + } 35 + 36 + protected function newRelationshipSource() { 37 + return new DiffusionCommitRelationshipSource(); 41 38 } 42 39 43 40 }
+4
src/applications/maniphest/relationship/ManiphestTaskHasMockRelationship.php
··· 33 33 return pht('Save Related Mocks'); 34 34 } 35 35 36 + protected function newRelationshipSource() { 37 + return new PholioMockRelationshipSource(); 38 + } 39 + 36 40 }
+4
src/applications/maniphest/relationship/ManiphestTaskHasParentRelationship.php
··· 37 37 return pht('Save Parent Tasks'); 38 38 } 39 39 40 + protected function newRelationshipSource() { 41 + return new ManiphestTaskRelationshipSource(); 42 + } 43 + 40 44 }
+4
src/applications/maniphest/relationship/ManiphestTaskHasRevisionRelationship.php
··· 33 33 return pht('Save Related Revisions'); 34 34 } 35 35 36 + protected function newRelationshipSource() { 37 + return new DifferentialRevisionRelationshipSource(); 38 + } 39 + 36 40 }
+4
src/applications/maniphest/relationship/ManiphestTaskHasSubtaskRelationship.php
··· 37 37 return pht('Save Subtasks'); 38 38 } 39 39 40 + protected function newRelationshipSource() { 41 + return new ManiphestTaskRelationshipSource(); 42 + } 43 + 40 44 }
-1
src/applications/phame/search/PhamePostFulltextEngine.php
··· 28 28 $post->getPHID(), 29 29 PhabricatorPhamePostPHIDType::TYPECONST, 30 30 PhabricatorTime::getNow()); 31 - 32 31 } 33 32 34 33 }
+8
src/applications/pholio/search/PholioMockFulltextEngine.php
··· 20 20 $mock->getAuthorPHID(), 21 21 PhabricatorPeopleUserPHIDType::TYPECONST, 22 22 $mock->getDateCreated()); 23 + 24 + $document->addRelationship( 25 + $mock->isClosed() 26 + ? PhabricatorSearchRelationship::RELATIONSHIP_CLOSED 27 + : PhabricatorSearchRelationship::RELATIONSHIP_OPEN, 28 + $mock->getPHID(), 29 + PholioMockPHIDType::TYPECONST, 30 + PhabricatorTime::getNow()); 23 31 } 24 32 25 33 }
+8
src/applications/repository/search/DiffusionCommitFulltextEngine.php
··· 47 47 $repository->getPHID(), 48 48 PhabricatorRepositoryRepositoryPHIDType::TYPECONST, 49 49 $date_created); 50 + 51 + $document->addRelationship( 52 + $commit->isUnreachable() 53 + ? PhabricatorSearchRelationship::RELATIONSHIP_CLOSED 54 + : PhabricatorSearchRelationship::RELATIONSHIP_OPEN, 55 + $commit->getPHID(), 56 + PhabricatorRepositoryCommitPHIDType::TYPECONST, 57 + PhabricatorTime::getNow()); 50 58 } 51 59 }
+2
src/applications/search/application/PhabricatorSearchApplication.php
··· 43 43 'order/(?P<engine>[^/]+)/' => 'PhabricatorSearchOrderController', 44 44 'rel/(?P<relationshipKey>[^/]+)/(?P<sourcePHID>[^/]+)/' 45 45 => 'PhabricatorSearchRelationshipController', 46 + 'source/(?P<relationshipKey>[^/]+)/(?P<sourcePHID>[^/]+)/' 47 + => 'PhabricatorSearchRelationshipSourceController', 46 48 ), 47 49 ); 48 50 }
+31
src/applications/search/controller/PhabricatorSearchBaseController.php
··· 2 2 3 3 abstract class PhabricatorSearchBaseController extends PhabricatorController { 4 4 5 + 5 6 const ACTION_ATTACH = 'attach'; 6 7 const ACTION_MERGE = 'merge'; 7 8 const ACTION_DEPENDENCIES = 'dependencies'; 8 9 const ACTION_BLOCKS = 'blocks'; 9 10 const ACTION_EDGE = 'edge'; 11 + 12 + protected function loadRelationshipObject() { 13 + $request = $this->getRequest(); 14 + $viewer = $this->getViewer(); 15 + 16 + $phid = $request->getURIData('sourcePHID'); 17 + 18 + return id(new PhabricatorObjectQuery()) 19 + ->setViewer($viewer) 20 + ->withPHIDs(array($phid)) 21 + ->requireCapabilities( 22 + array( 23 + PhabricatorPolicyCapability::CAN_VIEW, 24 + PhabricatorPolicyCapability::CAN_EDIT, 25 + )) 26 + ->executeOne(); 27 + } 28 + 29 + protected function loadRelationship($object) { 30 + $request = $this->getRequest(); 31 + $viewer = $this->getViewer(); 32 + 33 + $relationship_key = $request->getURIData('relationshipKey'); 34 + 35 + $list = PhabricatorObjectRelationshipList::newForObject( 36 + $viewer, 37 + $object); 38 + 39 + return $list->getRelationship($relationship_key); 40 + } 10 41 11 42 }
+5 -33
src/applications/search/controller/PhabricatorSearchRelationshipController.php
··· 6 6 public function handleRequest(AphrontRequest $request) { 7 7 $viewer = $this->getViewer(); 8 8 9 - $phid = $request->getURIData('sourcePHID'); 10 - $object = id(new PhabricatorObjectQuery()) 11 - ->setViewer($viewer) 12 - ->withPHIDs(array($phid)) 13 - ->requireCapabilities( 14 - array( 15 - PhabricatorPolicyCapability::CAN_VIEW, 16 - PhabricatorPolicyCapability::CAN_EDIT, 17 - )) 18 - ->executeOne(); 9 + $object = $this->loadRelationshipObject(); 19 10 if (!$object) { 20 11 return new Aphront404Response(); 21 12 } 22 13 23 - $list = PhabricatorObjectRelationshipList::newForObject( 24 - $viewer, 25 - $object); 26 - 27 - $relationship_key = $request->getURIData('relationshipKey'); 28 - $relationship = $list->getRelationship($relationship_key); 14 + $relationship = $this->loadRelationship($object); 29 15 if (!$relationship) { 30 16 return new Aphront404Response(); 31 17 } ··· 135 121 $dialog_button = $relationship->getDialogButtonText(); 136 122 $dialog_instructions = $relationship->getDialogInstructionsText(); 137 123 138 - // TODO: Remove this, this is just legacy support. 139 - $legacy_kinds = array( 140 - ManiphestTaskHasCommitEdgeType::EDGECONST => 'CMIT', 141 - ManiphestTaskHasMockEdgeType::EDGECONST => 'MOCK', 142 - ManiphestTaskHasRevisionEdgeType::EDGECONST => 'DREV', 143 - ManiphestTaskDependsOnTaskEdgeType::EDGECONST => 'TASK', 144 - ManiphestTaskDependedOnByTaskEdgeType::EDGECONST => 'TASK', 145 - ); 146 - 147 - $edge_type = $relationship->getEdgeConstant(); 148 - $legacy_kind = idx($legacy_kinds, $edge_type); 149 - if (!$legacy_kind) { 150 - throw new Exception( 151 - pht('Only specific legacy relationships are supported!')); 152 - } 124 + $source_uri = $relationship->getSourceURI($object); 153 125 154 126 return id(new PhabricatorObjectSelectorDialog()) 155 127 ->setUser($viewer) ··· 157 129 ->setHandles($handles) 158 130 ->setFilters($filters) 159 131 ->setSelectedFilter('created') 160 - ->setExcluded($phid) 132 + ->setExcluded($src_phid) 161 133 ->setCancelURI($done_uri) 162 - ->setSearchURI("/search/select/{$legacy_kind}/edge/") 134 + ->setSearchURI($source_uri) 163 135 ->setTitle($dialog_title) 164 136 ->setHeader($dialog_header) 165 137 ->setButtonText($dialog_button)
+89
src/applications/search/controller/PhabricatorSearchRelationshipSourceController.php
··· 1 + <?php 2 + 3 + final class PhabricatorSearchRelationshipSourceController 4 + extends PhabricatorSearchBaseController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $request->getViewer(); 8 + 9 + $object = $this->loadRelationshipObject(); 10 + if (!$object) { 11 + return new Aphront404Response(); 12 + } 13 + 14 + $relationship = $this->loadRelationship($object); 15 + if (!$relationship) { 16 + return new Aphront404Response(); 17 + } 18 + 19 + $source = $relationship->newSource(); 20 + $query = new PhabricatorSavedQuery(); 21 + 22 + $action = $request->getURIData('action'); 23 + $query_str = $request->getStr('query'); 24 + $filter = $request->getStr('filter'); 25 + 26 + $query->setEngineClassName('PhabricatorSearchApplicationSearchEngine'); 27 + $query->setParameter('query', $query_str); 28 + 29 + $types = $source->getResultPHIDTypes(); 30 + $query->setParameter('types', $types); 31 + 32 + $status_open = PhabricatorSearchRelationship::RELATIONSHIP_OPEN; 33 + 34 + switch ($filter) { 35 + case 'assigned': 36 + $query->setParameter('ownerPHIDs', array($viewer->getPHID())); 37 + $query->setParameter('statuses', array($status_open)); 38 + break; 39 + case 'created'; 40 + $query->setParameter('authorPHIDs', array($viewer->getPHID())); 41 + $query->setParameter('statuses', array($status_open)); 42 + break; 43 + case 'open': 44 + $query->setParameter('statuses', array($status_open)); 45 + break; 46 + } 47 + 48 + $query->setParameter('excludePHIDs', array($request->getStr('exclude'))); 49 + 50 + $capabilities = $relationship->getRequiredRelationshipCapabilities(); 51 + 52 + $results = id(new PhabricatorSearchDocumentQuery()) 53 + ->setViewer($viewer) 54 + ->requireObjectCapabilities($capabilities) 55 + ->withSavedQuery($query) 56 + ->setOffset(0) 57 + ->setLimit(100) 58 + ->execute(); 59 + 60 + $phids = array_fill_keys(mpull($results, 'getPHID'), true); 61 + $phids += $this->queryObjectNames($query_str, $capabilities); 62 + 63 + $phids = array_keys($phids); 64 + $handles = $viewer->loadHandles($phids); 65 + 66 + $data = array(); 67 + foreach ($handles as $handle) { 68 + $view = new PhabricatorHandleObjectSelectorDataView($handle); 69 + $data[] = $view->renderData(); 70 + } 71 + 72 + return id(new AphrontAjaxResponse())->setContent($data); 73 + } 74 + 75 + private function queryObjectNames($query, $capabilities) { 76 + $request = $this->getRequest(); 77 + $viewer = $request->getUser(); 78 + 79 + $objects = id(new PhabricatorObjectQuery()) 80 + ->setViewer($viewer) 81 + ->requireCapabilities($capabilities) 82 + ->withTypes(array($request->getURIData('type'))) 83 + ->withNames(array($query)) 84 + ->execute(); 85 + 86 + return mpull($objects, 'getPHID'); 87 + } 88 + 89 + }
+12
src/applications/search/relationship/DifferentialRevisionRelationshipSource.php
··· 1 + <?php 2 + 3 + final class DifferentialRevisionRelationshipSource 4 + extends PhabricatorObjectRelationshipSource { 5 + 6 + public function getResultPHIDTypes() { 7 + return array( 8 + DifferentialRevisionPHIDType::TYPECONST, 9 + ); 10 + } 11 + 12 + }
+12
src/applications/search/relationship/DiffusionCommitRelationshipSource.php
··· 1 + <?php 2 + 3 + final class DiffusionCommitRelationshipSource 4 + extends PhabricatorObjectRelationshipSource { 5 + 6 + public function getResultPHIDTypes() { 7 + return array( 8 + PhabricatorRepositoryCommitPHIDType::TYPECONST, 9 + ); 10 + } 11 + 12 + }
+12
src/applications/search/relationship/ManiphestTaskRelationshipSource.php
··· 1 + <?php 2 + 3 + final class ManiphestTaskRelationshipSource 4 + extends PhabricatorObjectRelationshipSource { 5 + 6 + public function getResultPHIDTypes() { 7 + return array( 8 + ManiphestTaskPHIDType::TYPECONST, 9 + ); 10 + } 11 + 12 + }
+19
src/applications/search/relationship/PhabricatorObjectRelationship.php
··· 47 47 PhabricatorPolicyCapability::CAN_EDIT); 48 48 } 49 49 50 + public function getRequiredRelationshipCapabilities() { 51 + return array( 52 + PhabricatorPolicyCapability::CAN_VIEW, 53 + ); 54 + } 55 + 56 + final public function newSource() { 57 + return $this->newRelationshipSource(); 58 + } 59 + 60 + abstract protected function newRelationshipSource(); 61 + 62 + final public function getSourceURI($object) { 63 + $relationship_key = $this->getRelationshipConstant(); 64 + $object_phid = $object->getPHID(); 65 + 66 + return "/search/source/{$relationship_key}/{$object_phid}/"; 67 + } 68 + 50 69 final public function newAction($object) { 51 70 $is_enabled = $this->isActionEnabled($object); 52 71 $action_uri = $this->getActionURI($object);
+7
src/applications/search/relationship/PhabricatorObjectRelationshipSource.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorObjectRelationshipSource extends Phobject { 4 + 5 + abstract public function getResultPHIDTypes(); 6 + 7 + }
+12
src/applications/search/relationship/PholioMockRelationshipSource.php
··· 1 + <?php 2 + 3 + final class PholioMockRelationshipSource 4 + extends PhabricatorObjectRelationshipSource { 5 + 6 + public function getResultPHIDTypes() { 7 + return array( 8 + PholioMockPHIDType::TYPECONST, 9 + ); 10 + } 11 + 12 + }