@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

Give Drydock Leases more modern status treatment

Summary:
Depends on D19073. Ref T13073. Give leases a normal header tag and try to wrangle their status constants a bit.

Also, try to capture the "status class" pattern a bit. Since we target PHP 5.2.3 we can't use `static::` so the actual subclass is kind of a mess. Not exactly sure if I want to stick with this or not. We could consider targeting PHP 5.3.0 instead to get `static::` / late static binding.

Test Plan: Viewed leases and lease lists, saw better and more conventional status information.

Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam

Maniphest Tasks: T13073

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

+242 -72
+3 -1
src/__phutil_library_map__.php
··· 3416 3416 'PhabricatorObjectRelationshipSource' => 'applications/search/relationship/PhabricatorObjectRelationshipSource.php', 3417 3417 'PhabricatorObjectRemarkupRule' => 'infrastructure/markup/rule/PhabricatorObjectRemarkupRule.php', 3418 3418 'PhabricatorObjectSelectorDialog' => 'view/control/PhabricatorObjectSelectorDialog.php', 3419 + 'PhabricatorObjectStatus' => 'infrastructure/status/PhabricatorObjectStatus.php', 3419 3420 'PhabricatorOffsetPagedQuery' => 'infrastructure/query/PhabricatorOffsetPagedQuery.php', 3420 3421 'PhabricatorOldWorldContentSource' => 'infrastructure/contentsource/PhabricatorOldWorldContentSource.php', 3421 3422 'PhabricatorOlderInlinesSetting' => 'applications/settings/setting/PhabricatorOlderInlinesSetting.php', ··· 6290 6291 'DrydockLeaseReleaseController' => 'DrydockLeaseController', 6291 6292 'DrydockLeaseReleasedLogType' => 'DrydockLogType', 6292 6293 'DrydockLeaseSearchEngine' => 'PhabricatorApplicationSearchEngine', 6293 - 'DrydockLeaseStatus' => 'DrydockConstants', 6294 + 'DrydockLeaseStatus' => 'PhabricatorObjectStatus', 6294 6295 'DrydockLeaseUpdateWorker' => 'DrydockWorker', 6295 6296 'DrydockLeaseViewController' => 'DrydockLeaseController', 6296 6297 'DrydockLeaseWaitingForResourcesLogType' => 'DrydockLogType', ··· 8994 8995 'PhabricatorObjectRelationshipSource' => 'Phobject', 8995 8996 'PhabricatorObjectRemarkupRule' => 'PhutilRemarkupRule', 8996 8997 'PhabricatorObjectSelectorDialog' => 'Phobject', 8998 + 'PhabricatorObjectStatus' => 'Phobject', 8997 8999 'PhabricatorOffsetPagedQuery' => 'PhabricatorQuery', 8998 9000 'PhabricatorOldWorldContentSource' => 'PhabricatorContentSource', 8999 9001 'PhabricatorOlderInlinesSetting' => 'PhabricatorSelectSetting',
+94 -12
src/applications/drydock/constants/DrydockLeaseStatus.php
··· 1 1 <?php 2 2 3 - final class DrydockLeaseStatus extends DrydockConstants { 3 + final class DrydockLeaseStatus 4 + extends PhabricatorObjectStatus { 4 5 5 6 const STATUS_PENDING = 'pending'; 6 7 const STATUS_ACQUIRED = 'acquired'; ··· 8 9 const STATUS_RELEASED = 'released'; 9 10 const STATUS_BROKEN = 'broken'; 10 11 const STATUS_DESTROYED = 'destroyed'; 12 + 13 + public static function newStatusObject($key) { 14 + return new self($key, id(new self())->getStatusSpecification($key)); 15 + } 11 16 12 17 public static function getStatusMap() { 13 - return array( 14 - self::STATUS_PENDING => pht('Pending'), 15 - self::STATUS_ACQUIRED => pht('Acquired'), 16 - self::STATUS_ACTIVE => pht('Active'), 17 - self::STATUS_RELEASED => pht('Released'), 18 - self::STATUS_BROKEN => pht('Broken'), 19 - self::STATUS_DESTROYED => pht('Destroyed'), 20 - ); 18 + $map = id(new self())->getStatusSpecifications(); 19 + return ipull($map, 'name', 'key'); 21 20 } 22 21 23 22 public static function getNameForStatus($status) { 24 - $map = self::getStatusMap(); 25 - return idx($map, $status, pht('Unknown')); 23 + $map = id(new self())->getStatusSpecification($status); 24 + return $map['name']; 26 25 } 27 26 28 27 public static function getAllStatuses() { 29 - return array_keys(self::getStatusMap()); 28 + return array_keys(id(new self())->getStatusSpecifications()); 29 + } 30 + 31 + public function isActivating() { 32 + return $this->getStatusProperty('isActivating'); 33 + } 34 + 35 + public function isActive() { 36 + return ($this->getKey() === self::STATUS_ACTIVE); 37 + } 38 + 39 + public function canRelease() { 40 + return $this->getStatusProperty('isReleasable'); 41 + } 42 + 43 + public function canReceiveCommands() { 44 + return $this->getStatusProperty('isCommandable'); 45 + } 46 + 47 + protected function newStatusSpecifications() { 48 + return array( 49 + array( 50 + 'key' => self::STATUS_PENDING, 51 + 'name' => pht('Pending'), 52 + 'icon' => 'fa-clock-o', 53 + 'color' => 'blue', 54 + 'isReleasable' => true, 55 + 'isCommandable' => true, 56 + 'isActivating' => true, 57 + ), 58 + array( 59 + 'key' => self::STATUS_ACQUIRED, 60 + 'name' => pht('Acquired'), 61 + 'icon' => 'fa-refresh', 62 + 'color' => 'blue', 63 + 'isReleasable' => true, 64 + 'isCommandable' => true, 65 + 'isActivating' => true, 66 + ), 67 + array( 68 + 'key' => self::STATUS_ACTIVE, 69 + 'name' => pht('Active'), 70 + 'icon' => 'fa-check', 71 + 'color' => 'green', 72 + 'isReleasable' => true, 73 + 'isCommandable' => true, 74 + 'isActivating' => false, 75 + ), 76 + array( 77 + 'key' => self::STATUS_RELEASED, 78 + 'name' => pht('Released'), 79 + 'icon' => 'fa-circle-o', 80 + 'color' => 'blue', 81 + 'isReleasable' => false, 82 + 'isCommandable' => false, 83 + 'isActivating' => false, 84 + ), 85 + array( 86 + 'key' => self::STATUS_BROKEN, 87 + 'name' => pht('Broken'), 88 + 'icon' => 'fa-times', 89 + 'color' => 'indigo', 90 + 'isReleasable' => true, 91 + 'isCommandable' => true, 92 + 'isActivating' => false, 93 + ), 94 + array( 95 + 'key' => self::STATUS_DESTROYED, 96 + 'name' => pht('Destroyed'), 97 + 'icon' => 'fa-times', 98 + 'color' => 'red', 99 + 'isReleasable' => false, 100 + 'isCommandable' => false, 101 + 'isActivating' => false, 102 + ), 103 + ); 104 + } 105 + 106 + protected function newUnknownStatusSpecification($status) { 107 + return array( 108 + 'isReleasable' => false, 109 + 'isCommandable' => false, 110 + 'isActivating' => false, 111 + ); 30 112 } 31 113 32 114 }
+11 -6
src/applications/drydock/controller/DrydockLeaseViewController.php
··· 22 22 23 23 $header = id(new PHUIHeaderView()) 24 24 ->setHeader($title) 25 - ->setHeaderIcon('fa-link'); 25 + ->setHeaderIcon('fa-link') 26 + ->setStatus( 27 + $lease->getStatusIcon(), 28 + $lease->getStatusColor(), 29 + $lease->getStatusDisplayName()); 26 30 27 31 if ($lease->isReleasing()) { 28 - $header->setStatus('fa-exclamation-triangle', 'red', pht('Releasing')); 32 + $header->addTag( 33 + id(new PHUITagView()) 34 + ->setType(PHUITagView::TYPE_SHADE) 35 + ->setIcon('fa-exclamation-triangle') 36 + ->setColor('red') 37 + ->setName('Releasing')); 29 38 } 30 39 31 40 $curtain = $this->buildCurtain($lease); ··· 117 126 $viewer = $this->getViewer(); 118 127 119 128 $view = new PHUIPropertyListView(); 120 - 121 - $view->addProperty( 122 - pht('Status'), 123 - DrydockLeaseStatus::getNameForStatus($lease->getStatus())); 124 129 125 130 $view->addProperty( 126 131 pht('Resource Type'),
+40 -43
src/applications/drydock/storage/DrydockLease.php
··· 175 175 return $this; 176 176 } 177 177 178 - public function isActivating() { 179 - switch ($this->getStatus()) { 180 - case DrydockLeaseStatus::STATUS_PENDING: 181 - case DrydockLeaseStatus::STATUS_ACQUIRED: 182 - return true; 183 - } 184 - 185 - return false; 186 - } 187 - 188 - public function isActive() { 189 - switch ($this->getStatus()) { 190 - case DrydockLeaseStatus::STATUS_ACTIVE: 191 - return true; 192 - } 193 - 194 - return false; 195 - } 196 - 197 178 public function setActivateWhenAcquired($activate) { 198 179 $this->activateWhenAcquired = true; 199 180 return $this; ··· 325 306 return $this->isActivated; 326 307 } 327 308 328 - public function canRelease() { 329 - if (!$this->getID()) { 330 - return false; 331 - } 332 - 333 - switch ($this->getStatus()) { 334 - case DrydockLeaseStatus::STATUS_RELEASED: 335 - case DrydockLeaseStatus::STATUS_DESTROYED: 336 - return false; 337 - default: 338 - return true; 339 - } 340 - } 341 - 342 - public function canReceiveCommands() { 343 - switch ($this->getStatus()) { 344 - case DrydockLeaseStatus::STATUS_RELEASED: 345 - case DrydockLeaseStatus::STATUS_DESTROYED: 346 - return false; 347 - default: 348 - return true; 349 - } 350 - } 351 - 352 309 public function scheduleUpdate($epoch = null) { 353 310 PhabricatorWorker::scheduleTask( 354 311 'DrydockLeaseUpdateWorker', ··· 439 396 public function getURI() { 440 397 $id = $this->getID(); 441 398 return "/drydock/lease/{$id}/"; 399 + } 400 + 401 + 402 + /* -( Status )------------------------------------------------------------- */ 403 + 404 + 405 + public function getStatusObject() { 406 + return DrydockLeaseStatus::newStatusObject($this->getStatus()); 407 + } 408 + 409 + public function getStatusIcon() { 410 + return $this->getStatusObject()->getIcon(); 411 + } 412 + 413 + public function getStatusColor() { 414 + return $this->getStatusObject()->getColor(); 415 + } 416 + 417 + public function getStatusDisplayName() { 418 + return $this->getStatusObject()->getDisplayName(); 419 + } 420 + 421 + public function isActivating() { 422 + return $this->getStatusObject()->isActivating(); 423 + } 424 + 425 + public function isActive() { 426 + return $this->getStatusObject()->isActive(); 427 + } 428 + 429 + public function canRelease() { 430 + if (!$this->getID()) { 431 + return false; 432 + } 433 + 434 + return $this->getStatusObject()->canRelease(); 435 + } 436 + 437 + public function canReceiveCommands() { 438 + return $this->getStatusObject()->canReceiveCommands(); 442 439 } 443 440 444 441
+10 -10
src/applications/drydock/view/DrydockLeaseListView.php
··· 26 26 if ($resource_phid) { 27 27 $item->addAttribute( 28 28 $viewer->renderHandle($resource_phid)); 29 + } else { 30 + $item->addAttribute( 31 + pht( 32 + 'Resource: %s', 33 + $lease->getResourceType())); 29 34 } 30 35 31 - $status = DrydockLeaseStatus::getNameForStatus($lease->getStatus()); 32 - $item->addAttribute($status); 33 36 $item->setEpoch($lease->getDateCreated()); 34 37 35 - // TODO: Tailor this for clarity. 36 - if ($lease->isActivating()) { 37 - $item->setStatusIcon('fa-dot-circle-o yellow'); 38 - } else if ($lease->isActive()) { 39 - $item->setStatusIcon('fa-dot-circle-o green'); 40 - } else { 41 - $item->setStatusIcon('fa-dot-circle-o red'); 42 - } 38 + $icon = $lease->getStatusIcon(); 39 + $color = $lease->getStatusColor(); 40 + $label = $lease->getStatusDisplayName(); 41 + 42 + $item->setStatusIcon("{$icon} {$color}", $label); 43 43 44 44 $view->addItem($item); 45 45 }
+84
src/infrastructure/status/PhabricatorObjectStatus.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorObjectStatus 4 + extends Phobject { 5 + 6 + private $key; 7 + private $properties; 8 + 9 + protected function __construct($key = null, array $properties = array()) { 10 + $this->key = $key; 11 + $this->properties = $properties; 12 + } 13 + 14 + protected function getStatusProperty($key) { 15 + if (!array_key_exists($key, $this->properties)) { 16 + throw new Exception( 17 + pht( 18 + 'Attempting to access unknown status property ("%s").', 19 + $key)); 20 + } 21 + 22 + return $this->properties[$key]; 23 + } 24 + 25 + public function getKey() { 26 + return $this->key; 27 + } 28 + 29 + public function getIcon() { 30 + return $this->getStatusProperty('icon'); 31 + } 32 + 33 + public function getDisplayName() { 34 + return $this->getStatusProperty('name'); 35 + } 36 + 37 + public function getColor() { 38 + return $this->getStatusProperty('color'); 39 + } 40 + 41 + protected function getStatusSpecification($status) { 42 + $map = self::getStatusSpecifications(); 43 + if (isset($map[$status])) { 44 + return $map[$status]; 45 + } 46 + 47 + return array( 48 + 'key' => $status, 49 + 'name' => pht('Unknown ("%s")', $status), 50 + 'icon' => 'fa-question-circle', 51 + 'color' => 'indigo', 52 + ) + $this->newUnknownStatusSpecification($status); 53 + } 54 + 55 + protected function getStatusSpecifications() { 56 + $map = $this->newStatusSpecifications(); 57 + 58 + $result = array(); 59 + foreach ($map as $item) { 60 + if (!array_key_exists('key', $item)) { 61 + throw new Exception(pht('Status specification has no "key".')); 62 + } 63 + 64 + $key = $item['key']; 65 + if (isset($result[$key])) { 66 + throw new Exception( 67 + pht( 68 + 'Multiple status definitions share the same key ("%s").', 69 + $key)); 70 + } 71 + 72 + $result[$key] = $item; 73 + } 74 + 75 + return $result; 76 + } 77 + 78 + abstract protected function newStatusSpecifications(); 79 + 80 + protected function newUnknownStatusSpecification($status) { 81 + return array(); 82 + } 83 + 84 + }