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

Remove "willRenderTimeline()" from ApplicationTransactionInterface

Summary:
Depends on D19914. Ref T11351. Some of the Phoilo rabbit holes go very deep.

`PhabricatorApplicationTransactionInterface` currently requires you to implement `willRenderTimeline()`. Almost every object just implements this as `return $timeline`; only Pholio, Diffusion, and Differential specialize it. In all cases, they are specializing it mostly to render inline comments.

The actual implementations are a bit of a weird mess and the way the data is threaded through the call stack is weird and not very modern.

Try to clean this up:

- Stop requiring `willRenderTimeline()` to be implemented.
- Stop requiring `getApplicationTransactionViewObject()` to be implemented (only the three above, plus Legalpad, implement this, and Legalpad's implementation is a no-op). These two methods are inherently pretty coupled for almost any reasonable thing you might want to do with the timeline.
- Simplify the handling of "renderdata" and call it "View Data". This is additional information about the current view of the transaction timeline that is required to render it correctly. This is only used in Differential, to decide if we can link an inline comment to an anchor on the same page or should link it to another page. We could perhaps do this on the client instead, but having this data doesn't seem inherently bad to me.
- If objects want to customize timeline rendering, they now implement `PhabricatorTimelineInterface` and provide a `TimelineEngine` which gets a nice formal stack.

This leaves a lot of empty `willRenderTimeline()` implementations hanging around. I'll remove these in the next change, it's just going to be deleting a couple dozen copies of an identical empty method implementation.

Test Plan:
- Viewed audits, revisions, and mocks with inline comments.
- Used "Show Older" to page a revision back in history (this is relevant for "View Data").
- Grepped for symbols: willRenderTimeline, getApplicationTransactionViewObject, Legalpad classes.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T11351

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

+365 -229
+9 -9
resources/celerity/map.php
··· 10 10 'conpherence.pkg.css' => 'e68cf1fa', 11 11 'conpherence.pkg.js' => '15191c65', 12 12 'core.pkg.css' => '9d1148a4', 13 - 'core.pkg.js' => '4bde473b', 13 + 'core.pkg.js' => 'bd89cb1d', 14 14 'differential.pkg.css' => '06dc617c', 15 15 'differential.pkg.js' => 'ef0b989b', 16 16 'diffusion.pkg.css' => 'a2d17c7d', ··· 425 425 'rsrc/js/application/transactions/behavior-comment-actions.js' => '59e27e74', 426 426 'rsrc/js/application/transactions/behavior-reorder-configs.js' => 'd7a74243', 427 427 'rsrc/js/application/transactions/behavior-reorder-fields.js' => 'b59e1e96', 428 - 'rsrc/js/application/transactions/behavior-show-older-transactions.js' => '8f29b364', 428 + 'rsrc/js/application/transactions/behavior-show-older-transactions.js' => '0e1eca96', 429 429 'rsrc/js/application/transactions/behavior-transaction-comment-form.js' => 'b23b49e6', 430 430 'rsrc/js/application/transactions/behavior-transaction-list.js' => '1f6794f6', 431 431 'rsrc/js/application/typeahead/behavior-typeahead-browse.js' => '635de1ec', ··· 639 639 'javelin-behavior-phabricator-remarkup-assist' => 'acd29eee', 640 640 'javelin-behavior-phabricator-reveal-content' => '60821bc7', 641 641 'javelin-behavior-phabricator-search-typeahead' => 'c3e917d9', 642 - 'javelin-behavior-phabricator-show-older-transactions' => '8f29b364', 642 + 'javelin-behavior-phabricator-show-older-transactions' => '0e1eca96', 643 643 'javelin-behavior-phabricator-tooltips' => 'c420b0b9', 644 644 'javelin-behavior-phabricator-transaction-comment-form' => 'b23b49e6', 645 645 'javelin-behavior-phabricator-transaction-list' => '1f6794f6', ··· 950 950 'javelin-install', 951 951 'phuix-button-view', 952 952 ), 953 + '0e1eca96' => array( 954 + 'javelin-behavior', 955 + 'javelin-stratcom', 956 + 'javelin-dom', 957 + 'phabricator-busy', 958 + ), 953 959 '0f764c35' => array( 954 960 'javelin-install', 955 961 'javelin-util', ··· 1580 1586 ), 1581 1587 '8e1baf68' => array( 1582 1588 'phui-button-css', 1583 - ), 1584 - '8f29b364' => array( 1585 - 'javelin-behavior', 1586 - 'javelin-stratcom', 1587 - 'javelin-dom', 1588 - 'phabricator-busy', 1589 1589 ), 1590 1590 '8ff5e24c' => array( 1591 1591 'javelin-behavior',
+14 -2
src/__phutil_library_map__.php
··· 647 647 'DifferentialRevisionSummaryTransaction' => 'applications/differential/xaction/DifferentialRevisionSummaryTransaction.php', 648 648 'DifferentialRevisionTestPlanHeraldField' => 'applications/differential/herald/DifferentialRevisionTestPlanHeraldField.php', 649 649 'DifferentialRevisionTestPlanTransaction' => 'applications/differential/xaction/DifferentialRevisionTestPlanTransaction.php', 650 + 'DifferentialRevisionTimelineEngine' => 'applications/differential/engine/DifferentialRevisionTimelineEngine.php', 650 651 'DifferentialRevisionTitleHeraldField' => 'applications/differential/herald/DifferentialRevisionTitleHeraldField.php', 651 652 'DifferentialRevisionTitleTransaction' => 'applications/differential/xaction/DifferentialRevisionTitleTransaction.php', 652 653 'DifferentialRevisionTransactionType' => 'applications/differential/xaction/DifferentialRevisionTransactionType.php', ··· 769 770 'DiffusionCommitSearchConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionCommitSearchConduitAPIMethod.php', 770 771 'DiffusionCommitStateTransaction' => 'applications/diffusion/xaction/DiffusionCommitStateTransaction.php', 771 772 'DiffusionCommitTagsController' => 'applications/diffusion/controller/DiffusionCommitTagsController.php', 773 + 'DiffusionCommitTimelineEngine' => 'applications/diffusion/engine/DiffusionCommitTimelineEngine.php', 772 774 'DiffusionCommitTransactionType' => 'applications/diffusion/xaction/DiffusionCommitTransactionType.php', 773 775 'DiffusionCommitVerifyTransaction' => 'applications/diffusion/xaction/DiffusionCommitVerifyTransaction.php', 774 776 'DiffusionCompareController' => 'applications/diffusion/controller/DiffusionCompareController.php', ··· 1630 1632 'LegalpadTransaction' => 'applications/legalpad/storage/LegalpadTransaction.php', 1631 1633 'LegalpadTransactionComment' => 'applications/legalpad/storage/LegalpadTransactionComment.php', 1632 1634 'LegalpadTransactionQuery' => 'applications/legalpad/query/LegalpadTransactionQuery.php', 1633 - 'LegalpadTransactionView' => 'applications/legalpad/view/LegalpadTransactionView.php', 1634 1635 'LiskChunkTestCase' => 'infrastructure/storage/lisk/__tests__/LiskChunkTestCase.php', 1635 1636 'LiskDAO' => 'infrastructure/storage/lisk/LiskDAO.php', 1636 1637 'LiskDAOTestCase' => 'infrastructure/storage/lisk/__tests__/LiskDAOTestCase.php', ··· 4433 4434 'PhabricatorStandardCustomFieldUsers' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldUsers.php', 4434 4435 'PhabricatorStandardPageView' => 'view/page/PhabricatorStandardPageView.php', 4435 4436 'PhabricatorStandardSelectCustomFieldDatasource' => 'infrastructure/customfield/datasource/PhabricatorStandardSelectCustomFieldDatasource.php', 4437 + 'PhabricatorStandardTimelineEngine' => 'applications/transactions/engine/PhabricatorStandardTimelineEngine.php', 4436 4438 'PhabricatorStaticEditField' => 'applications/transactions/editfield/PhabricatorStaticEditField.php', 4437 4439 'PhabricatorStatusController' => 'applications/system/controller/PhabricatorStatusController.php', 4438 4440 'PhabricatorStatusUIExample' => 'applications/uiexample/examples/PhabricatorStatusUIExample.php', ··· 4532 4534 'PhabricatorTimeFormatSetting' => 'applications/settings/setting/PhabricatorTimeFormatSetting.php', 4533 4535 'PhabricatorTimeGuard' => 'infrastructure/time/PhabricatorTimeGuard.php', 4534 4536 'PhabricatorTimeTestCase' => 'infrastructure/time/__tests__/PhabricatorTimeTestCase.php', 4537 + 'PhabricatorTimelineEngine' => 'applications/transactions/engine/PhabricatorTimelineEngine.php', 4538 + 'PhabricatorTimelineInterface' => 'applications/transactions/interface/PhabricatorTimelineInterface.php', 4535 4539 'PhabricatorTimezoneIgnoreOffsetSetting' => 'applications/settings/setting/PhabricatorTimezoneIgnoreOffsetSetting.php', 4536 4540 'PhabricatorTimezoneSetting' => 'applications/settings/setting/PhabricatorTimezoneSetting.php', 4537 4541 'PhabricatorTimezoneSetupCheck' => 'applications/config/check/PhabricatorTimezoneSetupCheck.php', ··· 4871 4875 'PholioMockSearchEngine' => 'applications/pholio/query/PholioMockSearchEngine.php', 4872 4876 'PholioMockStatusTransaction' => 'applications/pholio/xaction/PholioMockStatusTransaction.php', 4873 4877 'PholioMockThumbGridView' => 'applications/pholio/view/PholioMockThumbGridView.php', 4878 + 'PholioMockTimelineEngine' => 'applications/pholio/engine/PholioMockTimelineEngine.php', 4874 4879 'PholioMockTransactionType' => 'applications/pholio/xaction/PholioMockTransactionType.php', 4875 4880 'PholioMockViewController' => 'applications/pholio/controller/PholioMockViewController.php', 4876 4881 'PholioRemarkupRule' => 'applications/pholio/remarkup/PholioRemarkupRule.php', ··· 5991 5996 'PhabricatorSubscribableInterface', 5992 5997 'PhabricatorCustomFieldInterface', 5993 5998 'PhabricatorApplicationTransactionInterface', 5999 + 'PhabricatorTimelineInterface', 5994 6000 'PhabricatorMentionableInterface', 5995 6001 'PhabricatorDestructibleInterface', 5996 6002 'PhabricatorProjectInterface', ··· 6072 6078 'DifferentialRevisionSummaryTransaction' => 'DifferentialRevisionTransactionType', 6073 6079 'DifferentialRevisionTestPlanHeraldField' => 'DifferentialRevisionHeraldField', 6074 6080 'DifferentialRevisionTestPlanTransaction' => 'DifferentialRevisionTransactionType', 6081 + 'DifferentialRevisionTimelineEngine' => 'PhabricatorTimelineEngine', 6075 6082 'DifferentialRevisionTitleHeraldField' => 'DifferentialRevisionHeraldField', 6076 6083 'DifferentialRevisionTitleTransaction' => 'DifferentialRevisionTransactionType', 6077 6084 'DifferentialRevisionTransactionType' => 'PhabricatorModularTransactionType', ··· 6194 6201 'DiffusionCommitSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 6195 6202 'DiffusionCommitStateTransaction' => 'DiffusionCommitTransactionType', 6196 6203 'DiffusionCommitTagsController' => 'DiffusionController', 6204 + 'DiffusionCommitTimelineEngine' => 'PhabricatorTimelineEngine', 6197 6205 'DiffusionCommitTransactionType' => 'PhabricatorModularTransactionType', 6198 6206 'DiffusionCommitVerifyTransaction' => 'DiffusionCommitAuditTransaction', 6199 6207 'DiffusionCompareController' => 'DiffusionController', ··· 7201 7209 'LegalpadTransaction' => 'PhabricatorModularTransaction', 7202 7210 'LegalpadTransactionComment' => 'PhabricatorApplicationTransactionComment', 7203 7211 'LegalpadTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 7204 - 'LegalpadTransactionView' => 'PhabricatorApplicationTransactionView', 7205 7212 'LiskChunkTestCase' => 'PhabricatorTestCase', 7206 7213 'LiskDAO' => array( 7207 7214 'Phobject', ··· 10079 10086 'HarbormasterBuildkiteBuildableInterface', 10080 10087 'PhabricatorCustomFieldInterface', 10081 10088 'PhabricatorApplicationTransactionInterface', 10089 + 'PhabricatorTimelineInterface', 10082 10090 'PhabricatorFulltextInterface', 10083 10091 'PhabricatorFerretInterface', 10084 10092 'PhabricatorConduitResultInterface', ··· 10469 10477 'AphrontResponseProducerInterface', 10470 10478 ), 10471 10479 'PhabricatorStandardSelectCustomFieldDatasource' => 'PhabricatorTypeaheadDatasource', 10480 + 'PhabricatorStandardTimelineEngine' => 'PhabricatorTimelineEngine', 10472 10481 'PhabricatorStaticEditField' => 'PhabricatorEditField', 10473 10482 'PhabricatorStatusController' => 'PhabricatorController', 10474 10483 'PhabricatorStatusUIExample' => 'PhabricatorUIExample', ··· 10567 10576 'PhabricatorTimeFormatSetting' => 'PhabricatorSelectSetting', 10568 10577 'PhabricatorTimeGuard' => 'Phobject', 10569 10578 'PhabricatorTimeTestCase' => 'PhabricatorTestCase', 10579 + 'PhabricatorTimelineEngine' => 'Phobject', 10570 10580 'PhabricatorTimezoneIgnoreOffsetSetting' => 'PhabricatorInternalSetting', 10571 10581 'PhabricatorTimezoneSetting' => 'PhabricatorOptionGroupSetting', 10572 10582 'PhabricatorTimezoneSetupCheck' => 'PhabricatorSetupCheck', ··· 10967 10977 'PhabricatorTokenReceiverInterface', 10968 10978 'PhabricatorFlaggableInterface', 10969 10979 'PhabricatorApplicationTransactionInterface', 10980 + 'PhabricatorTimelineInterface', 10970 10981 'PhabricatorProjectInterface', 10971 10982 'PhabricatorDestructibleInterface', 10972 10983 'PhabricatorSpacesInterface', ··· 11001 11012 'PholioMockSearchEngine' => 'PhabricatorApplicationSearchEngine', 11002 11013 'PholioMockStatusTransaction' => 'PholioMockTransactionType', 11003 11014 'PholioMockThumbGridView' => 'AphrontView', 11015 + 'PholioMockTimelineEngine' => 'PhabricatorTimelineEngine', 11004 11016 'PholioMockTransactionType' => 'PholioTransactionType', 11005 11017 'PholioMockViewController' => 'PholioController', 11006 11018 'PholioRemarkupRule' => 'PhabricatorObjectRemarkupRule',
-4
src/applications/audit/storage/PhabricatorAuditTransaction.php
··· 32 32 return new PhabricatorAuditTransactionComment(); 33 33 } 34 34 35 - public function getApplicationTransactionViewObject() { 36 - return new PhabricatorAuditTransactionView(); 37 - } 38 - 39 35 public function getRemarkupBlocks() { 40 36 $blocks = parent::getRemarkupBlocks(); 41 37
+1
src/applications/badges/controller/PhabricatorBadgesCommentController.php
··· 51 51 52 52 if ($request->isAjax() && $is_preview) { 53 53 return id(new PhabricatorApplicationTransactionResponse()) 54 + ->setObject($badge) 54 55 ->setViewer($viewer) 55 56 ->setTransactions($xactions) 56 57 ->setIsPreview($is_preview);
+11 -9
src/applications/base/controller/PhabricatorController.php
··· 482 482 PhabricatorApplicationTransactionInterface $object, 483 483 PhabricatorApplicationTransactionQuery $query, 484 484 PhabricatorMarkupEngine $engine = null, 485 - $render_data = array()) { 485 + $view_data = array()) { 486 486 487 - $viewer = $this->getRequest()->getUser(); 487 + $request = $this->getRequest(); 488 + $viewer = $this->getViewer(); 488 489 $xaction = $object->getApplicationTransactionTemplate(); 489 - $view = $xaction->getApplicationTransactionViewObject(); 490 490 491 491 $pager = id(new AphrontCursorPagerView()) 492 - ->readFromRequest($this->getRequest()) 492 + ->readFromRequest($request) 493 493 ->setURI(new PhutilURI( 494 494 '/transactions/showolder/'.$object->getPHID().'/')); 495 495 ··· 500 500 ->executeWithCursorPager($pager); 501 501 $xactions = array_reverse($xactions); 502 502 503 + $timeline_engine = PhabricatorTimelineEngine::newForObject($object) 504 + ->setViewer($viewer) 505 + ->setTransactions($xactions) 506 + ->setViewData($view_data); 507 + 508 + $view = $timeline_engine->buildTimelineView(); 509 + 503 510 if ($engine) { 504 511 foreach ($xactions as $xaction) { 505 512 if ($xaction->getComment()) { ··· 513 520 } 514 521 515 522 $timeline = $view 516 - ->setUser($viewer) 517 - ->setObjectPHID($object->getPHID()) 518 - ->setTransactions($xactions) 519 523 ->setPager($pager) 520 - ->setRenderData($render_data) 521 524 ->setQuoteTargetID($this->getRequest()->getStr('quoteTargetID')) 522 525 ->setQuoteRef($this->getRequest()->getStr('quoteRef')); 523 - $object->willRenderTimeline($timeline, $this->getRequest()); 524 526 525 527 return $timeline; 526 528 }
+2 -6
src/applications/config/controller/PhabricatorConfigHistoryController.php
··· 16 16 17 17 $xaction = $object->getApplicationTransactionTemplate(); 18 18 19 - $view = $xaction->getApplicationTransactionViewObject(); 20 - 21 - $timeline = $view 22 - ->setUser($viewer) 19 + $timeline = id(new PhabricatorApplicationTransactionView()) 20 + ->setViewer($viewer) 23 21 ->setTransactions($xactions) 24 22 ->setRenderAsFeed(true) 25 23 ->setObjectPHID(PhabricatorPHIDConstants::PHID_VOID); 26 24 27 25 $timeline->setShouldTerminate(true); 28 - 29 - $object->willRenderTimeline($timeline, $this->getRequest()); 30 26 31 27 $title = pht('Settings History'); 32 28 $header = $this->buildHeaderView($title);
+78
src/applications/differential/engine/DifferentialRevisionTimelineEngine.php
··· 1 + <?php 2 + 3 + final class DifferentialRevisionTimelineEngine 4 + extends PhabricatorTimelineEngine { 5 + 6 + protected function newTimelineView() { 7 + $viewer = $this->getViewer(); 8 + $xactions = $this->getTransactions(); 9 + $revision = $this->getObject(); 10 + 11 + $view_data = $this->getViewData(); 12 + if (!$view_data) { 13 + $view_data = array(); 14 + } 15 + 16 + $left = idx($view_data, 'left'); 17 + $right = idx($view_data, 'right'); 18 + 19 + $diffs = id(new DifferentialDiffQuery()) 20 + ->setViewer($viewer) 21 + ->withIDs(array($left, $right)) 22 + ->execute(); 23 + $diffs = mpull($diffs, null, 'getID'); 24 + $left_diff = $diffs[$left]; 25 + $right_diff = $diffs[$right]; 26 + 27 + $old_ids = idx($view_data, 'old'); 28 + $new_ids = idx($view_data, 'new'); 29 + $old_ids = array_filter(explode(',', $old_ids)); 30 + $new_ids = array_filter(explode(',', $new_ids)); 31 + 32 + $type_inline = DifferentialTransaction::TYPE_INLINE; 33 + $changeset_ids = array_merge($old_ids, $new_ids); 34 + $inlines = array(); 35 + foreach ($xactions as $xaction) { 36 + if ($xaction->getTransactionType() == $type_inline) { 37 + $inlines[] = $xaction->getComment(); 38 + $changeset_ids[] = $xaction->getComment()->getChangesetID(); 39 + } 40 + } 41 + 42 + if ($changeset_ids) { 43 + $changesets = id(new DifferentialChangesetQuery()) 44 + ->setViewer($viewer) 45 + ->withIDs($changeset_ids) 46 + ->execute(); 47 + $changesets = mpull($changesets, null, 'getID'); 48 + } else { 49 + $changesets = array(); 50 + } 51 + 52 + foreach ($inlines as $key => $inline) { 53 + $inlines[$key] = DifferentialInlineComment::newFromModernComment( 54 + $inline); 55 + } 56 + 57 + $query = id(new DifferentialInlineCommentQuery()) 58 + ->needHidden(true) 59 + ->setViewer($viewer); 60 + 61 + // NOTE: This is a bit sketchy: this method adjusts the inlines as a 62 + // side effect, which means it will ultimately adjust the transaction 63 + // comments and affect timeline rendering. 64 + $query->adjustInlinesForChangesets( 65 + $inlines, 66 + array_select_keys($changesets, $old_ids), 67 + array_select_keys($changesets, $new_ids), 68 + $revision); 69 + 70 + return id(new DifferentialTransactionView()) 71 + ->setViewData($view_data) 72 + ->setChangesets($changesets) 73 + ->setRevision($revision) 74 + ->setLeftDiff($left_diff) 75 + ->setRightDiff($right_diff); 76 + } 77 + 78 + }
+10 -67
src/applications/differential/storage/DifferentialRevision.php
··· 11 11 PhabricatorSubscribableInterface, 12 12 PhabricatorCustomFieldInterface, 13 13 PhabricatorApplicationTransactionInterface, 14 + PhabricatorTimelineInterface, 14 15 PhabricatorMentionableInterface, 15 16 PhabricatorDestructibleInterface, 16 17 PhabricatorProjectInterface, ··· 998 999 return new DifferentialTransaction(); 999 1000 } 1000 1001 1001 - public function willRenderTimeline( 1002 - PhabricatorApplicationTransactionView $timeline, 1003 - AphrontRequest $request) { 1004 - $viewer = $request->getViewer(); 1005 - 1006 - $render_data = $timeline->getRenderData(); 1007 - $left = $request->getInt('left', idx($render_data, 'left')); 1008 - $right = $request->getInt('right', idx($render_data, 'right')); 1009 - 1010 - $diffs = id(new DifferentialDiffQuery()) 1011 - ->setViewer($request->getUser()) 1012 - ->withIDs(array($left, $right)) 1013 - ->execute(); 1014 - $diffs = mpull($diffs, null, 'getID'); 1015 - $left_diff = $diffs[$left]; 1016 - $right_diff = $diffs[$right]; 1017 - 1018 - $old_ids = $request->getStr('old', idx($render_data, 'old')); 1019 - $new_ids = $request->getStr('new', idx($render_data, 'new')); 1020 - $old_ids = array_filter(explode(',', $old_ids)); 1021 - $new_ids = array_filter(explode(',', $new_ids)); 1022 - 1023 - $type_inline = DifferentialTransaction::TYPE_INLINE; 1024 - $changeset_ids = array_merge($old_ids, $new_ids); 1025 - $inlines = array(); 1026 - foreach ($timeline->getTransactions() as $xaction) { 1027 - if ($xaction->getTransactionType() == $type_inline) { 1028 - $inlines[] = $xaction->getComment(); 1029 - $changeset_ids[] = $xaction->getComment()->getChangesetID(); 1030 - } 1031 - } 1032 - 1033 - if ($changeset_ids) { 1034 - $changesets = id(new DifferentialChangesetQuery()) 1035 - ->setViewer($request->getUser()) 1036 - ->withIDs($changeset_ids) 1037 - ->execute(); 1038 - $changesets = mpull($changesets, null, 'getID'); 1039 - } else { 1040 - $changesets = array(); 1041 - } 1042 - 1043 - foreach ($inlines as $key => $inline) { 1044 - $inlines[$key] = DifferentialInlineComment::newFromModernComment( 1045 - $inline); 1046 - } 1047 - 1048 - $query = id(new DifferentialInlineCommentQuery()) 1049 - ->needHidden(true) 1050 - ->setViewer($viewer); 1051 - 1052 - // NOTE: This is a bit sketchy: this method adjusts the inlines as a 1053 - // side effect, which means it will ultimately adjust the transaction 1054 - // comments and affect timeline rendering. 1055 - $query->adjustInlinesForChangesets( 1056 - $inlines, 1057 - array_select_keys($changesets, $old_ids), 1058 - array_select_keys($changesets, $new_ids), 1059 - $this); 1060 - 1061 - return $timeline 1062 - ->setChangesets($changesets) 1063 - ->setRevision($this) 1064 - ->setLeftDiff($left_diff) 1065 - ->setRightDiff($right_diff); 1066 - } 1067 - 1068 1002 1069 1003 /* -( PhabricatorDestructibleInterface )----------------------------------- */ 1070 1004 ··· 1205 1139 public function newDraftEngine() { 1206 1140 return new DifferentialRevisionDraftEngine(); 1207 1141 } 1142 + 1143 + 1144 + /* -( PhabricatorTimelineInterface )--------------------------------------- */ 1145 + 1146 + 1147 + public function newTimelineEngine() { 1148 + return new DifferentialRevisionTimelineEngine(); 1149 + } 1150 + 1208 1151 1209 1152 }
-4
src/applications/differential/storage/DifferentialTransaction.php
··· 65 65 return new DifferentialTransactionComment(); 66 66 } 67 67 68 - public function getApplicationTransactionViewObject() { 69 - return new DifferentialTransactionView(); 70 - } 71 - 72 68 public function shouldHide() { 73 69 $old = $this->getOldValue(); 74 70 $new = $this->getNewValue();
-2
src/applications/diffusion/controller/DiffusionCommitController.php
··· 740 740 $commit, 741 741 new PhabricatorAuditTransactionQuery()); 742 742 743 - $commit->willRenderTimeline($timeline, $this->getRequest()); 744 - 745 743 $timeline->setQuoteRef($commit->getMonogram()); 746 744 747 745 return $timeline;
+30
src/applications/diffusion/engine/DiffusionCommitTimelineEngine.php
··· 1 + <?php 2 + 3 + final class DiffusionCommitTimelineEngine 4 + extends PhabricatorTimelineEngine { 5 + 6 + protected function newTimelineView() { 7 + $xactions = $this->getTransactions(); 8 + 9 + $path_ids = array(); 10 + foreach ($xactions as $xaction) { 11 + if ($xaction->hasComment()) { 12 + $path_id = $xaction->getComment()->getPathID(); 13 + if ($path_id) { 14 + $path_ids[] = $path_id; 15 + } 16 + } 17 + } 18 + 19 + $path_map = array(); 20 + if ($path_ids) { 21 + $path_map = id(new DiffusionPathQuery()) 22 + ->withPathIDs($path_ids) 23 + ->execute(); 24 + $path_map = ipull($path_map, 'path', 'id'); 25 + } 26 + 27 + return id(new PhabricatorAuditTransactionView()) 28 + ->setPathMap($path_map); 29 + } 30 + }
-4
src/applications/legalpad/storage/LegalpadTransaction.php
··· 14 14 return new LegalpadTransactionComment(); 15 15 } 16 16 17 - public function getApplicationTransactionViewObject() { 18 - return new LegalpadTransactionView(); 19 - } 20 - 21 17 public function getBaseTransactionClass() { 22 18 return 'LegalpadDocumentTransactionType'; 23 19 }
-4
src/applications/legalpad/view/LegalpadTransactionView.php
··· 1 - <?php 2 - 3 - final class LegalpadTransactionView 4 - extends PhabricatorApplicationTransactionView {}
+1 -4
src/applications/pholio/controller/PholioMockCommentController.php
··· 68 68 } 69 69 70 70 if ($request->isAjax() && $is_preview) { 71 - $xaction_view = id(new PholioTransactionView()) 72 - ->setMock($mock); 73 - 74 71 return id(new PhabricatorApplicationTransactionResponse()) 72 + ->setObject($mock) 75 73 ->setViewer($viewer) 76 74 ->setTransactions($xactions) 77 - ->setTransactionView($xaction_view) 78 75 ->setIsPreview($is_preview); 79 76 } else { 80 77 return id(new AphrontRedirectResponse())->setURI($mock_uri);
+19
src/applications/pholio/engine/PholioMockTimelineEngine.php
··· 1 + <?php 2 + 3 + final class PholioMockTimelineEngine 4 + extends PhabricatorTimelineEngine { 5 + 6 + protected function newTimelineView() { 7 + $viewer = $this->getViewer(); 8 + $object = $this->getObject(); 9 + 10 + PholioMockQuery::loadImages( 11 + $viewer, 12 + array($object), 13 + $need_inline_comments = true); 14 + 15 + return id(new PholioTransactionView()) 16 + ->setMock($object); 17 + } 18 + 19 + }
+10 -11
src/applications/pholio/storage/PholioMock.php
··· 7 7 PhabricatorTokenReceiverInterface, 8 8 PhabricatorFlaggableInterface, 9 9 PhabricatorApplicationTransactionInterface, 10 + PhabricatorTimelineInterface, 10 11 PhabricatorProjectInterface, 11 12 PhabricatorDestructibleInterface, 12 13 PhabricatorSpacesInterface, ··· 228 229 return new PholioTransaction(); 229 230 } 230 231 231 - public function willRenderTimeline( 232 - PhabricatorApplicationTransactionView $timeline, 233 - AphrontRequest $request) { 234 - 235 - PholioMockQuery::loadImages( 236 - $request->getUser(), 237 - array($this), 238 - $need_inline_comments = true); 239 - $timeline->setMock($this); 240 - return $timeline; 241 - } 242 232 243 233 /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ 244 234 ··· 288 278 289 279 /* -( PhabricatorFerretInterface )----------------------------------------- */ 290 280 281 + 291 282 public function newFerretEngine() { 292 283 return new PholioMockFerretEngine(); 284 + } 285 + 286 + 287 + /* -( PhabricatorTimelineInterace )---------------------------------------- */ 288 + 289 + 290 + public function newTimelineEngine() { 291 + return new PholioMockTimelineEngine(); 293 292 } 294 293 295 294
-4
src/applications/pholio/storage/PholioTransaction.php
··· 23 23 return new PholioTransactionComment(); 24 24 } 25 25 26 - public function getApplicationTransactionViewObject() { 27 - return new PholioTransactionView(); 28 - } 29 - 30 26 public function getMailTags() { 31 27 $tags = array(); 32 28 switch ($this->getTransactionType()) {
+1
src/applications/ponder/controller/PonderAnswerCommentController.php
··· 50 50 51 51 if ($request->isAjax() && $is_preview) { 52 52 return id(new PhabricatorApplicationTransactionResponse()) 53 + ->setObject($answer) 53 54 ->setViewer($viewer) 54 55 ->setTransactions($xactions) 55 56 ->setIsPreview($is_preview);
+1
src/applications/ponder/controller/PonderQuestionCommentController.php
··· 46 46 47 47 if ($request->isAjax() && $is_preview) { 48 48 return id(new PhabricatorApplicationTransactionResponse()) 49 + ->setObject($question) 49 50 ->setViewer($viewer) 50 51 ->setTransactions($xactions) 51 52 ->setIsPreview($is_preview);
+1
src/applications/releeph/controller/request/ReleephRequestCommentController.php
··· 51 51 52 52 if ($request->isAjax() && $is_preview) { 53 53 return id(new PhabricatorApplicationTransactionResponse()) 54 + ->setObject($pull) 54 55 ->setViewer($viewer) 55 56 ->setTransactions($xactions) 56 57 ->setIsPreview($is_preview);
+9 -27
src/applications/repository/storage/PhabricatorRepositoryCommit.php
··· 14 14 HarbormasterBuildkiteBuildableInterface, 15 15 PhabricatorCustomFieldInterface, 16 16 PhabricatorApplicationTransactionInterface, 17 + PhabricatorTimelineInterface, 17 18 PhabricatorFulltextInterface, 18 19 PhabricatorFerretInterface, 19 20 PhabricatorConduitResultInterface, ··· 738 739 return new PhabricatorAuditTransaction(); 739 740 } 740 741 741 - public function willRenderTimeline( 742 - PhabricatorApplicationTransactionView $timeline, 743 - AphrontRequest $request) { 744 - 745 - $xactions = $timeline->getTransactions(); 746 - 747 - $path_ids = array(); 748 - foreach ($xactions as $xaction) { 749 - if ($xaction->hasComment()) { 750 - $path_id = $xaction->getComment()->getPathID(); 751 - if ($path_id) { 752 - $path_ids[] = $path_id; 753 - } 754 - } 755 - } 756 - 757 - $path_map = array(); 758 - if ($path_ids) { 759 - $path_map = id(new DiffusionPathQuery()) 760 - ->withPathIDs($path_ids) 761 - ->execute(); 762 - $path_map = ipull($path_map, 'path', 'id'); 763 - } 764 - 765 - return $timeline->setPathMap($path_map); 766 - } 767 - 768 742 /* -( PhabricatorFulltextInterface )--------------------------------------- */ 769 743 770 744 ··· 914 888 public function attachHasDraft(PhabricatorUser $viewer, $has_draft) { 915 889 $this->drafts[$viewer->getCacheFragment()] = $has_draft; 916 890 return $this; 891 + } 892 + 893 + 894 + /* -( PhabricatorTimelineInterface )--------------------------------------- */ 895 + 896 + 897 + public function newTimelineEngine() { 898 + return new DiffusionCommitTimelineEngine(); 917 899 } 918 900 919 901 }
+1
src/applications/slowvote/controller/PhabricatorSlowvoteCommentController.php
··· 51 51 52 52 if ($request->isAjax() && $is_preview) { 53 53 return id(new PhabricatorApplicationTransactionResponse()) 54 + ->setObject($poll) 54 55 ->setViewer($viewer) 55 56 ->setTransactions($xactions) 56 57 ->setIsPreview($is_preview);
+12 -1
src/applications/transactions/controller/PhabricatorApplicationTransactionShowOlderController.php
··· 27 27 return new Aphront404Response(); 28 28 } 29 29 30 - $timeline = $this->buildTransactionTimeline($object, $query); 30 + $raw_view_data = $request->getStr('viewData'); 31 + try { 32 + $view_data = phutil_json_decode($raw_view_data); 33 + } catch (Exception $ex) { 34 + $view_data = array(); 35 + } 36 + 37 + $timeline = $this->buildTransactionTimeline( 38 + $object, 39 + $query, 40 + null, 41 + $view_data); 31 42 32 43 $phui_timeline = $timeline->buildPHUITimelineView($with_hiding = false); 33 44 $phui_timeline->setShouldAddSpacers(false);
+1
src/applications/transactions/editengine/PhabricatorEditEngine.php
··· 1955 1955 $preview_content = $this->newCommentPreviewContent($object, $xactions); 1956 1956 1957 1957 return id(new PhabricatorApplicationTransactionResponse()) 1958 + ->setObject($object) 1958 1959 ->setViewer($viewer) 1959 1960 ->setTransactions($xactions) 1960 1961 ->setIsPreview($is_preview)
+4
src/applications/transactions/engine/PhabricatorStandardTimelineEngine.php
··· 1 + <?php 2 + 3 + final class PhabricatorStandardTimelineEngine 4 + extends PhabricatorTimelineEngine {}
+95
src/applications/transactions/engine/PhabricatorTimelineEngine.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorTimelineEngine 4 + extends Phobject { 5 + 6 + private $viewer; 7 + private $object; 8 + private $xactions; 9 + private $viewData; 10 + 11 + final public static function newForObject($object) { 12 + if ($object instanceof PhabricatorTimelineInterface) { 13 + $engine = $object->newTimelineEngine(); 14 + } else { 15 + $engine = new PhabricatorStandardTimelineEngine(); 16 + } 17 + 18 + $engine->setObject($object); 19 + 20 + return $engine; 21 + } 22 + 23 + final public function setViewer(PhabricatorUser $viewer) { 24 + $this->viewer = $viewer; 25 + return $this; 26 + } 27 + 28 + final public function getViewer() { 29 + return $this->viewer; 30 + } 31 + 32 + final public function setObject($object) { 33 + $this->object = $object; 34 + return $this; 35 + } 36 + 37 + final public function getObject() { 38 + return $this->object; 39 + } 40 + 41 + final public function setTransactions(array $xactions) { 42 + assert_instances_of($xactions, 'PhabricatorApplicationTransaction'); 43 + $this->xactions = $xactions; 44 + return $this; 45 + } 46 + 47 + final public function getTransactions() { 48 + return $this->xactions; 49 + } 50 + 51 + final public function setRequest(AphrontRequest $request) { 52 + $this->request = $request; 53 + return $this; 54 + } 55 + 56 + final public function getRequest() { 57 + return $this->request; 58 + } 59 + 60 + final public function setViewData(array $view_data) { 61 + $this->viewData = $view_data; 62 + return $this; 63 + } 64 + 65 + final public function getViewData() { 66 + return $this->viewData; 67 + } 68 + 69 + final public function buildTimelineView() { 70 + $view = $this->newTimelineView(); 71 + 72 + if (!($view instanceof PhabricatorApplicationTransactionView)) { 73 + throw new Exception( 74 + pht( 75 + 'Expected "newTimelineView()" to return an object of class "%s" '. 76 + '(in engine "%s").', 77 + 'PhabricatorApplicationTransactionView', 78 + get_class($this))); 79 + } 80 + 81 + $viewer = $this->getViewer(); 82 + $object = $this->getObject(); 83 + $xactions = $this->getTransactions(); 84 + 85 + return $view 86 + ->setViewer($viewer) 87 + ->setObjectPHID($object->getPHID()) 88 + ->setTransactions($xactions); 89 + } 90 + 91 + protected function newTimelineView() { 92 + return new PhabricatorApplicationTransactionView(); 93 + } 94 + 95 + }
-16
src/applications/transactions/interface/PhabricatorApplicationTransactionInterface.php
··· 35 35 */ 36 36 public function getApplicationTransactionTemplate(); 37 37 38 - /** 39 - * Hook to augment the $timeline with additional data for rendering. 40 - * 41 - * @return PhabricatorApplicationTransactionView 42 - */ 43 - public function willRenderTimeline( 44 - PhabricatorApplicationTransactionView $timeline, 45 - AphrontRequest $request); 46 - 47 38 } 48 39 49 40 // TEMPLATE IMPLEMENTATION ///////////////////////////////////////////////////// ··· 62 53 63 54 public function getApplicationTransactionTemplate() { 64 55 return new <<<???>>>Transaction(); 65 - } 66 - 67 - public function willRenderTimeline( 68 - PhabricatorApplicationTransactionView $timeline, 69 - AphrontRequest $request) { 70 - 71 - return $timeline; 72 56 } 73 57 74 58 */
+7
src/applications/transactions/interface/PhabricatorTimelineInterface.php
··· 1 + <?php 2 + 3 + interface PhabricatorTimelineInterface { 4 + 5 + public function newTimelineEngine(); 6 + 7 + }
+20 -22
src/applications/transactions/response/PhabricatorApplicationTransactionResponse.php
··· 6 6 private $viewer; 7 7 private $transactions; 8 8 private $isPreview; 9 - private $transactionView; 10 9 private $previewContent; 11 - 12 - public function setTransactionView($transaction_view) { 13 - $this->transactionView = $transaction_view; 14 - return $this; 15 - } 16 - 17 - public function getTransactionView() { 18 - return $this->transactionView; 19 - } 10 + private $object; 20 11 21 12 protected function buildProxy() { 22 13 return new AphrontAjaxResponse(); ··· 31 22 32 23 public function getTransactions() { 33 24 return $this->transactions; 25 + } 26 + 27 + public function setObject($object) { 28 + $this->object = $object; 29 + return $this; 30 + } 31 + 32 + public function getObject() { 33 + return $this->object; 34 34 } 35 35 36 36 public function setViewer(PhabricatorUser $viewer) { ··· 57 57 } 58 58 59 59 public function reduceProxyResponse() { 60 - if ($this->transactionView) { 61 - $view = $this->transactionView; 62 - } else if ($this->getTransactions()) { 63 - $view = head($this->getTransactions()) 64 - ->getApplicationTransactionViewObject(); 65 - } else { 66 - $view = new PhabricatorApplicationTransactionView(); 67 - } 60 + $object = $this->getObject(); 61 + $viewer = $this->getViewer(); 62 + $xactions = $this->getTransactions(); 63 + 64 + $timeline_engine = PhabricatorTimelineEngine::newForObject($object) 65 + ->setViewer($viewer) 66 + ->setTransactions($xactions); 67 + 68 + $view = $timeline_engine->buildTimelineView(); 68 69 69 - $view 70 - ->setUser($this->getViewer()) 71 - ->setTransactions($this->getTransactions()) 72 - ->setIsPreview($this->isPreview); 70 + $view->setIsPreview($this->isPreview); 73 71 74 72 if ($this->isPreview) { 75 73 $xactions = mpull($view->buildEvents(), 'render');
-4
src/applications/transactions/storage/PhabricatorApplicationTransaction.php
··· 79 79 throw new PhutilMethodNotImplementedException(); 80 80 } 81 81 82 - public function getApplicationTransactionViewObject() { 83 - return new PhabricatorApplicationTransactionView(); 84 - } 85 - 86 82 public function getMetadataValue($key, $default = null) { 87 83 return idx($this->metadata, $key, $default); 88 84 }
+15 -24
src/applications/transactions/view/PhabricatorApplicationTransactionView.php
··· 15 15 private $quoteRef; 16 16 private $pager; 17 17 private $renderAsFeed; 18 - private $renderData = array(); 19 18 private $hideCommentOptions = false; 19 + private $viewData = array(); 20 20 21 21 public function setRenderAsFeed($feed) { 22 22 $this->renderAsFeed = $feed; ··· 97 97 return $this->pager; 98 98 } 99 99 100 - /** 101 - * This is additional data that may be necessary to render the next set 102 - * of transactions. Objects that implement 103 - * PhabricatorApplicationTransactionInterface use this data in 104 - * willRenderTimeline. 105 - */ 106 - public function setRenderData(array $data) { 107 - $this->renderData = $data; 100 + public function setHideCommentOptions($hide_comment_options) { 101 + $this->hideCommentOptions = $hide_comment_options; 108 102 return $this; 109 103 } 110 104 111 - public function getRenderData() { 112 - return $this->renderData; 105 + public function getHideCommentOptions() { 106 + return $this->hideCommentOptions; 113 107 } 114 108 115 - public function setHideCommentOptions($hide_comment_options) { 116 - $this->hideCommentOptions = $hide_comment_options; 109 + public function setViewData(array $view_data) { 110 + $this->viewData = $view_data; 117 111 return $this; 118 112 } 119 113 120 - public function getHideCommentOptions() { 121 - return $this->hideCommentOptions; 114 + public function getViewData() { 115 + return $this->viewData; 122 116 } 123 117 124 118 public function buildEvents($with_hiding = false) { ··· 216 210 } 217 211 218 212 $view = id(new PHUITimelineView()) 219 - ->setUser($this->getUser()) 213 + ->setViewer($this->getViewer()) 220 214 ->setShouldTerminate($this->shouldTerminate) 221 215 ->setQuoteTargetID($this->getQuoteTargetID()) 222 - ->setQuoteRef($this->getQuoteRef()); 216 + ->setQuoteRef($this->getQuoteRef()) 217 + ->setViewData($this->getViewData()); 223 218 224 219 $events = $this->buildEvents($with_hiding); 225 220 foreach ($events as $event) { ··· 230 225 $view->setPager($this->getPager()); 231 226 } 232 227 233 - if ($this->getRenderData()) { 234 - $view->setRenderData($this->getRenderData()); 235 - } 236 - 237 228 return $view; 238 229 } 239 230 ··· 246 237 $field = PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT; 247 238 248 239 $engine = id(new PhabricatorMarkupEngine()) 249 - ->setViewer($this->getUser()); 240 + ->setViewer($this->getViewer()); 250 241 foreach ($this->transactions as $xaction) { 251 242 if (!$xaction->hasComment()) { 252 243 continue; ··· 414 405 private function renderEvent( 415 406 PhabricatorApplicationTransaction $xaction, 416 407 array $group) { 417 - $viewer = $this->getUser(); 408 + $viewer = $this->getViewer(); 418 409 419 410 $event = id(new PHUITimelineEventView()) 420 - ->setUser($viewer) 411 + ->setViewer($viewer) 421 412 ->setAuthorPHID($xaction->getAuthorPHID()) 422 413 ->setTransactionPHID($xaction->getPHID()) 423 414 ->setUserHandle($xaction->getHandle($xaction->getAuthorPHID()))
+8 -4
src/view/phui/PHUITimelineView.php
··· 7 7 private $shouldTerminate = false; 8 8 private $shouldAddSpacers = true; 9 9 private $pager; 10 - private $renderData = array(); 10 + private $viewData = array(); 11 11 private $quoteTargetID; 12 12 private $quoteRef; 13 13 ··· 40 40 return $this; 41 41 } 42 42 43 - public function setRenderData(array $data) { 44 - $this->renderData = $data; 43 + public function setViewData(array $data) { 44 + $this->viewData = $data; 45 45 return $this; 46 46 } 47 47 48 + public function getViewData() { 49 + return $this->viewData; 50 + } 51 + 48 52 public function setQuoteTargetID($quote_target_id) { 49 53 $this->quoteTargetID = $quote_target_id; 50 54 return $this; ··· 72 76 'phabricator-show-older-transactions', 73 77 array( 74 78 'timelineID' => $this->id, 75 - 'renderData' => $this->renderData, 79 + 'viewData' => $this->getViewData(), 76 80 )); 77 81 } 78 82 $events = $this->buildEvents();
+5 -1
webroot/rsrc/js/application/transactions/behavior-show-older-transactions.js
··· 83 83 }; 84 84 85 85 var fetch_older_workflow = function(href, callback, swap) { 86 - return new JX.Workflow(href, config.renderData) 86 + var params = { 87 + viewData: JX.JSON.stringify(config.viewData) 88 + }; 89 + 90 + return new JX.Workflow(href, params) 87 91 .setHandler(JX.bind(null, callback, swap)); 88 92 }; 89 93