@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.

Use property tabs in Files

Summary:
See screenshots. Some simplifications:

- Tabbed and non-tabbed lists are now allowed to be mixed. We just make the non-tabbed lists permanent and put them on the bottom (e.g., image and audio data in Files).
- You can provide a tab name instead of an entire tab object and we'll build an object for you.
- We respect `setSelected()` on the tab objects now.

Test Plan: See screenshots.

Reviewers: chad, btrahan

Reviewed By: chad

CC: chad, aran

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

+125 -121
+46 -46
src/__celerity_resource_map__.php
··· 3921 3921 ), 3922 3922 'phui-property-list-view-css' => 3923 3923 array( 3924 - 'uri' => '/res/7c39fbe1/rsrc/css/phui/phui-property-list-view.css', 3924 + 'uri' => '/res/81bdc80f/rsrc/css/phui/phui-property-list-view.css', 3925 3925 'type' => 'css', 3926 3926 'requires' => 3927 3927 array( ··· 4309 4309 ), array( 4310 4310 'packages' => 4311 4311 array( 4312 - '7a1959db' => 4312 + '71e32b00' => 4313 4313 array( 4314 4314 'name' => 'core.pkg.css', 4315 4315 'symbols' => ··· 4358 4358 41 => 'phabricator-tag-view-css', 4359 4359 42 => 'phui-list-view-css', 4360 4360 ), 4361 - 'uri' => '/res/pkg/7a1959db/core.pkg.css', 4361 + 'uri' => '/res/pkg/71e32b00/core.pkg.css', 4362 4362 'type' => 'css', 4363 4363 ), 4364 4364 '2c1dba03' => ··· 4550 4550 ), 4551 4551 'reverse' => 4552 4552 array( 4553 - 'aphront-dialog-view-css' => '7a1959db', 4554 - 'aphront-error-view-css' => '7a1959db', 4555 - 'aphront-list-filter-view-css' => '7a1959db', 4556 - 'aphront-pager-view-css' => '7a1959db', 4557 - 'aphront-panel-view-css' => '7a1959db', 4558 - 'aphront-table-view-css' => '7a1959db', 4559 - 'aphront-tokenizer-control-css' => '7a1959db', 4560 - 'aphront-tooltip-css' => '7a1959db', 4561 - 'aphront-typeahead-control-css' => '7a1959db', 4553 + 'aphront-dialog-view-css' => '71e32b00', 4554 + 'aphront-error-view-css' => '71e32b00', 4555 + 'aphront-list-filter-view-css' => '71e32b00', 4556 + 'aphront-pager-view-css' => '71e32b00', 4557 + 'aphront-panel-view-css' => '71e32b00', 4558 + 'aphront-table-view-css' => '71e32b00', 4559 + 'aphront-tokenizer-control-css' => '71e32b00', 4560 + 'aphront-tooltip-css' => '71e32b00', 4561 + 'aphront-typeahead-control-css' => '71e32b00', 4562 4562 'differential-changeset-view-css' => '7cd7e387', 4563 4563 'differential-core-view-css' => '7cd7e387', 4564 4564 'differential-inline-comment-editor' => '5e9e5c4e', ··· 4572 4572 'differential-table-of-contents-css' => '7cd7e387', 4573 4573 'diffusion-commit-view-css' => '270f4eb4', 4574 4574 'diffusion-icons-css' => '270f4eb4', 4575 - 'global-drag-and-drop-css' => '7a1959db', 4575 + 'global-drag-and-drop-css' => '71e32b00', 4576 4576 'inline-comment-summary-css' => '7cd7e387', 4577 4577 'javelin-aphlict' => '2c1dba03', 4578 4578 'javelin-behavior' => '3e3be199', ··· 4647 4647 'javelin-util' => '3e3be199', 4648 4648 'javelin-vector' => '3e3be199', 4649 4649 'javelin-workflow' => '3e3be199', 4650 - 'lightbox-attachment-css' => '7a1959db', 4650 + 'lightbox-attachment-css' => '71e32b00', 4651 4651 'maniphest-task-summary-css' => '49898640', 4652 - 'phabricator-action-list-view-css' => '7a1959db', 4653 - 'phabricator-application-launch-view-css' => '7a1959db', 4652 + 'phabricator-action-list-view-css' => '71e32b00', 4653 + 'phabricator-application-launch-view-css' => '71e32b00', 4654 4654 'phabricator-busy' => '2c1dba03', 4655 4655 'phabricator-content-source-view-css' => '7cd7e387', 4656 - 'phabricator-core-css' => '7a1959db', 4657 - 'phabricator-crumbs-view-css' => '7a1959db', 4656 + 'phabricator-core-css' => '71e32b00', 4657 + 'phabricator-crumbs-view-css' => '71e32b00', 4658 4658 'phabricator-drag-and-drop-file-upload' => '5e9e5c4e', 4659 4659 'phabricator-dropdown-menu' => '2c1dba03', 4660 4660 'phabricator-file-upload' => '2c1dba03', 4661 - 'phabricator-filetree-view-css' => '7a1959db', 4662 - 'phabricator-flag-css' => '7a1959db', 4661 + 'phabricator-filetree-view-css' => '71e32b00', 4662 + 'phabricator-flag-css' => '71e32b00', 4663 4663 'phabricator-hovercard' => '2c1dba03', 4664 - 'phabricator-jump-nav' => '7a1959db', 4664 + 'phabricator-jump-nav' => '71e32b00', 4665 4665 'phabricator-keyboard-shortcut' => '2c1dba03', 4666 4666 'phabricator-keyboard-shortcut-manager' => '2c1dba03', 4667 - 'phabricator-main-menu-view' => '7a1959db', 4667 + 'phabricator-main-menu-view' => '71e32b00', 4668 4668 'phabricator-menu-item' => '2c1dba03', 4669 - 'phabricator-nav-view-css' => '7a1959db', 4669 + 'phabricator-nav-view-css' => '71e32b00', 4670 4670 'phabricator-notification' => '2c1dba03', 4671 - 'phabricator-notification-css' => '7a1959db', 4672 - 'phabricator-notification-menu-css' => '7a1959db', 4671 + 'phabricator-notification-css' => '71e32b00', 4672 + 'phabricator-notification-menu-css' => '71e32b00', 4673 4673 'phabricator-object-selector-css' => '7cd7e387', 4674 4674 'phabricator-phtize' => '2c1dba03', 4675 4675 'phabricator-prefab' => '2c1dba03', 4676 4676 'phabricator-project-tag-css' => '49898640', 4677 - 'phabricator-remarkup-css' => '7a1959db', 4677 + 'phabricator-remarkup-css' => '71e32b00', 4678 4678 'phabricator-shaped-request' => '5e9e5c4e', 4679 - 'phabricator-side-menu-view-css' => '7a1959db', 4680 - 'phabricator-standard-page-view' => '7a1959db', 4681 - 'phabricator-tag-view-css' => '7a1959db', 4679 + 'phabricator-side-menu-view-css' => '71e32b00', 4680 + 'phabricator-standard-page-view' => '71e32b00', 4681 + 'phabricator-tag-view-css' => '71e32b00', 4682 4682 'phabricator-textareautils' => '2c1dba03', 4683 4683 'phabricator-tooltip' => '2c1dba03', 4684 - 'phabricator-transaction-view-css' => '7a1959db', 4685 - 'phabricator-zindex-css' => '7a1959db', 4686 - 'phui-button-css' => '7a1959db', 4687 - 'phui-form-css' => '7a1959db', 4688 - 'phui-form-view-css' => '7a1959db', 4689 - 'phui-header-view-css' => '7a1959db', 4690 - 'phui-icon-view-css' => '7a1959db', 4691 - 'phui-list-view-css' => '7a1959db', 4692 - 'phui-object-item-list-view-css' => '7a1959db', 4693 - 'phui-property-list-view-css' => '7a1959db', 4694 - 'phui-spacing-css' => '7a1959db', 4695 - 'sprite-apps-large-css' => '7a1959db', 4696 - 'sprite-gradient-css' => '7a1959db', 4697 - 'sprite-icons-css' => '7a1959db', 4698 - 'sprite-menu-css' => '7a1959db', 4699 - 'sprite-status-css' => '7a1959db', 4700 - 'syntax-highlighting-css' => '7a1959db', 4684 + 'phabricator-transaction-view-css' => '71e32b00', 4685 + 'phabricator-zindex-css' => '71e32b00', 4686 + 'phui-button-css' => '71e32b00', 4687 + 'phui-form-css' => '71e32b00', 4688 + 'phui-form-view-css' => '71e32b00', 4689 + 'phui-header-view-css' => '71e32b00', 4690 + 'phui-icon-view-css' => '71e32b00', 4691 + 'phui-list-view-css' => '71e32b00', 4692 + 'phui-object-item-list-view-css' => '71e32b00', 4693 + 'phui-property-list-view-css' => '71e32b00', 4694 + 'phui-spacing-css' => '71e32b00', 4695 + 'sprite-apps-large-css' => '71e32b00', 4696 + 'sprite-gradient-css' => '71e32b00', 4697 + 'sprite-icons-css' => '71e32b00', 4698 + 'sprite-menu-css' => '71e32b00', 4699 + 'sprite-status-css' => '71e32b00', 4700 + 'syntax-highlighting-css' => '71e32b00', 4701 4701 ), 4702 4702 ));
+39 -34
src/applications/files/controller/PhabricatorFileInfoController.php
··· 44 44 } 45 45 46 46 $actions = $this->buildActionView($file); 47 - $properties_array = $this->buildPropertyView($file, $actions); 48 47 $timeline = $this->buildTransactionView($file, $xactions); 49 48 $crumbs = $this->buildApplicationCrumbs(); 50 49 $crumbs->setActionList($actions); ··· 56 55 $object_box = id(new PHUIObjectBoxView()) 57 56 ->setHeader($header); 58 57 59 - foreach ($properties_array as $property_item) { 60 - $object_box->addPropertyList($property_item); 61 - } 58 + $this->buildPropertyViews($object_box, $file, $actions); 62 59 63 60 return $this->buildApplicationPage( 64 61 array( ··· 164 161 return $view; 165 162 } 166 163 167 - private function buildPropertyView( 164 + private function buildPropertyViews( 165 + PHUIObjectBoxView $box, 168 166 PhabricatorFile $file, 169 167 PhabricatorActionListView $actions) { 170 168 $request = $this->getRequest(); 171 169 $user = $request->getUser(); 172 170 173 - $listview = array(); 171 + 174 172 $properties = id(new PHUIPropertyListView()); 175 173 $properties->setActionList($actions); 174 + $box->addPropertyList($properties, pht('Details')); 176 175 177 176 if ($file->getAuthorPHID()) { 178 177 $properties->addProperty( ··· 184 183 pht('Created'), 185 184 phabricator_datetime($file->getDateCreated(), $user)); 186 185 187 - $properties->addProperty( 186 + 187 + $finfo = id(new PHUIPropertyListView()); 188 + $box->addPropertyList($finfo, pht('File Info')); 189 + 190 + $finfo->addProperty( 188 191 pht('Size'), 189 192 phabricator_format_bytes($file->getByteSize())); 190 193 191 - $properties->addSectionHeader(pht('Technical Details')); 192 - 193 - $properties->addProperty( 194 + $finfo->addProperty( 194 195 pht('Mime Type'), 195 196 $file->getMimeType()); 196 197 197 - $properties->addProperty( 198 + $width = $file->getImageWidth(); 199 + if ($width) { 200 + $finfo->addProperty( 201 + pht('Width'), 202 + pht('%s px', new PhutilNumber($width))); 203 + } 204 + 205 + $height = $file->getImageHeight(); 206 + if ($height) { 207 + $finfo->addProperty( 208 + pht('Height'), 209 + pht('%s px', new PhutilNumber($height))); 210 + } 211 + 212 + 213 + $storage_properties = new PHUIPropertyListView(); 214 + $box->addPropertyList($storage_properties, pht('Storage')); 215 + 216 + $storage_properties->addProperty( 198 217 pht('Engine'), 199 218 $file->getStorageEngine()); 200 219 201 - $properties->addProperty( 220 + $storage_properties->addProperty( 202 221 pht('Format'), 203 222 $file->getStorageFormat()); 204 223 205 - $properties->addProperty( 224 + $storage_properties->addProperty( 206 225 pht('Handle'), 207 226 $file->getStorageHandle()); 208 227 209 - $listview[] = $properties; 210 - 211 - $metadata = $file->getMetadata(); 212 - if (!empty($metadata)) { 213 - $mdata = id(new PHUIPropertyListView()) 214 - ->addSectionHeader(pht('Metadata')); 215 - 216 - foreach ($metadata as $key => $value) { 217 - $mdata->addProperty( 218 - PhabricatorFile::getMetadataName($key), 219 - $value); 220 - } 221 - $listview[] = $mdata; 222 - } 223 228 224 229 $phids = $file->getObjectPHIDs(); 225 230 if ($phids) { 226 231 $attached = new PHUIPropertyListView(); 227 - $attached->addSectionHeader(pht('Attached')); 232 + $box->addPropertyList($attached, pht('Attached')); 233 + 228 234 $attached->addProperty( 229 235 pht('Attached To'), 230 236 $this->renderHandlesForPHIDs($phids)); 231 - $listview[] = $attached; 232 237 } 233 238 234 - if ($file->isViewableImage()) { 235 239 240 + if ($file->isViewableImage()) { 236 241 $image = phutil_tag( 237 242 'img', 238 243 array( ··· 249 254 250 255 $media = id(new PHUIPropertyListView()) 251 256 ->addImageContent($linked_image); 252 - $listview[] = $media; 257 + 258 + $box->addPropertyList($media); 253 259 } else if ($file->isAudio()) { 254 260 $audio = phutil_tag( 255 261 'audio', ··· 265 271 ))); 266 272 $media = id(new PHUIPropertyListView()) 267 273 ->addImageContent($audio); 268 - $listview[] = $media; 274 + 275 + $box->addPropertyList($media); 269 276 } 270 - 271 - return $listview; 272 277 } 273 278 274 279 }
-16
src/applications/files/storage/PhabricatorFile.php
··· 725 725 return $this; 726 726 } 727 727 728 - public static function getMetadataName($metadata) { 729 - switch ($metadata) { 730 - case self::METADATA_IMAGE_WIDTH: 731 - $name = pht('Width'); 732 - break; 733 - case self::METADATA_IMAGE_HEIGHT: 734 - $name = pht('Height'); 735 - break; 736 - default: 737 - $name = ucfirst($metadata); 738 - break; 739 - } 740 - 741 - return $name; 742 - } 743 - 744 728 745 729 /** 746 730 * Load (or build) the {@class:PhabricatorFile} objects for builtin file
+3 -6
src/applications/uiexample/examples/PHUIPropertyListExample.php
··· 17 17 18 18 $details1 = id(new PHUIListItemView()) 19 19 ->setName('Details') 20 - ->setSelected(true) 21 - ->setType(PHUIListItemView::TYPE_LINK); 20 + ->setSelected(true); 22 21 23 22 $details2 = id(new PHUIListItemView()) 24 23 ->setName('Rainbow Info') 25 - ->setStatusColor(PHUIListItemView::STATUS_WARN) 26 - ->setType(PHUIListItemView::TYPE_LINK); 24 + ->setStatusColor(PHUIListItemView::STATUS_WARN); 27 25 28 26 $details3 = id(new PHUIListItemView()) 29 27 ->setName('Pasta Haiku') 30 - ->setStatusColor(PHUIListItemView::STATUS_FAIL) 31 - ->setType(PHUIListItemView::TYPE_LINK); 28 + ->setStatusColor(PHUIListItemView::STATUS_FAIL); 32 29 33 30 $statustabs = id(new PHUIListView()) 34 31 ->setType(PHUIListView::NAVBAR_LIST)
+35 -18
src/view/phui/PHUIObjectBoxView.php
··· 11 11 12 12 private $tabs = array(); 13 13 private $propertyLists = array(); 14 - private $selectedTab; 15 14 16 15 public function addPropertyList( 17 16 PHUIPropertyListView $property_list, 18 - PHUIListItemView $tab = null) { 19 - 20 - if ($this->propertyLists) { 21 - $already_has_tabs = (bool)$this->tabs; 22 - $adding_new_tab = (bool)$tab; 17 + $tab = null) { 23 18 24 - if ($already_has_tabs xor $adding_new_tab) { 25 - throw new Exception( 26 - "You can not mix tabbed and un-tabbed property lists in the same ". 27 - "BoxView."); 28 - } 19 + if (!($tab instanceof PHUIListItemView) && 20 + ($tab !== null)) { 21 + assert_stringlike($tab); 22 + $tab = id(new PHUIListItemView())->setName($tab); 29 23 } 30 24 31 25 if ($tab) { ··· 40 34 } 41 35 42 36 if ($tab) { 43 - if (!$this->tabs) { 44 - $this->selectedTab = $key; 45 - } 46 - 47 37 if (empty($this->tabs[$key])) { 48 38 $tab->addSigil('phui-object-box-tab'); 49 39 $tab->setMetadata( ··· 53 43 54 44 if (!$tab->getHref()) { 55 45 $tab->setHref('#'); 46 + } 47 + 48 + if (!$tab->getType()) { 49 + $tab->setType(PHUIListItemView::TYPE_LINK); 56 50 } 57 51 58 52 $this->tabs[$key] = $tab; ··· 121 115 } 122 116 } 123 117 118 + $tab_lists = array(); 124 119 $property_lists = array(); 125 120 $tab_map = array(); 121 + 122 + $default_key = 'tab.default'; 123 + 124 + // Find the selected tab, or select the first tab if none are selected. 125 + if ($this->tabs) { 126 + $selected_tab = null; 127 + foreach ($this->tabs as $key => $tab) { 128 + if ($tab->getSelected()) { 129 + $selected_tab = $key; 130 + break; 131 + } 132 + } 133 + if ($selected_tab === null) { 134 + head($this->tabs)->setSelected(true); 135 + $selected_tab = head_key($this->tabs); 136 + } 137 + } 138 + 126 139 foreach ($this->propertyLists as $key => $list) { 127 140 $group = new PHUIPropertyGroupView(); 128 141 foreach ($list as $item) { 129 142 $group->addPropertyList($item); 130 143 } 131 144 132 - if ($this->tabs) { 145 + if ($this->tabs && $key != $default_key) { 133 146 $tab_id = celerity_generate_unique_node_id(); 134 147 $tab_map[$key] = $tab_id; 135 148 136 - if ($key === $this->selectedTab) { 149 + if ($key === $selected_tab) { 137 150 $style = null; 138 151 } else { 139 152 $style = 'display: none'; 140 153 } 141 154 142 - $property_lists[] = phutil_tag( 155 + $tab_lists[] = phutil_tag( 143 156 'div', 144 157 array( 145 158 'style' => $style, ··· 147 160 ), 148 161 $group); 149 162 } else { 163 + if ($this->tabs) { 164 + $group->addClass('phui-property-group-noninitial'); 165 + } 150 166 $property_lists[] = $group; 151 167 } 152 168 } ··· 170 186 $exception_errors, 171 187 $this->form, 172 188 $tabs, 189 + $tab_lists, 173 190 $property_lists, 174 191 $this->renderChildren(), 175 192 ))
+2 -1
webroot/rsrc/css/phui/phui-property-list-view.css
··· 24 24 } 25 25 26 26 .phui-property-list-section + 27 - .phui-property-list-section { 27 + .phui-property-list-section, 28 + .phui-property-group-noninitial { 28 29 border-color: {$thinblueborder}; 29 30 border-style: solid; 30 31 border-width: 1px 0 0;