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

Fix datepicker to show correct error messages on Calendar event edit view

Summary: Ref T8024, Fix datepicker to show correct error messages on Calendar event edit view.

Test Plan: Edit Calendar event, set blank title, and valid new end time, error page should correctly point out invalid title, but reflec the updated time.

Reviewers: #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: Korvin, epriestley

Maniphest Tasks: T8024

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

+211 -89
+2
src/__phutil_library_map__.php
··· 114 114 'AphrontFormChooseButtonControl' => 'view/form/control/AphrontFormChooseButtonControl.php', 115 115 'AphrontFormControl' => 'view/form/control/AphrontFormControl.php', 116 116 'AphrontFormDateControl' => 'view/form/control/AphrontFormDateControl.php', 117 + 'AphrontFormDateControlValue' => 'view/form/control/AphrontFormDateControlValue.php', 117 118 'AphrontFormDividerControl' => 'view/form/control/AphrontFormDividerControl.php', 118 119 'AphrontFormFileControl' => 'view/form/control/AphrontFormFileControl.php', 119 120 'AphrontFormMarkupControl' => 'view/form/control/AphrontFormMarkupControl.php', ··· 3360 3361 'AphrontFormChooseButtonControl' => 'AphrontFormControl', 3361 3362 'AphrontFormControl' => 'AphrontView', 3362 3363 'AphrontFormDateControl' => 'AphrontFormControl', 3364 + 'AphrontFormDateControlValue' => 'Phobject', 3363 3365 'AphrontFormDividerControl' => 'AphrontFormControl', 3364 3366 'AphrontFormFileControl' => 'AphrontFormControl', 3365 3367 'AphrontFormMarkupControl' => 'AphrontFormControl',
+84 -86
src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
··· 18 18 $user = $request->getUser(); 19 19 $user_phid = $user->getPHID(); 20 20 $error_name = true; 21 + $error_start_date = true; 22 + $error_end_date = true; 21 23 $validation_exception = null; 22 24 23 - $start_time = id(new AphrontFormDateControl()) 24 - ->setUser($user) 25 - ->setName('start') 26 - ->setLabel(pht('Start')) 27 - ->setInitialTime(AphrontFormDateControl::TIME_START_OF_DAY); 28 - 29 - $end_time = id(new AphrontFormDateControl()) 30 - ->setUser($user) 31 - ->setName('end') 32 - ->setLabel(pht('End')) 33 - ->setInitialTime(AphrontFormDateControl::TIME_END_OF_DAY); 34 - 35 25 if ($this->isCreate()) { 36 26 $event = PhabricatorCalendarEvent::initializeNewCalendarEvent($user); 37 - $end_value = $end_time->readValueFromRequest($request); 38 - $start_value = $start_time->readValueFromRequest($request); 27 + $end_value = AphrontFormDateControlValue::newFromEpoch($user, time()); 28 + $start_value = AphrontFormDateControlValue::newFromEpoch($user, time()); 39 29 $submit_label = pht('Create'); 40 30 $page_title = pht('Create Event'); 41 31 $redirect = 'created'; ··· 56 46 return new Aphront404Response(); 57 47 } 58 48 59 - $end_time->setValue($event->getDateTo()); 60 - $start_time->setValue($event->getDateFrom()); 49 + $end_value = AphrontFormDateControlValue::newFromEpoch( 50 + $user, 51 + $event->getDateTo()); 52 + $start_value = AphrontFormDateControlValue::newFromEpoch( 53 + $user, 54 + $event->getDateFrom()); 55 + 61 56 $submit_label = pht('Update'); 62 57 $page_title = pht('Update Event'); 63 58 ··· 76 71 $cancel_uri = '/'.$event->getMonogram(); 77 72 } 78 73 79 - $errors = array(); 80 74 $name = $event->getName(); 81 75 $description = $event->getDescription(); 82 76 $type = $event->getStatus(); ··· 90 84 $xactions = array(); 91 85 $name = $request->getStr('name'); 92 86 $type = $request->getInt('status'); 93 - $start_value = $start_time->readValueFromRequest($request); 94 - $end_value = $end_time->readValueFromRequest($request); 87 + 88 + $start_value = AphrontFormDateControlValue::newFromRequest( 89 + $request, 90 + 'start'); 91 + $end_value = AphrontFormDateControlValue::newFromRequest( 92 + $request, 93 + 'end'); 95 94 $description = $request->getStr('description'); 96 95 $subscribers = $request->getArr('subscribers'); 97 96 $edit_policy = $request->getStr('editPolicy'); ··· 107 106 } 108 107 } 109 108 110 - if ($start_time->getError()) { 111 - $errors[] = pht('Invalid start time; reset to default.'); 112 - } 113 - if ($end_time->getError()) { 114 - $errors[] = pht('Invalid end time; reset to default.'); 115 - } 116 - if (!$errors) { 117 - $xactions[] = id(new PhabricatorCalendarEventTransaction()) 118 - ->setTransactionType( 119 - PhabricatorCalendarEventTransaction::TYPE_NAME) 120 - ->setNewValue($name); 109 + $xactions[] = id(new PhabricatorCalendarEventTransaction()) 110 + ->setTransactionType( 111 + PhabricatorCalendarEventTransaction::TYPE_NAME) 112 + ->setNewValue($name); 121 113 122 - $xactions[] = id(new PhabricatorCalendarEventTransaction()) 123 - ->setTransactionType( 124 - PhabricatorCalendarEventTransaction::TYPE_START_DATE) 125 - ->setNewValue($start_value); 114 + $xactions[] = id(new PhabricatorCalendarEventTransaction()) 115 + ->setTransactionType( 116 + PhabricatorCalendarEventTransaction::TYPE_START_DATE) 117 + ->setNewValue($start_value); 126 118 127 - $xactions[] = id(new PhabricatorCalendarEventTransaction()) 128 - ->setTransactionType( 129 - PhabricatorCalendarEventTransaction::TYPE_END_DATE) 130 - ->setNewValue($end_value); 119 + $xactions[] = id(new PhabricatorCalendarEventTransaction()) 120 + ->setTransactionType( 121 + PhabricatorCalendarEventTransaction::TYPE_END_DATE) 122 + ->setNewValue($end_value); 131 123 132 - $xactions[] = id(new PhabricatorCalendarEventTransaction()) 133 - ->setTransactionType( 134 - PhabricatorCalendarEventTransaction::TYPE_STATUS) 135 - ->setNewValue($type); 124 + $xactions[] = id(new PhabricatorCalendarEventTransaction()) 125 + ->setTransactionType( 126 + PhabricatorCalendarEventTransaction::TYPE_STATUS) 127 + ->setNewValue($type); 136 128 137 - $xactions[] = id(new PhabricatorCalendarEventTransaction()) 138 - ->setTransactionType( 139 - PhabricatorTransactions::TYPE_SUBSCRIBERS) 140 - ->setNewValue(array('=' => array_fuse($subscribers))); 129 + $xactions[] = id(new PhabricatorCalendarEventTransaction()) 130 + ->setTransactionType( 131 + PhabricatorTransactions::TYPE_SUBSCRIBERS) 132 + ->setNewValue(array('=' => array_fuse($subscribers))); 141 133 142 - $xactions[] = id(new PhabricatorCalendarEventTransaction()) 143 - ->setTransactionType( 144 - PhabricatorCalendarEventTransaction::TYPE_INVITE) 145 - ->setNewValue($new_invitees); 134 + $xactions[] = id(new PhabricatorCalendarEventTransaction()) 135 + ->setTransactionType( 136 + PhabricatorCalendarEventTransaction::TYPE_INVITE) 137 + ->setNewValue($new_invitees); 146 138 147 - $xactions[] = id(new PhabricatorCalendarEventTransaction()) 148 - ->setTransactionType( 149 - PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION) 150 - ->setNewValue($description); 139 + $xactions[] = id(new PhabricatorCalendarEventTransaction()) 140 + ->setTransactionType( 141 + PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION) 142 + ->setNewValue($description); 151 143 152 - $xactions[] = id(new PhabricatorCalendarEventTransaction()) 153 - ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) 154 - ->setNewValue($request->getStr('viewPolicy')); 144 + $xactions[] = id(new PhabricatorCalendarEventTransaction()) 145 + ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) 146 + ->setNewValue($request->getStr('viewPolicy')); 155 147 156 - $xactions[] = id(new PhabricatorCalendarEventTransaction()) 157 - ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) 158 - ->setNewValue($request->getStr('editPolicy')); 148 + $xactions[] = id(new PhabricatorCalendarEventTransaction()) 149 + ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) 150 + ->setNewValue($request->getStr('editPolicy')); 159 151 160 - $editor = id(new PhabricatorCalendarEventEditor()) 161 - ->setActor($user) 162 - ->setContentSourceFromRequest($request) 163 - ->setContinueOnNoEffect(true); 152 + $editor = id(new PhabricatorCalendarEventEditor()) 153 + ->setActor($user) 154 + ->setContentSourceFromRequest($request) 155 + ->setContinueOnNoEffect(true); 164 156 165 - try { 166 - $xactions = $editor->applyTransactions($event, $xactions); 167 - $response = id(new AphrontRedirectResponse()); 168 - return $response->setURI('/E'.$event->getID()); 169 - } catch (PhabricatorApplicationTransactionValidationException $ex) { 170 - $validation_exception = $ex; 171 - $error_name = $ex 172 - ->getShortMessage(PhabricatorCalendarEventTransaction::TYPE_NAME); 157 + try { 158 + $xactions = $editor->applyTransactions($event, $xactions); 159 + $response = id(new AphrontRedirectResponse()); 160 + return $response->setURI('/E'.$event->getID()); 161 + } catch (PhabricatorApplicationTransactionValidationException $ex) { 162 + $validation_exception = $ex; 163 + $error_name = $ex->getShortMessage( 164 + PhabricatorCalendarEventTransaction::TYPE_NAME); 165 + $error_start_date = $ex->getShortMessage( 166 + PhabricatorCalendarEventTransaction::TYPE_START_DATE); 167 + $error_end_date = $ex->getShortMessage( 168 + PhabricatorCalendarEventTransaction::TYPE_END_DATE); 173 169 174 - $event->setViewPolicy($view_policy); 175 - $event->setEditPolicy($edit_policy); 176 - } 177 - } else { 178 170 $event->setViewPolicy($view_policy); 179 171 $event->setEditPolicy($edit_policy); 180 172 } 181 173 } 182 174 183 - $error_view = null; 184 - if ($errors) { 185 - $error_view = id(new PHUIInfoView()) 186 - ->setTitle(pht('Status can not be set!')) 187 - ->setErrors($errors); 188 - } 189 - 190 175 $name = id(new AphrontFormTextControl()) 191 176 ->setLabel(pht('Name')) 192 177 ->setName('name') ··· 199 184 ->setValue($type) 200 185 ->setOptions($event->getStatusOptions()); 201 186 187 + $start_control = id(new AphrontFormDateControl()) 188 + ->setUser($user) 189 + ->setName('start') 190 + ->setLabel(pht('Start')) 191 + ->setError($error_start_date) 192 + ->setValue($start_value); 193 + 194 + $end_control = id(new AphrontFormDateControl()) 195 + ->setUser($user) 196 + ->setName('end') 197 + ->setLabel(pht('End')) 198 + ->setError($error_end_date) 199 + ->setValue($end_value); 200 + 202 201 $description = id(new AphrontFormTextAreaControl()) 203 202 ->setLabel(pht('Description')) 204 203 ->setName('description') ··· 235 234 ->setUser($user) 236 235 ->appendChild($name) 237 236 ->appendChild($status_select) 238 - ->appendChild($start_time) 239 - ->appendChild($end_time) 237 + ->appendChild($start_control) 238 + ->appendChild($end_control) 240 239 ->appendControl($view_policies) 241 240 ->appendControl($edit_policies) 242 241 ->appendControl($subscribers) ··· 261 260 262 261 $form_box = id(new PHUIObjectBoxView()) 263 262 ->setHeaderText($page_title) 264 - ->setFormErrors($errors) 265 263 ->setForm($form); 266 264 267 265 $crumbs = $this->buildApplicationCrumbs();
+16 -2
src/applications/calendar/editor/PhabricatorCalendarEventEditor.php
··· 83 83 PhabricatorApplicationTransaction $xaction) { 84 84 switch ($xaction->getTransactionType()) { 85 85 case PhabricatorCalendarEventTransaction::TYPE_NAME: 86 - case PhabricatorCalendarEventTransaction::TYPE_START_DATE: 87 - case PhabricatorCalendarEventTransaction::TYPE_END_DATE: 88 86 case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION: 89 87 case PhabricatorCalendarEventTransaction::TYPE_CANCEL: 90 88 case PhabricatorCalendarEventTransaction::TYPE_INVITE: 91 89 return $xaction->getNewValue(); 92 90 case PhabricatorCalendarEventTransaction::TYPE_STATUS: 93 91 return (int)$xaction->getNewValue(); 92 + case PhabricatorCalendarEventTransaction::TYPE_START_DATE: 93 + case PhabricatorCalendarEventTransaction::TYPE_END_DATE: 94 + return $xaction->getNewValue()->getEpoch(); 94 95 } 95 96 96 97 return parent::getCustomTransactionNewValue($object, $xaction); ··· 202 203 203 204 $error->setIsMissingFieldError(true); 204 205 $errors[] = $error; 206 + } 207 + break; 208 + case PhabricatorCalendarEventTransaction::TYPE_START_DATE: 209 + case PhabricatorCalendarEventTransaction::TYPE_END_DATE: 210 + foreach ($xactions as $xaction) { 211 + $date_value = $xaction->getNewValue(); 212 + if (!$date_value->isValid()) { 213 + $errors[] = new PhabricatorApplicationTransactionValidationError( 214 + $type, 215 + pht('Invalid'), 216 + pht('Invalid date.'), 217 + $xaction); 218 + } 205 219 } 206 220 break; 207 221 }
+12 -1
src/view/form/control/AphrontFormDateControl.php
··· 10 10 private $valueYear; 11 11 private $valueTime; 12 12 private $allowNull; 13 + private $continueOnInvalidDate = false; 13 14 14 15 public function setAllowNull($allow_null) { 15 16 $this->allowNull = $allow_null; ··· 84 85 } 85 86 86 87 public function setValue($epoch) { 88 + if ($epoch instanceof AphrontFormDateControlValue) { 89 + $this->continueOnInvalidDate = true; 90 + $this->valueYear = $epoch->getValueYear(); 91 + $this->valueMonth = $epoch->getValueMonth(); 92 + $this->valueDay = $epoch->getValueDay(); 93 + $this->valueTime = $epoch->getValueTime(); 94 + 95 + return parent::setValue($epoch->getEpoch()); 96 + } 97 + 87 98 $result = parent::setValue($epoch); 88 99 89 100 if ($epoch === null) { ··· 165 176 protected function renderInput() { 166 177 167 178 $disabled = null; 168 - if ($this->getValue() === null) { 179 + if ($this->getValue() === null && !$this->continueOnInvalidDate) { 169 180 $this->setValue($this->getInitialValue()); 170 181 if ($this->allowNull) { 171 182 $disabled = 'disabled';
+97
src/view/form/control/AphrontFormDateControlValue.php
··· 1 + <?php 2 + 3 + final class AphrontFormDateControlValue extends Phobject { 4 + 5 + private $valueDay; 6 + private $valueMonth; 7 + private $valueYear; 8 + private $valueTime; 9 + 10 + private $viewer; 11 + private $zone; 12 + 13 + public function getValueDay() { 14 + return $this->valueDay; 15 + } 16 + 17 + public function getValueMonth() { 18 + return $this->valueMonth; 19 + } 20 + 21 + public function getValueYear() { 22 + return $this->valueYear; 23 + } 24 + 25 + public function getValueTime() { 26 + return $this->valueTime; 27 + } 28 + 29 + public function isValid() { 30 + return ($this->getEpoch() !== null); 31 + } 32 + 33 + public static function newFromRequest($request, $key) { 34 + $value = new AphrontFormDateControlValue(); 35 + $value->viewer = $request->getViewer(); 36 + 37 + $value->valueDay = $request->getInt($key.'_d'); 38 + $value->valueMonth = $request->getInt($key.'_m'); 39 + $value->valueYear = $request->getInt($key.'_y'); 40 + $value->valueTime = $request->getStr($key.'_t'); 41 + 42 + return $value; 43 + } 44 + 45 + public static function newFromEpoch(PhabricatorUser $viewer, $epoch) { 46 + $value = new AphrontFormDateControlValue(); 47 + $value->viewer = $viewer; 48 + $readable = $value->formatTime($epoch, 'Y!m!d!g:i A'); 49 + $readable = explode('!', $readable, 4); 50 + 51 + $value->valueYear = $readable[0]; 52 + $value->valueMonth = $readable[1]; 53 + $value->valueDay = $readable[2]; 54 + $value->valueTime = $readable[3]; 55 + 56 + return $value; 57 + } 58 + 59 + private function formatTime($epoch, $format) { 60 + return phabricator_format_local_time( 61 + $epoch, 62 + $this->viewer, 63 + $format); 64 + } 65 + 66 + public function getEpoch() { 67 + $year = $this->valueYear; 68 + $month = $this->valueMonth; 69 + $day = $this->valueDay; 70 + $time = $this->valueTime; 71 + $zone = $this->getTimezone(); 72 + 73 + if (!strlen($time)) { 74 + return null; 75 + } 76 + 77 + try { 78 + $date = new DateTime("{$year}-{$month}-{$day} {$time}", $zone); 79 + $value = $date->format('U'); 80 + } catch (Exception $ex) { 81 + $value = null; 82 + } 83 + return $value; 84 + } 85 + 86 + private function getTimezone() { 87 + if ($this->zone) { 88 + return $this->zone; 89 + } 90 + 91 + $viewer_zone = $this->viewer->getTimezoneIdentifier(); 92 + $this->zone = new DateTimeZone($viewer_zone); 93 + return $this->zone; 94 + } 95 + 96 + 97 + }