Index: src/__phutil_library_map__.php =================================================================== --- src/__phutil_library_map__.php +++ src/__phutil_library_map__.php @@ -653,6 +653,7 @@ 'DrydockLeaseListController' => 'applications/drydock/controller/DrydockLeaseListController.php', 'DrydockLeaseQuery' => 'applications/drydock/query/DrydockLeaseQuery.php', 'DrydockLeaseReleaseController' => 'applications/drydock/controller/DrydockLeaseReleaseController.php', + 'DrydockLeaseSearchEngine' => 'applications/drydock/query/DrydockLeaseSearchEngine.php', 'DrydockLeaseStatus' => 'applications/drydock/constants/DrydockLeaseStatus.php', 'DrydockLeaseViewController' => 'applications/drydock/controller/DrydockLeaseViewController.php', 'DrydockLocalCommandInterface' => 'applications/drydock/interface/command/DrydockLocalCommandInterface.php', @@ -3046,10 +3047,19 @@ 'DrydockController' => 'PhabricatorController', 'DrydockDAO' => 'PhabricatorLiskDAO', 'DrydockFilesystemInterface' => 'DrydockInterface', - 'DrydockLease' => 'DrydockDAO', - 'DrydockLeaseListController' => 'DrydockController', - 'DrydockLeaseQuery' => 'PhabricatorOffsetPagedQuery', + 'DrydockLease' => + array( + 0 => 'DrydockDAO', + 1 => 'PhabricatorPolicyInterface', + ), + 'DrydockLeaseListController' => + array( + 0 => 'DrydockController', + 1 => 'PhabricatorApplicationSearchResultsControllerInterface', + ), + 'DrydockLeaseQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DrydockLeaseReleaseController' => 'DrydockController', + 'DrydockLeaseSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DrydockLeaseStatus' => 'DrydockConstants', 'DrydockLeaseViewController' => 'DrydockController', 'DrydockLocalCommandInterface' => 'DrydockCommandInterface', Index: src/applications/drydock/application/PhabricatorApplicationDrydock.php =================================================================== --- src/applications/drydock/application/PhabricatorApplicationDrydock.php +++ src/applications/drydock/application/PhabricatorApplicationDrydock.php @@ -46,7 +46,7 @@ '(?P[1-9]\d*)/close/' => 'DrydockResourceCloseController', ), 'lease/' => array( - '' => 'DrydockLeaseListController', + '(?:query/(?P[^/]+)/)?' => 'DrydockLeaseListController', '(?P[1-9]\d*)/' => 'DrydockLeaseViewController', '(?P[1-9]\d*)/release/' => 'DrydockLeaseReleaseController', ), Index: src/applications/drydock/constants/DrydockLeaseStatus.php =================================================================== --- src/applications/drydock/constants/DrydockLeaseStatus.php +++ src/applications/drydock/constants/DrydockLeaseStatus.php @@ -10,16 +10,27 @@ const STATUS_EXPIRED = 4; public static function getNameForStatus($status) { - static $map = array( - self::STATUS_PENDING => 'Pending', - self::STATUS_ACQUIRING => 'Acquiring', - self::STATUS_ACTIVE => 'Active', - self::STATUS_RELEASED => 'Released', - self::STATUS_BROKEN => 'Broken', - self::STATUS_EXPIRED => 'Expired', + $map = array( + self::STATUS_PENDING => pht('Pending'), + self::STATUS_ACQUIRING => pht('Acquiring'), + self::STATUS_ACTIVE => pht('Active'), + self::STATUS_RELEASED => pht('Released'), + self::STATUS_BROKEN => pht('Broken'), + self::STATUS_EXPIRED => pht('Expired'), ); - return idx($map, $status, 'Unknown'); + return idx($map, $status, pht('Unknown')); + } + + public static function getAllStatuses() { + return array( + self::STATUS_PENDING, + self::STATUS_ACQUIRING, + self::STATUS_ACTIVE, + self::STATUS_RELEASED, + self::STATUS_BROKEN, + self::STATUS_EXPIRED, + ); } } Index: src/applications/drydock/controller/DrydockController.php =================================================================== --- src/applications/drydock/controller/DrydockController.php +++ src/applications/drydock/controller/DrydockController.php @@ -2,12 +2,17 @@ abstract class DrydockController extends PhabricatorController { - final protected function buildSideNav($selected) { + final protected function buildSideNav($selected = null) { $nav = new AphrontSideNavFilterView(); $nav->setBaseURI(new PhutilURI('/drydock/')); $nav->addFilter('blueprint', 'Blueprints'); $nav->addFilter('resource', 'Resources'); - $nav->addFilter('lease', 'Leases'); + + id(new DrydockLeaseSearchEngine()) + ->setViewer($this->getRequest()->getUser()) + ->addNavigationItems($nav->getMenu(), pht('Leases')); + + $nav->addLabel(pht('Logs')); $nav->addFilter('log', 'Logs'); $nav->selectFilter($selected, 'resource'); @@ -80,11 +85,12 @@ protected function buildLeaseListView(array $leases) { assert_instances_of($leases, 'DrydockLease'); - $user = $this->getRequest()->getUser(); + $viewer = $this->getRequest()->getUser(); $view = new PHUIObjectItemListView(); foreach ($leases as $lease) { $item = id(new PHUIObjectItemView()) + ->setUser($viewer) ->setHeader($lease->getLeaseName()) ->setHref($this->getApplicationURI('/lease/'.$lease->getID().'/')); @@ -107,9 +113,7 @@ $status = DrydockLeaseStatus::getNameForStatus($lease->getStatus()); $item->addAttribute($status); - - $date_created = phabricator_date($lease->getDateCreated(), $user); - $item->addAttribute(pht('Created on %s', $date_created)); + $item->setEpoch($lease->getDateCreated()); if ($lease->isActive()) { $item->setBarColor('green'); Index: src/applications/drydock/controller/DrydockLeaseListController.php =================================================================== --- src/applications/drydock/controller/DrydockLeaseListController.php +++ src/applications/drydock/controller/DrydockLeaseListController.php @@ -1,46 +1,34 @@ getRequest(); - $user = $request->getUser(); - - $nav = $this->buildSideNav('lease'); - - $pager = new AphrontPagerView(); - $pager->setURI(new PhutilURI('/drydock/lease/'), 'offset'); - $pager->setOffset($request->getInt('offset')); - - $leases = id(new DrydockLeaseQuery()) - ->setViewer($user) - ->executeWithOffsetPager($pager); - - $title = pht('Leases'); + private $queryKey; - $header = id(new PHUIHeaderView()) - ->setHeader($title); + public function shouldAllowPublic() { + return true; + } - $lease_list = $this->buildLeaseListView($leases); + public function willProcessRequest(array $data) { + $this->queryKey = idx($data, 'queryKey'); + } - $nav->appendChild( - array( - $header, - $lease_list, - $pager, - )); + public function processRequest() { + $request = $this->getRequest(); + $controller = id(new PhabricatorApplicationSearchController($request)) + ->setQueryKey($this->queryKey) + ->setSearchEngine(new DrydockLeaseSearchEngine()) + ->setNavigation($this->buildSideNav()); - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb($title, $request->getRequestURI()); - $nav->setCrumbs($crumbs); + return $this->delegateToController($controller); + } - return $this->buildApplicationPage( - $nav, - array( - 'device' => true, - 'title' => $title, - )); + public function renderResultsList( + array $leases, + PhabricatorSavedQuery $query) { + assert_instances_of($leases, 'DrydockLease'); + return $this->buildLeaseListView($leases); } } Index: src/applications/drydock/query/DrydockLeaseQuery.php =================================================================== --- src/applications/drydock/query/DrydockLeaseQuery.php +++ src/applications/drydock/query/DrydockLeaseQuery.php @@ -5,6 +5,7 @@ private $ids; private $resourceIDs; + private $statuses; public function withIDs(array $ids) { $this->ids = $ids; @@ -16,6 +17,11 @@ return $this; } + public function withStatuses(array $statuses) { + $this->statuses = $statuses; + return $this; + } + public function loadPage() { $table = new DrydockLease(); $conn_r = $table->establishConnection('r'); @@ -67,6 +73,13 @@ $this->ids); } + if ($this->statuses) { + $where[] = qsprintf( + $conn_r, + 'status IN (%Ld)', + $this->statuses); + } + $where[] = $this->buildPagingClause($conn_r); return $this->formatWhereClause($where); Index: src/applications/drydock/query/DrydockLeaseSearchEngine.php =================================================================== --- /dev/null +++ src/applications/drydock/query/DrydockLeaseSearchEngine.php @@ -0,0 +1,81 @@ +setParameter( + 'statuses', + $this->readListFromRequest($request, 'statuses')); + + return $saved; + } + + public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { + $query = id(new DrydockLeaseQuery()); + + $statuses = $saved->getParameter('statuses', array()); + if ($statuses) { + $query->withStatuses($statuses); + } + + return $query; + } + + public function buildSearchForm( + AphrontFormView $form, + PhabricatorSavedQuery $saved) { + + $statuses = $saved->getParameter('statuses', array()); + + $status_control = id(new AphrontFormCheckboxControl()) + ->setLabel(pht('Status')); + foreach (DrydockLeaseStatus::getAllStatuses() as $status) { + $status_control->addCheckbox( + 'statuses[]', + $status, + DrydockLeaseStatus::getNameForStatus($status), + in_array($status, $statuses)); + } + + $form + ->appendChild($status_control); + + } + + protected function getURI($path) { + return '/drydock/lease/'.$path; + } + + public function getBuiltinQueryNames() { + $names = array( + 'active' => pht('Active Leases'), + 'all' => pht('All Leases'), + ); + + return $names; + } + + public function buildSavedQueryFromBuiltin($query_key) { + $query = $this->newSavedQuery(); + $query->setQueryKey($query_key); + + switch ($query_key) { + case 'active': + return $query->setParameter( + 'statuses', + array( + DrydockLeaseStatus::STATUS_PENDING, + DrydockLeaseStatus::STATUS_ACQUIRING, + DrydockLeaseStatus::STATUS_ACTIVE, + )); + case 'all': + return $query; + } + + return parent::buildSavedQueryFromBuiltin($query_key); + } + +} Index: src/applications/search/engine/PhabricatorApplicationSearchEngine.php =================================================================== --- src/applications/search/engine/PhabricatorApplicationSearchEngine.php +++ src/applications/search/engine/PhabricatorApplicationSearchEngine.php @@ -108,10 +108,10 @@ } - public function addNavigationItems(PHUIListView $menu) { + public function addNavigationItems(PHUIListView $menu, $label = null) { $viewer = $this->requireViewer(); - $menu->newLabel(pht('Queries')); + $menu->newLabel(coalesce($label, pht('Queries'))); $named_queries = $this->loadEnabledNamedQueries();