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

Fix and improve Full Transactions View

Summary:
Fix T16483.

1. Fix the page to actually load things
2. Add a way to query for a specific object
3. Add link from object pages to the full history (under "Advanced")

Test Plan:
- Visit `/feed/transactions/` and see looots of entries.
- enter object names and phids into the query, list is filtered to these objects only.
- Visit a random task object, hit Advanced -> View All Transactions, see full history including things that are normally hidden.

Reviewers: aklapper, valerio.bozzolan, O1 Blessed Committers, mainframe98

Reviewed By: O1 Blessed Committers, mainframe98

Subscribers: mainframe98, tobiaswiese, Matthew, Cigaryno

Maniphest Tasks: T16483

Differential Revision: https://we.phorge.it/D26732

Aviv Eyal 30ef575d b8ca0550

+86 -38
-22
src/applications/base/PhabricatorApplication.php
··· 470 470 return $result; 471 471 } 472 472 473 - /** 474 - * Determine if an application is enabled at all, and if a viewer is given 475 - * if the application is available to a viewer, by application class name. 476 - * 477 - * To check if an application is enabled at all, use 478 - * @{method:isClassInstalled}. 479 - * 480 - * @param class-string<PhabricatorApplication> $class Application class name. 481 - * @param PhabricatorUser|null $viewer Viewing user. 482 - * @return bool True if the class is enabled or if the enabled application is 483 - * available to the viewer when a viewer is given. 484 - * @task meta 485 - */ 486 - final public static function isClassInstalledForViewerIfAny( 487 - $class, 488 - ?PhabricatorUser $viewer) { 489 - 490 - return $viewer 491 - ? self::isClassInstalledForViewer($class, $viewer) 492 - : self::isClassInstalled($class); 493 - } 494 - 495 473 /* -( PhabricatorPolicyInterface )----------------------------------------- */ 496 474 497 475
+1 -1
src/applications/feed/application/PhabricatorFeedApplication.php
··· 33 33 '(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorFeedListController', 34 34 'transactions/' => array( 35 35 $this->getQueryRoutePattern() 36 - => 'PhabricatorFeedTransactionListController', 36 + => PhabricatorFeedTransactionListController::class, 37 37 ), 38 38 ), 39 39 );
+57 -2
src/applications/feed/query/PhabricatorFeedTransactionQuery.php
··· 6 6 private $phids; 7 7 private $authorPHIDs; 8 8 private $objectTypes; 9 + private $objectPHIDs; 9 10 private $createdMin; 10 11 private $createdMax; 11 12 ··· 24 25 return $this; 25 26 } 26 27 28 + public function withObjectPHIDs(array $object_phids) { 29 + $this->objectPHIDs = $object_phids; 30 + return $this; 31 + } 32 + 27 33 public function withDateCreatedBetween($min, $max) { 28 34 $this->createdMin = $min; 29 35 $this->createdMax = $max; ··· 39 45 } 40 46 41 47 protected function loadPage() { 48 + $this->normalizeObjectPHIDs(); 42 49 $queries = $this->newTransactionQueries(); 43 50 44 51 $xactions = array(); ··· 80 87 81 88 $xaction_phids = $this->phids; 82 89 $author_phids = $this->authorPHIDs; 90 + $object_phids = $this->objectPHIDs; 83 91 84 92 foreach ($queries as $query) { 85 93 $query->withDateCreatedBetween($created_min, $created_max); ··· 92 100 $query->withAuthorPHIDs($author_phids); 93 101 } 94 102 103 + if ($object_phids !== null) { 104 + $query->withObjectPHIDs($object_phids); 105 + } 106 + 95 107 if ($limit !== null) { 96 108 $query->setLimit($limit); 97 109 } ··· 162 174 foreach ($queries as $key => $query) { 163 175 $app = $query->getQueryApplicationClass(); 164 176 if ($app !== null && 165 - PhabricatorApplication::isClassInstalledForViewerIfAny($app, 166 - $viewer)) { 177 + !PhabricatorApplication::isClassInstalledForViewer($app, $viewer)) { 167 178 unset($queries[$key]); 168 179 } 169 180 } ··· 222 233 protected function applyExternalCursorConstraintsToQuery( 223 234 PhabricatorCursorPagedPolicyAwareQuery $subquery, 224 235 $cursor) { 236 + 225 237 $subquery->withPHIDs(array($cursor)); 238 + } 239 + 240 + private function normalizeObjectPHIDs() { 241 + if (!$this->objectPHIDs) { 242 + return; 243 + } 244 + 245 + $have_non_phids = false; 246 + foreach ($this->objectPHIDs as $name) { 247 + if (strncmp($name, 'PHID-', 5)) { 248 + $have_non_phids = true; 249 + break; 250 + } 251 + } 252 + 253 + if ($have_non_phids) { 254 + 255 + // "Names" field in ObjectQuery also handles PHIDs. 256 + $objects = id(new PhabricatorObjectQuery()) 257 + ->setViewer($this->getViewer()) 258 + ->withNames($this->objectPHIDs) 259 + ->execute(); 260 + 261 + if (!$objects) { 262 + // nothing resolved to anything. 263 + throw new PhabricatorSearchConstraintException( 264 + pht("objectPHID inputs didn't match any known objects.")); 265 + } 266 + 267 + $phids = mpull($objects, 'getPHID'); 268 + 269 + } else { 270 + $phids = $this->objectPHIDs; 271 + } 272 + 273 + $phid_types = array(); 274 + foreach ($phids as $phid) { 275 + $phid_type = phid_get_type($phid); 276 + $phid_types[$phid_type] = $phid_type; 277 + } 278 + 279 + $this->objectPHIDs = $phids; 280 + $this->objectTypes = $phid_types; 226 281 } 227 282 228 283 }
+23 -13
src/applications/feed/query/PhabricatorFeedTransactionSearchEngine.php
··· 21 21 ->setLabel(pht('Authors')) 22 22 ->setKey('authorPHIDs') 23 23 ->setAliases(array('author', 'authors')), 24 + id(new PhabricatorSearchStringListField()) 25 + ->setLabel(pht('Object PHIDs')) 26 + ->setKey('objectPHIDs') 27 + ->setAliases(array('objectPhid')) 28 + ->setPlaceholder(pht('Comma separated list of PHIDs or object names.')), 24 29 id(new PhabricatorSearchDatasourceField()) 25 30 ->setLabel(pht('Object Types')) 26 31 ->setKey('objectTypes') ··· 44 49 45 50 if ($map['objectTypes']) { 46 51 $query->withObjectTypes($map['objectTypes']); 52 + } 53 + 54 + if ($map['objectPHIDs']) { 55 + $query->withObjectPHIDs($map['objectPHIDs']); 47 56 } 48 57 49 58 $created_min = $map['createdStart']; ··· 91 100 } 92 101 93 102 /** 94 - * @param array<PhabricatorApplicationTransaction> $objects 103 + * @param array<PhabricatorApplicationTransaction> $xactions 95 104 * @param PhabricatorSavedQuery $query 96 105 * @param array<PhabricatorObjectHandle> $handles 97 106 */ 98 107 protected function renderResultList( 99 - array $objects, 108 + array $xactions, 100 109 PhabricatorSavedQuery $query, 101 110 array $handles) { 102 - assert_instances_of($objects, PhabricatorApplicationTransaction::class); 111 + 112 + assert_instances_of($xactions, PhabricatorApplicationTransaction::class); 103 113 104 114 $viewer = $this->requireViewer(); 105 115 106 116 $handle_phids = array(); 107 - foreach ($objects as $object) { 108 - $author_phid = $object->getAuthorPHID(); 117 + foreach ($xactions as $xaction) { 118 + $author_phid = $xaction->getAuthorPHID(); 109 119 if ($author_phid !== null) { 110 120 $handle_phids[] = $author_phid; 111 121 } 112 - $object_phid = $object->getObjectPHID(); 122 + $object_phid = $xaction->getObjectPHID(); 113 123 if ($object_phid !== null) { 114 124 $handle_phids[] = $object_phid; 115 125 } ··· 118 128 $handles = $viewer->loadHandles($handle_phids); 119 129 120 130 $rows = array(); 121 - foreach ($objects as $object) { 122 - $author_phid = $object->getAuthorPHID(); 123 - $object_phid = $object->getObjectPHID(); 131 + foreach ($xactions as $xaction) { 132 + $author_phid = $xaction->getAuthorPHID(); 133 + $object_phid = $xaction->getObjectPHID(); 124 134 125 135 try { 126 - $title = $object->getTitle(); 127 - } catch (Exception $ex) { 136 + $title = $xaction->getTitle(); 137 + } catch (Throwable $ex) { 128 138 $title = null; 129 139 } 130 140 ··· 132 142 $handles[$author_phid]->renderLink(), 133 143 $handles[$object_phid]->renderLink(), 134 144 AphrontTableView::renderSingleDisplayLine($title), 135 - phabricator_datetime($object->getDateCreated(), $viewer), 145 + phabricator_datetime($xaction->getDateCreated(), $viewer), 136 146 ); 137 147 } 138 148 ··· 214 224 $description = $xaction 215 225 ->setRenderingTarget(PhabricatorApplicationTransaction::TARGET_TEXT) 216 226 ->getTitle(); 217 - } catch (Exception $ex) { 227 + } catch (Throwable $ex) { 218 228 $description = null; 219 229 } 220 230 $xaction->setRenderingTarget($old_target);
+5
src/applications/system/events/PhabricatorSystemDebugUIEventListener.php
··· 44 44 ->setName(pht('View Hovercard')) 45 45 ->setHref(urisprintf('/search/hovercard/?names=%s', $phid)); 46 46 47 + $submenu[] = id(new PhabricatorActionView()) 48 + ->setIcon('fa-list') 49 + ->setName(pht('View full transaction history')) 50 + ->setHref(urisprintf('/feed/transactions?objectPHIDs=%s', $phid)); 51 + 47 52 if ($object instanceof DifferentialRevision) { 48 53 $submenu[] = id(new PhabricatorActionView()) 49 54 ->setIcon('fa-database')