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

Allow transactions to be grouped in the TimelineView

Summary: TimelineView on Maniphest is often kind of hard to parse because related/simultaneous transactions aren't visually grouped. Allow grouping. I'm going to clean this up a little bit more.

Test Plan: See screenshot.

Reviewers: chad

Reviewed By: chad

CC: aran

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

+144 -53
+1 -1
src/__celerity_resource_map__.php
··· 3461 3461 ), 3462 3462 'phabricator-timeline-view-css' => 3463 3463 array( 3464 - 'uri' => '/res/725f6b17/rsrc/css/layout/phabricator-timeline-view.css', 3464 + 'uri' => '/res/79b6d385/rsrc/css/layout/phabricator-timeline-view.css', 3465 3465 'type' => 'css', 3466 3466 'requires' => 3467 3467 array(
+57 -4
src/applications/uiexample/examples/PhabricatorTimelineExample.php
··· 111 111 ->setColor($color); 112 112 } 113 113 114 + $vhandle = $handle->renderLink(); 115 + 116 + $group_event = id(new PhabricatorTimelineEventView()) 117 + ->setUserHandle($handle) 118 + ->setTitle(pht('%s went to the store.', $vhandle)); 119 + 120 + $group_event->addEventToGroup( 121 + id(new PhabricatorTimelineEventView()) 122 + ->setUserHandle($handle) 123 + ->setTitle(pht('%s bought an apple.', $vhandle)) 124 + ->setColor('green') 125 + ->setIcon('check')); 126 + 127 + $group_event->addEventToGroup( 128 + id(new PhabricatorTimelineEventView()) 129 + ->setUserHandle($handle) 130 + ->setTitle(pht('%s bought a banana.', $vhandle)) 131 + ->setColor('yellow') 132 + ->setIcon('check')); 133 + 134 + $group_event->addEventToGroup( 135 + id(new PhabricatorTimelineEventView()) 136 + ->setUserHandle($handle) 137 + ->setTitle(pht('%s bought a cherry.', $vhandle)) 138 + ->setColor('red') 139 + ->setIcon('check')); 140 + 141 + $group_event->addEventToGroup( 142 + id(new PhabricatorTimelineEventView()) 143 + ->setUserHandle($handle) 144 + ->setTitle(pht('%s paid for his goods.', $vhandle))); 145 + 146 + $group_event->addEventToGroup( 147 + id(new PhabricatorTimelineEventView()) 148 + ->setUserHandle($handle) 149 + ->setTitle(pht('%s returned home.', $vhandle)) 150 + ->setIcon('home') 151 + ->setColor('blue')); 152 + 153 + $group_event->addEventToGroup( 154 + id(new PhabricatorTimelineEventView()) 155 + ->setUserHandle($handle) 156 + ->setTitle(pht('%s related on his adventures.', $vhandle)) 157 + ->appendChild( 158 + pht( 159 + 'Today, I went to the store. I bought an apple. I bought a '. 160 + 'banana. I bought a cherry. I paid for my goods, then I returned '. 161 + 'home.'))); 162 + 163 + $events[] = $group_event; 164 + 114 165 $anchor = 0; 115 - foreach ($events as $event) { 116 - $event->setUser($user); 117 - $event->setDateCreated(time() + ($anchor * 60 * 8)); 118 - $event->setAnchor(++$anchor); 166 + foreach ($events as $group) { 167 + foreach ($group->getEventGroup() as $event) { 168 + $event->setUser($user); 169 + $event->setDateCreated(time() + ($anchor * 60 * 8)); 170 + $event->setAnchor(++$anchor); 171 + } 119 172 } 120 173 121 174 $timeline = id(new PhabricatorTimelineView());
+69 -30
src/view/layout/PhabricatorTimelineEventView.php
··· 14 14 private $isEdited; 15 15 private $transactionPHID; 16 16 private $isPreview; 17 + private $eventGroup = array(); 17 18 18 19 public function setTransactionPHID($transaction_phid) { 19 20 $this->transactionPHID = $transaction_phid; ··· 99 100 return $this; 100 101 } 101 102 102 - public function render() { 103 + public function getEventGroup() { 104 + return array_merge(array($this), $this->eventGroup); 105 + } 106 + 107 + public function addEventToGroup(PhabricatorTimelineEventView $event) { 108 + $this->eventGroup[] = $event; 109 + return $this; 110 + } 111 + 112 + 113 + public function renderEventTitle() { 103 114 $title = $this->title; 104 115 if (($title === null) && !$this->hasChildren()) { 105 116 $title = ''; ··· 115 126 if ($this->icon) { 116 127 $title_classes[] = 'phabricator-timeline-title-with-icon'; 117 128 129 + $fill_classes = array(); 130 + $fill_classes[] = 'phabricator-timeline-icon-fill'; 131 + if ($this->color) { 132 + $fill_classes[] = 'phabricator-timeline-icon-fill-'.$this->color; 133 + } 134 + 118 135 $icon = phutil_tag( 119 136 'span', 120 137 array( 121 - 'class' => 'phabricator-timeline-icon-fill', 138 + 'class' => implode(' ', $fill_classes), 122 139 ), 123 140 phutil_tag( 124 141 'span', ··· 134 151 array( 135 152 'class' => implode(' ', $title_classes), 136 153 ), 137 - array($title, $extra)); 154 + array($icon, $title, $extra)); 155 + } 138 156 139 - $title = array($icon, $title); 157 + return $title; 158 + } 159 + 160 + public function render() { 161 + 162 + $group_titles = array(); 163 + $group_children = array(); 164 + foreach ($this->getEventGroup() as $event) { 165 + $group_titles[] = $event->renderEventTitle(); 166 + if ($event->hasChildren()) { 167 + $group_children[] = $event->renderChildren(); 168 + } 140 169 } 141 170 142 171 $wedge = phutil_tag( ··· 160 189 161 190 $classes = array(); 162 191 $classes[] = 'phabricator-timeline-event-view'; 163 - $classes[] = 'phabricator-timeline-border'; 164 - if ($this->hasChildren()) { 192 + if ($group_children) { 165 193 $classes[] = 'phabricator-timeline-major-event'; 166 194 $content = phutil_tag( 167 195 'div', 168 196 array( 169 - 'class' => implode(' ', $content_classes), 197 + 'class' => 'phabricator-timeline-inner-content', 170 198 ), 171 - phutil_tag( 172 - 'div', 173 - array( 174 - 'class' => 'phabricator-timeline-inner-content', 175 - ), 176 - array( 177 - $title, 178 - phutil_tag( 179 - 'div', 180 - array( 181 - 'class' => 'phabricator-timeline-core-content', 182 - ), 183 - $this->renderChildren()), 184 - ))); 185 - $content = array($image, $wedge, $content); 199 + array( 200 + $group_titles, 201 + phutil_tag( 202 + 'div', 203 + array( 204 + 'class' => 'phabricator-timeline-core-content', 205 + ), 206 + $group_children), 207 + )); 186 208 } else { 187 209 $classes[] = 'phabricator-timeline-minor-event'; 188 - $content = phutil_tag( 189 - 'div', 190 - array( 191 - 'class' => implode(' ', $content_classes), 192 - ), 193 - array($image, $wedge, $title)); 210 + $content = $group_titles; 194 211 } 195 212 213 + $content = phutil_tag( 214 + 'div', 215 + array( 216 + 'class' => 'phabricator-timeline-group phabricator-timeline-border', 217 + ), 218 + $content); 219 + 220 + $content = phutil_tag( 221 + 'div', 222 + array( 223 + 'class' => implode(' ', $content_classes), 224 + ), 225 + array($image, $wedge, $content)); 226 + 196 227 $outer_classes = $this->classes; 197 228 $outer_classes[] = 'phabricator-timeline-shell'; 198 - if ($this->color) { 199 - $outer_classes[] = 'phabricator-timeline-'.$this->color; 229 + $color = null; 230 + foreach ($this->getEventGroup() as $event) { 231 + if ($event->color) { 232 + $color = $event->color; 233 + break; 234 + } 235 + } 236 + 237 + if ($color) { 238 + $outer_classes[] = 'phabricator-timeline-'.$color; 200 239 } 201 240 202 241 $sigil = null;
+17 -18
webroot/rsrc/css/layout/phabricator-timeline-view.css
··· 6 6 background: #eeedf0; 7 7 } 8 8 9 - .phabricator-timeline-event-view { 10 - border-width: 0 0 0 3px; 9 + .phabricator-timeline-group { 10 + border-width: 0 3px; 11 11 border-style: solid; 12 12 border-color: #c0c5d1; 13 - 14 13 } 15 14 16 15 .device-desktop .phabricator-timeline-event-view { ··· 21 20 22 21 .device-desktop .phabricator-timeline-spacer { 23 22 min-height: 20px; 24 - border-right-width: 0; 23 + border-width: 0 0 0 3px; 24 + border-style: solid; 25 + border-color: #c0c5d1; 25 26 } 26 27 27 28 .device-desktop .phabricator-timeline-major-event, ··· 91 92 .phabricator-timeline-title { 92 93 padding: 0 5px; 93 94 overflow-x: auto; 95 + overflow-y: hidden; 94 96 } 95 97 96 98 .phabricator-timeline-title-with-icon { ··· 112 114 position: relative; 113 115 margin-left: 3px; 114 116 margin-right: 3px; 115 - 116 - border-right-width: 3px; 117 - border-right-style: solid; 118 117 } 119 118 120 119 .device .phabricator-timeline-image { ··· 131 130 width: 30px; 132 131 height: 30px; 133 132 background-color: #c0c5d1; 134 - top: 0; 133 + top: -1px; 135 134 left: -3px; 136 135 } 137 136 ··· 199 198 border-color: #333; 200 199 } 201 200 202 - .phabricator-timeline-red .phabricator-timeline-icon-fill { 201 + .phabricator-timeline-icon-fill-red { 203 202 background-color: {$red}; 204 203 } 205 204 206 - .phabricator-timeline-orange .phabricator-timeline-icon-fill { 205 + .phabricator-timeline-icon-fill-orange { 207 206 background-color: {$orange}; 208 207 } 209 208 210 - .phabricator-timeline-yellow .phabricator-timeline-icon-fill { 209 + .phabricator-timeline-icon-fill-yellow { 211 210 background-color: {$yellow}; 212 211 } 213 212 214 - .phabricator-timeline-green .phabricator-timeline-icon-fill { 213 + .phabricator-timeline-icon-fill-green { 215 214 background-color: {$green}; 216 215 } 217 216 218 - .phabricator-timeline-sky .phabricator-timeline-icon-fill { 217 + .phabricator-timeline-icon-fill-sky { 219 218 background-color: {$sky}; 220 219 } 221 220 222 - .phabricator-timeline-blue .phabricator-timeline-icon-fill { 221 + .phabricator-timeline-icon-fill-blue { 223 222 background-color: {$blue}; 224 223 } 225 224 226 - .phabricator-timeline-indigo .phabricator-timeline-icon-fill { 225 + .phabricator-timeline-icon-fill-indigo { 227 226 background-color: {$indigo}; 228 227 } 229 228 230 - .phabricator-timeline-violet .phabricator-timeline-icon-fill { 229 + .phabricator-timeline-icon-fill-violet { 231 230 background-color: {$violet}; 232 231 } 233 232 234 - .phabricator-timeline-grey .phabricator-timeline-icon-fill { 233 + .phabricator-timeline-icon-fill-grey { 235 234 background-color: #888; 236 235 } 237 236 238 - .phabricator-timeline-black .phabricator-timeline-icon-fill { 237 + .phabricator-timeline-icon-fill-black { 239 238 background-color: #333; 240 239 } 241 240