mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-18 19:40:55 +01:00
Refactor Calendar Search, and implement Projects on events
Summary: Ref T7950, Refactor Calendar Search, and implement Projects on events Test Plan: Verify that all queries in Calendar search still work, and that events can now have associated Projects that you can search by in Calendar Search. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Maniphest Tasks: T7950 Differential Revision: https://secure.phabricator.com/D13393
This commit is contained in:
parent
1bb2978a89
commit
c3efa261f9
9 changed files with 274 additions and 209 deletions
|
@ -2549,6 +2549,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSearchDAO' => 'applications/search/storage/PhabricatorSearchDAO.php',
|
'PhabricatorSearchDAO' => 'applications/search/storage/PhabricatorSearchDAO.php',
|
||||||
'PhabricatorSearchDatasource' => 'applications/search/typeahead/PhabricatorSearchDatasource.php',
|
'PhabricatorSearchDatasource' => 'applications/search/typeahead/PhabricatorSearchDatasource.php',
|
||||||
'PhabricatorSearchDatasourceField' => 'applications/search/field/PhabricatorSearchDatasourceField.php',
|
'PhabricatorSearchDatasourceField' => 'applications/search/field/PhabricatorSearchDatasourceField.php',
|
||||||
|
'PhabricatorSearchDateControlField' => 'applications/search/field/PhabricatorSearchDateControlField.php',
|
||||||
'PhabricatorSearchDateField' => 'applications/search/field/PhabricatorSearchDateField.php',
|
'PhabricatorSearchDateField' => 'applications/search/field/PhabricatorSearchDateField.php',
|
||||||
'PhabricatorSearchDeleteController' => 'applications/search/controller/PhabricatorSearchDeleteController.php',
|
'PhabricatorSearchDeleteController' => 'applications/search/controller/PhabricatorSearchDeleteController.php',
|
||||||
'PhabricatorSearchDocument' => 'applications/search/storage/document/PhabricatorSearchDocument.php',
|
'PhabricatorSearchDocument' => 'applications/search/storage/document/PhabricatorSearchDocument.php',
|
||||||
|
@ -5086,6 +5087,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCalendarEvent' => array(
|
'PhabricatorCalendarEvent' => array(
|
||||||
'PhabricatorCalendarDAO',
|
'PhabricatorCalendarDAO',
|
||||||
'PhabricatorPolicyInterface',
|
'PhabricatorPolicyInterface',
|
||||||
|
'PhabricatorProjectInterface',
|
||||||
'PhabricatorMarkupInterface',
|
'PhabricatorMarkupInterface',
|
||||||
'PhabricatorApplicationTransactionInterface',
|
'PhabricatorApplicationTransactionInterface',
|
||||||
'PhabricatorSubscribableInterface',
|
'PhabricatorSubscribableInterface',
|
||||||
|
@ -6286,6 +6288,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSearchDAO' => 'PhabricatorLiskDAO',
|
'PhabricatorSearchDAO' => 'PhabricatorLiskDAO',
|
||||||
'PhabricatorSearchDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
'PhabricatorSearchDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||||
'PhabricatorSearchDatasourceField' => 'PhabricatorSearchTokenizerField',
|
'PhabricatorSearchDatasourceField' => 'PhabricatorSearchTokenizerField',
|
||||||
|
'PhabricatorSearchDateControlField' => 'PhabricatorSearchField',
|
||||||
'PhabricatorSearchDateField' => 'PhabricatorSearchField',
|
'PhabricatorSearchDateField' => 'PhabricatorSearchField',
|
||||||
'PhabricatorSearchDeleteController' => 'PhabricatorSearchBaseController',
|
'PhabricatorSearchDeleteController' => 'PhabricatorSearchBaseController',
|
||||||
'PhabricatorSearchDocument' => 'PhabricatorSearchDAO',
|
'PhabricatorSearchDocument' => 'PhabricatorSearchDAO',
|
||||||
|
|
|
@ -140,6 +140,15 @@ final class PhabricatorCalendarEventEditController
|
||||||
$cancel_uri = '/'.$event->getMonogram();
|
$cancel_uri = '/'.$event->getMonogram();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->isCreate()) {
|
||||||
|
$projects = array();
|
||||||
|
} else {
|
||||||
|
$projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||||
|
$event->getPHID(),
|
||||||
|
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
|
||||||
|
$projects = array_reverse($projects);
|
||||||
|
}
|
||||||
|
|
||||||
$name = $event->getName();
|
$name = $event->getName();
|
||||||
$description = $event->getDescription();
|
$description = $event->getDescription();
|
||||||
$is_all_day = $event->getIsAllDay();
|
$is_all_day = $event->getIsAllDay();
|
||||||
|
@ -167,6 +176,7 @@ final class PhabricatorCalendarEventEditController
|
||||||
$request,
|
$request,
|
||||||
'recurrenceEndDate');
|
'recurrenceEndDate');
|
||||||
$recurrence_end_date_value->setOptional(true);
|
$recurrence_end_date_value->setOptional(true);
|
||||||
|
$projects = $request->getArr('projects');
|
||||||
$description = $request->getStr('description');
|
$description = $request->getStr('description');
|
||||||
$subscribers = $request->getArr('subscribers');
|
$subscribers = $request->getArr('subscribers');
|
||||||
$edit_policy = $request->getStr('editPolicy');
|
$edit_policy = $request->getStr('editPolicy');
|
||||||
|
@ -262,6 +272,12 @@ final class PhabricatorCalendarEventEditController
|
||||||
->setContinueOnNoEffect(true);
|
->setContinueOnNoEffect(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
$proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
|
||||||
|
$xactions[] = id(new PhabricatorCalendarEventTransaction())
|
||||||
|
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
|
||||||
|
->setMetadataValue('edge:type', $proj_edge_type)
|
||||||
|
->setNewValue(array('=' => array_fuse($projects)));
|
||||||
|
|
||||||
$xactions = $editor->applyTransactions($event, $xactions);
|
$xactions = $editor->applyTransactions($event, $xactions);
|
||||||
$response = id(new AphrontRedirectResponse());
|
$response = id(new AphrontRedirectResponse());
|
||||||
switch ($next_workflow) {
|
switch ($next_workflow) {
|
||||||
|
@ -437,6 +453,13 @@ final class PhabricatorCalendarEventEditController
|
||||||
->setValue($end_disabled);
|
->setValue($end_disabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$projects = id(new AphrontFormTokenizerControl())
|
||||||
|
->setLabel(pht('Projects'))
|
||||||
|
->setName('projects')
|
||||||
|
->setValue($projects)
|
||||||
|
->setUser($viewer)
|
||||||
|
->setDatasource(new PhabricatorProjectDatasource());
|
||||||
|
|
||||||
$description = id(new PhabricatorRemarkupControl())
|
$description = id(new PhabricatorRemarkupControl())
|
||||||
->setLabel(pht('Description'))
|
->setLabel(pht('Description'))
|
||||||
->setName('description')
|
->setName('description')
|
||||||
|
@ -511,6 +534,7 @@ final class PhabricatorCalendarEventEditController
|
||||||
->appendControl($edit_policies)
|
->appendControl($edit_policies)
|
||||||
->appendControl($subscribers)
|
->appendControl($subscribers)
|
||||||
->appendControl($invitees)
|
->appendControl($invitees)
|
||||||
|
->appendChild($projects)
|
||||||
->appendChild($description)
|
->appendChild($description)
|
||||||
->appendChild($icon);
|
->appendChild($icon);
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,10 @@ final class PhabricatorCalendarEventQuery
|
||||||
|
|
||||||
private $generateGhosts = false;
|
private $generateGhosts = false;
|
||||||
|
|
||||||
|
public function newResultObject() {
|
||||||
|
return new PhabricatorCalendarEvent();
|
||||||
|
}
|
||||||
|
|
||||||
public function setGenerateGhosts($generate_ghosts) {
|
public function setGenerateGhosts($generate_ghosts) {
|
||||||
$this->generateGhosts = $generate_ghosts;
|
$this->generateGhosts = $generate_ghosts;
|
||||||
return $this;
|
return $this;
|
||||||
|
|
|
@ -15,66 +15,137 @@ final class PhabricatorCalendarEventSearchEngine
|
||||||
return 'PhabricatorCalendarApplication';
|
return 'PhabricatorCalendarApplication';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
public function newQuery() {
|
||||||
$saved = new PhabricatorSavedQuery();
|
return new PhabricatorCalendarEventQuery();
|
||||||
|
|
||||||
$saved->setParameter(
|
|
||||||
'rangeStart',
|
|
||||||
$this->readDateFromRequest($request, 'rangeStart'));
|
|
||||||
|
|
||||||
$saved->setParameter(
|
|
||||||
'rangeEnd',
|
|
||||||
$this->readDateFromRequest($request, 'rangeEnd'));
|
|
||||||
|
|
||||||
$saved->setParameter(
|
|
||||||
'upcoming',
|
|
||||||
$this->readBoolFromRequest($request, 'upcoming'));
|
|
||||||
|
|
||||||
$saved->setParameter(
|
|
||||||
'invitedPHIDs',
|
|
||||||
$this->readUsersFromRequest($request, 'invited'));
|
|
||||||
|
|
||||||
$saved->setParameter(
|
|
||||||
'creatorPHIDs',
|
|
||||||
$this->readUsersFromRequest($request, 'creators'));
|
|
||||||
|
|
||||||
$saved->setParameter(
|
|
||||||
'isCancelled',
|
|
||||||
$request->getStr('isCancelled'));
|
|
||||||
|
|
||||||
$saved->setParameter(
|
|
||||||
'display',
|
|
||||||
$request->getStr('display'));
|
|
||||||
|
|
||||||
return $saved;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
protected function shouldShowOrderField() {
|
||||||
$query = id(new PhabricatorCalendarEventQuery())
|
return false;
|
||||||
->setGenerateGhosts(true);
|
}
|
||||||
|
|
||||||
|
protected function buildCustomSearchFields() {
|
||||||
|
return array(
|
||||||
|
id(new PhabricatorSearchDatasourceField())
|
||||||
|
->setLabel(pht('Created By'))
|
||||||
|
->setKey('creatorPHIDs')
|
||||||
|
->setDatasource(new PhabricatorPeopleUserFunctionDatasource()),
|
||||||
|
id(new PhabricatorSearchDatasourceField())
|
||||||
|
->setLabel(pht('Invited'))
|
||||||
|
->setKey('invitedPHIDs')
|
||||||
|
->setDatasource(new PhabricatorPeopleUserFunctionDatasource()),
|
||||||
|
id(new PhabricatorSearchDateControlField())
|
||||||
|
->setLabel(pht('Occurs After'))
|
||||||
|
->setKey('rangeStart'),
|
||||||
|
id(new PhabricatorSearchDateControlField())
|
||||||
|
->setLabel(pht('Occurs Before'))
|
||||||
|
->setKey('rangeEnd')
|
||||||
|
->setAliases(array('rangeEnd')),
|
||||||
|
id(new PhabricatorSearchCheckboxesField())
|
||||||
|
->setKey('upcoming')
|
||||||
|
->setOptions(array(
|
||||||
|
'upcoming' => pht('Show only upcoming events.'),
|
||||||
|
)),
|
||||||
|
id(new PhabricatorSearchSelectField())
|
||||||
|
->setLabel(pht('Cancelled Events'))
|
||||||
|
->setKey('isCancelled')
|
||||||
|
->setOptions($this->getCancelledOptions())
|
||||||
|
->setDefault('active'),
|
||||||
|
id(new PhabricatorSearchSelectField())
|
||||||
|
->setLabel(pht('Display Options'))
|
||||||
|
->setKey('display')
|
||||||
|
->setOptions($this->getViewOptions())
|
||||||
|
->setDefault('month'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getCancelledOptions() {
|
||||||
|
return array(
|
||||||
|
'active' => pht('Active Events Only'),
|
||||||
|
'cancelled' => pht('Cancelled Events Only'),
|
||||||
|
'both' => pht('Both Cancelled and Active Events'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getViewOptions() {
|
||||||
|
return array(
|
||||||
|
'month' => pht('Month View'),
|
||||||
|
'day' => pht('Day View'),
|
||||||
|
'list' => pht('List View'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildQueryFromParameters(array $map) {
|
||||||
|
$query = $this->newQuery();
|
||||||
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
|
if ($map['creatorPHIDs']) {
|
||||||
|
$query->withCreatorPHIDs($map['creatorPHIDs']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($map['invitedPHIDs']) {
|
||||||
|
$query->withInvitedPHIDs($map['invitedPHIDs']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$range_start = $map['rangeStart'];
|
||||||
|
$range_end = $map['rangeEnd'];
|
||||||
|
$display = $map['display'];
|
||||||
|
|
||||||
|
if ($map['upcoming'] && $map['upcoming'][0] == 'upcoming') {
|
||||||
|
$upcoming = true;
|
||||||
|
} else {
|
||||||
|
$upcoming = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($range_start, $range_end) = $this->getQueryDateRange(
|
||||||
|
$range_start,
|
||||||
|
$range_end,
|
||||||
|
$display,
|
||||||
|
$upcoming);
|
||||||
|
|
||||||
|
$query->withDateRange($range_start, $range_end);
|
||||||
|
|
||||||
|
switch ($map['isCancelled']) {
|
||||||
|
case 'active':
|
||||||
|
$query->withIsCancelled(false);
|
||||||
|
break;
|
||||||
|
case 'cancelled':
|
||||||
|
$query->withIsCancelled(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->setGenerateGhosts(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getQueryDateRange(
|
||||||
|
$start_date_wild,
|
||||||
|
$end_date_wild,
|
||||||
|
$display,
|
||||||
|
$upcoming) {
|
||||||
|
|
||||||
|
$start_date_value = $this->getSafeDate($start_date_wild);
|
||||||
|
$end_date_value = $this->getSafeDate($end_date_wild);
|
||||||
|
|
||||||
$viewer = $this->requireViewer();
|
$viewer = $this->requireViewer();
|
||||||
$timezone = new DateTimeZone($viewer->getTimezoneIdentifier());
|
$timezone = new DateTimeZone($viewer->getTimezoneIdentifier());
|
||||||
|
$min_range = null;
|
||||||
|
$max_range = null;
|
||||||
|
|
||||||
$min_range = $this->getDateFrom($saved)->getEpoch();
|
$min_range = $start_date_value->getEpoch();
|
||||||
$max_range = $this->getDateTo($saved)->getEpoch();
|
$max_range = $end_date_value->getEpoch();
|
||||||
|
|
||||||
$user_datasource = id(new PhabricatorPeopleUserFunctionDatasource())
|
if ($display == 'month' || $display == 'day') {
|
||||||
->setViewer($viewer);
|
|
||||||
|
|
||||||
if ($this->isMonthView($saved) ||
|
|
||||||
$this->isDayView($saved)) {
|
|
||||||
list($start_year, $start_month, $start_day) =
|
list($start_year, $start_month, $start_day) =
|
||||||
$this->getDisplayYearAndMonthAndDay($saved);
|
$this->getDisplayYearAndMonthAndDay($min_range, $max_range, $display);
|
||||||
|
|
||||||
$start_day = new DateTime(
|
$start_day = new DateTime(
|
||||||
"{$start_year}-{$start_month}-{$start_day}",
|
"{$start_year}-{$start_month}-{$start_day}",
|
||||||
$timezone);
|
$timezone);
|
||||||
$next = clone $start_day;
|
$next = clone $start_day;
|
||||||
|
|
||||||
if ($this->isMonthView($saved)) {
|
if ($display == 'month') {
|
||||||
$next->modify('+1 month');
|
$next->modify('+1 month');
|
||||||
} else if ($this->isDayView($saved)) {
|
} else if ($display == 'day') {
|
||||||
$next->modify('+6 day');
|
$next->modify('+7 day');
|
||||||
}
|
}
|
||||||
|
|
||||||
$display_start = $start_day->format('U');
|
$display_start = $start_day->format('U');
|
||||||
|
@ -92,7 +163,7 @@ final class PhabricatorCalendarEventSearchEngine
|
||||||
if (!$min_range || ($min_range < $display_start)) {
|
if (!$min_range || ($min_range < $display_start)) {
|
||||||
$min_range = $display_start;
|
$min_range = $display_start;
|
||||||
|
|
||||||
if ($this->isMonthView($saved) &&
|
if ($display == 'month' &&
|
||||||
$first_of_month !== $start_of_week) {
|
$first_of_month !== $start_of_week) {
|
||||||
$interim_day_num = ($first_of_month + 7 - $start_of_week) % 7;
|
$interim_day_num = ($first_of_month + 7 - $start_of_week) % 7;
|
||||||
$min_range = id(clone $start_day)
|
$min_range = id(clone $start_day)
|
||||||
|
@ -103,18 +174,17 @@ final class PhabricatorCalendarEventSearchEngine
|
||||||
if (!$max_range || ($max_range > $display_end)) {
|
if (!$max_range || ($max_range > $display_end)) {
|
||||||
$max_range = $display_end;
|
$max_range = $display_end;
|
||||||
|
|
||||||
if ($this->isMonthView($saved) &&
|
if ($display == 'month' &&
|
||||||
$last_of_month !== $end_of_week) {
|
$last_of_month !== $end_of_week) {
|
||||||
$interim_day_num = ($end_of_week + 7 - $last_of_month) % 7;
|
$interim_day_num = ($end_of_week + 7 - $last_of_month) % 7;
|
||||||
$max_range = id(clone $next)
|
$max_range = id(clone $next)
|
||||||
->modify('+'.$interim_day_num.' days')
|
->modify('+'.$interim_day_num.' days')
|
||||||
->format('U');
|
->format('U');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($saved->getParameter('upcoming')) {
|
if ($upcoming) {
|
||||||
if ($min_range) {
|
if ($min_range) {
|
||||||
$min_range = max(time(), $min_range);
|
$min_range = max(time(), $min_range);
|
||||||
} else {
|
} else {
|
||||||
|
@ -122,128 +192,7 @@ final class PhabricatorCalendarEventSearchEngine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($min_range || $max_range) {
|
return array($min_range, $max_range);
|
||||||
$query->withDateRange($min_range, $max_range);
|
|
||||||
}
|
|
||||||
|
|
||||||
$invited_phids = $saved->getParameter('invitedPHIDs', array());
|
|
||||||
$invited_phids = $user_datasource->evaluateTokens($invited_phids);
|
|
||||||
if ($invited_phids) {
|
|
||||||
$query->withInvitedPHIDs($invited_phids);
|
|
||||||
}
|
|
||||||
|
|
||||||
$creator_phids = $saved->getParameter('creatorPHIDs', array());
|
|
||||||
$creator_phids = $user_datasource->evaluateTokens($creator_phids);
|
|
||||||
if ($creator_phids) {
|
|
||||||
$query->withCreatorPHIDs($creator_phids);
|
|
||||||
}
|
|
||||||
|
|
||||||
$is_cancelled = $saved->getParameter('isCancelled', 'active');
|
|
||||||
|
|
||||||
switch ($is_cancelled) {
|
|
||||||
case 'active':
|
|
||||||
$query->withIsCancelled(false);
|
|
||||||
break;
|
|
||||||
case 'cancelled':
|
|
||||||
$query->withIsCancelled(true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $query;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function buildSearchForm(
|
|
||||||
AphrontFormView $form,
|
|
||||||
PhabricatorSavedQuery $saved) {
|
|
||||||
|
|
||||||
$range_start = $this->getDateFrom($saved);
|
|
||||||
$e_start = null;
|
|
||||||
|
|
||||||
$range_end = $this->getDateTo($saved);
|
|
||||||
$e_end = null;
|
|
||||||
|
|
||||||
if (!$range_start->isValid()) {
|
|
||||||
$this->addError(pht('Start date is not valid.'));
|
|
||||||
$e_start = pht('Invalid');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$range_end->isValid()) {
|
|
||||||
$this->addError(pht('End date is not valid.'));
|
|
||||||
$e_end = pht('Invalid');
|
|
||||||
}
|
|
||||||
|
|
||||||
$start_epoch = $range_start->getEpoch();
|
|
||||||
$end_epoch = $range_end->getEpoch();
|
|
||||||
|
|
||||||
if ($start_epoch && $end_epoch && ($start_epoch > $end_epoch)) {
|
|
||||||
$this->addError(pht('End date must be after start date.'));
|
|
||||||
$e_start = pht('Invalid');
|
|
||||||
$e_end = pht('Invalid');
|
|
||||||
}
|
|
||||||
|
|
||||||
$upcoming = $saved->getParameter('upcoming');
|
|
||||||
$is_cancelled = $saved->getParameter('isCancelled', 'active');
|
|
||||||
$display = $saved->getParameter('display', 'month');
|
|
||||||
|
|
||||||
$invited_phids = $saved->getParameter('invitedPHIDs', array());
|
|
||||||
$creator_phids = $saved->getParameter('creatorPHIDs', array());
|
|
||||||
$resolution_types = array(
|
|
||||||
'active' => pht('Active Events Only'),
|
|
||||||
'cancelled' => pht('Cancelled Events Only'),
|
|
||||||
'both' => pht('Both Cancelled and Active Events'),
|
|
||||||
);
|
|
||||||
$display_options = array(
|
|
||||||
'month' => pht('Month View'),
|
|
||||||
'day' => pht('Day View (beta)'),
|
|
||||||
'list' => pht('List View'),
|
|
||||||
);
|
|
||||||
|
|
||||||
$form
|
|
||||||
->appendControl(
|
|
||||||
id(new AphrontFormTokenizerControl())
|
|
||||||
->setDatasource(new PhabricatorPeopleUserFunctionDatasource())
|
|
||||||
->setName('creators')
|
|
||||||
->setLabel(pht('Created By'))
|
|
||||||
->setValue($creator_phids))
|
|
||||||
->appendControl(
|
|
||||||
id(new AphrontFormTokenizerControl())
|
|
||||||
->setDatasource(new PhabricatorPeopleUserFunctionDatasource())
|
|
||||||
->setName('invited')
|
|
||||||
->setLabel(pht('Invited'))
|
|
||||||
->setValue($invited_phids))
|
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormDateControl())
|
|
||||||
->setLabel(pht('Occurs After'))
|
|
||||||
->setUser($this->requireViewer())
|
|
||||||
->setName('rangeStart')
|
|
||||||
->setError($e_start)
|
|
||||||
->setValue($range_start))
|
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormDateControl())
|
|
||||||
->setLabel(pht('Occurs Before'))
|
|
||||||
->setUser($this->requireViewer())
|
|
||||||
->setName('rangeEnd')
|
|
||||||
->setError($e_end)
|
|
||||||
->setValue($range_end))
|
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormCheckboxControl())
|
|
||||||
->addCheckbox(
|
|
||||||
'upcoming',
|
|
||||||
1,
|
|
||||||
pht('Show only upcoming events.'),
|
|
||||||
$upcoming))
|
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormSelectControl())
|
|
||||||
->setLabel(pht('Cancelled Events'))
|
|
||||||
->setName('isCancelled')
|
|
||||||
->setValue($is_cancelled)
|
|
||||||
->setOptions($resolution_types))
|
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormSelectControl())
|
|
||||||
->setLabel(pht('Display Options'))
|
|
||||||
->setName('display')
|
|
||||||
->setValue($display)
|
|
||||||
->setOptions($display_options));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getURI($path) {
|
protected function getURI($path) {
|
||||||
|
@ -279,7 +228,9 @@ final class PhabricatorCalendarEventSearchEngine
|
||||||
case 'day':
|
case 'day':
|
||||||
return $query->setParameter('display', 'day');
|
return $query->setParameter('display', 'day');
|
||||||
case 'upcoming':
|
case 'upcoming':
|
||||||
return $query->setParameter('upcoming', true);
|
return $query->setParameter('upcoming', array(
|
||||||
|
0 => 'upcoming',
|
||||||
|
));
|
||||||
case 'all':
|
case 'all':
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
@ -311,6 +262,7 @@ final class PhabricatorCalendarEventSearchEngine
|
||||||
assert_instances_of($events, 'PhabricatorCalendarEvent');
|
assert_instances_of($events, 'PhabricatorCalendarEvent');
|
||||||
$viewer = $this->requireViewer();
|
$viewer = $this->requireViewer();
|
||||||
$list = new PHUIObjectItemListView();
|
$list = new PHUIObjectItemListView();
|
||||||
|
|
||||||
foreach ($events as $event) {
|
foreach ($events as $event) {
|
||||||
$from = phabricator_datetime($event->getDateFrom(), $viewer);
|
$from = phabricator_datetime($event->getDateFrom(), $viewer);
|
||||||
$duration = '';
|
$duration = '';
|
||||||
|
@ -349,11 +301,15 @@ final class PhabricatorCalendarEventSearchEngine
|
||||||
array $statuses,
|
array $statuses,
|
||||||
PhabricatorSavedQuery $query,
|
PhabricatorSavedQuery $query,
|
||||||
array $handles) {
|
array $handles) {
|
||||||
|
|
||||||
$viewer = $this->requireViewer();
|
$viewer = $this->requireViewer();
|
||||||
$now = time();
|
$now = time();
|
||||||
|
|
||||||
list($start_year, $start_month) =
|
list($start_year, $start_month) =
|
||||||
$this->getDisplayYearAndMonthAndDay($query);
|
$this->getDisplayYearAndMonthAndDay(
|
||||||
|
$this->getQueryDateFrom($query)->getEpoch(),
|
||||||
|
$this->getQueryDateTo($query)->getEpoch(),
|
||||||
|
$query->getParameter('display'));
|
||||||
|
|
||||||
$now_year = phabricator_format_local_time($now, $viewer, 'Y');
|
$now_year = phabricator_format_local_time($now, $viewer, 'Y');
|
||||||
$now_month = phabricator_format_local_time($now, $viewer, 'm');
|
$now_month = phabricator_format_local_time($now, $viewer, 'm');
|
||||||
|
@ -361,15 +317,15 @@ final class PhabricatorCalendarEventSearchEngine
|
||||||
|
|
||||||
if ($start_month == $now_month && $start_year == $now_year) {
|
if ($start_month == $now_month && $start_year == $now_year) {
|
||||||
$month_view = new PHUICalendarMonthView(
|
$month_view = new PHUICalendarMonthView(
|
||||||
$this->getDateFrom($query),
|
$this->getQueryDateFrom($query),
|
||||||
$this->getDateTo($query),
|
$this->getQueryDateTo($query),
|
||||||
$start_month,
|
$start_month,
|
||||||
$start_year,
|
$start_year,
|
||||||
$now_day);
|
$now_day);
|
||||||
} else {
|
} else {
|
||||||
$month_view = new PHUICalendarMonthView(
|
$month_view = new PHUICalendarMonthView(
|
||||||
$this->getDateFrom($query),
|
$this->getQueryDateFrom($query),
|
||||||
$this->getDateTo($query),
|
$this->getQueryDateTo($query),
|
||||||
$start_month,
|
$start_month,
|
||||||
$start_year);
|
$start_year);
|
||||||
}
|
}
|
||||||
|
@ -406,13 +362,18 @@ final class PhabricatorCalendarEventSearchEngine
|
||||||
array $statuses,
|
array $statuses,
|
||||||
PhabricatorSavedQuery $query,
|
PhabricatorSavedQuery $query,
|
||||||
array $handles) {
|
array $handles) {
|
||||||
|
|
||||||
$viewer = $this->requireViewer();
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
list($start_year, $start_month, $start_day) =
|
list($start_year, $start_month, $start_day) =
|
||||||
$this->getDisplayYearAndMonthAndDay($query);
|
$this->getDisplayYearAndMonthAndDay(
|
||||||
|
$this->getQueryDateFrom($query)->getEpoch(),
|
||||||
|
$this->getQueryDateTo($query)->getEpoch(),
|
||||||
|
$query->getParameter('display'));
|
||||||
|
|
||||||
$day_view = id(new PHUICalendarDayView(
|
$day_view = id(new PHUICalendarDayView(
|
||||||
$this->getDateFrom($query),
|
$this->getQueryDateFrom($query)->getEpoch(),
|
||||||
$this->getDateTo($query),
|
$this->getQueryDateTo($query)->getEpoch(),
|
||||||
$start_year,
|
$start_year,
|
||||||
$start_month,
|
$start_month,
|
||||||
$start_day))
|
$start_day))
|
||||||
|
@ -454,21 +415,26 @@ final class PhabricatorCalendarEventSearchEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getDisplayYearAndMonthAndDay(
|
private function getDisplayYearAndMonthAndDay(
|
||||||
PhabricatorSavedQuery $query) {
|
$range_start,
|
||||||
|
$range_end,
|
||||||
|
$display) {
|
||||||
|
|
||||||
$viewer = $this->requireViewer();
|
$viewer = $this->requireViewer();
|
||||||
|
$epoch = null;
|
||||||
|
|
||||||
if ($this->calendarYear && $this->calendarMonth) {
|
if ($this->calendarYear && $this->calendarMonth) {
|
||||||
$start_year = $this->calendarYear;
|
$start_year = $this->calendarYear;
|
||||||
$start_month = $this->calendarMonth;
|
$start_month = $this->calendarMonth;
|
||||||
$start_day = $this->calendarDay ? $this->calendarDay : 1;
|
$start_day = $this->calendarDay ? $this->calendarDay : 1;
|
||||||
} else {
|
} else {
|
||||||
$epoch = $this->getDateFrom($query)->getEpoch();
|
if ($range_start) {
|
||||||
if (!$epoch) {
|
$epoch = $range_start;
|
||||||
$epoch = $this->getDateTo($query)->getEpoch();
|
} else if ($range_end) {
|
||||||
if (!$epoch) {
|
$epoch = $range_end;
|
||||||
$epoch = time();
|
} else {
|
||||||
}
|
$epoch = time();
|
||||||
}
|
}
|
||||||
if ($this->isMonthView($query)) {
|
if ($display == 'month') {
|
||||||
$day = 1;
|
$day = 1;
|
||||||
} else {
|
} else {
|
||||||
$day = phabricator_format_local_time($epoch, $viewer, 'd');
|
$day = phabricator_format_local_time($epoch, $viewer, 'd');
|
||||||
|
@ -488,20 +454,30 @@ final class PhabricatorCalendarEventSearchEngine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getDateFrom(PhabricatorSavedQuery $saved) {
|
private function getQueryDateFrom(PhabricatorSavedQuery $saved) {
|
||||||
return $this->getDate($saved, 'rangeStart');
|
return $this->getQueryDate($saved, 'rangeStart');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getDateTo(PhabricatorSavedQuery $saved) {
|
private function getQueryDateTo(PhabricatorSavedQuery $saved) {
|
||||||
return $this->getDate($saved, 'rangeEnd');
|
return $this->getQueryDate($saved, 'rangeEnd');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getDate(PhabricatorSavedQuery $saved, $key) {
|
private function getQueryDate(PhabricatorSavedQuery $saved, $key) {
|
||||||
$viewer = $this->requireViewer();
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
$wild = $saved->getParameter($key);
|
$wild = $saved->getParameter($key);
|
||||||
if ($wild) {
|
return $this->getSafeDate($wild);
|
||||||
$value = AphrontFormDateControlValue::newFromWild($viewer, $wild);
|
}
|
||||||
|
|
||||||
|
private function getSafeDate($value) {
|
||||||
|
$viewer = $this->requireViewer();
|
||||||
|
if ($value) {
|
||||||
|
// ideally this would be consistent and always pass in the same type
|
||||||
|
if ($value instanceof AphrontFormDateControlValue) {
|
||||||
|
return $value;
|
||||||
|
} else {
|
||||||
|
$value = AphrontFormDateControlValue::newFromWild($viewer, $value);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$value = AphrontFormDateControlValue::newFromEpoch(
|
$value = AphrontFormDateControlValue::newFromEpoch(
|
||||||
$viewer,
|
$viewer,
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
||||||
implements PhabricatorPolicyInterface,
|
implements PhabricatorPolicyInterface,
|
||||||
|
PhabricatorProjectInterface,
|
||||||
PhabricatorMarkupInterface,
|
PhabricatorMarkupInterface,
|
||||||
PhabricatorApplicationTransactionInterface,
|
PhabricatorApplicationTransactionInterface,
|
||||||
PhabricatorSubscribableInterface,
|
PhabricatorSubscribableInterface,
|
||||||
|
|
|
@ -266,7 +266,7 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = $this->newQuery();
|
$query = $this->newQuery();
|
||||||
if ($query) {
|
if ($query && $this->shouldShowOrderField()) {
|
||||||
$orders = $query->getBuiltinOrders();
|
$orders = $query->getBuiltinOrders();
|
||||||
$orders = ipull($orders, 'name');
|
$orders = ipull($orders, 'name');
|
||||||
|
|
||||||
|
@ -293,6 +293,10 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
return $field_map;
|
return $field_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function shouldShowOrderField() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private function adjustFieldsForDisplay(array $field_map) {
|
private function adjustFieldsForDisplay(array $field_map) {
|
||||||
$order = $this->getDefaultFieldOrder();
|
$order = $this->getDefaultFieldOrder();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorSearchDateControlField
|
||||||
|
extends PhabricatorSearchField {
|
||||||
|
|
||||||
|
protected function getValueExistsInRequest(AphrontRequest $request, $key) {
|
||||||
|
// The control doesn't actually submit a value with the same name as the
|
||||||
|
// key, so look for the "_d" value instead, which has the date part of the
|
||||||
|
// control value.
|
||||||
|
return $request->getExists($key.'_d');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getValueFromRequest(AphrontRequest $request, $key) {
|
||||||
|
$value = AphrontFormDateControlValue::newFromRequest($request, $key);
|
||||||
|
$value->setOptional(true);
|
||||||
|
return $value->getDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newControl() {
|
||||||
|
return id(new AphrontFormDateControl())
|
||||||
|
->setAllowNull(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function didReadValueFromSavedQuery($value) {
|
||||||
|
if (!$value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value instanceof AphrontFormDateControlValue && $value->getEpoch()) {
|
||||||
|
return $value->setOptional(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = AphrontFormDateControlValue::newFromWild(
|
||||||
|
$this->getViewer(),
|
||||||
|
$value);
|
||||||
|
return $value->setOptional(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -208,8 +208,15 @@ final class PHUICalendarDayView extends AphrontView {
|
||||||
private function getQueryRangeWarning() {
|
private function getQueryRangeWarning() {
|
||||||
$errors = array();
|
$errors = array();
|
||||||
|
|
||||||
$range_start_epoch = $this->rangeStart->getEpoch();
|
$range_start_epoch = null;
|
||||||
$range_end_epoch = $this->rangeEnd->getEpoch();
|
$range_end_epoch = null;
|
||||||
|
|
||||||
|
if ($this->rangeStart) {
|
||||||
|
$range_start_epoch = $this->rangeStart->getEpoch();
|
||||||
|
}
|
||||||
|
if ($this->rangeEnd) {
|
||||||
|
$range_end_epoch = $this->rangeEnd->getEpoch();
|
||||||
|
}
|
||||||
|
|
||||||
$day_start = $this->getDateTime();
|
$day_start = $this->getDateTime();
|
||||||
$day_end = id(clone $day_start)->modify('+1 day');
|
$day_end = id(clone $day_start)->modify('+1 day');
|
||||||
|
@ -226,10 +233,10 @@ final class PHUICalendarDayView extends AphrontView {
|
||||||
$errors[] = pht('Part of the day is out of range');
|
$errors[] = pht('Part of the day is out of range');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($this->rangeEnd->getEpoch() != null &&
|
if (($range_end_epoch != null &&
|
||||||
$this->rangeEnd->getEpoch() < $day_start) ||
|
$range_end_epoch < $day_start) ||
|
||||||
($this->rangeStart->getEpoch() != null &&
|
($range_start_epoch != null &&
|
||||||
$this->rangeStart->getEpoch() > $day_end)) {
|
$range_start_epoch > $day_end)) {
|
||||||
$errors[] = pht('Day is out of query range');
|
$errors[] = pht('Day is out of query range');
|
||||||
}
|
}
|
||||||
return $errors;
|
return $errors;
|
||||||
|
|
|
@ -434,8 +434,15 @@ final class PHUICalendarMonthView extends AphrontView {
|
||||||
private function getQueryRangeWarning() {
|
private function getQueryRangeWarning() {
|
||||||
$errors = array();
|
$errors = array();
|
||||||
|
|
||||||
$range_start_epoch = $this->rangeStart->getEpoch();
|
$range_start_epoch = null;
|
||||||
$range_end_epoch = $this->rangeEnd->getEpoch();
|
$range_end_epoch = null;
|
||||||
|
|
||||||
|
if ($this->rangeStart) {
|
||||||
|
$range_start_epoch = $this->rangeStart->getEpoch();
|
||||||
|
}
|
||||||
|
if ($this->rangeEnd) {
|
||||||
|
$range_end_epoch = $this->rangeEnd->getEpoch();
|
||||||
|
}
|
||||||
|
|
||||||
$month_start = $this->getDateTime();
|
$month_start = $this->getDateTime();
|
||||||
$month_end = id(clone $month_start)->modify('+1 month');
|
$month_end = id(clone $month_start)->modify('+1 month');
|
||||||
|
@ -452,10 +459,10 @@ final class PHUICalendarMonthView extends AphrontView {
|
||||||
$errors[] = pht('Part of the month is out of range');
|
$errors[] = pht('Part of the month is out of range');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($this->rangeEnd->getEpoch() != null &&
|
if (($range_end_epoch != null &&
|
||||||
$this->rangeEnd->getEpoch() < $month_start) ||
|
$range_end_epoch < $month_start) ||
|
||||||
($this->rangeStart->getEpoch() != null &&
|
($range_start_epoch != null &&
|
||||||
$this->rangeStart->getEpoch() > $month_end)) {
|
$range_start_epoch > $month_end)) {
|
||||||
$errors[] = pht('Month is out of query range');
|
$errors[] = pht('Month is out of query range');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue