@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
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Support Spaces transactions

Summary:
Ref T8424. This adds crude integration with Paste's edit/view workflows: you can change the space a Paste appears in, see transactions, and get a policy callout.

Lots of rough edges and non-obviousness but it pretty much works.

Test Plan:
- Created and updated Pastes.
- Moved them between spaces, saw policy effects.
- Read transactions.
- Looked at feed.
- Faked query to return no spaces, saw control and other stuff vanish.
- Faked query to return no spaces, created pastes.
- Tried to submit bad values and got errors.

Reviewers: chad, btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T8424

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

+306 -79
+3 -3
resources/celerity/map.php
··· 7 7 */ 8 8 return array( 9 9 'names' => array( 10 - 'core.pkg.css' => 'e2460e8f', 10 + 'core.pkg.css' => 'd7ecac6d', 11 11 'core.pkg.js' => '3bbe23c6', 12 12 'darkconsole.pkg.js' => 'e7393ebb', 13 13 'differential.pkg.css' => '02273347', ··· 136 136 'rsrc/css/phui/phui-fontkit.css' => 'dd8ddf27', 137 137 'rsrc/css/phui/phui-form-view.css' => '808329f2', 138 138 'rsrc/css/phui/phui-form.css' => '25876baf', 139 - 'rsrc/css/phui/phui-header-view.css' => '75aaf372', 139 + 'rsrc/css/phui/phui-header-view.css' => '2dd74fe0', 140 140 'rsrc/css/phui/phui-icon.css' => 'bc766998', 141 141 'rsrc/css/phui/phui-image-mask.css' => '5a8b09c8', 142 142 'rsrc/css/phui/phui-info-panel.css' => '27ea50a1', ··· 779 779 'phui-fontkit-css' => 'dd8ddf27', 780 780 'phui-form-css' => '25876baf', 781 781 'phui-form-view-css' => '808329f2', 782 - 'phui-header-view-css' => '75aaf372', 782 + 'phui-header-view-css' => '2dd74fe0', 783 783 'phui-icon-view-css' => 'bc766998', 784 784 'phui-image-mask-css' => '5a8b09c8', 785 785 'phui-info-panel-css' => '27ea50a1',
+2
src/__phutil_library_map__.php
··· 2560 2560 'PhabricatorSpacesCapabilityCreateSpaces' => 'applications/spaces/capability/PhabricatorSpacesCapabilityCreateSpaces.php', 2561 2561 'PhabricatorSpacesCapabilityDefaultEdit' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultEdit.php', 2562 2562 'PhabricatorSpacesCapabilityDefaultView' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultView.php', 2563 + 'PhabricatorSpacesControl' => 'applications/spaces/view/PhabricatorSpacesControl.php', 2563 2564 'PhabricatorSpacesController' => 'applications/spaces/controller/PhabricatorSpacesController.php', 2564 2565 'PhabricatorSpacesDAO' => 'applications/spaces/storage/PhabricatorSpacesDAO.php', 2565 2566 'PhabricatorSpacesEditController' => 'applications/spaces/controller/PhabricatorSpacesEditController.php', ··· 6041 6042 'PhabricatorSpacesCapabilityCreateSpaces' => 'PhabricatorPolicyCapability', 6042 6043 'PhabricatorSpacesCapabilityDefaultEdit' => 'PhabricatorPolicyCapability', 6043 6044 'PhabricatorSpacesCapabilityDefaultView' => 'PhabricatorPolicyCapability', 6045 + 'PhabricatorSpacesControl' => 'AphrontFormControl', 6044 6046 'PhabricatorSpacesController' => 'PhabricatorController', 6045 6047 'PhabricatorSpacesDAO' => 'PhabricatorLiskDAO', 6046 6048 'PhabricatorSpacesEditController' => 'PhabricatorSpacesController',
+53 -48
src/applications/paste/controller/PhabricatorPasteEditController.php
··· 57 57 } 58 58 } 59 59 60 - $text = null; 61 - $e_text = true; 62 - $errors = array(); 60 + $v_space = $paste->getSpacePHID(); 63 61 if ($is_create && $parent) { 64 62 $v_title = pht('Fork of %s', $parent->getFullName()); 65 63 $v_language = $parent->getLanguage(); 66 64 $v_text = $parent->getRawContent(); 65 + $v_space = $parent->getSpacePHID(); 67 66 } else { 68 67 $v_title = $paste->getTitle(); 69 68 $v_language = $paste->getLanguage(); ··· 81 80 $v_projects = array_reverse($v_projects); 82 81 } 83 82 83 + $validation_exception = null; 84 84 if ($request->isFormPost()) { 85 85 $xactions = array(); 86 86 87 87 $v_text = $request->getStr('text'); 88 - if (!strlen($v_text)) { 89 - $e_text = pht('Required'); 90 - $errors[] = pht('The paste may not be blank.'); 91 - } else { 92 - $e_text = null; 93 - } 94 - 95 88 $v_title = $request->getStr('title'); 96 89 $v_language = $request->getStr('language'); 97 90 $v_view_policy = $request->getStr('can_view'); 98 91 $v_edit_policy = $request->getStr('can_edit'); 99 92 $v_projects = $request->getArr('projects'); 93 + $v_space = $request->getStr('spacePHID'); 100 94 101 95 // NOTE: The author is the only editor and can always view the paste, 102 96 // so it's impossible for them to choose an invalid policy. 103 97 104 - if (!$errors) { 105 - if ($is_create || ($v_text !== $paste->getRawContent())) { 106 - $file = PhabricatorPasteEditor::initializeFileForPaste( 107 - $user, 108 - $v_title, 109 - $v_text); 98 + if ($is_create || ($v_text !== $paste->getRawContent())) { 99 + $file = PhabricatorPasteEditor::initializeFileForPaste( 100 + $user, 101 + $v_title, 102 + $v_text); 103 + 104 + $xactions[] = id(new PhabricatorPasteTransaction()) 105 + ->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT) 106 + ->setNewValue($file->getPHID()); 107 + } 110 108 111 - $xactions[] = id(new PhabricatorPasteTransaction()) 112 - ->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT) 113 - ->setNewValue($file->getPHID()); 114 - } 109 + $xactions[] = id(new PhabricatorPasteTransaction()) 110 + ->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE) 111 + ->setNewValue($v_title); 112 + $xactions[] = id(new PhabricatorPasteTransaction()) 113 + ->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE) 114 + ->setNewValue($v_language); 115 + $xactions[] = id(new PhabricatorPasteTransaction()) 116 + ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) 117 + ->setNewValue($v_view_policy); 118 + $xactions[] = id(new PhabricatorPasteTransaction()) 119 + ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) 120 + ->setNewValue($v_edit_policy); 121 + $xactions[] = id(new PhabricatorPasteTransaction()) 122 + ->setTransactionType(PhabricatorTransactions::TYPE_SPACE) 123 + ->setNewValue($v_space); 115 124 116 - $xactions[] = id(new PhabricatorPasteTransaction()) 117 - ->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE) 118 - ->setNewValue($v_title); 119 - $xactions[] = id(new PhabricatorPasteTransaction()) 120 - ->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE) 121 - ->setNewValue($v_language); 122 - $xactions[] = id(new PhabricatorPasteTransaction()) 123 - ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) 124 - ->setNewValue($v_view_policy); 125 - $xactions[] = id(new PhabricatorPasteTransaction()) 126 - ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) 127 - ->setNewValue($v_edit_policy); 125 + $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; 126 + $xactions[] = id(new PhabricatorPasteTransaction()) 127 + ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 128 + ->setMetadataValue('edge:type', $proj_edge_type) 129 + ->setNewValue(array('=' => array_fuse($v_projects))); 128 130 129 - $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; 130 - $xactions[] = id(new PhabricatorPasteTransaction()) 131 - ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 132 - ->setMetadataValue('edge:type', $proj_edge_type) 133 - ->setNewValue(array('=' => array_fuse($v_projects))); 131 + $editor = id(new PhabricatorPasteEditor()) 132 + ->setActor($user) 133 + ->setContentSourceFromRequest($request) 134 + ->setContinueOnNoEffect(true); 134 135 135 - $editor = id(new PhabricatorPasteEditor()) 136 - ->setActor($user) 137 - ->setContentSourceFromRequest($request) 138 - ->setContinueOnNoEffect(true); 136 + try { 139 137 $xactions = $editor->applyTransactions($paste, $xactions); 140 138 return id(new AphrontRedirectResponse())->setURI($paste->getURI()); 141 - } else { 142 - // make sure we update policy so its correctly populated to what 143 - // the user chose 144 - $paste->setViewPolicy($v_view_policy); 145 - $paste->setEditPolicy($v_edit_policy); 139 + } catch (PhabricatorApplicationTransactionValidationException $ex) { 140 + $validation_exception = $ex; 146 141 } 147 142 } 148 143 ··· 172 167 ->setObject($paste) 173 168 ->execute(); 174 169 170 + $form->appendControl( 171 + id(new PhabricatorSpacesControl()) 172 + ->setObject($paste) 173 + ->setValue($v_space) 174 + ->setName('spacePHID')); 175 + 175 176 $form->appendChild( 176 177 id(new AphrontFormPolicyControl()) 177 178 ->setUser($user) 178 179 ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) 179 180 ->setPolicyObject($paste) 180 181 ->setPolicies($policies) 182 + ->setValue($v_view_policy) 181 183 ->setName('can_view')); 182 184 183 185 $form->appendChild( ··· 186 188 ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) 187 189 ->setPolicyObject($paste) 188 190 ->setPolicies($policies) 191 + ->setValue($v_edit_policy) 189 192 ->setName('can_edit')); 190 193 191 194 $form->appendControl( ··· 199 202 ->appendChild( 200 203 id(new AphrontFormTextAreaControl()) 201 204 ->setLabel(pht('Text')) 202 - ->setError($e_text) 203 205 ->setValue($v_text) 204 206 ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL) 205 207 ->setCustomClass('PhabricatorMonospaced') ··· 222 224 223 225 $form_box = id(new PHUIObjectBoxView()) 224 226 ->setHeaderText($title) 225 - ->setFormErrors($errors) 226 227 ->setForm($form); 228 + 229 + if ($validation_exception) { 230 + $form_box->setValidationException($validation_exception); 231 + } 227 232 228 233 $crumbs = $this->buildApplicationCrumbs($this->buildSideNavView()); 229 234 if (!$is_create) {
+5 -1
src/applications/paste/storage/PhabricatorPaste.php
··· 42 42 } 43 43 44 44 public function getURI() { 45 - return '/P'.$this->getID(); 45 + return '/'.$this->getMonogram(); 46 + } 47 + 48 + public function getMonogram() { 49 + return 'P'.$this->getID(); 46 50 } 47 51 48 52 protected function getConfiguration() {
+14
src/applications/people/storage/PhabricatorUser.php
··· 751 751 $email->getUserPHID()); 752 752 } 753 753 754 + public function getDefaultSpacePHID() { 755 + // TODO: We might let the user switch which space they're "in" later on; 756 + // for now just use the global space if one exists. 757 + 758 + $spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($this); 759 + foreach ($spaces as $space) { 760 + if ($space->getIsDefaultNamespace()) { 761 + return $space->getPHID(); 762 + } 763 + } 764 + 765 + return null; 766 + } 767 + 754 768 755 769 /** 756 770 * Grant a user a source of authority, to let them bypass policy checks they
+1 -1
src/applications/spaces/application/PhabricatorSpacesApplication.php
··· 15 15 } 16 16 17 17 public function getFontIcon() { 18 - return 'fa-compass'; 18 + return 'fa-th-large'; 19 19 } 20 20 21 21 public function getTitleGlyph() {
+3
src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php
··· 28 28 29 29 foreach ($handles as $phid => $handle) { 30 30 $namespace = $objects[$phid]; 31 + $monogram = $namespace->getMonogram(); 32 + 31 33 $handle->setName($namespace->getNamespaceName()); 34 + $handle->setURI('/'.$monogram); 32 35 } 33 36 } 34 37
+49
src/applications/spaces/view/PhabricatorSpacesControl.php
··· 1 + <?php 2 + 3 + final class PhabricatorSpacesControl extends AphrontFormControl { 4 + 5 + private $object; 6 + 7 + protected function shouldRender() { 8 + // Render this control only if some Spaces exist. 9 + return PhabricatorSpacesNamespaceQuery::getAllSpaces(); 10 + } 11 + 12 + public function setObject(PhabricatorSpacesInterface $object) { 13 + $this->object = $object; 14 + return $this; 15 + } 16 + 17 + protected function getCustomControlClass() { 18 + return ''; 19 + } 20 + 21 + protected function getOptions() { 22 + $viewer = $this->getUser(); 23 + $viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($viewer); 24 + 25 + $map = mpull($viewer_spaces, 'getNamespaceName', 'getPHID'); 26 + asort($map); 27 + 28 + return $map; 29 + } 30 + 31 + public function renderInput() { 32 + $viewer = $this->getUser(); 33 + 34 + $this->setLabel(pht('Space')); 35 + 36 + $value = $this->getValue(); 37 + if ($value === null) { 38 + $value = $viewer->getDefaultSpacePHID(); 39 + } 40 + 41 + return AphrontFormSelectControl::renderSelectTag( 42 + $value, 43 + $this->getOptions(), 44 + array( 45 + 'name' => $this->getName(), 46 + )); 47 + } 48 + 49 + }
+1
src/applications/transactions/constants/PhabricatorTransactions.php
··· 12 12 const TYPE_BUILDABLE = 'harbormaster:buildable'; 13 13 const TYPE_TOKEN = 'token:give'; 14 14 const TYPE_INLINESTATE = 'core:inlinestate'; 15 + const TYPE_SPACE = 'core:space'; 15 16 16 17 const COLOR_RED = 'red'; 17 18 const COLOR_ORANGE = 'orange';
+87 -11
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 264 264 $types[] = PhabricatorTransactions::TYPE_EDGE; 265 265 } 266 266 267 + if ($this->object instanceof PhabricatorSpacesInterface) { 268 + $types[] = PhabricatorTransactions::TYPE_SPACE; 269 + } 270 + 267 271 return $types; 268 272 } 269 273 ··· 292 296 return $object->getEditPolicy(); 293 297 case PhabricatorTransactions::TYPE_JOIN_POLICY: 294 298 return $object->getJoinPolicy(); 299 + case PhabricatorTransactions::TYPE_SPACE: 300 + $space_phid = $object->getSpacePHID(); 301 + if ($space_phid === null) { 302 + if ($this->getIsNewObject()) { 303 + // In this case, just return `null` so we know this is the initial 304 + // transaction and it should be hidden. 305 + return null; 306 + } 307 + 308 + $default_space = PhabricatorSpacesNamespaceQuery::getDefaultSpace(); 309 + if ($default_space) { 310 + $space_phid = $default_space->getPHID(); 311 + } 312 + } 313 + return $space_phid; 295 314 case PhabricatorTransactions::TYPE_EDGE: 296 315 $edge_type = $xaction->getMetadataValue('edge:type'); 297 316 if (!$edge_type) { ··· 337 356 case PhabricatorTransactions::TYPE_BUILDABLE: 338 357 case PhabricatorTransactions::TYPE_TOKEN: 339 358 case PhabricatorTransactions::TYPE_INLINESTATE: 340 - return $xaction->getNewValue(); 359 + case PhabricatorTransactions::TYPE_SPACE: 360 + $space_phid = $xaction->getNewValue(); 361 + if (!strlen($space_phid)) { 362 + // If an install has no Spaces, we might end up with the empty string 363 + // here instead of a strict `null`. Just make this work like callers 364 + // might reasonably expect. 365 + return null; 366 + } else { 367 + return $space_phid; 368 + } 341 369 case PhabricatorTransactions::TYPE_EDGE: 342 370 return $this->getEdgeTransactionNewValue($xaction); 343 371 case PhabricatorTransactions::TYPE_CUSTOMFIELD: ··· 437 465 case PhabricatorTransactions::TYPE_SUBSCRIBERS: 438 466 case PhabricatorTransactions::TYPE_INLINESTATE: 439 467 case PhabricatorTransactions::TYPE_EDGE: 468 + case PhabricatorTransactions::TYPE_SPACE: 440 469 case PhabricatorTransactions::TYPE_COMMENT: 441 470 return $this->applyBuiltinInternalTransaction($object, $xaction); 442 471 } ··· 485 514 case PhabricatorTransactions::TYPE_EDIT_POLICY: 486 515 case PhabricatorTransactions::TYPE_JOIN_POLICY: 487 516 case PhabricatorTransactions::TYPE_INLINESTATE: 517 + case PhabricatorTransactions::TYPE_SPACE: 488 518 case PhabricatorTransactions::TYPE_COMMENT: 489 519 return $this->applyBuiltinExternalTransaction($object, $xaction); 490 520 } ··· 536 566 break; 537 567 case PhabricatorTransactions::TYPE_JOIN_POLICY: 538 568 $object->setJoinPolicy($xaction->getNewValue()); 569 + break; 570 + case PhabricatorTransactions::TYPE_SPACE: 571 + $object->setSpacePHID($xaction->getNewValue()); 539 572 break; 540 573 } 541 574 } ··· 1190 1223 PhabricatorPolicyCapability::CAN_VIEW); 1191 1224 break; 1192 1225 case PhabricatorTransactions::TYPE_VIEW_POLICY: 1193 - PhabricatorPolicyFilter::requireCapability( 1194 - $actor, 1195 - $object, 1196 - PhabricatorPolicyCapability::CAN_EDIT); 1197 - break; 1198 1226 case PhabricatorTransactions::TYPE_EDIT_POLICY: 1199 - PhabricatorPolicyFilter::requireCapability( 1200 - $actor, 1201 - $object, 1202 - PhabricatorPolicyCapability::CAN_EDIT); 1203 - break; 1204 1227 case PhabricatorTransactions::TYPE_JOIN_POLICY: 1228 + case PhabricatorTransactions::TYPE_SPACE: 1205 1229 PhabricatorPolicyFilter::requireCapability( 1206 1230 $actor, 1207 1231 $object, ··· 1882 1906 $type, 1883 1907 PhabricatorPolicyCapability::CAN_EDIT); 1884 1908 break; 1909 + case PhabricatorTransactions::TYPE_SPACE: 1910 + $errors[] = $this->validateSpaceTransactions( 1911 + $object, 1912 + $xactions, 1913 + $type); 1914 + break; 1885 1915 case PhabricatorTransactions::TYPE_CUSTOMFIELD: 1886 1916 $groups = array(); 1887 1917 foreach ($xactions as $xaction) { ··· 1967 1997 1968 1998 return $errors; 1969 1999 } 2000 + 2001 + 2002 + private function validateSpaceTransactions( 2003 + PhabricatorLiskDAO $object, 2004 + array $xactions, 2005 + $transaction_type) { 2006 + $errors = array(); 2007 + 2008 + $all_spaces = PhabricatorSpacesNamespaceQuery::getAllSpaces(); 2009 + $viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces( 2010 + $this->getActor()); 2011 + foreach ($xactions as $xaction) { 2012 + $space_phid = $xaction->getNewValue(); 2013 + 2014 + if ($space_phid === null) { 2015 + if (!$all_spaces) { 2016 + // The install doesn't have any spaces, so this is fine. 2017 + continue; 2018 + } 2019 + 2020 + // The install has some spaces, so every object needs to be put 2021 + // in a valid space. 2022 + $errors[] = new PhabricatorApplicationTransactionValidationError( 2023 + $transaction_type, 2024 + pht('Invalid'), 2025 + pht('You must choose a space for this object.'), 2026 + $xaction); 2027 + continue; 2028 + } 2029 + 2030 + // If the PHID isn't `null`, it needs to be a valid space that the 2031 + // viewer can see. 2032 + if (empty($viewer_spaces[$space_phid])) { 2033 + $errors[] = new PhabricatorApplicationTransactionValidationError( 2034 + $transaction_type, 2035 + pht('Invalid'), 2036 + pht( 2037 + 'You can not shift this object in the selected space, because '. 2038 + 'the space does not exist or you do not have access to it.'), 2039 + $xaction); 2040 + } 2041 + } 2042 + 2043 + return $errors; 2044 + } 2045 + 1970 2046 1971 2047 protected function adjustObjectForPolicyChecks( 1972 2048 PhabricatorLiskDAO $object,
+26
src/applications/transactions/storage/PhabricatorApplicationTransaction.php
··· 250 250 $phids[] = array($new); 251 251 } 252 252 break; 253 + case PhabricatorTransactions::TYPE_SPACE: 254 + if ($old) { 255 + $phids[] = array($old); 256 + } 257 + if ($new) { 258 + $phids[] = array($new); 259 + } 260 + break; 253 261 case PhabricatorTransactions::TYPE_TOKEN: 254 262 break; 255 263 case PhabricatorTransactions::TYPE_BUILDABLE: ··· 369 377 return 'fa-wrench'; 370 378 case PhabricatorTransactions::TYPE_TOKEN: 371 379 return 'fa-trophy'; 380 + case PhabricatorTransactions::TYPE_SPACE: 381 + return 'fa-th-large'; 372 382 } 373 383 374 384 return 'fa-pencil'; ··· 438 448 case PhabricatorTransactions::TYPE_VIEW_POLICY: 439 449 case PhabricatorTransactions::TYPE_EDIT_POLICY: 440 450 case PhabricatorTransactions::TYPE_JOIN_POLICY: 451 + case PhabricatorTransactions::TYPE_SPACE: 441 452 if ($this->getOldValue() === null) { 442 453 return true; 443 454 } else { ··· 597 608 return pht( 598 609 'All users are already subscribed to this %s.', 599 610 $this->getApplicationObjectTypeName()); 611 + case PhabricatorTransactions::TYPE_SPACE: 612 + return pht('This object is already in that space.'); 600 613 case PhabricatorTransactions::TYPE_EDGE: 601 614 return pht('Edges already exist; transaction has no effect.'); 602 615 } ··· 636 649 $this->getApplicationObjectTypeName(), 637 650 $this->renderPolicyName($old, 'old'), 638 651 $this->renderPolicyName($new, 'new')); 652 + case PhabricatorTransactions::TYPE_SPACE: 653 + return pht( 654 + '%s shifted this object from the %s space to the %s space.', 655 + $this->renderHandleLink($author_phid), 656 + $this->renderHandleLink($old), 657 + $this->renderHandleLink($new)); 639 658 case PhabricatorTransactions::TYPE_SUBSCRIBERS: 640 659 $add = array_diff($new, $old); 641 660 $rem = array_diff($old, $new); ··· 821 840 '%s updated subscribers of %s.', 822 841 $this->renderHandleLink($author_phid), 823 842 $this->renderHandleLink($object_phid)); 843 + case PhabricatorTransactions::TYPE_SPACE: 844 + return pht( 845 + '%s shifted %s from the %s space to the %s space.', 846 + $this->renderHandleLink($author_phid), 847 + $this->renderHandleLink($object_phid), 848 + $this->renderHandleLink($old), 849 + $this->renderHandleLink($new)); 824 850 case PhabricatorTransactions::TYPE_EDGE: 825 851 $new = ipull($new, 'dst'); 826 852 $old = ipull($old, 'dst');
+54 -15
src/view/phui/PHUIHeaderView.php
··· 174 174 175 175 $header = array(); 176 176 177 + $header[] = $this->renderObjectSpaceInformation(); 178 + 179 + if ($this->objectName) { 180 + $header[] = array( 181 + phutil_tag( 182 + 'a', 183 + array( 184 + 'href' => '/'.$this->objectName, 185 + ), 186 + $this->objectName), 187 + ' ', 188 + ); 189 + } 190 + 177 191 if ($this->actionLinks) { 178 192 $actions = array(); 179 193 foreach ($this->actionLinks as $button) { ··· 200 214 } 201 215 $header[] = $this->header; 202 216 203 - if ($this->objectName) { 204 - array_unshift( 205 - $header, 206 - phutil_tag( 207 - 'a', 208 - array( 209 - 'href' => '/'.$this->objectName, 210 - ), 211 - $this->objectName), 212 - ' '); 213 - } 214 - 215 217 if ($this->tags) { 216 218 $header[] = ' '; 217 219 $header[] = phutil_tag( ··· 268 270 } 269 271 270 272 private function renderPolicyProperty(PhabricatorPolicyInterface $object) { 271 - $policies = PhabricatorPolicyQuery::loadPolicies( 272 - $this->getUser(), 273 - $object); 273 + $viewer = $this->getUser(); 274 + 275 + $policies = PhabricatorPolicyQuery::loadPolicies($viewer, $object); 274 276 275 277 $view_capability = PhabricatorPolicyCapability::CAN_VIEW; 276 278 $policy = idx($policies, $view_capability); ··· 294 296 295 297 return array($icon, $link); 296 298 } 299 + 300 + private function renderObjectSpaceInformation() { 301 + $viewer = $this->getUser(); 302 + 303 + $object = $this->policyObject; 304 + if (!$object) { 305 + return; 306 + } 307 + 308 + if (!($object instanceof PhabricatorSpacesInterface)) { 309 + return; 310 + } 311 + 312 + $space_phid = $object->getSpacePHID(); 313 + if ($space_phid === null) { 314 + $default_space = PhabricatorSpacesNamespaceQuery::getDefaultSpace(); 315 + if ($default_space) { 316 + $space_phid = $default_space->getPHID(); 317 + } 318 + } 319 + 320 + if ($space_phid === null) { 321 + return; 322 + } 323 + 324 + return phutil_tag( 325 + 'span', 326 + array( 327 + 'class' => 'spaces-name', 328 + ), 329 + array( 330 + $viewer->renderHandle($space_phid), 331 + ' | ', 332 + )); 333 + } 334 + 335 + 297 336 }
+8
webroot/rsrc/css/phui/phui-header-view.css
··· 140 140 .device .phui-header-action-links .phui-mobile-menu { 141 141 display: inline-block; 142 142 } 143 + 144 + .spaces-name { 145 + color: {$lightbluetext}; 146 + } 147 + 148 + .spaces-name .phui-handle { 149 + color: #000; 150 + }