diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 4697562d45..49a9294311 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1868,7 +1868,6 @@ phutil_register_library_map(array( 'PonderVoteSaveController' => 'applications/ponder/controller/PonderVoteSaveController.php', 'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php', 'QueryFormattingTestCase' => 'infrastructure/storage/__tests__/QueryFormattingTestCase.php', - 'ReleephActiveProjectListView' => 'applications/releeph/view/project/list/ReleephActiveProjectListView.php', 'ReleephAuthorFieldSpecification' => 'applications/releeph/field/specification/ReleephAuthorFieldSpecification.php', 'ReleephBranch' => 'applications/releeph/storage/ReleephBranch.php', 'ReleephBranchAccessController' => 'applications/releeph/controller/branch/ReleephBranchAccessController.php', @@ -1897,7 +1896,6 @@ phutil_register_library_map(array( 'ReleephFieldSelector' => 'applications/releeph/field/selector/ReleephFieldSelector.php', 'ReleephFieldSpecification' => 'applications/releeph/field/specification/ReleephFieldSpecification.php', 'ReleephFieldSpecificationIncompleteException' => 'applications/releeph/field/exception/ReleephFieldSpecificationIncompleteException.php', - 'ReleephInactiveProjectListView' => 'applications/releeph/view/project/list/ReleephInactiveProjectListView.php', 'ReleephIntentFieldSpecification' => 'applications/releeph/field/specification/ReleephIntentFieldSpecification.php', 'ReleephLevelFieldSpecification' => 'applications/releeph/field/specification/ReleephLevelFieldSpecification.php', 'ReleephObjectHandleLoader' => 'applications/releeph/ReleephObjectHandleLoader.php', @@ -1910,6 +1908,7 @@ phutil_register_library_map(array( 'ReleephProjectEditController' => 'applications/releeph/controller/project/ReleephProjectEditController.php', 'ReleephProjectListController' => 'applications/releeph/controller/project/ReleephProjectListController.php', 'ReleephProjectQuery' => 'applications/releeph/query/ReleephProjectQuery.php', + 'ReleephProjectSearchEngine' => 'applications/releeph/query/ReleephProjectSearchEngine.php', 'ReleephProjectView' => 'applications/releeph/view/ReleephProjectView.php', 'ReleephProjectViewController' => 'applications/releeph/controller/project/ReleephProjectViewController.php', 'ReleephReasonFieldSpecification' => 'applications/releeph/field/specification/ReleephReasonFieldSpecification.php', @@ -3911,7 +3910,6 @@ phutil_register_library_map(array( 'PonderVoteSaveController' => 'PonderController', 'ProjectRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'QueryFormattingTestCase' => 'PhabricatorTestCase', - 'ReleephActiveProjectListView' => 'AphrontView', 'ReleephAuthorFieldSpecification' => 'ReleephFieldSpecification', 'ReleephBranch' => 'ReleephDAO', 'ReleephBranchAccessController' => 'ReleephProjectController', @@ -3920,7 +3918,7 @@ phutil_register_library_map(array( 'ReleephBranchCreateController' => 'ReleephProjectController', 'ReleephBranchEditController' => 'ReleephProjectController', 'ReleephBranchEditor' => 'PhabricatorEditor', - 'ReleephBranchNamePreviewController' => 'PhabricatorController', + 'ReleephBranchNamePreviewController' => 'ReleephController', 'ReleephBranchPreviewView' => 'AphrontFormControl', 'ReleephBranchViewController' => 'ReleephProjectController', 'ReleephCommitFinderException' => 'Exception', @@ -3936,7 +3934,6 @@ phutil_register_library_map(array( 'ReleephFieldParseException' => 'Exception', 'ReleephFieldSpecification' => 'PhabricatorMarkupInterface', 'ReleephFieldSpecificationIncompleteException' => 'Exception', - 'ReleephInactiveProjectListView' => 'AphrontView', 'ReleephIntentFieldSpecification' => 'ReleephFieldSpecification', 'ReleephLevelFieldSpecification' => 'ReleephFieldSpecification', 'ReleephObjectHandleLoader' => 'ObjectHandleLoader', @@ -3950,8 +3947,13 @@ phutil_register_library_map(array( 'ReleephProjectController' => 'ReleephController', 'ReleephProjectCreateController' => 'ReleephProjectController', 'ReleephProjectEditController' => 'ReleephProjectController', - 'ReleephProjectListController' => 'PhabricatorController', + 'ReleephProjectListController' => + array( + 0 => 'ReleephController', + 1 => 'PhabricatorApplicationSearchResultsControllerInterface', + ), 'ReleephProjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'ReleephProjectSearchEngine' => 'PhabricatorApplicationSearchEngine', 'ReleephProjectView' => 'AphrontView', 'ReleephProjectViewController' => 'ReleephProjectController', 'ReleephReasonFieldSpecification' => 'ReleephFieldSpecification', diff --git a/src/applications/releeph/application/PhabricatorApplicationReleeph.php b/src/applications/releeph/application/PhabricatorApplicationReleeph.php index ff710a1dca..b8eb8eefa0 100644 --- a/src/applications/releeph/application/PhabricatorApplicationReleeph.php +++ b/src/applications/releeph/application/PhabricatorApplicationReleeph.php @@ -35,7 +35,7 @@ final class PhabricatorApplicationReleeph extends PhabricatorApplication { '/releeph/' => array( '' => 'ReleephProjectListController', 'project/' => array( - '(?:(?Pactive|inactive)/)?' => 'ReleephProjectListController', + '(?:query/(?P[^/]+)/)?' => 'ReleephProjectListController', 'create/' => 'ReleephProjectCreateController', '(?P[1-9]\d*)/' => array( '' => 'ReleephProjectViewController', diff --git a/src/applications/releeph/controller/ReleephController.php b/src/applications/releeph/controller/ReleephController.php index 66037e92bb..1a2078ef5c 100644 --- a/src/applications/releeph/controller/ReleephController.php +++ b/src/applications/releeph/controller/ReleephController.php @@ -15,4 +15,27 @@ abstract class ReleephController extends PhabricatorController { return $response->setContent($page->render()); } + public function buildSideNavView($for_app = false) { + $user = $this->getRequest()->getUser(); + + $nav = new AphrontSideNavFilterView(); + $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); + + if ($for_app) { + $nav->addFilter('project/create/', pht('Create Project')); + } + + id(new ReleephProjectSearchEngine()) + ->setViewer($user) + ->addNavigationItems($nav->getMenu()); + + $nav->selectFilter(null); + + return $nav; + } + + public function buildApplicationMenu() { + return $this->buildSideNavView(true)->getMenu(); + } + } diff --git a/src/applications/releeph/controller/project/ReleephProjectListController.php b/src/applications/releeph/controller/project/ReleephProjectListController.php index 53071e091a..33537dd101 100644 --- a/src/applications/releeph/controller/project/ReleephProjectListController.php +++ b/src/applications/releeph/controller/project/ReleephProjectListController.php @@ -1,95 +1,109 @@ filter = idx($data, 'filter', 'active'); + $this->queryKey = idx($data, 'queryKey'); } public function processRequest() { $request = $this->getRequest(); - $user = $request->getUser(); + $controller = id(new PhabricatorApplicationSearchController($request)) + ->setQueryKey($this->queryKey) + ->setSearchEngine(new ReleephProjectSearchEngine()) + ->setNavigation($this->buildSideNavView()); - $query = id(new ReleephProjectQuery()) - ->setViewer($user) - ->setOrder(ReleephProjectQuery::ORDER_NAME); - - switch ($this->filter) { - case 'inactive': - $query->withActive(0); - $is_active = false; - break; - case 'active': - $query->withActive(1); - $is_active = true; - break; - default: - throw new Exception("Unknown filter '{$this->filter}'!"); - } - - $pager = new AphrontCursorPagerView(); - $pager->readFromRequest($request); - - $releeph_projects = $query->executeWithCursorPager($pager); - - $releeph_projects_set = new LiskDAOSet(); - foreach ($releeph_projects as $releeph_project) { - $releeph_projects_set->addToSet($releeph_project); - } - - $panel = new AphrontPanelView(); - - if ($is_active) { - $view_inactive_link = phutil_tag( - 'a', - array( - 'href' => '/releeph/project/inactive/', - ), - pht('View inactive projects')); - $panel - ->setHeader(hsprintf( - 'Active Releeph Projects · %s', $view_inactive_link)) - ->appendChild( - id(new ReleephActiveProjectListView()) - ->setUser($this->getRequest()->getUser()) - ->setReleephProjects($releeph_projects)); - } else { - $view_active_link = phutil_tag( - 'a', - array( - 'href' => '/releeph/project/' - ), - pht('View active projects')); - $panel - ->setHeader(hsprintf( - 'Inactive Releeph Projects · %s', $view_active_link)) - ->appendChild( - id(new ReleephInactiveProjectListView()) - ->setUser($this->getRequest()->getUser()) - ->setReleephProjects($releeph_projects)); - } - - if ($is_active) { - $create_new_project_button = phutil_tag( - 'a', - array( - 'href' => '/releeph/project/create/', - 'class' => 'green button', - ), - pht('Create New Project')); - $panel->addButton($create_new_project_button); - } - - return $this->buildApplicationPage( - array( - $panel, - $pager, - ), - array( - 'title' => pht('All Releeph Projects'), - )); + return $this->delegateToController($controller); } + public function renderResultsList( + array $projects, + PhabricatorSavedQuery $query) { + assert_instances_of($projects, 'ReleephProject'); + $viewer = $this->getRequest()->getUser(); + + $list = id(new PhabricatorObjectItemListView()) + ->setUser($viewer); + + foreach ($projects as $project) { + $id = $project->getID(); + + $item = id(new PhabricatorObjectItemView()) + ->setHeader($project->getName()) + ->setHref($this->getApplicationURI("project/{$id}/")); + + $edit_uri = $this->getApplicationURI("project/{$id}/edit/"); + $item->addAction( + id(new PHUIListItemView()) + ->setIcon('edit') + ->setHref($edit_uri)); + + if ($project->getIsActive()) { + $disable_uri = $this->getApplicationURI( + "project/{$id}/action/deactivate/"); + + $item->addAction( + id(new PHUIListItemView()) + ->setIcon('delete') + ->setName(pht('Deactivate')) + ->setWorkflow(true) + ->setHref($disable_uri)); + } else { + $enable_uri = $this->getApplicationURI( + "project/{$id}/action/activate/"); + + $item->setDisabled(true); + $item->addIcon('none', pht('Inactive')); + $item->addAction( + id(new PHUIListItemView()) + ->setIcon('new') + ->setName(pht('Reactivate')) + ->setWorkflow(true) + ->setHref($enable_uri)); + } + + // TODO: See T3551. + + $repo = $project->loadPhabricatorRepository(); + if ($repo) { + $item->addAttribute( + phutil_tag( + 'a', + array( + 'href' => '/diffusion/'.$repo->getCallsign().'/', + ), + 'r'.$repo->getCallsign())); + } + + $arc = $project->loadArcanistProject(); + if ($arc) { + $item->addAttribute($arc->getName()); + } + + $list->addItem($item); + } + + return $list; + } + + public function buildApplicationCrumbs() { + $crumbs = parent::buildApplicationCrumbs(); + + $crumbs->addAction( + id(new PHUIListItemView()) + ->setName(pht('Create Project')) + ->setHref($this->getApplicationURI('project/create/')) + ->setIcon('create')); + + return $crumbs; + } + + } diff --git a/src/applications/releeph/query/ReleephProjectSearchEngine.php b/src/applications/releeph/query/ReleephProjectSearchEngine.php new file mode 100644 index 0000000000..2e9685b12f --- /dev/null +++ b/src/applications/releeph/query/ReleephProjectSearchEngine.php @@ -0,0 +1,85 @@ +setParameter('active', $request->getStr('active')); + + return $saved; + } + + public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { + $query = id(new ReleephProjectQuery()) + ->setOrder(ReleephProjectQuery::ORDER_NAME); + + $active = $saved->getParameter('active'); + $value = idx($this->getActiveValues(), $active); + if ($value !== null) { + $query->withActive($value); + } + + return $query; + } + + public function buildSearchForm( + AphrontFormView $form, + PhabricatorSavedQuery $saved_query) { + + $form->appendChild( + id(new AphrontFormSelectControl()) + ->setName('active') + ->setLabel(pht('Show Projects')) + ->setValue($saved_query->getParameter('active')) + ->setOptions($this->getActiveOptions())); + + } + + protected function getURI($path) { + return '/releeph/project/'.$path; + } + + public function getBuiltinQueryNames() { + $names = array( + 'active' => pht('Active'), + 'all' => pht('All'), + ); + + return $names; + } + + public function buildSavedQueryFromBuiltin($query_key) { + + $query = $this->newSavedQuery(); + $query->setQueryKey($query_key); + + switch ($query_key) { + case 'active': + return $query + ->setParameter('active', 'active'); + case 'all': + return $query; + } + + return parent::buildSavedQueryFromBuiltin($query_key); + } + + private function getActiveOptions() { + return array( + 'all' => pht('Active and Inactive Projects'), + 'active' => pht('Active Projects'), + 'inactive' => pht('Inactive Projects'), + ); + } + + private function getActiveValues() { + return array( + 'all' => null, + 'active' => 1, + 'inactive' => 0, + ); + } + +} diff --git a/src/applications/releeph/view/project/list/ReleephActiveProjectListView.php b/src/applications/releeph/view/project/list/ReleephActiveProjectListView.php deleted file mode 100644 index 6b9d533f2b..0000000000 --- a/src/applications/releeph/view/project/list/ReleephActiveProjectListView.php +++ /dev/null @@ -1,102 +0,0 @@ -releephProjects = $releeph_projects; - return $this; - } - - public function render() { - $rows = array(); - foreach ($this->releephProjects as $releeph_project) { - $project_uri = $releeph_project->getURI(); - - $name_link = phutil_tag( - 'a', - array( - 'href' => $project_uri, - 'style' => 'font-weight: bold;', - ), - $releeph_project->getName()); - - $edit_button = phutil_tag( - 'a', - array( - 'href' => $releeph_project->getURI('edit/'), - 'class' => 'small grey button', - ), - 'Edit'); - - $deactivate_button = javelin_tag( - 'a', - array( - 'href' => $releeph_project->getURI('action/deactivate/'), - 'class' => 'small grey button', - 'sigil' => 'workflow', - ), - 'Remove'); - - $arc_project = $releeph_project->loadArcanistProject(); - if ($arc_project) { - $arc_project_name = $arc_project->getName(); - } else { - $arc_project_name = phutil_tag( - 'i', - array(), - 'Deleted Arcanist Project'); - } - - $repo = $releeph_project->loadPhabricatorRepository(); - - if ($repo) { - $vcs_type = - PhabricatorRepositoryType::getNameForRepositoryType( - $repo->getVersionControlSystem()); - - $rows[] = array( - $name_link, - $repo->getName(), - $arc_project_name, - $vcs_type, - $edit_button, - $deactivate_button, - ); - } else { - $rows[] = array( - $name_link, - phutil_tag('i', array(), 'Deleted Repository'), - $arc_project_name, - null, - null, - $deactivate_button, - ); - } - } - - $table = new AphrontTableView($rows); - - $table->setHeaders(array( - 'Name', - 'Repository', - 'Arcanist Project', - 'Type', - '', - '' - )); - - $table->setColumnClasses(array( - null, - null, - 'wide', - null, - 'action', - 'action' - )); - - return $table->render(); - } - -} diff --git a/src/applications/releeph/view/project/list/ReleephInactiveProjectListView.php b/src/applications/releeph/view/project/list/ReleephInactiveProjectListView.php deleted file mode 100644 index 765145e207..0000000000 --- a/src/applications/releeph/view/project/list/ReleephInactiveProjectListView.php +++ /dev/null @@ -1,112 +0,0 @@ -releephProjects = $releeph_projects; - return $this; - } - - public function render() { - $rows = array(); - - $phids = array(); - foreach ($this->releephProjects as $releeph_project) { - $phids[] = $releeph_project->getCreatedByUserPHID(); - if ($phid = $releeph_project->getDetail('last_deactivated_user')) { - $phids[] = $phid; - } - } - - $handles = id(new PhabricatorObjectHandleData($phids)) - ->setViewer($this->getUser()) - ->loadHandles(); - - foreach ($this->releephProjects as $releeph_project) { - $repository = $releeph_project->loadPhabricatorRepository(); - - if (!$repository) { - // Ignore projects referring to repositories that have been deleted. - continue; - } - - $activate_link = javelin_tag( - 'a', - array( - 'href' => $releeph_project->getURI('action/activate/'), - 'class' => 'small grey button', - 'sigil' => 'workflow', - ), - 'Revive'); - - $delete_link = javelin_tag( - 'a', - array( - 'href' => $releeph_project->getURI('action/delete/'), - 'class' => 'small grey button', - 'sigil' => 'workflow', - ), - 'Delete'); - - $rows[] = array( - $releeph_project->getName(), - $repository->getName(), - $this->renderCreationInfo($releeph_project, $handles), - $this->renderDeletionInfo($releeph_project, $handles), - $activate_link, - $delete_link, - ); - } - - $table = new AphrontTableView($rows); - - $table->setHeaders(array( - 'Name', - 'Repository', - 'Created', - 'Deleted', - '', - '', - )); - - $table->setColumnClasses(array( - null, - null, - null, - 'wide', - 'action', - 'action', - )); - - return $table->render(); - } - - private function renderCreationInfo($releeph_project, $handles) { - $creator = $handles[$releeph_project->getCreatedByUserPHID()]; - $when = $releeph_project->getDateCreated(); - return hsprintf( - '%s by %s', - phabricator_relative_date($when, $this->user), - $creator->getName()); - } - - private function renderDeletionInfo($releeph_project, $handles) { - $deleted_on = $releeph_project->getDetail('last_deactivated_time'); - - $deleted_by_name = null; - $deleted_by_phid = $releeph_project->getDetail('last_deactivated_user'); - if ($deleted_by_phid) { - $deleted_by_name = $handles[$deleted_by_phid]->getName(); - } else { - $deleted_by_name = 'unknown'; - } - - return hsprintf( - '%s by %s', - phabricator_relative_date($deleted_on, $this->user), - $deleted_by_name); - } - -}