diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 59d0714f48..245a43a357 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -119,7 +119,7 @@ return array( 'rsrc/css/layout/phabricator-hovercard-view.css' => '44394670', 'rsrc/css/layout/phabricator-side-menu-view.css' => 'c1db9e9c', 'rsrc/css/layout/phabricator-source-code-view.css' => '2ceee894', - 'rsrc/css/phui/calendar/phui-calendar-day.css' => 'de035c8a', + 'rsrc/css/phui/calendar/phui-calendar-day.css' => 'a00b748d', 'rsrc/css/phui/calendar/phui-calendar-list.css' => 'c1d0ca59', 'rsrc/css/phui/calendar/phui-calendar-month.css' => 'a92e47d2', 'rsrc/css/phui/calendar/phui-calendar.css' => '8675968e', @@ -780,7 +780,7 @@ return array( 'phui-box-css' => '7b3a2eed', 'phui-button-css' => 'de610129', 'phui-calendar-css' => '8675968e', - 'phui-calendar-day-css' => 'de035c8a', + 'phui-calendar-day-css' => 'a00b748d', 'phui-calendar-list-css' => 'c1d0ca59', 'phui-calendar-month-css' => 'a92e47d2', 'phui-crumbs-view-css' => '594d719e', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 4874fa702f..4f64828c6d 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -102,6 +102,7 @@ phutil_register_library_map(array( 'AphrontApplicationConfiguration' => 'aphront/configuration/AphrontApplicationConfiguration.php', 'AphrontBarView' => 'view/widget/bars/AphrontBarView.php', 'AphrontCSRFException' => 'aphront/exception/AphrontCSRFException.php', + 'AphrontCalendarDayEventView' => 'applications/calendar/view/AphrontCalendarDayEventView.php', 'AphrontCalendarEventView' => 'applications/calendar/view/AphrontCalendarEventView.php', 'AphrontController' => 'aphront/AphrontController.php', 'AphrontCursorPagerView' => 'view/control/AphrontCursorPagerView.php', @@ -1159,6 +1160,7 @@ phutil_register_library_map(array( 'PHUIButtonBarView' => 'view/phui/PHUIButtonBarView.php', 'PHUIButtonExample' => 'applications/uiexample/examples/PHUIButtonExample.php', 'PHUIButtonView' => 'view/phui/PHUIButtonView.php', + 'PHUICalendarDayView' => 'view/phui/calendar/PHUICalendarDayView.php', 'PHUICalendarListView' => 'view/phui/calendar/PHUICalendarListView.php', 'PHUICalendarMonthView' => 'view/phui/calendar/PHUICalendarMonthView.php', 'PHUICalendarWidgetView' => 'view/phui/calendar/PHUICalendarWidgetView.php', @@ -1498,7 +1500,6 @@ phutil_register_library_map(array( 'PhabricatorCalendarEventEditController' => 'applications/calendar/controller/PhabricatorCalendarEventEditController.php', 'PhabricatorCalendarEventEditor' => 'applications/calendar/editor/PhabricatorCalendarEventEditor.php', 'PhabricatorCalendarEventEmailCommand' => 'applications/calendar/command/PhabricatorCalendarEventEmailCommand.php', - 'PhabricatorCalendarEventInvalidEpochException' => 'applications/calendar/exception/PhabricatorCalendarEventInvalidEpochException.php', 'PhabricatorCalendarEventInvitee' => 'applications/calendar/storage/PhabricatorCalendarEventInvitee.php', 'PhabricatorCalendarEventInviteeQuery' => 'applications/calendar/query/PhabricatorCalendarEventInviteeQuery.php', 'PhabricatorCalendarEventJoinController' => 'applications/calendar/controller/PhabricatorCalendarEventJoinController.php', @@ -3349,6 +3350,7 @@ phutil_register_library_map(array( 'AphrontAjaxResponse' => 'AphrontResponse', 'AphrontBarView' => 'AphrontView', 'AphrontCSRFException' => 'AphrontException', + 'AphrontCalendarDayEventView' => 'AphrontView', 'AphrontCalendarEventView' => 'AphrontView', 'AphrontController' => 'Phobject', 'AphrontCursorPagerView' => 'AphrontView', @@ -4483,6 +4485,7 @@ phutil_register_library_map(array( 'PHUIButtonBarView' => 'AphrontTagView', 'PHUIButtonExample' => 'PhabricatorUIExample', 'PHUIButtonView' => 'AphrontTagView', + 'PHUICalendarDayView' => 'AphrontView', 'PHUICalendarListView' => 'AphrontTagView', 'PHUICalendarMonthView' => 'AphrontView', 'PHUICalendarWidgetView' => 'AphrontTagView', @@ -4848,7 +4851,6 @@ phutil_register_library_map(array( 'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorCalendarEventEmailCommand' => 'MetaMTAEmailTransactionCommand', - 'PhabricatorCalendarEventInvalidEpochException' => 'Exception', 'PhabricatorCalendarEventInvitee' => array( 'PhabricatorCalendarDAO', 'PhabricatorPolicyInterface', diff --git a/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php b/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php index b65180ce66..95790e17b5 100644 --- a/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php +++ b/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php @@ -5,6 +5,7 @@ final class PhabricatorCalendarEventSearchEngine private $calendarYear; private $calendarMonth; + private $calendarDay; public function getResultTypeDescription() { return pht('Calendar Events'); @@ -144,6 +145,7 @@ final class PhabricatorCalendarEventSearchEngine ); $display_options = array( 'month' => pht('Month View'), + 'day' => pht('Day View (beta)'), 'list' => pht('List View'), ); @@ -249,6 +251,8 @@ final class PhabricatorCalendarEventSearchEngine if ($query->getParameter('display') == 'month') { return $this->buildCalendarView($events, $query, $handles); + } else if ($query->getParameter('display') == 'day') { + return $this->buildCalendarDayView($events, $query, $handles); } assert_instances_of($events, 'PhabricatorCalendarEvent'); @@ -349,6 +353,34 @@ final class PhabricatorCalendarEventSearchEngine return $month_view; } + private function buildCalendarDayView( + array $statuses, + PhabricatorSavedQuery $query, + array $handles) { + $viewer = $this->requireViewer(); + list($start_month, $start_year, $start_day) = + $this->getDisplayMonthAndYearAndDay($query); + + $day_view = new PHUICalendarDayView( + $start_month, + $start_year, + $start_day); + + $day_view->setUser($viewer); + + $phids = mpull($statuses, 'getUserPHID'); + + foreach ($statuses as $status) { + $event = new AphrontCalendarDayEventView(); + $event->setEpochRange($status->getDateFrom(), $status->getDateTo()); + + $event->setName($status->getName()); + $day_view->addEvent($event); + } + + return $day_view; + } + private function getDisplayMonthAndYear( PhabricatorSavedQuery $query) { $viewer = $this->requireViewer(); @@ -372,6 +404,28 @@ final class PhabricatorCalendarEventSearchEngine return array($start_month, $start_year); } + private function getDisplayMonthAndYearAndDay( + PhabricatorSavedQuery $query) { + $viewer = $this->requireViewer(); + if ($this->calendarYear && $this->calendarMonth && $this->calendarDay) { + $start_year = $this->calendarYear; + $start_month = $this->calendarMonth; + $start_day = $this->calendarDay; + } else { + $epoch = $query->getParameter('rangeStart'); + if (!$epoch) { + $epoch = $query->getParameter('rangeEnd'); + if (!$epoch) { + $epoch = time(); + } + } + $start_year = phabricator_format_local_time($epoch, $viewer, 'Y'); + $start_month = phabricator_format_local_time($epoch, $viewer, 'm'); + $start_day = phabricator_format_local_time($epoch, $viewer, 'd'); + } + return array($start_year, $start_month, $start_day); + } + public function getPageSize(PhabricatorSavedQuery $saved) { return $saved->getParameter('limit', 1000); } diff --git a/src/applications/calendar/view/AphrontCalendarDayEventView.php b/src/applications/calendar/view/AphrontCalendarDayEventView.php new file mode 100644 index 0000000000..98502d078d --- /dev/null +++ b/src/applications/calendar/view/AphrontCalendarDayEventView.php @@ -0,0 +1,39 @@ +name = $name; + return $this; + } + + public function getName() { + return $this->name; + } + + public function setEpochRange($start, $end) { + $this->epochStart = $start; + $this->epochEnd = $end; + return $this; + } + + public function getEpochStart() { + return $this->epochStart; + } + + public function getEpochEnd() { + return $this->epochEnd; + } + + public function render() { + $box = new PHUIObjectBoxView(); + $box->setHeaderText($this->name); + return $box; + + } +} diff --git a/src/view/phui/calendar/PHUICalendarDayView.php b/src/view/phui/calendar/PHUICalendarDayView.php new file mode 100644 index 0000000000..2f7436bc63 --- /dev/null +++ b/src/view/phui/calendar/PHUICalendarDayView.php @@ -0,0 +1,131 @@ +events[] = $event; + return $this; + } + + public function __construct($year, $month, $day = null) { + $this->day = $day; + $this->month = $month; + $this->year = $year; + } + + public function render() { + require_celerity_resource('phui-calendar-day-css'); + + $day_box = new PHUIObjectBoxView(); + $day_of_week = $this->getDayOfWeek(); + $header_text = $this->getDateTime()->format('F j, Y'); + $header_text = $day_of_week.', '.$header_text; + $day_box->setHeaderText($header_text); + $hours = $this->getHoursOfDay(); + $rows = array(); + + foreach ($hours as $hour) { + // time slot + $cell_time = phutil_tag( + 'td', + array('class' => 'phui-calendar-day-hour'), + $hour->format('g:i A')); + + $event_boxes = array(); + foreach ($this->events as $event) { + if ($event->getEpochStart() >= $hour->format('U') + && $event->getEpochStart() < $hour->modify('+1 hour')->format('U')) { + $event_boxes[] = $this->drawEvent($event); + } + } + + // events starting in time slot + $cell_event = phutil_tag( + 'td', + array(), + $event_boxes); + + + $row = phutil_tag( + 'tr', + array(), + array($cell_time, $cell_event)); + + $rows[] = $row; + } + + $table = phutil_tag( + 'table', + array('class' => 'phui-calendar-day-view'), + array( + '', + $rows, + )); + + $day_box->appendChild($table); + return $day_box; + + } + + private function drawEvent(AphrontCalendarDayEventView $event) { + $name = phutil_tag( + 'div', + array(), + $event->getName()); + + $div = phutil_tag( + 'div', + array('class' => 'phui-calendar-day-event'), + $name); + + return $div; + } + + private function getDayOfWeek() { + $date = $this->getDateTime(); + $day_of_week = $date->format('l'); + return $day_of_week; + } + + // returns DateTime of each hour in the day + private function getHoursOfDay() { + $included_datetimes = array(); + + $day_datetime = $this->getDateTime(); + $day_epoch = $day_datetime->format('U'); + + $day_datetime->modify('+1 day'); + $next_day_epoch = $day_datetime->format('U'); + + $included_time = $day_epoch; + $included_datetime = $this->getDateTime(); + + while ($included_time < $next_day_epoch) { + $included_datetimes[] = clone $included_datetime; + + $included_datetime->modify('+1 hour'); + $included_time = $included_datetime->format('U'); + } + + return $included_datetimes; + } + + private function getDateTime() { + $user = $this->user; + + $timezone = new DateTimeZone($user->getTimezoneIdentifier()); + + $day = $this->day; + $month = $this->month; + $year = $this->year; + + $date = new DateTime("{$year}-{$month}-{$day} ", $timezone); + + return $date; + } +} diff --git a/webroot/rsrc/css/phui/calendar/phui-calendar-day.css b/webroot/rsrc/css/phui/calendar/phui-calendar-day.css index 9c8dd62331..ee3119c1ac 100644 --- a/webroot/rsrc/css/phui/calendar/phui-calendar-day.css +++ b/webroot/rsrc/css/phui/calendar/phui-calendar-day.css @@ -1,3 +1,35 @@ /** * @provides phui-calendar-day-css */ + +.phui-calendar-day-view { + overflow: scroll; + width: 100%; +} + +.phui-calendar-day-hour { + width: 60px; + font-size: 10px; +} + +.phui-calendar-day-view tr { + width: 100%; + height: 60px; + border: 1px solid {$lightgreyborder}; +} + +.phui-calendar-day-view td { + position: relative; +} + +.phui-calendar-day-view td div.phui-calendar-day-event { + width: 100%; + background-color: {$darkgreybackground}; + position: absolute; + top: 0; + bottom: 0; +} + +.phui-calendar-day-view td div.phui-calendar-day-event div { + padding: 4px; +}