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

Put feed on project home, move history to a separate page

Summary:
Ref T10054. This shuffles some stuff around to move us closer to mocks in M1450 in terms of what information is on which pages.

Home now has feed, members, watchers, link to "edit project / project edit history".

History now has edit history, edit details, edit picture, archive/unarchive.

Test Plan:
New home page:

{F1064889}

New edit/history page:

{F1064890}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10054

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

+234 -153
+2 -2
src/__phutil_library_map__.php
··· 2881 2881 'PhabricatorProjectEditController' => 'applications/project/controller/PhabricatorProjectEditController.php', 2882 2882 'PhabricatorProjectEditEngine' => 'applications/project/engine/PhabricatorProjectEditEngine.php', 2883 2883 'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php', 2884 - 'PhabricatorProjectFeedController' => 'applications/project/controller/PhabricatorProjectFeedController.php', 2885 2884 'PhabricatorProjectFulltextEngine' => 'applications/project/search/PhabricatorProjectFulltextEngine.php', 2886 2885 'PhabricatorProjectHeraldAction' => 'applications/project/herald/PhabricatorProjectHeraldAction.php', 2886 + 'PhabricatorProjectHistoryController' => 'applications/project/controller/PhabricatorProjectHistoryController.php', 2887 2887 'PhabricatorProjectIconSet' => 'applications/project/icon/PhabricatorProjectIconSet.php', 2888 2888 'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php', 2889 2889 'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php', ··· 7283 7283 'PhabricatorProjectEditController' => 'PhabricatorProjectController', 7284 7284 'PhabricatorProjectEditEngine' => 'PhabricatorEditEngine', 7285 7285 'PhabricatorProjectEditPictureController' => 'PhabricatorProjectController', 7286 - 'PhabricatorProjectFeedController' => 'PhabricatorProjectController', 7287 7286 'PhabricatorProjectFulltextEngine' => 'PhabricatorFulltextEngine', 7288 7287 'PhabricatorProjectHeraldAction' => 'HeraldAction', 7288 + 'PhabricatorProjectHistoryController' => 'PhabricatorProjectController', 7289 7289 'PhabricatorProjectIconSet' => 'PhabricatorIconSet', 7290 7290 'PhabricatorProjectListController' => 'PhabricatorProjectController', 7291 7291 'PhabricatorProjectListView' => 'AphrontView',
+1 -1
src/applications/files/controller/PhabricatorFileComposeController.php
··· 44 44 )); 45 45 46 46 if ($project_phid) { 47 - $edit_uri = '/project/profile/'.$project->getID().'/'; 47 + $edit_uri = '/project/history/'.$project->getID().'/'; 48 48 49 49 $xactions = array(); 50 50 $xactions[] = id(new PhabricatorProjectTransaction())
-2
src/applications/project/application/PhabricatorProjectApplication.php
··· 55 55 => 'PhabricatorProjectMembersRemoveController', 56 56 'profile/(?P<id>[1-9]\d*)/' 57 57 => 'PhabricatorProjectProfileController', 58 - 'feed/(?P<id>[1-9]\d*)/' 59 - => 'PhabricatorProjectFeedController', 60 58 'view/(?P<id>[1-9]\d*)/' 61 59 => 'PhabricatorProjectViewController', 62 60 'picture/(?P<id>[1-9]\d*)/'
+1 -1
src/applications/project/controller/PhabricatorProjectArchiveController.php
··· 20 20 return new Aphront404Response(); 21 21 } 22 22 23 - $edit_uri = $this->getApplicationURI('profile/'.$project->getID().'/'); 23 + $edit_uri = $this->getApplicationURI('history/'.$project->getID().'/'); 24 24 25 25 if ($request->isFormPost()) { 26 26 if ($project->isArchived()) {
+2 -2
src/applications/project/controller/PhabricatorProjectEditPictureController.php
··· 23 23 24 24 $this->setProject($project); 25 25 26 - $edit_uri = $this->getApplicationURI('profile/'.$project->getID().'/'); 27 - $view_uri = $this->getApplicationURI('profile/'.$project->getID().'/'); 26 + $edit_uri = $this->getApplicationURI('history/'.$project->getID().'/'); 27 + $view_uri = $this->getApplicationURI('history/'.$project->getID().'/'); 28 28 29 29 $supported_formats = PhabricatorFile::getTransformableImageFormats(); 30 30 $e_file = true;
-62
src/applications/project/controller/PhabricatorProjectFeedController.php
··· 1 - <?php 2 - 3 - final class PhabricatorProjectFeedController 4 - extends PhabricatorProjectController { 5 - 6 - public function shouldAllowPublic() { 7 - return true; 8 - } 9 - 10 - public function handleRequest(AphrontRequest $request) { 11 - $viewer = $request->getUser(); 12 - 13 - $response = $this->loadProject(); 14 - if ($response) { 15 - return $response; 16 - } 17 - 18 - $project = $this->getProject(); 19 - $id = $project->getID(); 20 - 21 - $stories = id(new PhabricatorFeedQuery()) 22 - ->setViewer($viewer) 23 - ->setFilterPHIDs( 24 - array( 25 - $project->getPHID(), 26 - )) 27 - ->setLimit(50) 28 - ->execute(); 29 - 30 - $feed = $this->renderStories($stories); 31 - 32 - $box = id(new PHUIObjectBoxView()) 33 - ->setHeaderText(pht('Project Activity')) 34 - ->appendChild($feed); 35 - 36 - $nav = $this->getProfileMenu(); 37 - $nav->selectFilter('feed'); 38 - 39 - $crumbs = $this->buildApplicationCrumbs(); 40 - $crumbs->addTextCrumb(pht('Feed')); 41 - 42 - return $this->newPage() 43 - ->setNavigation($nav) 44 - ->setCrumbs($crumbs) 45 - ->setTitle(array($project->getName(), pht('Feed'))) 46 - ->appendChild($box); 47 - } 48 - 49 - private function renderStories(array $stories) { 50 - assert_instances_of($stories, 'PhabricatorFeedStory'); 51 - 52 - $builder = new PhabricatorFeedBuilder($stories); 53 - $builder->setUser($this->getRequest()->getUser()); 54 - $builder->setShowHovercards(true); 55 - $view = $builder->buildView(); 56 - 57 - return phutil_tag_div( 58 - 'profile-feed', 59 - $view->render()); 60 - } 61 - 62 - }
+133
src/applications/project/controller/PhabricatorProjectHistoryController.php
··· 1 + <?php 2 + 3 + final class PhabricatorProjectHistoryController 4 + extends PhabricatorProjectController { 5 + 6 + public function shouldAllowPublic() { 7 + return true; 8 + } 9 + 10 + public function handleRequest(AphrontRequest $request) { 11 + $response = $this->loadProject(); 12 + if ($response) { 13 + return $response; 14 + } 15 + 16 + $viewer = $request->getUser(); 17 + $project = $this->getProject(); 18 + $id = $project->getID(); 19 + $picture = $project->getProfileImageURI(); 20 + 21 + $header = id(new PHUIHeaderView()) 22 + ->setHeader(pht('Project History')) 23 + ->setUser($viewer) 24 + ->setPolicyObject($project) 25 + ->setImage($picture); 26 + 27 + if ($project->getStatus() == PhabricatorProjectStatus::STATUS_ACTIVE) { 28 + $header->setStatus('fa-check', 'bluegrey', pht('Active')); 29 + } else { 30 + $header->setStatus('fa-ban', 'red', pht('Archived')); 31 + } 32 + 33 + $actions = $this->buildActionListView($project); 34 + $properties = $this->buildPropertyListView($project, $actions); 35 + 36 + $object_box = id(new PHUIObjectBoxView()) 37 + ->setHeader($header) 38 + ->addPropertyList($properties); 39 + 40 + $timeline = $this->buildTransactionTimeline( 41 + $project, 42 + new PhabricatorProjectTransactionQuery()); 43 + $timeline->setShouldTerminate(true); 44 + 45 + $nav = $this->getProfileMenu(); 46 + $nav->selectFilter(PhabricatorProject::PANEL_PROFILE); 47 + 48 + $crumbs = $this->buildApplicationCrumbs(); 49 + $crumbs->addTextCrumb(pht('History')); 50 + 51 + return $this->newPage() 52 + ->setNavigation($nav) 53 + ->setCrumbs($crumbs) 54 + ->setTitle($project->getName()) 55 + ->appendChild( 56 + array( 57 + $object_box, 58 + $timeline, 59 + )); 60 + } 61 + 62 + private function buildActionListView(PhabricatorProject $project) { 63 + $request = $this->getRequest(); 64 + $viewer = $request->getUser(); 65 + 66 + $id = $project->getID(); 67 + 68 + $view = id(new PhabricatorActionListView()) 69 + ->setUser($viewer); 70 + 71 + $can_edit = PhabricatorPolicyFilter::hasCapability( 72 + $viewer, 73 + $project, 74 + PhabricatorPolicyCapability::CAN_EDIT); 75 + 76 + $view->addAction( 77 + id(new PhabricatorActionView()) 78 + ->setName(pht('Back to Profile')) 79 + ->setIcon('fa-chevron-left') 80 + ->setHref($project->getURI())); 81 + 82 + $view->addAction( 83 + id(new PhabricatorActionView()) 84 + ->setName(pht('Edit Details')) 85 + ->setIcon('fa-pencil') 86 + ->setHref($this->getApplicationURI("edit/{$id}/")) 87 + ->setDisabled(!$can_edit) 88 + ->setWorkflow(!$can_edit)); 89 + 90 + $view->addAction( 91 + id(new PhabricatorActionView()) 92 + ->setName(pht('Edit Picture')) 93 + ->setIcon('fa-picture-o') 94 + ->setHref($this->getApplicationURI("picture/{$id}/")) 95 + ->setDisabled(!$can_edit) 96 + ->setWorkflow(!$can_edit)); 97 + 98 + if ($project->isArchived()) { 99 + $view->addAction( 100 + id(new PhabricatorActionView()) 101 + ->setName(pht('Activate Project')) 102 + ->setIcon('fa-check') 103 + ->setHref($this->getApplicationURI("archive/{$id}/")) 104 + ->setDisabled(!$can_edit) 105 + ->setWorkflow(true)); 106 + } else { 107 + $view->addAction( 108 + id(new PhabricatorActionView()) 109 + ->setName(pht('Archive Project')) 110 + ->setIcon('fa-ban') 111 + ->setHref($this->getApplicationURI("archive/{$id}/")) 112 + ->setDisabled(!$can_edit) 113 + ->setWorkflow(true)); 114 + } 115 + 116 + return $view; 117 + } 118 + 119 + private function buildPropertyListView( 120 + PhabricatorProject $project, 121 + PhabricatorActionListView $actions) { 122 + $request = $this->getRequest(); 123 + $viewer = $request->getUser(); 124 + 125 + $view = id(new PHUIPropertyListView()) 126 + ->setUser($viewer) 127 + ->setActionList($actions); 128 + 129 + return $view; 130 + } 131 + 132 + 133 + }
+54 -70
src/applications/project/controller/PhabricatorProjectProfileController.php
··· 8 8 } 9 9 10 10 public function handleRequest(AphrontRequest $request) { 11 - $viewer = $request->getUser(); 12 - 13 11 $response = $this->loadProject(); 14 12 if ($response) { 15 13 return $response; 16 14 } 17 15 16 + $viewer = $request->getUser(); 18 17 $project = $this->getProject(); 19 18 $id = $project->getID(); 20 19 $picture = $project->getProfileImageURI(); ··· 38 37 ->setHeader($header) 39 38 ->addPropertyList($properties); 40 39 41 - $timeline = $this->buildTransactionTimeline( 42 - $project, 43 - new PhabricatorProjectTransactionQuery()); 44 - $timeline->setShouldTerminate(true); 40 + $member_list = id(new PhabricatorProjectMemberListView()) 41 + ->setUser($viewer) 42 + ->setProject($project) 43 + ->setLimit(5) 44 + ->setUserPHIDs($project->getMemberPHIDs()); 45 + 46 + $watcher_list = id(new PhabricatorProjectWatcherListView()) 47 + ->setUser($viewer) 48 + ->setProject($project) 49 + ->setLimit(5) 50 + ->setUserPHIDs($project->getWatcherPHIDs()); 45 51 46 52 $nav = $this->getProfileMenu(); 47 53 $nav->selectFilter(PhabricatorProject::PANEL_PROFILE); 48 54 55 + 56 + $stories = id(new PhabricatorFeedQuery()) 57 + ->setViewer($viewer) 58 + ->setFilterPHIDs( 59 + array( 60 + $project->getPHID(), 61 + )) 62 + ->setLimit(50) 63 + ->execute(); 64 + 65 + $feed = $this->renderStories($stories); 66 + 67 + $feed = id(new PHUIObjectBoxView()) 68 + ->setHeaderText(pht('Recent Activity')) 69 + ->appendChild($feed); 70 + 71 + $columns = id(new AphrontMultiColumnView()) 72 + ->setFluidLayout(true) 73 + ->addColumn($feed) 74 + ->addColumn( 75 + array( 76 + $member_list, 77 + $watcher_list, 78 + )); 79 + 49 80 $crumbs = $this->buildApplicationCrumbs(); 50 81 51 82 return $this->newPage() ··· 53 84 ->setCrumbs($crumbs) 54 85 ->setTitle($project->getName()) 55 86 ->setPageObjectPHIDs(array($project->getPHID())) 56 - ->appendChild($object_box) 57 - ->appendChild($timeline); 87 + ->appendChild( 88 + array( 89 + $object_box, 90 + $columns, 91 + )); 58 92 } 59 93 60 94 private function buildActionListView(PhabricatorProject $project) { ··· 66 100 $view = id(new PhabricatorActionListView()) 67 101 ->setUser($viewer) 68 102 ->setObject($project); 69 - 70 - $can_edit = PhabricatorPolicyFilter::hasCapability( 71 - $viewer, 72 - $project, 73 - PhabricatorPolicyCapability::CAN_EDIT); 74 103 75 104 $view->addAction( 76 105 id(new PhabricatorActionView()) 77 - ->setName(pht('Edit Details')) 106 + ->setName(pht('Edit Project')) 78 107 ->setIcon('fa-pencil') 79 - ->setHref($this->getApplicationURI("edit/{$id}/")) 80 - ->setDisabled(!$can_edit) 81 - ->setWorkflow(!$can_edit)); 82 - 83 - $view->addAction( 84 - id(new PhabricatorActionView()) 85 - ->setName(pht('Edit Picture')) 86 - ->setIcon('fa-picture-o') 87 - ->setHref($this->getApplicationURI("picture/{$id}/")) 88 - ->setDisabled(!$can_edit) 89 - ->setWorkflow(!$can_edit)); 90 - 91 - if ($project->isArchived()) { 92 - $view->addAction( 93 - id(new PhabricatorActionView()) 94 - ->setName(pht('Activate Project')) 95 - ->setIcon('fa-check') 96 - ->setHref($this->getApplicationURI("archive/{$id}/")) 97 - ->setDisabled(!$can_edit) 98 - ->setWorkflow(true)); 99 - } else { 100 - $view->addAction( 101 - id(new PhabricatorActionView()) 102 - ->setName(pht('Archive Project')) 103 - ->setIcon('fa-ban') 104 - ->setHref($this->getApplicationURI("archive/{$id}/")) 105 - ->setDisabled(!$can_edit) 106 - ->setWorkflow(true)); 107 - } 108 + ->setHref($this->getApplicationURI("history/{$id}/"))); 108 109 109 110 return $view; 110 111 } ··· 120 121 ->setObject($project) 121 122 ->setActionList($actions); 122 123 123 - $hashtags = array(); 124 - foreach ($project->getSlugs() as $slug) { 125 - $hashtags[] = id(new PHUITagView()) 126 - ->setType(PHUITagView::TYPE_OBJECT) 127 - ->setName('#'.$slug->getSlug()); 128 - } 129 - 130 - if ($hashtags) { 131 - $view->addProperty(pht('Hashtags'), phutil_implode_html(' ', $hashtags)); 132 - } 133 - 134 - $view->addProperty( 135 - pht('Members'), 136 - $project->getMemberPHIDs() 137 - ? $viewer 138 - ->renderHandleList($project->getMemberPHIDs()) 139 - ->setAsInline(true) 140 - : phutil_tag('em', array(), pht('None'))); 141 - 142 - $view->addProperty( 143 - pht('Watchers'), 144 - $project->getWatcherPHIDs() 145 - ? $viewer 146 - ->renderHandleList($project->getWatcherPHIDs()) 147 - ->setAsInline(true) 148 - : phutil_tag('em', array(), pht('None'))); 149 - 150 124 $view->addProperty( 151 125 pht('Looks Like'), 152 126 $viewer->renderHandle($project->getPHID())->setAsTag(true)); ··· 159 133 return $view; 160 134 } 161 135 136 + private function renderStories(array $stories) { 137 + assert_instances_of($stories, 'PhabricatorFeedStory'); 138 + 139 + $builder = new PhabricatorFeedBuilder($stories); 140 + $builder->setUser($this->getRequest()->getUser()); 141 + $builder->setShowHovercards(true); 142 + $view = $builder->buildView(); 143 + 144 + return phutil_tag_div('profile-feed', $view->render()); 145 + } 162 146 163 147 }
+6 -1
src/applications/project/engine/PhabricatorProjectEditEngine.php
··· 78 78 } 79 79 80 80 protected function getObjectViewURI($object) { 81 - return $object->getURI(); 81 + if ($this->getIsCreate()) { 82 + return $object->getURI(); 83 + } else { 84 + $id = $object->getID(); 85 + return "/project/history/{$id}/"; 86 + } 82 87 } 83 88 84 89 protected function getObjectCreateCancelURI($object) {
-9
src/applications/project/engine/PhabricatorProjectProfilePanelEngine.php
··· 32 32 ->setPanelProperty('name', pht('Open Tasks')) 33 33 ->setPanelProperty('uri', $uri); 34 34 35 - // TODO: This is temporary. 36 - $id = $object->getID(); 37 - $panels[] = $this->newPanel() 38 - ->setBuiltinKey('feed') 39 - ->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY) 40 - ->setPanelProperty('icon', 'feed') 41 - ->setPanelProperty('name', pht('Feed')) 42 - ->setPanelProperty('uri', "/project/feed/{$id}/"); 43 - 44 35 $panels[] = $this->newPanel() 45 36 ->setBuiltinKey(PhabricatorProject::PANEL_MEMBERS) 46 37 ->setPanelKey(PhabricatorProjectMembersProfilePanel::PANELKEY);
+35 -3
src/applications/project/view/PhabricatorProjectUserListView.php
··· 4 4 5 5 private $project; 6 6 private $userPHIDs; 7 + private $limit; 7 8 8 9 public function setProject(PhabricatorProject $project) { 9 10 $this->project = $project; ··· 21 22 22 23 public function getUserPHIDs() { 23 24 return $this->userPHIDs; 25 + } 26 + 27 + public function setLimit($limit) { 28 + $this->limit = $limit; 29 + return $this; 30 + } 31 + 32 + public function getLimit() { 33 + return $this->limit; 24 34 } 25 35 26 36 abstract protected function canEditList(); ··· 39 49 $list = id(new PHUIObjectItemListView()) 40 50 ->setNoDataString($no_data); 41 51 42 - $user_phids = array_reverse($user_phids); 52 + $limit = $this->getLimit(); 53 + 54 + // If we're showing everything, show oldest to newest. If we're showing 55 + // only a slice, show newest to oldest. 56 + if (!$limit) { 57 + $user_phids = array_reverse($user_phids); 58 + } 59 + 43 60 $handles = $viewer->loadHandles($user_phids); 44 61 45 62 // Always put the viewer first if they are on the list. ··· 48 65 array_select_keys($user_phids, array($viewer->getPHID())) + 49 66 $user_phids; 50 67 51 - foreach ($user_phids as $user_phid) { 68 + if ($limit) { 69 + $render_phids = array_slice($user_phids, 0, $limit); 70 + } else { 71 + $render_phids = $user_phids; 72 + } 73 + 74 + foreach ($render_phids as $user_phid) { 52 75 $handle = $handles[$user_phid]; 53 76 54 77 $item = id(new PHUIObjectItemView()) ··· 70 93 $list->addItem($item); 71 94 } 72 95 96 + if ($user_phids) { 97 + $header = pht( 98 + '%s (%s)', 99 + $this->getHeaderText(), 100 + phutil_count($user_phids)); 101 + } else { 102 + $header = $this->getHeaderText(); 103 + } 104 + 73 105 return id(new PHUIObjectBoxView()) 74 - ->setHeaderText($this->getHeaderText()) 106 + ->setHeaderText($header) 75 107 ->setObjectList($list); 76 108 } 77 109