@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
at recaptime-dev/main 221 lines 6.2 kB view raw
1<?php 2 3final class DrydockRepositoryOperationStatusView 4 extends AphrontView { 5 6 private $operation; 7 private $boxView; 8 9 public function setOperation(DrydockRepositoryOperation $operation) { 10 $this->operation = $operation; 11 return $this; 12 } 13 14 public function getOperation() { 15 return $this->operation; 16 } 17 18 public function setBoxView(PHUIObjectBoxView $box_view) { 19 $this->boxView = $box_view; 20 return $this; 21 } 22 23 public function getBoxView() { 24 return $this->boxView; 25 } 26 27 public function render() { 28 $viewer = $this->getUser(); 29 $operation = $this->getOperation(); 30 31 $list = $this->renderUnderwayState(); 32 33 // If the operation is currently underway, refresh the status view. 34 if ($operation->isUnderway()) { 35 $status_id = celerity_generate_unique_node_id(); 36 $id = $operation->getID(); 37 38 $list->setID($status_id); 39 40 Javelin::initBehavior( 41 'drydock-live-operation-status', 42 array( 43 'statusID' => $status_id, 44 'updateURI' => "/drydock/operation/{$id}/status/", 45 )); 46 } 47 48 $box_view = $this->getBoxView(); 49 if (!$box_view) { 50 $box_view = id(new PHUIObjectBoxView()) 51 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 52 ->setHeaderText(pht('Operation Status')); 53 } 54 $box_view->setObjectList($list); 55 56 return $box_view; 57 } 58 59 public function renderUnderwayState() { 60 $viewer = $this->getUser(); 61 $operation = $this->getOperation(); 62 63 $id = $operation->getID(); 64 65 $state = $operation->getOperationState(); 66 $icon = DrydockRepositoryOperation::getOperationStateIcon($state); 67 $name = DrydockRepositoryOperation::getOperationStateName($state); 68 69 $item = id(new PHUIObjectItemView()) 70 ->setHref("/drydock/operation/{$id}/") 71 ->setObjectName(pht('Operation %d', $id)) 72 ->setHeader($operation->getOperationDescription($viewer)) 73 ->setStatusIcon($icon, $name); 74 75 if ($state != DrydockRepositoryOperation::STATE_FAIL) { 76 $item->addAttribute($operation->getOperationCurrentStatus($viewer)); 77 } else { 78 $vcs_error = $operation->getCommandError(); 79 if ($vcs_error) { 80 switch ($vcs_error['phase']) { 81 case DrydockWorkingCopyBlueprintImplementation::PHASE_SQUASHMERGE: 82 $message = pht( 83 'This change did not merge cleanly. This usually indicates '. 84 'that the change is out of date and needs to be updated.'); 85 break; 86 case DrydockWorkingCopyBlueprintImplementation::PHASE_REMOTEFETCH: 87 $message = pht( 88 'This change could not be fetched from the remote.'); 89 break; 90 case DrydockWorkingCopyBlueprintImplementation::PHASE_MERGEFETCH: 91 $message = pht( 92 'This change could not be fetched from the remote staging '. 93 'area. It may not have been pushed, or may have been removed.'); 94 break; 95 case DrydockLandRepositoryOperation::PHASE_COMMIT: 96 $message = pht( 97 'Committing this change failed. It may already have been '. 98 'merged.'); 99 break; 100 case DrydockLandRepositoryOperation::PHASE_PUSH: 101 $message = pht( 102 'The push failed. This usually indicates '. 103 'that the change is breaking some rules or '. 104 'some custom commit hook has failed.'); 105 break; 106 default: 107 $message = pht( 108 'Operation encountered an error while performing repository '. 109 'operations.'); 110 break; 111 } 112 113 $item->addAttribute($message); 114 115 $table = $this->renderVCSErrorTable($vcs_error); 116 list($links, $info) = $this->renderDetailToggles($table); 117 118 $item->addAttribute($links); 119 $item->appendChild($info); 120 } else { 121 $item->addAttribute(pht('Operation encountered an error.')); 122 } 123 124 $is_dismissed = $operation->getIsDismissed(); 125 126 $item->addAction( 127 id(new PHUIListItemView()) 128 ->setName('Dismiss') 129 ->setIcon('fa-times') 130 ->setDisabled($is_dismissed) 131 ->setWorkflow(true) 132 ->setHref("/drydock/operation/{$id}/dismiss/")); 133 } 134 135 return id(new PHUIObjectItemListView()) 136 ->addItem($item); 137 } 138 139 private function renderVCSErrorTable(array $vcs_error) { 140 $rows = array(); 141 142 $rows[] = array( 143 pht('Command'), 144 phutil_censor_credentials($vcs_error['command']), 145 ); 146 147 $rows[] = array(pht('Error'), $vcs_error['err']); 148 149 $rows[] = array( 150 pht('Stdout'), 151 phutil_censor_credentials($vcs_error['stdout']), 152 ); 153 154 $rows[] = array( 155 pht('Stderr'), 156 phutil_censor_credentials($vcs_error['stderr']), 157 ); 158 159 $table = id(new AphrontTableView($rows)) 160 ->setColumnClasses( 161 array( 162 'header', 163 'wide prewrap', 164 )); 165 166 return $table; 167 } 168 169 private function renderDetailToggles(AphrontTableView $table) { 170 $show_id = celerity_generate_unique_node_id(); 171 $hide_id = celerity_generate_unique_node_id(); 172 $info_id = celerity_generate_unique_node_id(); 173 174 Javelin::initBehavior('phabricator-reveal-content'); 175 176 $show_details = javelin_tag( 177 'a', 178 array( 179 'id' => $show_id, 180 'href' => '#', 181 'sigil' => 'reveal-content', 182 'mustcapture' => true, 183 'meta' => array( 184 'hideIDs' => array($show_id), 185 'showIDs' => array($hide_id, $info_id), 186 ), 187 ), 188 pht('Show Details')); 189 190 $hide_details = javelin_tag( 191 'a', 192 array( 193 'id' => $hide_id, 194 'href' => '#', 195 'sigil' => 'reveal-content', 196 'mustcapture' => true, 197 'style' => 'display: none', 198 'meta' => array( 199 'hideIDs' => array($hide_id, $info_id), 200 'showIDs' => array($show_id), 201 ), 202 ), 203 pht('Hide Details')); 204 205 $info = javelin_tag( 206 'div', 207 array( 208 'id' => $info_id, 209 'style' => 'display: none', 210 ), 211 $table); 212 213 $links = array( 214 $show_details, 215 $hide_details, 216 ); 217 218 return array($links, $info); 219 } 220 221}