diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index a7e6796ef2..a204da62da 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2881,9 +2881,9 @@ phutil_register_library_map(array( 'PhabricatorProjectEditController' => 'applications/project/controller/PhabricatorProjectEditController.php', 'PhabricatorProjectEditEngine' => 'applications/project/engine/PhabricatorProjectEditEngine.php', 'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php', - 'PhabricatorProjectFeedController' => 'applications/project/controller/PhabricatorProjectFeedController.php', 'PhabricatorProjectFulltextEngine' => 'applications/project/search/PhabricatorProjectFulltextEngine.php', 'PhabricatorProjectHeraldAction' => 'applications/project/herald/PhabricatorProjectHeraldAction.php', + 'PhabricatorProjectHistoryController' => 'applications/project/controller/PhabricatorProjectHistoryController.php', 'PhabricatorProjectIconSet' => 'applications/project/icon/PhabricatorProjectIconSet.php', 'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php', 'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php', @@ -7283,9 +7283,9 @@ phutil_register_library_map(array( 'PhabricatorProjectEditController' => 'PhabricatorProjectController', 'PhabricatorProjectEditEngine' => 'PhabricatorEditEngine', 'PhabricatorProjectEditPictureController' => 'PhabricatorProjectController', - 'PhabricatorProjectFeedController' => 'PhabricatorProjectController', 'PhabricatorProjectFulltextEngine' => 'PhabricatorFulltextEngine', 'PhabricatorProjectHeraldAction' => 'HeraldAction', + 'PhabricatorProjectHistoryController' => 'PhabricatorProjectController', 'PhabricatorProjectIconSet' => 'PhabricatorIconSet', 'PhabricatorProjectListController' => 'PhabricatorProjectController', 'PhabricatorProjectListView' => 'AphrontView', diff --git a/src/applications/files/controller/PhabricatorFileComposeController.php b/src/applications/files/controller/PhabricatorFileComposeController.php index 17e605f3a9..404cf44aca 100644 --- a/src/applications/files/controller/PhabricatorFileComposeController.php +++ b/src/applications/files/controller/PhabricatorFileComposeController.php @@ -44,7 +44,7 @@ final class PhabricatorFileComposeController )); if ($project_phid) { - $edit_uri = '/project/profile/'.$project->getID().'/'; + $edit_uri = '/project/history/'.$project->getID().'/'; $xactions = array(); $xactions[] = id(new PhabricatorProjectTransaction()) diff --git a/src/applications/project/application/PhabricatorProjectApplication.php b/src/applications/project/application/PhabricatorProjectApplication.php index d2990f527a..e1b484ffe2 100644 --- a/src/applications/project/application/PhabricatorProjectApplication.php +++ b/src/applications/project/application/PhabricatorProjectApplication.php @@ -55,8 +55,6 @@ final class PhabricatorProjectApplication extends PhabricatorApplication { => 'PhabricatorProjectMembersRemoveController', 'profile/(?P[1-9]\d*)/' => 'PhabricatorProjectProfileController', - 'feed/(?P[1-9]\d*)/' - => 'PhabricatorProjectFeedController', 'view/(?P[1-9]\d*)/' => 'PhabricatorProjectViewController', 'picture/(?P[1-9]\d*)/' diff --git a/src/applications/project/controller/PhabricatorProjectArchiveController.php b/src/applications/project/controller/PhabricatorProjectArchiveController.php index d6470ca1eb..505af27ef1 100644 --- a/src/applications/project/controller/PhabricatorProjectArchiveController.php +++ b/src/applications/project/controller/PhabricatorProjectArchiveController.php @@ -20,7 +20,7 @@ final class PhabricatorProjectArchiveController return new Aphront404Response(); } - $edit_uri = $this->getApplicationURI('profile/'.$project->getID().'/'); + $edit_uri = $this->getApplicationURI('history/'.$project->getID().'/'); if ($request->isFormPost()) { if ($project->isArchived()) { diff --git a/src/applications/project/controller/PhabricatorProjectEditPictureController.php b/src/applications/project/controller/PhabricatorProjectEditPictureController.php index 41ccb94eb3..b0c013dadc 100644 --- a/src/applications/project/controller/PhabricatorProjectEditPictureController.php +++ b/src/applications/project/controller/PhabricatorProjectEditPictureController.php @@ -23,8 +23,8 @@ final class PhabricatorProjectEditPictureController $this->setProject($project); - $edit_uri = $this->getApplicationURI('profile/'.$project->getID().'/'); - $view_uri = $this->getApplicationURI('profile/'.$project->getID().'/'); + $edit_uri = $this->getApplicationURI('history/'.$project->getID().'/'); + $view_uri = $this->getApplicationURI('history/'.$project->getID().'/'); $supported_formats = PhabricatorFile::getTransformableImageFormats(); $e_file = true; diff --git a/src/applications/project/controller/PhabricatorProjectFeedController.php b/src/applications/project/controller/PhabricatorProjectFeedController.php deleted file mode 100644 index a108384088..0000000000 --- a/src/applications/project/controller/PhabricatorProjectFeedController.php +++ /dev/null @@ -1,62 +0,0 @@ -getUser(); - - $response = $this->loadProject(); - if ($response) { - return $response; - } - - $project = $this->getProject(); - $id = $project->getID(); - - $stories = id(new PhabricatorFeedQuery()) - ->setViewer($viewer) - ->setFilterPHIDs( - array( - $project->getPHID(), - )) - ->setLimit(50) - ->execute(); - - $feed = $this->renderStories($stories); - - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Project Activity')) - ->appendChild($feed); - - $nav = $this->getProfileMenu(); - $nav->selectFilter('feed'); - - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb(pht('Feed')); - - return $this->newPage() - ->setNavigation($nav) - ->setCrumbs($crumbs) - ->setTitle(array($project->getName(), pht('Feed'))) - ->appendChild($box); - } - - private function renderStories(array $stories) { - assert_instances_of($stories, 'PhabricatorFeedStory'); - - $builder = new PhabricatorFeedBuilder($stories); - $builder->setUser($this->getRequest()->getUser()); - $builder->setShowHovercards(true); - $view = $builder->buildView(); - - return phutil_tag_div( - 'profile-feed', - $view->render()); - } - -} diff --git a/src/applications/project/controller/PhabricatorProjectHistoryController.php b/src/applications/project/controller/PhabricatorProjectHistoryController.php new file mode 100644 index 0000000000..aa58e081f4 --- /dev/null +++ b/src/applications/project/controller/PhabricatorProjectHistoryController.php @@ -0,0 +1,133 @@ +loadProject(); + if ($response) { + return $response; + } + + $viewer = $request->getUser(); + $project = $this->getProject(); + $id = $project->getID(); + $picture = $project->getProfileImageURI(); + + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Project History')) + ->setUser($viewer) + ->setPolicyObject($project) + ->setImage($picture); + + if ($project->getStatus() == PhabricatorProjectStatus::STATUS_ACTIVE) { + $header->setStatus('fa-check', 'bluegrey', pht('Active')); + } else { + $header->setStatus('fa-ban', 'red', pht('Archived')); + } + + $actions = $this->buildActionListView($project); + $properties = $this->buildPropertyListView($project, $actions); + + $object_box = id(new PHUIObjectBoxView()) + ->setHeader($header) + ->addPropertyList($properties); + + $timeline = $this->buildTransactionTimeline( + $project, + new PhabricatorProjectTransactionQuery()); + $timeline->setShouldTerminate(true); + + $nav = $this->getProfileMenu(); + $nav->selectFilter(PhabricatorProject::PANEL_PROFILE); + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('History')); + + return $this->newPage() + ->setNavigation($nav) + ->setCrumbs($crumbs) + ->setTitle($project->getName()) + ->appendChild( + array( + $object_box, + $timeline, + )); + } + + private function buildActionListView(PhabricatorProject $project) { + $request = $this->getRequest(); + $viewer = $request->getUser(); + + $id = $project->getID(); + + $view = id(new PhabricatorActionListView()) + ->setUser($viewer); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $project, + PhabricatorPolicyCapability::CAN_EDIT); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Back to Profile')) + ->setIcon('fa-chevron-left') + ->setHref($project->getURI())); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Edit Details')) + ->setIcon('fa-pencil') + ->setHref($this->getApplicationURI("edit/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit)); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Edit Picture')) + ->setIcon('fa-picture-o') + ->setHref($this->getApplicationURI("picture/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit)); + + if ($project->isArchived()) { + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Activate Project')) + ->setIcon('fa-check') + ->setHref($this->getApplicationURI("archive/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(true)); + } else { + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Archive Project')) + ->setIcon('fa-ban') + ->setHref($this->getApplicationURI("archive/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(true)); + } + + return $view; + } + + private function buildPropertyListView( + PhabricatorProject $project, + PhabricatorActionListView $actions) { + $request = $this->getRequest(); + $viewer = $request->getUser(); + + $view = id(new PHUIPropertyListView()) + ->setUser($viewer) + ->setActionList($actions); + + return $view; + } + + +} diff --git a/src/applications/project/controller/PhabricatorProjectProfileController.php b/src/applications/project/controller/PhabricatorProjectProfileController.php index 89600e97d7..9bb694d9ba 100644 --- a/src/applications/project/controller/PhabricatorProjectProfileController.php +++ b/src/applications/project/controller/PhabricatorProjectProfileController.php @@ -8,13 +8,12 @@ final class PhabricatorProjectProfileController } public function handleRequest(AphrontRequest $request) { - $viewer = $request->getUser(); - $response = $this->loadProject(); if ($response) { return $response; } + $viewer = $request->getUser(); $project = $this->getProject(); $id = $project->getID(); $picture = $project->getProfileImageURI(); @@ -38,14 +37,46 @@ final class PhabricatorProjectProfileController ->setHeader($header) ->addPropertyList($properties); - $timeline = $this->buildTransactionTimeline( - $project, - new PhabricatorProjectTransactionQuery()); - $timeline->setShouldTerminate(true); + $member_list = id(new PhabricatorProjectMemberListView()) + ->setUser($viewer) + ->setProject($project) + ->setLimit(5) + ->setUserPHIDs($project->getMemberPHIDs()); + + $watcher_list = id(new PhabricatorProjectWatcherListView()) + ->setUser($viewer) + ->setProject($project) + ->setLimit(5) + ->setUserPHIDs($project->getWatcherPHIDs()); $nav = $this->getProfileMenu(); $nav->selectFilter(PhabricatorProject::PANEL_PROFILE); + + $stories = id(new PhabricatorFeedQuery()) + ->setViewer($viewer) + ->setFilterPHIDs( + array( + $project->getPHID(), + )) + ->setLimit(50) + ->execute(); + + $feed = $this->renderStories($stories); + + $feed = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Recent Activity')) + ->appendChild($feed); + + $columns = id(new AphrontMultiColumnView()) + ->setFluidLayout(true) + ->addColumn($feed) + ->addColumn( + array( + $member_list, + $watcher_list, + )); + $crumbs = $this->buildApplicationCrumbs(); return $this->newPage() @@ -53,8 +84,11 @@ final class PhabricatorProjectProfileController ->setCrumbs($crumbs) ->setTitle($project->getName()) ->setPageObjectPHIDs(array($project->getPHID())) - ->appendChild($object_box) - ->appendChild($timeline); + ->appendChild( + array( + $object_box, + $columns, + )); } private function buildActionListView(PhabricatorProject $project) { @@ -67,44 +101,11 @@ final class PhabricatorProjectProfileController ->setUser($viewer) ->setObject($project); - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $project, - PhabricatorPolicyCapability::CAN_EDIT); - $view->addAction( id(new PhabricatorActionView()) - ->setName(pht('Edit Details')) + ->setName(pht('Edit Project')) ->setIcon('fa-pencil') - ->setHref($this->getApplicationURI("edit/{$id}/")) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - $view->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Edit Picture')) - ->setIcon('fa-picture-o') - ->setHref($this->getApplicationURI("picture/{$id}/")) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - if ($project->isArchived()) { - $view->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Activate Project')) - ->setIcon('fa-check') - ->setHref($this->getApplicationURI("archive/{$id}/")) - ->setDisabled(!$can_edit) - ->setWorkflow(true)); - } else { - $view->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Archive Project')) - ->setIcon('fa-ban') - ->setHref($this->getApplicationURI("archive/{$id}/")) - ->setDisabled(!$can_edit) - ->setWorkflow(true)); - } + ->setHref($this->getApplicationURI("history/{$id}/"))); return $view; } @@ -120,33 +121,6 @@ final class PhabricatorProjectProfileController ->setObject($project) ->setActionList($actions); - $hashtags = array(); - foreach ($project->getSlugs() as $slug) { - $hashtags[] = id(new PHUITagView()) - ->setType(PHUITagView::TYPE_OBJECT) - ->setName('#'.$slug->getSlug()); - } - - if ($hashtags) { - $view->addProperty(pht('Hashtags'), phutil_implode_html(' ', $hashtags)); - } - - $view->addProperty( - pht('Members'), - $project->getMemberPHIDs() - ? $viewer - ->renderHandleList($project->getMemberPHIDs()) - ->setAsInline(true) - : phutil_tag('em', array(), pht('None'))); - - $view->addProperty( - pht('Watchers'), - $project->getWatcherPHIDs() - ? $viewer - ->renderHandleList($project->getWatcherPHIDs()) - ->setAsInline(true) - : phutil_tag('em', array(), pht('None'))); - $view->addProperty( pht('Looks Like'), $viewer->renderHandle($project->getPHID())->setAsTag(true)); @@ -159,5 +133,15 @@ final class PhabricatorProjectProfileController return $view; } + private function renderStories(array $stories) { + assert_instances_of($stories, 'PhabricatorFeedStory'); + + $builder = new PhabricatorFeedBuilder($stories); + $builder->setUser($this->getRequest()->getUser()); + $builder->setShowHovercards(true); + $view = $builder->buildView(); + + return phutil_tag_div('profile-feed', $view->render()); + } } diff --git a/src/applications/project/engine/PhabricatorProjectEditEngine.php b/src/applications/project/engine/PhabricatorProjectEditEngine.php index 389c585fce..42a2000c86 100644 --- a/src/applications/project/engine/PhabricatorProjectEditEngine.php +++ b/src/applications/project/engine/PhabricatorProjectEditEngine.php @@ -78,7 +78,12 @@ final class PhabricatorProjectEditEngine } protected function getObjectViewURI($object) { - return $object->getURI(); + if ($this->getIsCreate()) { + return $object->getURI(); + } else { + $id = $object->getID(); + return "/project/history/{$id}/"; + } } protected function getObjectCreateCancelURI($object) { diff --git a/src/applications/project/engine/PhabricatorProjectProfilePanelEngine.php b/src/applications/project/engine/PhabricatorProjectProfilePanelEngine.php index d37caeecf8..f88faa15c4 100644 --- a/src/applications/project/engine/PhabricatorProjectProfilePanelEngine.php +++ b/src/applications/project/engine/PhabricatorProjectProfilePanelEngine.php @@ -32,15 +32,6 @@ final class PhabricatorProjectProfilePanelEngine ->setPanelProperty('name', pht('Open Tasks')) ->setPanelProperty('uri', $uri); - // TODO: This is temporary. - $id = $object->getID(); - $panels[] = $this->newPanel() - ->setBuiltinKey('feed') - ->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY) - ->setPanelProperty('icon', 'feed') - ->setPanelProperty('name', pht('Feed')) - ->setPanelProperty('uri', "/project/feed/{$id}/"); - $panels[] = $this->newPanel() ->setBuiltinKey(PhabricatorProject::PANEL_MEMBERS) ->setPanelKey(PhabricatorProjectMembersProfilePanel::PANELKEY); diff --git a/src/applications/project/view/PhabricatorProjectUserListView.php b/src/applications/project/view/PhabricatorProjectUserListView.php index e42b427ed3..f93b9da695 100644 --- a/src/applications/project/view/PhabricatorProjectUserListView.php +++ b/src/applications/project/view/PhabricatorProjectUserListView.php @@ -4,6 +4,7 @@ abstract class PhabricatorProjectUserListView extends AphrontView { private $project; private $userPHIDs; + private $limit; public function setProject(PhabricatorProject $project) { $this->project = $project; @@ -23,6 +24,15 @@ abstract class PhabricatorProjectUserListView extends AphrontView { return $this->userPHIDs; } + public function setLimit($limit) { + $this->limit = $limit; + return $this; + } + + public function getLimit() { + return $this->limit; + } + abstract protected function canEditList(); abstract protected function getNoDataString(); abstract protected function getRemoveURI($phid); @@ -39,7 +49,14 @@ abstract class PhabricatorProjectUserListView extends AphrontView { $list = id(new PHUIObjectItemListView()) ->setNoDataString($no_data); - $user_phids = array_reverse($user_phids); + $limit = $this->getLimit(); + + // If we're showing everything, show oldest to newest. If we're showing + // only a slice, show newest to oldest. + if (!$limit) { + $user_phids = array_reverse($user_phids); + } + $handles = $viewer->loadHandles($user_phids); // Always put the viewer first if they are on the list. @@ -48,7 +65,13 @@ abstract class PhabricatorProjectUserListView extends AphrontView { array_select_keys($user_phids, array($viewer->getPHID())) + $user_phids; - foreach ($user_phids as $user_phid) { + if ($limit) { + $render_phids = array_slice($user_phids, 0, $limit); + } else { + $render_phids = $user_phids; + } + + foreach ($render_phids as $user_phid) { $handle = $handles[$user_phid]; $item = id(new PHUIObjectItemView()) @@ -70,8 +93,17 @@ abstract class PhabricatorProjectUserListView extends AphrontView { $list->addItem($item); } + if ($user_phids) { + $header = pht( + '%s (%s)', + $this->getHeaderText(), + phutil_count($user_phids)); + } else { + $header = $this->getHeaderText(); + } + return id(new PHUIObjectBoxView()) - ->setHeaderText($this->getHeaderText()) + ->setHeaderText($header) ->setObjectList($list); }