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

Clean up recurring event information on Calendar events

Summary: Ref T11326. This adds prev/next links for recurring events (ala D16179) and moves the "accept/decline" buttons closer to the invite list. This might need some fiddling, but should be a little more human-friendly.

Test Plan: {F1740541}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T11326

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

+176 -51
+153 -43
src/applications/calendar/controller/PhabricatorCalendarEventViewController.php
··· 49 49 $subheader = $this->buildSubheaderView($event); 50 50 $curtain = $this->buildCurtain($event); 51 51 $details = $this->buildPropertySection($event); 52 + $recurring = $this->buildRecurringSection($event); 52 53 $description = $this->buildDescriptionView($event); 53 54 54 55 $comment_view = id(new PhabricatorCalendarEventEditEngine()) ··· 58 59 $timeline->setQuoteRef($monogram); 59 60 $comment_view->setTransactionTimeline($timeline); 60 61 62 + $details_header = id(new PHUIHeaderView()) 63 + ->setHeader(pht('Details')); 64 + $recurring_header = $this->buildRecurringHeader($event); 65 + 61 66 $view = id(new PHUITwoColumnView()) 62 67 ->setHeader($header) 63 68 ->setSubheader($subheader) ··· 67 72 $comment_view, 68 73 )) 69 74 ->setCurtain($curtain) 70 - ->addPropertySection(pht('Details'), $details) 75 + ->addPropertySection($details_header, $details) 76 + ->addPropertySection($recurring_header, $recurring) 71 77 ->addPropertySection(pht('Description'), $description); 72 78 73 79 return $this->newPage() ··· 92 98 $status = pht('Active'); 93 99 } 94 100 95 - $invite_status = $event->getUserInviteStatus($viewer->getPHID()); 96 - $status_invited = PhabricatorCalendarEventInvitee::STATUS_INVITED; 97 - $is_invite_pending = ($invite_status == $status_invited); 98 - 99 101 $header = id(new PHUIHeaderView()) 100 102 ->setUser($viewer) 101 103 ->setHeader($event->getName()) ··· 103 105 ->setPolicyObject($event) 104 106 ->setHeaderIcon($event->getIcon()); 105 107 106 - if ($is_invite_pending) { 107 - $decline_button = id(new PHUIButtonView()) 108 - ->setTag('a') 109 - ->setIcon('fa-times grey') 110 - ->setHref($this->getApplicationURI("/event/decline/{$id}/")) 111 - ->setWorkflow(true) 112 - ->setText(pht('Decline')); 113 - 114 - $accept_button = id(new PHUIButtonView()) 115 - ->setTag('a') 116 - ->setIcon('fa-check green') 117 - ->setHref($this->getApplicationURI("/event/accept/{$id}/")) 118 - ->setWorkflow(true) 119 - ->setText(pht('Accept')); 120 - 121 - $header->addActionLink($decline_button) 122 - ->addActionLink($accept_button); 108 + foreach ($this->buildRSVPActions($event) as $action) { 109 + $header->addActionLink($action); 123 110 } 111 + 124 112 return $header; 125 113 } 126 114 ··· 215 203 $properties = id(new PHUIPropertyListView()) 216 204 ->setUser($viewer); 217 205 218 - if ($event->getIsRecurring()) { 219 - $properties->addProperty( 220 - pht('Recurs'), 221 - ucwords(idx($event->getRecurrenceFrequency(), 'rule'))); 222 - 223 - if ($event->getRecurrenceEndDate()) { 224 - $properties->addProperty( 225 - pht('Recurrence Ends'), 226 - phabricator_datetime($event->getRecurrenceEndDate(), $viewer)); 227 - } 228 - 229 - if ($event->getInstanceOfEventPHID()) { 230 - $properties->addProperty( 231 - pht('Recurrence of Event'), 232 - pht('%s of %s', 233 - $event->getSequenceIndex(), 234 - $viewer->renderHandle($event->getInstanceOfEventPHID())->render())); 235 - } 236 - } 237 - 238 206 $invitees = $event->getInvitees(); 239 207 foreach ($invitees as $key => $invitee) { 240 208 if ($invitee->isUninvited()) { ··· 293 261 return $properties; 294 262 } 295 263 264 + private function buildRecurringHeader(PhabricatorCalendarEvent $event) { 265 + $viewer = $this->getViewer(); 266 + 267 + if (!$event->getIsRecurring()) { 268 + return null; 269 + } 270 + 271 + $header = id(new PHUIHeaderView()) 272 + ->setHeader(pht('Recurring Event')); 273 + 274 + $sequence = $event->getSequenceIndex(); 275 + if ($event->isParentEvent()) { 276 + $parent = $event; 277 + } else { 278 + $parent = $event->getParentEvent(); 279 + } 280 + 281 + $next_uri = $parent->getURI().'/'.($sequence + 1); 282 + if ($sequence) { 283 + if ($sequence > 1) { 284 + $previous_uri = $parent->getURI().'/'.($sequence - 1); 285 + } else { 286 + $previous_uri = $parent->getURI(); 287 + } 288 + $has_previous = true; 289 + } else { 290 + $has_previous = false; 291 + $previous_uri = null; 292 + } 293 + 294 + $prev_button = id(new PHUIButtonView()) 295 + ->setTag('a') 296 + ->setIcon('fa-chevron-left') 297 + ->setHref($previous_uri) 298 + ->setDisabled(!$has_previous) 299 + ->setText(pht('Previous')); 300 + 301 + $next_button = id(new PHUIButtonView()) 302 + ->setTag('a') 303 + ->setIcon('fa-chevron-right') 304 + ->setHref($next_uri) 305 + ->setText(pht('Next')); 306 + 307 + $header 308 + ->addActionLink($next_button) 309 + ->addActionLink($prev_button); 310 + 311 + return $header; 312 + } 313 + 314 + private function buildRecurringSection(PhabricatorCalendarEvent $event) { 315 + $viewer = $this->getViewer(); 316 + 317 + if (!$event->getIsRecurring()) { 318 + return null; 319 + } 320 + 321 + $properties = id(new PHUIPropertyListView()) 322 + ->setUser($viewer); 323 + 324 + $is_parent = $event->isParentEvent(); 325 + if ($is_parent) { 326 + $parent_link = null; 327 + } else { 328 + $parent = $event->getParentEvent(); 329 + $parent_link = $viewer 330 + ->renderHandle($parent->getPHID()) 331 + ->render(); 332 + } 333 + 334 + $rule = $event->getFrequencyRule(); 335 + switch ($rule) { 336 + case PhabricatorCalendarEvent::FREQUENCY_DAILY: 337 + if ($is_parent) { 338 + $message = pht('This event repeats every day.'); 339 + } else { 340 + $message = pht( 341 + 'This event is an instance of %s, and repeats every day.', 342 + $parent_link); 343 + } 344 + break; 345 + case PhabricatorCalendarEvent::FREQUENCY_WEEKLY: 346 + if ($is_parent) { 347 + $message = pht('This event repeats every week.'); 348 + } else { 349 + $message = pht( 350 + 'This event is an instance of %s, and repeats every week.', 351 + $parent_link); 352 + } 353 + break; 354 + case PhabricatorCalendarEvent::FREQUENCY_MONTHLY: 355 + if ($is_parent) { 356 + $message = pht('This event repeats every month.'); 357 + } else { 358 + $message = pht( 359 + 'This event is an instance of %s, and repeats every month.', 360 + $parent_link); 361 + } 362 + break; 363 + case PhabricatorCalendarEvent::FREQUENCY_YEARLY: 364 + if ($is_parent) { 365 + $message = pht('This event repeats every year.'); 366 + } else { 367 + $message = pht( 368 + 'This event is an instance of %s, and repeats every year.', 369 + $parent_link); 370 + } 371 + break; 372 + } 373 + 374 + $properties->addProperty(pht('Event Series'), $message); 375 + 376 + return $properties; 377 + } 378 + 296 379 private function buildDescriptionView( 297 380 PhabricatorCalendarEvent $event) { 298 381 $viewer = $this->getViewer(); ··· 308 391 309 392 return null; 310 393 } 311 - 312 394 313 395 private function loadEvent() { 314 396 $request = $this->getRequest(); ··· 397 479 ->setContent($content); 398 480 } 399 481 482 + 483 + private function buildRSVPActions(PhabricatorCalendarEvent $event) { 484 + $viewer = $this->getViewer(); 485 + $id = $event->getID(); 486 + 487 + $invite_status = $event->getUserInviteStatus($viewer->getPHID()); 488 + $status_invited = PhabricatorCalendarEventInvitee::STATUS_INVITED; 489 + $is_invite_pending = ($invite_status == $status_invited); 490 + if (!$is_invite_pending) { 491 + return array(); 492 + } 493 + 494 + $decline_button = id(new PHUIButtonView()) 495 + ->setTag('a') 496 + ->setIcon('fa-times grey') 497 + ->setHref($this->getApplicationURI("/event/decline/{$id}/")) 498 + ->setWorkflow(true) 499 + ->setText(pht('Decline')); 500 + 501 + $accept_button = id(new PHUIButtonView()) 502 + ->setTag('a') 503 + ->setIcon('fa-check green') 504 + ->setHref($this->getApplicationURI("/event/accept/{$id}/")) 505 + ->setWorkflow(true) 506 + ->setText(pht('Accept')); 507 + 508 + return array($decline_button, $accept_button); 509 + } 400 510 401 511 }
+1 -1
src/applications/calendar/storage/PhabricatorCalendarEvent.php
··· 457 457 } 458 458 459 459 public function isParentEvent() { 460 - return ($this->isRecurring && !$this->instanceOfEventPHID); 460 + return ($this->getIsRecurring() && !$this->getInstanceOfEventPHID()); 461 461 } 462 462 463 463 public function isChildEvent() {
+22 -7
src/view/phui/PHUITwoColumnView.php
··· 48 48 } 49 49 50 50 public function addPropertySection($title, $section) { 51 - $this->propertySection[] = array($title, $section); 51 + $this->propertySection[] = array( 52 + 'header' => $title, 53 + 'content' => $section, 54 + ); 52 55 return $this; 53 56 } 54 57 ··· 146 149 $sections = $this->propertySection; 147 150 148 151 if ($sections) { 149 - foreach ($sections as $content) { 150 - if ($content[1]) { 151 - $view[] = id(new PHUIObjectBoxView()) 152 - ->setHeaderText($content[0]) 153 - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 154 - ->appendChild($content[1]); 152 + foreach ($sections as $section) { 153 + $section_header = $section['header']; 154 + 155 + $section_content = $section['content']; 156 + if ($section_content === null) { 157 + continue; 155 158 } 159 + 160 + if ($section_header instanceof PHUIHeaderView) { 161 + $header = $section_header; 162 + } else { 163 + $header = id(new PHUIHeaderView()) 164 + ->setHeader($section_header); 165 + } 166 + 167 + $view[] = id(new PHUIObjectBoxView()) 168 + ->setHeader($header) 169 + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 170 + ->appendChild($section_content); 156 171 } 157 172 } 158 173