1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-14 02:42:40 +01:00

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
This commit is contained in:
lkassianik 2015-05-24 11:22:33 -07:00
parent 963485a3da
commit 18fe6d58ae
8 changed files with 173 additions and 34 deletions

View file

@ -121,7 +121,7 @@ return array(
'rsrc/css/layout/phabricator-hovercard-view.css' => 'dd9121a9', 'rsrc/css/layout/phabricator-hovercard-view.css' => 'dd9121a9',
'rsrc/css/layout/phabricator-side-menu-view.css' => 'c1db9e9c', 'rsrc/css/layout/phabricator-side-menu-view.css' => 'c1db9e9c',
'rsrc/css/layout/phabricator-source-code-view.css' => '2ceee894', 'rsrc/css/layout/phabricator-source-code-view.css' => '2ceee894',
'rsrc/css/phui/calendar/phui-calendar-day.css' => 'feba82c5', 'rsrc/css/phui/calendar/phui-calendar-day.css' => 'd1cf6f93',
'rsrc/css/phui/calendar/phui-calendar-list.css' => 'c1c7f338', 'rsrc/css/phui/calendar/phui-calendar-list.css' => 'c1c7f338',
'rsrc/css/phui/calendar/phui-calendar-month.css' => '476be7e0', 'rsrc/css/phui/calendar/phui-calendar-month.css' => '476be7e0',
'rsrc/css/phui/calendar/phui-calendar.css' => 'ccabe893', 'rsrc/css/phui/calendar/phui-calendar.css' => 'ccabe893',
@ -331,7 +331,7 @@ return array(
'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'b1a59974', 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'b1a59974',
'rsrc/js/application/aphlict/behavior-aphlict-status.js' => 'ea681761', 'rsrc/js/application/aphlict/behavior-aphlict-status.js' => 'ea681761',
'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18', 'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18',
'rsrc/js/application/calendar/behavior-day-view.js' => 'dc0065ab', 'rsrc/js/application/calendar/behavior-day-view.js' => '28a60488',
'rsrc/js/application/calendar/behavior-event-all-day.js' => '38dcf3c8', 'rsrc/js/application/calendar/behavior-event-all-day.js' => '38dcf3c8',
'rsrc/js/application/config/behavior-reorder-fields.js' => '14a827de', 'rsrc/js/application/config/behavior-reorder-fields.js' => '14a827de',
'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '10246726', 'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '10246726',
@ -554,7 +554,7 @@ return array(
'javelin-behavior-dashboard-move-panels' => '82439934', 'javelin-behavior-dashboard-move-panels' => '82439934',
'javelin-behavior-dashboard-query-panel-select' => '453c5375', 'javelin-behavior-dashboard-query-panel-select' => '453c5375',
'javelin-behavior-dashboard-tab-panel' => 'd4eecc63', 'javelin-behavior-dashboard-tab-panel' => 'd4eecc63',
'javelin-behavior-day-view' => 'dc0065ab', 'javelin-behavior-day-view' => '28a60488',
'javelin-behavior-device' => 'a205cf28', 'javelin-behavior-device' => 'a205cf28',
'javelin-behavior-differential-add-reviewers-and-ccs' => 'e10f8e18', 'javelin-behavior-differential-add-reviewers-and-ccs' => 'e10f8e18',
'javelin-behavior-differential-comment-jump' => '4fdb476d', 'javelin-behavior-differential-comment-jump' => '4fdb476d',
@ -767,7 +767,7 @@ return array(
'phui-box-css' => '7b3a2eed', 'phui-box-css' => '7b3a2eed',
'phui-button-css' => 'de610129', 'phui-button-css' => 'de610129',
'phui-calendar-css' => 'ccabe893', 'phui-calendar-css' => 'ccabe893',
'phui-calendar-day-css' => 'feba82c5', 'phui-calendar-day-css' => 'd1cf6f93',
'phui-calendar-list-css' => 'c1c7f338', 'phui-calendar-list-css' => 'c1c7f338',
'phui-calendar-month-css' => '476be7e0', 'phui-calendar-month-css' => '476be7e0',
'phui-crumbs-view-css' => '594d719e', 'phui-crumbs-view-css' => '594d719e',

View file

@ -14,8 +14,8 @@ final class PhabricatorCalendarEventEditController
} }
public function handleRequest(AphrontRequest $request) { public function handleRequest(AphrontRequest $request) {
$user = $request->getUser(); $viewer = $request->getViewer();
$user_phid = $user->getPHID(); $user_phid = $viewer->getPHID();
$error_name = true; $error_name = true;
$error_start_date = true; $error_start_date = true;
$error_end_date = true; $error_end_date = true;
@ -25,9 +25,41 @@ final class PhabricatorCalendarEventEditController
$start_date_id = celerity_generate_unique_node_id(); $start_date_id = celerity_generate_unique_node_id();
$end_date_id = null; $end_date_id = null;
$next_workflow = $request->getStr('next');
$uri_query = $request->getStr('query');
if ($this->isCreate()) { if ($this->isCreate()) {
$event = PhabricatorCalendarEvent::initializeNewCalendarEvent($user); $event = PhabricatorCalendarEvent::initializeNewCalendarEvent($viewer);
list($start_value, $end_value) = $this->getDefaultTimeValues($user);
$create_start_year = $request->getInt('year');
$create_start_month = $request->getInt('month');
$create_start_day = $request->getInt('day');
$create_start_time = $request->getStr('time');
if ($create_start_year) {
$start = AphrontFormDateControlValue::newFromParts(
$viewer,
$create_start_year,
$create_start_month,
$create_start_day,
$create_start_time);
if (!$start->isValid()) {
return new Aphront400Response();
}
$start_value = AphrontFormDateControlValue::newFromEpoch(
$viewer,
$start->getEpoch());
$end = clone $start_value->getDateTime();
$end->modify('+1 hour');
$end_value = AphrontFormDateControlValue::newFromEpoch(
$viewer,
$end->format('U'));
} else {
list($start_value, $end_value) = $this->getDefaultTimeValues($viewer);
}
$submit_label = pht('Create'); $submit_label = pht('Create');
$page_title = pht('Create Event'); $page_title = pht('Create Event');
@ -38,7 +70,7 @@ final class PhabricatorCalendarEventEditController
$end_date_id = celerity_generate_unique_node_id(); $end_date_id = celerity_generate_unique_node_id();
} else { } else {
$event = id(new PhabricatorCalendarEventQuery()) $event = id(new PhabricatorCalendarEventQuery())
->setViewer($user) ->setViewer($viewer)
->withIDs(array($this->id)) ->withIDs(array($this->id))
->requireCapabilities( ->requireCapabilities(
array( array(
@ -51,10 +83,10 @@ final class PhabricatorCalendarEventEditController
} }
$end_value = AphrontFormDateControlValue::newFromEpoch( $end_value = AphrontFormDateControlValue::newFromEpoch(
$user, $viewer,
$event->getDateTo()); $event->getDateTo());
$start_value = AphrontFormDateControlValue::newFromEpoch( $start_value = AphrontFormDateControlValue::newFromEpoch(
$user, $viewer,
$event->getDateFrom()); $event->getDateFrom());
$submit_label = pht('Update'); $submit_label = pht('Update');
@ -81,7 +113,7 @@ final class PhabricatorCalendarEventEditController
$icon = $event->getIcon(); $icon = $event->getIcon();
$current_policies = id(new PhabricatorPolicyQuery()) $current_policies = id(new PhabricatorPolicyQuery())
->setViewer($user) ->setViewer($viewer)
->setObject($event) ->setObject($event)
->execute(); ->execute();
@ -106,9 +138,9 @@ final class PhabricatorCalendarEventEditController
$new_invitees = $this->getNewInviteeList($invitees, $event); $new_invitees = $this->getNewInviteeList($invitees, $event);
$status_attending = PhabricatorCalendarEventInvitee::STATUS_ATTENDING; $status_attending = PhabricatorCalendarEventInvitee::STATUS_ATTENDING;
if ($this->isCreate()) { if ($this->isCreate()) {
$status = idx($new_invitees, $user->getPHID()); $status = idx($new_invitees, $viewer->getPHID());
if ($status) { if ($status) {
$new_invitees[$user->getPHID()] = $status_attending; $new_invitees[$viewer->getPHID()] = $status_attending;
} }
} }
@ -161,14 +193,29 @@ final class PhabricatorCalendarEventEditController
->setNewValue($request->getStr('editPolicy')); ->setNewValue($request->getStr('editPolicy'));
$editor = id(new PhabricatorCalendarEventEditor()) $editor = id(new PhabricatorCalendarEventEditor())
->setActor($user) ->setActor($viewer)
->setContentSourceFromRequest($request) ->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true); ->setContinueOnNoEffect(true);
try { try {
$xactions = $editor->applyTransactions($event, $xactions); $xactions = $editor->applyTransactions($event, $xactions);
$response = id(new AphrontRedirectResponse()); $response = id(new AphrontRedirectResponse());
return $response->setURI('/E'.$event->getID()); switch ($next_workflow) {
case 'day':
if (!$uri_query) {
$uri_query = 'month';
}
$year = $start_value->getDateTime()->format('Y');
$month = $start_value->getDateTime()->format('m');
$day = $start_value->getDateTime()->format('d');
$response->setURI(
'/calendar/query/'.$uri_query.'/'.$year.'/'.$month.'/'.$day.'/');
break;
default:
$response->setURI('/E'.$event->getID());
break;
}
return $response;
} catch (PhabricatorApplicationTransactionValidationException $ex) { } catch (PhabricatorApplicationTransactionValidationException $ex) {
$validation_exception = $ex; $validation_exception = $ex;
$error_name = $ex->getShortMessage( $error_name = $ex->getShortMessage(
@ -204,7 +251,7 @@ final class PhabricatorCalendarEventEditController
$all_day_id); $all_day_id);
$start_control = id(new AphrontFormDateControl()) $start_control = id(new AphrontFormDateControl())
->setUser($user) ->setUser($viewer)
->setName('start') ->setName('start')
->setLabel(pht('Start')) ->setLabel(pht('Start'))
->setError($error_start_date) ->setError($error_start_date)
@ -214,7 +261,7 @@ final class PhabricatorCalendarEventEditController
->setEndDateID($end_date_id); ->setEndDateID($end_date_id);
$end_control = id(new AphrontFormDateControl()) $end_control = id(new AphrontFormDateControl())
->setUser($user) ->setUser($viewer)
->setName('end') ->setName('end')
->setLabel(pht('End')) ->setLabel(pht('End'))
->setError($error_end_date) ->setError($error_end_date)
@ -228,13 +275,13 @@ final class PhabricatorCalendarEventEditController
->setValue($description); ->setValue($description);
$view_policies = id(new AphrontFormPolicyControl()) $view_policies = id(new AphrontFormPolicyControl())
->setUser($user) ->setUser($viewer)
->setCapability(PhabricatorPolicyCapability::CAN_VIEW) ->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
->setPolicyObject($event) ->setPolicyObject($event)
->setPolicies($current_policies) ->setPolicies($current_policies)
->setName('viewPolicy'); ->setName('viewPolicy');
$edit_policies = id(new AphrontFormPolicyControl()) $edit_policies = id(new AphrontFormPolicyControl())
->setUser($user) ->setUser($viewer)
->setCapability(PhabricatorPolicyCapability::CAN_EDIT) ->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
->setPolicyObject($event) ->setPolicyObject($event)
->setPolicies($current_policies) ->setPolicies($current_policies)
@ -244,14 +291,14 @@ final class PhabricatorCalendarEventEditController
->setLabel(pht('Subscribers')) ->setLabel(pht('Subscribers'))
->setName('subscribers') ->setName('subscribers')
->setValue($subscribers) ->setValue($subscribers)
->setUser($user) ->setUser($viewer)
->setDatasource(new PhabricatorMetaMTAMailableDatasource()); ->setDatasource(new PhabricatorMetaMTAMailableDatasource());
$invitees = id(new AphrontFormTokenizerControl()) $invitees = id(new AphrontFormTokenizerControl())
->setLabel(pht('Invitees')) ->setLabel(pht('Invitees'))
->setName('invitees') ->setName('invitees')
->setValue($invitees) ->setValue($invitees)
->setUser($user) ->setUser($viewer)
->setDatasource(new PhabricatorMetaMTAMailableDatasource()); ->setDatasource(new PhabricatorMetaMTAMailableDatasource());
if ($this->isCreate()) { if ($this->isCreate()) {
@ -269,7 +316,9 @@ final class PhabricatorCalendarEventEditController
->setValue($icon); ->setValue($icon);
$form = id(new AphrontFormView()) $form = id(new AphrontFormView())
->setUser($user) ->addHiddenInput('next', $next_workflow)
->addHiddenInput('query', $uri_query)
->setUser($viewer)
->appendChild($name) ->appendChild($name)
->appendChild($all_day_checkbox) ->appendChild($all_day_checkbox)
->appendChild($start_control) ->appendChild($start_control)
@ -351,19 +400,19 @@ final class PhabricatorCalendarEventEditController
return $new; return $new;
} }
private function getDefaultTimeValues($user) { private function getDefaultTimeValues($viewer) {
$start = new DateTime('@'.time()); $start = new DateTime('@'.time());
$start->setTimeZone($user->getTimeZone()); $start->setTimeZone($viewer->getTimeZone());
$start->setTime($start->format('H'), 0, 0); $start->setTime($start->format('H'), 0, 0);
$start->modify('+1 hour'); $start->modify('+1 hour');
$end = id(clone $start)->modify('+1 hour'); $end = id(clone $start)->modify('+1 hour');
$start_value = AphrontFormDateControlValue::newFromEpoch( $start_value = AphrontFormDateControlValue::newFromEpoch(
$user, $viewer,
$start->format('U')); $start->format('U'));
$end_value = AphrontFormDateControlValue::newFromEpoch( $end_value = AphrontFormDateControlValue::newFromEpoch(
$user, $viewer,
$end->format('U')); $end->format('U'));
return array($start_value, $end_value); return array($start_value, $end_value);

View file

@ -390,12 +390,13 @@ final class PhabricatorCalendarEventSearchEngine
list($start_year, $start_month, $start_day) = list($start_year, $start_month, $start_day) =
$this->getDisplayYearAndMonthAndDay($query); $this->getDisplayYearAndMonthAndDay($query);
$day_view = new PHUICalendarDayView( $day_view = id(new PHUICalendarDayView(
$this->getDateFrom($query), $this->getDateFrom($query),
$this->getDateTo($query), $this->getDateTo($query),
$start_year, $start_year,
$start_month, $start_month,
$start_day); $start_day))
->setQuery($query->getQueryKey());
$day_view->setUser($viewer); $day_view->setUser($viewer);
@ -408,7 +409,13 @@ final class PhabricatorCalendarEventSearchEngine
$viewer_is_invited = $status->getIsUserInvited($viewer->getPHID()); $viewer_is_invited = $status->getIsUserInvited($viewer->getPHID());
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$status,
PhabricatorPolicyCapability::CAN_EDIT);
$event = new AphrontCalendarEventView(); $event = new AphrontCalendarEventView();
$event->setCanEdit($can_edit);
$event->setEventID($status->getID()); $event->setEventID($status->getID());
$event->setEpochRange($status->getDateFrom(), $status->getDateTo()); $event->setEpochRange($status->getDateFrom(), $status->getDateTo());
$event->setIsAllDay($status->getIsAllDay()); $event->setIsAllDay($status->getIsAllDay());

View file

@ -12,6 +12,7 @@ final class AphrontCalendarEventView extends AphrontView {
private $uri; private $uri;
private $isAllDay; private $isAllDay;
private $icon; private $icon;
private $canEdit;
public function setURI($uri) { public function setURI($uri) {
$this->uri = $uri; $this->uri = $uri;
@ -97,6 +98,14 @@ final class AphrontCalendarEventView extends AphrontView {
return $this->icon; return $this->icon;
} }
public function setCanEdit($can_edit) {
$this->canEdit = $can_edit;
return $this;
}
public function getCanEdit() {
return $this->canEdit;
}
public function getMultiDay() { public function getMultiDay() {
$nextday = strtotime('12:00 AM Tomorrow', $this->getEpochStart()); $nextday = strtotime('12:00 AM Tomorrow', $this->getEpochStart());

View file

@ -211,6 +211,19 @@ final class AphrontFormDateControlValue extends Phobject {
return $value; return $value;
} }
public function getDateTime() {
$epoch = $this->getEpoch();
$date = null;
if ($epoch) {
$zone = $this->getTimezone();
$date = new DateTime('@'.$epoch);
$date->setTimeZone($zone);
}
return $date;
}
private function getTimezone() { private function getTimezone() {
if ($this->zone) { if ($this->zone) {
return $this->zone; return $this->zone;

View file

@ -8,6 +8,7 @@ final class PHUICalendarDayView extends AphrontView {
private $month; private $month;
private $year; private $year;
private $browseURI; private $browseURI;
private $query;
private $events = array(); private $events = array();
private $allDayEvents = array(); private $allDayEvents = array();
@ -25,6 +26,14 @@ final class PHUICalendarDayView extends AphrontView {
return $this->browseURI; return $this->browseURI;
} }
public function setQuery($query) {
$this->query = $query;
return $this;
}
private function getQuery() {
return $this->query;
}
public function __construct( public function __construct(
$range_start, $range_start,
$range_end, $range_end,
@ -128,6 +137,7 @@ final class PHUICalendarDayView extends AphrontView {
'width' => '100%', 'width' => '100%',
'top' => $top.'px', 'top' => $top.'px',
'height' => $height.'px', 'height' => $height.'px',
'canEdit' => $event->getCanEdit(),
); );
} }
} }
@ -148,6 +158,10 @@ final class PHUICalendarDayView extends AphrontView {
Javelin::initBehavior( Javelin::initBehavior(
'day-view', 'day-view',
array( array(
'year' => $first_event_hour->format('Y'),
'month' => $first_event_hour->format('m'),
'day' => $first_event_hour->format('d'),
'query' => $this->getQuery(),
'allDayEvents' => $js_today_all_day_events, 'allDayEvents' => $js_today_all_day_events,
'todayEvents' => $js_today_events, 'todayEvents' => $js_today_events,
'hours' => $js_hours, 'hours' => $js_hours,

View file

@ -29,6 +29,11 @@
.phui-calendar-day-view td { .phui-calendar-day-view td {
position: relative; position: relative;
cursor: pointer;
}
.phui-calendar-day-view td:hover {
background: {$lightbluebackground};
} }
.phui-calendar-day-view tr + tr td.phui-calendar-day-events { .phui-calendar-day-view tr + tr td.phui-calendar-day-events {
@ -47,6 +52,10 @@ div.phui-calendar-day-event {
min-height: 30px; min-height: 30px;
} }
.can-drag a {
cursor: move;
}
div.phui-calendar-day-event.all-day { div.phui-calendar-day-event.all-day {
position: relative; position: relative;
} }

View file

@ -100,10 +100,15 @@ JX.behavior('day-view', function(config) {
}, },
name); name);
var class_name = 'phui-calendar-day-event';
if (e.canEdit) {
class_name = class_name + ' can-drag';
}
var div = JX.$N( var div = JX.$N(
'div', 'div',
{ {
className: 'phui-calendar-day-event', className: class_name,
sigil: sigil, sigil: sigil,
meta: {eventID: eventID, record: e, uri: uri}, meta: {eventID: eventID, record: e, uri: uri},
style: { style: {
@ -169,7 +174,11 @@ JX.behavior('day-view', function(config) {
var cell_event = JX.$N( var cell_event = JX.$N(
'td', 'td',
{ {
className: 'phui-calendar-day-events' meta: {
time: hours[i]['hour_meridian']
},
className: 'phui-calendar-day-events',
sigil: 'phui-calendar-day-event-cell'
}); });
var row = JX.$N( var row = JX.$N(
@ -195,6 +204,11 @@ JX.behavior('day-view', function(config) {
} }
var year = config.year;
var month = config.month;
var day = config.day;
var query = config.query;
var hours = config.hours; var hours = config.hours;
var first_event_hour = config.firstEventHour; var first_event_hour = config.firstEventHour;
var first_event_hour_epoch = parseInt(config.firstEventHourEpoch, 10); var first_event_hour_epoch = parseInt(config.firstEventHourEpoch, 10);
@ -234,6 +248,10 @@ JX.behavior('day-view', function(config) {
if (!e.isNormalMouseEvent()) { if (!e.isNormalMouseEvent()) {
return; return;
} }
var data = e.getNodeData('phui-calendar-day-event');
if (!data.record.canEdit) {
return;
}
e.kill(); e.kill();
dragging = e.getNode('phui-calendar-day-event'); dragging = e.getNode('phui-calendar-day-event');
JX.DOM.alterClass(dragging, 'phui-drag', true); JX.DOM.alterClass(dragging, 'phui-drag', true);
@ -264,12 +282,13 @@ JX.behavior('day-view', function(config) {
dragging.style.top = new_top + 'px'; dragging.style.top = new_top + 'px';
}); });
JX.Stratcom.listen('mouseup', null, function(){ JX.Stratcom.listen('mouseup', null, function(){
var data = JX.Stratcom.getData(dragging);
var record = data.record;
if (!dragging) { if (!dragging) {
return; return;
} }
var data = JX.Stratcom.getData(dragging);
var record = data.record;
if (new_top == offset_top) { if (new_top == offset_top) {
var now = new Date(); var now = new Date();
if (now.getTime() - click_time.getTime() < 250) { if (now.getTime() - click_time.getTime() < 250) {
@ -304,6 +323,25 @@ JX.behavior('day-view', function(config) {
} }
}); });
JX.DOM.listen(table, 'click', 'phui-calendar-day-event-cell', function(e){
if (!e.isNormalClick()) {
return;
}
var data = e.getNodeData('phui-calendar-day-event-cell');
var time = data.time;
new JX.Workflow(
'/calendar/event/create/',
{
year: year,
month: month,
day: day,
time: time,
next: 'day',
query: query
})
.start();
});
var hourly_events_wrapper = JX.$N( var hourly_events_wrapper = JX.$N(
'div', 'div',
{style: { {style: {