diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index f8d01fc2f4..d660e79aee 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -449,6 +449,7 @@ phutil_register_library_map(array( 'DrydockResource' => 'applications/drydock/storage/DrydockResource.php', 'DrydockResourceCloseController' => 'applications/drydock/controller/DrydockResourceCloseController.php', 'DrydockResourceListController' => 'applications/drydock/controller/DrydockResourceListController.php', + 'DrydockResourceQuery' => 'applications/drydock/query/DrydockResourceQuery.php', 'DrydockResourceStatus' => 'applications/drydock/constants/DrydockResourceStatus.php', 'DrydockResourceViewController' => 'applications/drydock/controller/DrydockResourceViewController.php', 'DrydockSSHCommandInterface' => 'applications/drydock/interface/command/DrydockSSHCommandInterface.php', @@ -1739,6 +1740,7 @@ phutil_register_library_map(array( 'DrydockResource' => 'DrydockDAO', 'DrydockResourceCloseController' => 'DrydockController', 'DrydockResourceListController' => 'DrydockController', + 'DrydockResourceQuery' => 'PhabricatorOffsetPagedQuery', 'DrydockResourceStatus' => 'DrydockConstants', 'DrydockResourceViewController' => 'DrydockController', 'DrydockSSHCommandInterface' => 'DrydockCommandInterface', diff --git a/src/applications/drydock/blueprint/DrydockLocalHostBlueprint.php b/src/applications/drydock/blueprint/DrydockLocalHostBlueprint.php index eecdbd4fb2..2b03a87940 100644 --- a/src/applications/drydock/blueprint/DrydockLocalHostBlueprint.php +++ b/src/applications/drydock/blueprint/DrydockLocalHostBlueprint.php @@ -28,7 +28,7 @@ final class DrydockLocalHostBlueprint extends DrydockBlueprint { Filesystem::assertIsDirectory($path); Filesystem::assertWritable($path); - $resource = $this->newResourceTemplate('localhost'); + $resource = $this->newResourceTemplate('Host (localhost)'); $resource->setStatus(DrydockResourceStatus::STATUS_OPEN); $resource->setAttribute('path', $path); $resource->save(); diff --git a/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprint.php b/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprint.php index 665753275a..32f8b05118 100644 --- a/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprint.php +++ b/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprint.php @@ -62,7 +62,8 @@ final class DrydockWorkingCopyBlueprint extends DrydockBlueprint { $this->log(pht('Complete.')); - $resource = $this->newResourceTemplate($repository->getCallsign()); + $resource = $this->newResourceTemplate( + 'Working Copy ('.$repository->getCallsign().')'); $resource->setStatus(DrydockResourceStatus::STATUS_OPEN); $resource->setAttribute('lease.host', $host_lease->getID()); $resource->setAttribute('path', $path); diff --git a/src/applications/drydock/controller/DrydockController.php b/src/applications/drydock/controller/DrydockController.php index 103be607af..0ea54bb6a4 100644 --- a/src/applications/drydock/controller/DrydockController.php +++ b/src/applications/drydock/controller/DrydockController.php @@ -86,4 +86,88 @@ abstract class DrydockController extends PhabricatorController { return $panel; } + protected function buildLeaseListView(array $leases) { + assert_instances_of($leases, 'DrydockLease'); + + $user = $this->getRequest()->getUser(); + $view = new PhabricatorObjectItemListView(); + + foreach ($leases as $lease) { + $item = id(new PhabricatorObjectItemView()) + ->setHeader($lease->getLeaseName()) + ->setHref($this->getApplicationURI('/lease/'.$lease->getID().'/')); + + if ($lease->hasAttachedResource()) { + $resource = $lease->getResource(); + + $resource_href = '/resource/'.$resource->getID().'/'; + $resource_href = $this->getApplicationURI($resource_href); + + $resource_name = $resource->getName(); + + $item->addAttribute( + phutil_render_tag( + 'a', + array( + 'href' => $resource_href, + ), + phutil_escape_html($resource_name))); + } + + $status = DrydockLeaseStatus::getNameForStatus($lease->getStatus()); + $item->addAttribute(phutil_escape_html($status)); + + $date_created = phabricator_date($lease->getDateCreated(), $user); + $item->addAttribute(pht('Created on %s', $date_created)); + + if ($lease->isActive()) { + $item->setBarColor('green'); + } else { + $item->setBarColor('red'); + } + + $view->addItem($item); + } + + return $view; + } + + protected function buildResourceListView(array $resources) { + assert_instances_of($resources, 'DrydockResource'); + + $user = $this->getRequest()->getUser(); + $view = new PhabricatorObjectItemListView(); + + foreach ($resources as $resource) { + $name = pht('Resource %d', $resource->getID()).': '.$resource->getName(); + + $item = id(new PhabricatorObjectItemView()) + ->setHref($this->getApplicationURI('/resource/'.$resource->getID().'/')) + ->setHeader($name); + + $status = DrydockResourceStatus::getNameForStatus($resource->getStatus()); + $item->addAttribute($status); + + switch ($resource->getStatus()) { + case DrydockResourceStatus::STATUS_PENDING: + $item->setBarColor('yellow'); + break; + case DrydockResourceStatus::STATUS_OPEN: + $item->setBarColor('green'); + break; + case DrydockResourceStatus::STATUS_DESTROYED: + $item->setBarColor('black'); + break; + default: + $item->setBarColor('red'); + break; + } + + $view->addItem($item); + } + + return $view; + } + + } diff --git a/src/applications/drydock/controller/DrydockLeaseListController.php b/src/applications/drydock/controller/DrydockLeaseListController.php index f43d1d5716..43507b3ea4 100644 --- a/src/applications/drydock/controller/DrydockLeaseListController.php +++ b/src/applications/drydock/controller/DrydockLeaseListController.php @@ -12,84 +12,36 @@ final class DrydockLeaseListController extends DrydockController { $pager->setURI(new PhutilURI('/drydock/lease/'), 'offset'); $pager->setOffset($request->getInt('offset')); - $data = id(new DrydockLease())->loadAllWhere( - '1 = 1 ORDER BY id DESC LIMIT %d, %d', - $pager->getOffset(), - $pager->getPageSize() + 1); - $data = $pager->sliceResults($data); + $leases = id(new DrydockLeaseQuery()) + ->needResources(true) + ->executeWithOffsetPager($pager); - $resource_ids = mpull($data, 'getResourceID'); - $resources = array(); - if ($resource_ids) { - $resources = id(new DrydockResource())->loadAllWhere( - 'id IN (%Ld)', - $resource_ids); - } + $title = pht('Leases'); - $rows = array(); - foreach ($data as $lease) { - $resource = idx($resources, $lease->getResourceID()); + $header = id(new PhabricatorHeaderView()) + ->setHeader($title); - $lease_uri = '/lease/'.$lease->getID().'/'; - $lease_uri = $this->getApplicationURI($lease_uri); + $lease_list = $this->buildLeaseListView($leases); - $resource_uri = '/resource/'.$lease->getResourceID().'/'; - $resource_uri = $this->getApplicationURI($resource_uri); - - $rows[] = array( - phutil_render_tag( - 'a', - array( - 'href' => $lease_uri, - ), - $lease->getID()), - phutil_render_tag( - 'a', - array( - 'href' => $resource_uri, - ), - $lease->getResourceID()), - DrydockLeaseStatus::getNameForStatus($lease->getStatus()), - phutil_escape_html($lease->getResourceType()), - ($resource - ? phutil_escape_html($resource->getName()) - : null), - phabricator_datetime($lease->getDateCreated(), $user), - ); - } - - $table = new AphrontTableView($rows); - $table->setHeaders( + $nav->appendChild( array( - 'ID', - 'Resource ID', - 'Status', - 'Resource Type', - 'Resource', - 'Created', - )); - $table->setColumnClasses( - array( - '', - '', - '', - '', - 'wide pri', - 'right', + $header, + $lease_list, + $pager, )); - $panel = new AphrontPanelView(); - $panel->setHeader('Drydock Leases'); + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addCrumb( + id(new PhabricatorCrumbView()) + ->setName($title) + ->setHref($request->getRequestURI())); + $nav->setCrumbs($crumbs); - $panel->appendChild($table); - $panel->appendChild($pager); - - $nav->appendChild($panel); - return $this->buildStandardPageResponse( + return $this->buildApplicationPage( $nav, array( 'device' => true, - 'title' => 'Leases', + 'title' => $title, )); } diff --git a/src/applications/drydock/controller/DrydockLeaseViewController.php b/src/applications/drydock/controller/DrydockLeaseViewController.php index 7de7b4ce8c..21ab432f91 100644 --- a/src/applications/drydock/controller/DrydockLeaseViewController.php +++ b/src/applications/drydock/controller/DrydockLeaseViewController.php @@ -12,14 +12,14 @@ final class DrydockLeaseViewController extends DrydockController { $request = $this->getRequest(); $user = $request->getUser(); - $nav = $this->buildSideNav('lease'); - $lease = id(new DrydockLease())->load($this->id); if (!$lease) { return new Aphront404Response(); } - $title = 'Lease '.$lease->getID(); + $lease_uri = $this->getApplicationURI('lease/'.$lease->getID().'/'); + + $title = pht('Lease %d', $lease->getID()); $header = id(new PhabricatorHeaderView()) ->setHeader($title); @@ -28,9 +28,7 @@ final class DrydockLeaseViewController extends DrydockController { $properties = $this->buildPropertyListView($lease); $pager = new AphrontPagerView(); - $pager->setURI( - new PhutilURI($this->getApplicationURI('lease/'.$lease->getID().'/')), - 'offset'); + $pager->setURI(new PhutilURI($lease_uri), 'offset'); $pager->setOffset($request->getInt('offset')); $logs = id(new DrydockLogQuery()) @@ -40,16 +38,20 @@ final class DrydockLeaseViewController extends DrydockController { $log_table = $this->buildLogTableView($logs); $log_table->appendChild($pager); - $nav->appendChild( + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addCrumb( + id(new PhabricatorCrumbView()) + ->setName($title) + ->setHref($lease_uri)); + + return $this->buildApplicationPage( array( + $crumbs, $header, $actions, $properties, $log_table, - )); - - return $this->buildApplicationPage( - $nav, + ), array( 'device' => true, 'title' => $title, diff --git a/src/applications/drydock/controller/DrydockResourceListController.php b/src/applications/drydock/controller/DrydockResourceListController.php index 8ca1e5c1fb..505a6d1560 100644 --- a/src/applications/drydock/controller/DrydockResourceListController.php +++ b/src/applications/drydock/controller/DrydockResourceListController.php @@ -6,66 +6,38 @@ final class DrydockResourceListController extends DrydockController { $request = $this->getRequest(); $user = $request->getUser(); - $nav = $this->buildSideNav('resource'); + $title = pht('Resources'); + + $resource_header = id(new PhabricatorHeaderView()) + ->setHeader($title); $pager = new AphrontPagerView(); - $pager->setURI(new PhutilURI('/drydock/resource/'), 'page'); + $pager->setURI(new PhutilURI('/drydock/resource/'), 'offset'); + $resources = id(new DrydockResourceQuery()) + ->executeWithOffsetPager($pager); - $data = id(new DrydockResource())->loadAllWhere( - '1 = 1 ORDER BY id DESC LIMIT %d, %d', - $pager->getOffset(), - $pager->getPageSize() + 1); - $data = $pager->sliceResults($data); + $resource_list = $this->buildResourceListView($resources); - $rows = array(); - foreach ($data as $resource) { - $resource_uri = '/resource/'.$resource->getID().'/'; - $resource_uri = $this->getApplicationURI($resource_uri); + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addCrumb( + id(new PhabricatorCrumbView()) + ->setName($title) + ->setHref($request->getRequestURI())); - $rows[] = array( - phutil_render_tag( - 'a', - array( - 'href' => $resource_uri, - ), - $resource->getID()), - phutil_escape_html($resource->getType()), - DrydockResourceStatus::getNameForStatus($resource->getStatus()), - phutil_escape_html(nonempty($resource->getName(), 'Unnamed')), - phabricator_datetime($resource->getDateCreated(), $user), - ); - } - - $table = new AphrontTableView($rows); - $table->setHeaders( + $nav = $this->buildSideNav('resource'); + $nav->setCrumbs($crumbs); + $nav->appendChild( array( - 'ID', - 'Type', - 'Status', - 'Resource', - 'Created', - )); - $table->setColumnClasses( - array( - '', - '', - '', - 'pri wide', - 'right', + $resource_header, + $resource_list, + $pager, )); - $panel = new AphrontPanelView(); - $panel->setHeader('Drydock Resources'); - - $panel->appendChild($table); - $panel->appendChild($pager); - - $nav->appendChild($panel); - - return $this->buildStandardPageResponse( + return $this->buildApplicationPage( $nav, array( - 'title' => 'Resources', + 'title' => $title, + 'device' => true, )); } diff --git a/src/applications/drydock/controller/DrydockResourceViewController.php b/src/applications/drydock/controller/DrydockResourceViewController.php index 93f3eaebcb..47ffb98d4f 100644 --- a/src/applications/drydock/controller/DrydockResourceViewController.php +++ b/src/applications/drydock/controller/DrydockResourceViewController.php @@ -12,8 +12,6 @@ final class DrydockResourceViewController extends DrydockController { $request = $this->getRequest(); $user = $request->getUser(); - $nav = $this->buildSideNav('resource'); - $resource = id(new DrydockResource())->load($this->id); if (!$resource) { return new Aphront404Response(); @@ -32,8 +30,12 @@ final class DrydockResourceViewController extends DrydockController { $leases = id(new DrydockLeaseQuery()) ->withResourceIDs(array($resource->getID())) + ->needResources(true) ->execute(); + $lease_header = id(new PhabricatorHeaderView()) + ->setHeader(pht('Leases')); + $lease_list = $this->buildLeaseListView($leases); $lease_list->setNoDataString(pht('This resource has no leases.')); @@ -48,17 +50,21 @@ final class DrydockResourceViewController extends DrydockController { $log_table = $this->buildLogTableView($logs); $log_table->appendChild($pager); - $nav->appendChild( + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addCrumb( + id(new PhabricatorCrumbView()) + ->setName(pht('Resource %d', $resource->getID()))); + + return $this->buildApplicationPage( array( + $crumbs, $header, $actions, $properties, + $lease_header, $lease_list, $log_table, - )); - - return $this->buildApplicationPage( - $nav, + ), array( 'device' => true, 'title' => $title, @@ -114,34 +120,4 @@ final class DrydockResourceViewController extends DrydockController { return $view; } - private function buildLeaseListView(array $leases) { - assert_instances_of($leases, 'DrydockLease'); - - $user = $this->getRequest()->getUser(); - - $view = new PhabricatorObjectItemListView(); - - foreach ($leases as $lease) { - $item = id(new PhabricatorObjectItemView()) - ->setHeader($lease->getLeaseName()) - ->setHref($this->getApplicationURI('/lease/'.$lease->getID().'/')); - - $status = DrydockLeaseStatus::getNameForStatus($lease->getStatus()); - $item->addAttribute(phutil_escape_html($status)); - - $date_created = phabricator_date($lease->getDateCreated(), $user); - $item->addAttribute(pht('Created on %s', $date_created)); - - if ($lease->isActive()) { - $item->setBarColor('green'); - } else { - $item->setBarColor('red'); - } - - $view->addItem($item); - } - - return $view; - } - } diff --git a/src/applications/drydock/query/DrydockResourceQuery.php b/src/applications/drydock/query/DrydockResourceQuery.php new file mode 100644 index 0000000000..c33f73bbcd --- /dev/null +++ b/src/applications/drydock/query/DrydockResourceQuery.php @@ -0,0 +1,46 @@ +ids = $ids; + return $this; + } + + public function execute() { + $table = new DrydockResource(); + $conn_r = $table->establishConnection('r'); + + $data = queryfx_all( + $conn_r, + 'SELECT resource.* FROM %T resource %Q %Q %Q', + $table->getTableName(), + $this->buildWhereClause($conn_r), + $this->buildOrderClause($conn_r), + $this->buildLimitClause($conn_r)); + + $resources = $table->loadAllFromArray($data); + + return $resources; + } + + private function buildWhereClause(AphrontDatabaseConnection $conn_r) { + $where = array(); + + if ($this->ids) { + $where[] = qsprintf( + $conn_r, + 'id IN (%Ld)', + $this->ids); + } + + return $this->formatWhereClause($where); + } + + private function buildOrderClause(AphrontDatabaseConnection $conn_r) { + return qsprintf($conn_r, 'ORDER BY id DESC'); + } + +} diff --git a/src/applications/drydock/storage/DrydockLease.php b/src/applications/drydock/storage/DrydockLease.php index 8363dbd686..71f624f3af 100644 --- a/src/applications/drydock/storage/DrydockLease.php +++ b/src/applications/drydock/storage/DrydockLease.php @@ -64,7 +64,6 @@ final class DrydockLease extends DrydockDAO { } public function getResource() { - $this->assertActive(); if ($this->resource === null) { throw new Exception("Resource is not yet loaded."); } @@ -72,13 +71,15 @@ final class DrydockLease extends DrydockDAO { } public function attachResource(DrydockResource $resource) { - $this->assertActive(); $this->resource = $resource; return $this; } + public function hasAttachedResource() { + return ($this->resource !== null); + } + public function loadResource() { - $this->assertActive(); return id(new DrydockResource())->loadOneWhere( 'id = %d', $this->getResourceID()); @@ -115,6 +116,7 @@ final class DrydockLease extends DrydockDAO { } public function release() { + $this->assertActive(); $this->setStatus(DrydockLeaseStatus::STATUS_RELEASED); $this->save();