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

Clicking in day view should create new event

Summary: Ref T8300, clicking in day view should create new event

Test Plan: Open day view, click in an empty slot, new event modal should open.

Reviewers: epriestley, #blessed_reviewers, chad

Reviewed By: epriestley, #blessed_reviewers

Subscribers: Korvin, epriestley

Maniphest Tasks: T8300

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

+173 -34
+4 -4
resources/celerity/map.php
··· 121 121 'rsrc/css/layout/phabricator-hovercard-view.css' => 'dd9121a9', 122 122 'rsrc/css/layout/phabricator-side-menu-view.css' => 'c1db9e9c', 123 123 'rsrc/css/layout/phabricator-source-code-view.css' => '2ceee894', 124 - 'rsrc/css/phui/calendar/phui-calendar-day.css' => 'feba82c5', 124 + 'rsrc/css/phui/calendar/phui-calendar-day.css' => 'd1cf6f93', 125 125 'rsrc/css/phui/calendar/phui-calendar-list.css' => 'c1c7f338', 126 126 'rsrc/css/phui/calendar/phui-calendar-month.css' => '476be7e0', 127 127 'rsrc/css/phui/calendar/phui-calendar.css' => 'ccabe893', ··· 331 331 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'b1a59974', 332 332 'rsrc/js/application/aphlict/behavior-aphlict-status.js' => 'ea681761', 333 333 'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18', 334 - 'rsrc/js/application/calendar/behavior-day-view.js' => 'dc0065ab', 334 + 'rsrc/js/application/calendar/behavior-day-view.js' => '28a60488', 335 335 'rsrc/js/application/calendar/behavior-event-all-day.js' => '38dcf3c8', 336 336 'rsrc/js/application/config/behavior-reorder-fields.js' => '14a827de', 337 337 'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '10246726', ··· 554 554 'javelin-behavior-dashboard-move-panels' => '82439934', 555 555 'javelin-behavior-dashboard-query-panel-select' => '453c5375', 556 556 'javelin-behavior-dashboard-tab-panel' => 'd4eecc63', 557 - 'javelin-behavior-day-view' => 'dc0065ab', 557 + 'javelin-behavior-day-view' => '28a60488', 558 558 'javelin-behavior-device' => 'a205cf28', 559 559 'javelin-behavior-differential-add-reviewers-and-ccs' => 'e10f8e18', 560 560 'javelin-behavior-differential-comment-jump' => '4fdb476d', ··· 767 767 'phui-box-css' => '7b3a2eed', 768 768 'phui-button-css' => 'de610129', 769 769 'phui-calendar-css' => 'ccabe893', 770 - 'phui-calendar-day-css' => 'feba82c5', 770 + 'phui-calendar-day-css' => 'd1cf6f93', 771 771 'phui-calendar-list-css' => 'c1c7f338', 772 772 'phui-calendar-month-css' => '476be7e0', 773 773 'phui-crumbs-view-css' => '594d719e',
+72 -23
src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
··· 14 14 } 15 15 16 16 public function handleRequest(AphrontRequest $request) { 17 - $user = $request->getUser(); 18 - $user_phid = $user->getPHID(); 17 + $viewer = $request->getViewer(); 18 + $user_phid = $viewer->getPHID(); 19 19 $error_name = true; 20 20 $error_start_date = true; 21 21 $error_end_date = true; ··· 25 25 $start_date_id = celerity_generate_unique_node_id(); 26 26 $end_date_id = null; 27 27 28 + $next_workflow = $request->getStr('next'); 29 + $uri_query = $request->getStr('query'); 30 + 28 31 if ($this->isCreate()) { 29 - $event = PhabricatorCalendarEvent::initializeNewCalendarEvent($user); 30 - list($start_value, $end_value) = $this->getDefaultTimeValues($user); 32 + $event = PhabricatorCalendarEvent::initializeNewCalendarEvent($viewer); 33 + 34 + $create_start_year = $request->getInt('year'); 35 + $create_start_month = $request->getInt('month'); 36 + $create_start_day = $request->getInt('day'); 37 + $create_start_time = $request->getStr('time'); 38 + 39 + if ($create_start_year) { 40 + $start = AphrontFormDateControlValue::newFromParts( 41 + $viewer, 42 + $create_start_year, 43 + $create_start_month, 44 + $create_start_day, 45 + $create_start_time); 46 + if (!$start->isValid()) { 47 + return new Aphront400Response(); 48 + } 49 + $start_value = AphrontFormDateControlValue::newFromEpoch( 50 + $viewer, 51 + $start->getEpoch()); 52 + 53 + $end = clone $start_value->getDateTime(); 54 + $end->modify('+1 hour'); 55 + $end_value = AphrontFormDateControlValue::newFromEpoch( 56 + $viewer, 57 + $end->format('U')); 58 + 59 + } else { 60 + list($start_value, $end_value) = $this->getDefaultTimeValues($viewer); 61 + } 62 + 31 63 32 64 $submit_label = pht('Create'); 33 65 $page_title = pht('Create Event'); ··· 38 70 $end_date_id = celerity_generate_unique_node_id(); 39 71 } else { 40 72 $event = id(new PhabricatorCalendarEventQuery()) 41 - ->setViewer($user) 73 + ->setViewer($viewer) 42 74 ->withIDs(array($this->id)) 43 75 ->requireCapabilities( 44 76 array( ··· 51 83 } 52 84 53 85 $end_value = AphrontFormDateControlValue::newFromEpoch( 54 - $user, 86 + $viewer, 55 87 $event->getDateTo()); 56 88 $start_value = AphrontFormDateControlValue::newFromEpoch( 57 - $user, 89 + $viewer, 58 90 $event->getDateFrom()); 59 91 60 92 $submit_label = pht('Update'); ··· 81 113 $icon = $event->getIcon(); 82 114 83 115 $current_policies = id(new PhabricatorPolicyQuery()) 84 - ->setViewer($user) 116 + ->setViewer($viewer) 85 117 ->setObject($event) 86 118 ->execute(); 87 119 ··· 106 138 $new_invitees = $this->getNewInviteeList($invitees, $event); 107 139 $status_attending = PhabricatorCalendarEventInvitee::STATUS_ATTENDING; 108 140 if ($this->isCreate()) { 109 - $status = idx($new_invitees, $user->getPHID()); 141 + $status = idx($new_invitees, $viewer->getPHID()); 110 142 if ($status) { 111 - $new_invitees[$user->getPHID()] = $status_attending; 143 + $new_invitees[$viewer->getPHID()] = $status_attending; 112 144 } 113 145 } 114 146 ··· 161 193 ->setNewValue($request->getStr('editPolicy')); 162 194 163 195 $editor = id(new PhabricatorCalendarEventEditor()) 164 - ->setActor($user) 196 + ->setActor($viewer) 165 197 ->setContentSourceFromRequest($request) 166 198 ->setContinueOnNoEffect(true); 167 199 168 200 try { 169 201 $xactions = $editor->applyTransactions($event, $xactions); 170 202 $response = id(new AphrontRedirectResponse()); 171 - return $response->setURI('/E'.$event->getID()); 203 + switch ($next_workflow) { 204 + case 'day': 205 + if (!$uri_query) { 206 + $uri_query = 'month'; 207 + } 208 + $year = $start_value->getDateTime()->format('Y'); 209 + $month = $start_value->getDateTime()->format('m'); 210 + $day = $start_value->getDateTime()->format('d'); 211 + $response->setURI( 212 + '/calendar/query/'.$uri_query.'/'.$year.'/'.$month.'/'.$day.'/'); 213 + break; 214 + default: 215 + $response->setURI('/E'.$event->getID()); 216 + break; 217 + } 218 + return $response; 172 219 } catch (PhabricatorApplicationTransactionValidationException $ex) { 173 220 $validation_exception = $ex; 174 221 $error_name = $ex->getShortMessage( ··· 204 251 $all_day_id); 205 252 206 253 $start_control = id(new AphrontFormDateControl()) 207 - ->setUser($user) 254 + ->setUser($viewer) 208 255 ->setName('start') 209 256 ->setLabel(pht('Start')) 210 257 ->setError($error_start_date) ··· 214 261 ->setEndDateID($end_date_id); 215 262 216 263 $end_control = id(new AphrontFormDateControl()) 217 - ->setUser($user) 264 + ->setUser($viewer) 218 265 ->setName('end') 219 266 ->setLabel(pht('End')) 220 267 ->setError($error_end_date) ··· 228 275 ->setValue($description); 229 276 230 277 $view_policies = id(new AphrontFormPolicyControl()) 231 - ->setUser($user) 278 + ->setUser($viewer) 232 279 ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) 233 280 ->setPolicyObject($event) 234 281 ->setPolicies($current_policies) 235 282 ->setName('viewPolicy'); 236 283 $edit_policies = id(new AphrontFormPolicyControl()) 237 - ->setUser($user) 284 + ->setUser($viewer) 238 285 ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) 239 286 ->setPolicyObject($event) 240 287 ->setPolicies($current_policies) ··· 244 291 ->setLabel(pht('Subscribers')) 245 292 ->setName('subscribers') 246 293 ->setValue($subscribers) 247 - ->setUser($user) 294 + ->setUser($viewer) 248 295 ->setDatasource(new PhabricatorMetaMTAMailableDatasource()); 249 296 250 297 $invitees = id(new AphrontFormTokenizerControl()) 251 298 ->setLabel(pht('Invitees')) 252 299 ->setName('invitees') 253 300 ->setValue($invitees) 254 - ->setUser($user) 301 + ->setUser($viewer) 255 302 ->setDatasource(new PhabricatorMetaMTAMailableDatasource()); 256 303 257 304 if ($this->isCreate()) { ··· 269 316 ->setValue($icon); 270 317 271 318 $form = id(new AphrontFormView()) 272 - ->setUser($user) 319 + ->addHiddenInput('next', $next_workflow) 320 + ->addHiddenInput('query', $uri_query) 321 + ->setUser($viewer) 273 322 ->appendChild($name) 274 323 ->appendChild($all_day_checkbox) 275 324 ->appendChild($start_control) ··· 351 400 return $new; 352 401 } 353 402 354 - private function getDefaultTimeValues($user) { 403 + private function getDefaultTimeValues($viewer) { 355 404 $start = new DateTime('@'.time()); 356 - $start->setTimeZone($user->getTimeZone()); 405 + $start->setTimeZone($viewer->getTimeZone()); 357 406 358 407 $start->setTime($start->format('H'), 0, 0); 359 408 $start->modify('+1 hour'); 360 409 $end = id(clone $start)->modify('+1 hour'); 361 410 362 411 $start_value = AphrontFormDateControlValue::newFromEpoch( 363 - $user, 412 + $viewer, 364 413 $start->format('U')); 365 414 $end_value = AphrontFormDateControlValue::newFromEpoch( 366 - $user, 415 + $viewer, 367 416 $end->format('U')); 368 417 369 418 return array($start_value, $end_value);
+9 -2
src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php
··· 390 390 list($start_year, $start_month, $start_day) = 391 391 $this->getDisplayYearAndMonthAndDay($query); 392 392 393 - $day_view = new PHUICalendarDayView( 393 + $day_view = id(new PHUICalendarDayView( 394 394 $this->getDateFrom($query), 395 395 $this->getDateTo($query), 396 396 $start_year, 397 397 $start_month, 398 - $start_day); 398 + $start_day)) 399 + ->setQuery($query->getQueryKey()); 399 400 400 401 $day_view->setUser($viewer); 401 402 ··· 408 409 409 410 $viewer_is_invited = $status->getIsUserInvited($viewer->getPHID()); 410 411 412 + $can_edit = PhabricatorPolicyFilter::hasCapability( 413 + $viewer, 414 + $status, 415 + PhabricatorPolicyCapability::CAN_EDIT); 416 + 411 417 $event = new AphrontCalendarEventView(); 418 + $event->setCanEdit($can_edit); 412 419 $event->setEventID($status->getID()); 413 420 $event->setEpochRange($status->getDateFrom(), $status->getDateTo()); 414 421 $event->setIsAllDay($status->getIsAllDay());
+9
src/applications/calendar/view/AphrontCalendarEventView.php
··· 12 12 private $uri; 13 13 private $isAllDay; 14 14 private $icon; 15 + private $canEdit; 15 16 16 17 public function setURI($uri) { 17 18 $this->uri = $uri; ··· 97 98 return $this->icon; 98 99 } 99 100 101 + public function setCanEdit($can_edit) { 102 + $this->canEdit = $can_edit; 103 + return $this; 104 + } 105 + 106 + public function getCanEdit() { 107 + return $this->canEdit; 108 + } 100 109 101 110 public function getMultiDay() { 102 111 $nextday = strtotime('12:00 AM Tomorrow', $this->getEpochStart());
+13
src/view/form/control/AphrontFormDateControlValue.php
··· 211 211 return $value; 212 212 } 213 213 214 + public function getDateTime() { 215 + $epoch = $this->getEpoch(); 216 + $date = null; 217 + 218 + if ($epoch) { 219 + $zone = $this->getTimezone(); 220 + $date = new DateTime('@'.$epoch); 221 + $date->setTimeZone($zone); 222 + } 223 + 224 + return $date; 225 + } 226 + 214 227 private function getTimezone() { 215 228 if ($this->zone) { 216 229 return $this->zone;
+14
src/view/phui/calendar/PHUICalendarDayView.php
··· 8 8 private $month; 9 9 private $year; 10 10 private $browseURI; 11 + private $query; 11 12 private $events = array(); 12 13 13 14 private $allDayEvents = array(); ··· 23 24 } 24 25 private function getBrowseURI() { 25 26 return $this->browseURI; 27 + } 28 + 29 + public function setQuery($query) { 30 + $this->query = $query; 31 + return $this; 32 + } 33 + private function getQuery() { 34 + return $this->query; 26 35 } 27 36 28 37 public function __construct( ··· 128 137 'width' => '100%', 129 138 'top' => $top.'px', 130 139 'height' => $height.'px', 140 + 'canEdit' => $event->getCanEdit(), 131 141 ); 132 142 } 133 143 } ··· 148 158 Javelin::initBehavior( 149 159 'day-view', 150 160 array( 161 + 'year' => $first_event_hour->format('Y'), 162 + 'month' => $first_event_hour->format('m'), 163 + 'day' => $first_event_hour->format('d'), 164 + 'query' => $this->getQuery(), 151 165 'allDayEvents' => $js_today_all_day_events, 152 166 'todayEvents' => $js_today_events, 153 167 'hours' => $js_hours,
+9
webroot/rsrc/css/phui/calendar/phui-calendar-day.css
··· 29 29 30 30 .phui-calendar-day-view td { 31 31 position: relative; 32 + cursor: pointer; 33 + } 34 + 35 + .phui-calendar-day-view td:hover { 36 + background: {$lightbluebackground}; 32 37 } 33 38 34 39 .phui-calendar-day-view tr + tr td.phui-calendar-day-events { ··· 45 50 top: 0; 46 51 bottom: 0; 47 52 min-height: 30px; 53 + } 54 + 55 + .can-drag a { 56 + cursor: move; 48 57 } 49 58 50 59 div.phui-calendar-day-event.all-day {
+43 -5
webroot/rsrc/js/application/calendar/behavior-day-view.js
··· 100 100 }, 101 101 name); 102 102 103 + var class_name = 'phui-calendar-day-event'; 104 + if (e.canEdit) { 105 + class_name = class_name + ' can-drag'; 106 + } 107 + 103 108 var div = JX.$N( 104 109 'div', 105 110 { 106 - className: 'phui-calendar-day-event', 111 + className: class_name, 107 112 sigil: sigil, 108 113 meta: {eventID: eventID, record: e, uri: uri}, 109 114 style: { ··· 169 174 var cell_event = JX.$N( 170 175 'td', 171 176 { 172 - className: 'phui-calendar-day-events' 177 + meta: { 178 + time: hours[i]['hour_meridian'] 179 + }, 180 + className: 'phui-calendar-day-events', 181 + sigil: 'phui-calendar-day-event-cell' 173 182 }); 174 183 175 184 var row = JX.$N( ··· 194 203 JX.DOM.setContent(hourly_events_wrapper, drawn_hourly_events); 195 204 196 205 } 206 + 207 + var year = config.year; 208 + var month = config.month; 209 + var day = config.day; 210 + var query = config.query; 197 211 198 212 var hours = config.hours; 199 213 var first_event_hour = config.firstEventHour; ··· 234 248 if (!e.isNormalMouseEvent()) { 235 249 return; 236 250 } 251 + var data = e.getNodeData('phui-calendar-day-event'); 252 + if (!data.record.canEdit) { 253 + return; 254 + } 237 255 e.kill(); 238 256 dragging = e.getNode('phui-calendar-day-event'); 239 257 JX.DOM.alterClass(dragging, 'phui-drag', true); ··· 264 282 dragging.style.top = new_top + 'px'; 265 283 }); 266 284 JX.Stratcom.listen('mouseup', null, function(){ 267 - var data = JX.Stratcom.getData(dragging); 268 - var record = data.record; 269 - 270 285 if (!dragging) { 271 286 return; 272 287 } 288 + 289 + var data = JX.Stratcom.getData(dragging); 290 + var record = data.record; 291 + 273 292 if (new_top == offset_top) { 274 293 var now = new Date(); 275 294 if (now.getTime() - click_time.getTime() < 250) { ··· 302 321 if (e.isNormalClick()) { 303 322 e.kill(); 304 323 } 324 + }); 325 + 326 + JX.DOM.listen(table, 'click', 'phui-calendar-day-event-cell', function(e){ 327 + if (!e.isNormalClick()) { 328 + return; 329 + } 330 + var data = e.getNodeData('phui-calendar-day-event-cell'); 331 + var time = data.time; 332 + new JX.Workflow( 333 + '/calendar/event/create/', 334 + { 335 + year: year, 336 + month: month, 337 + day: day, 338 + time: time, 339 + next: 'day', 340 + query: query 341 + }) 342 + .start(); 305 343 }); 306 344 307 345 var hourly_events_wrapper = JX.$N(