mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-20 20:40:56 +01:00
Use ApplicationSearch in the calendar event list view
Summary: Ref T4375. Basic ApplicationSearch integration to power this more flexibly. Test Plan: {F108762} Reviewers: btrahan, chad Reviewed By: btrahan CC: aran Maniphest Tasks: T4375 Differential Revision: https://secure.phabricator.com/D8148
This commit is contained in:
parent
8410cbecb0
commit
0ae0f352b0
7 changed files with 262 additions and 89 deletions
|
@ -1267,6 +1267,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCalendarEventListController' => 'applications/calendar/controller/PhabricatorCalendarEventListController.php',
|
||||
'PhabricatorCalendarEventOverlapException' => 'applications/calendar/exception/PhabricatorCalendarEventOverlapException.php',
|
||||
'PhabricatorCalendarEventQuery' => 'applications/calendar/query/PhabricatorCalendarEventQuery.php',
|
||||
'PhabricatorCalendarEventSearchEngine' => 'applications/calendar/query/PhabricatorCalendarEventSearchEngine.php',
|
||||
'PhabricatorCalendarHoliday' => 'applications/calendar/storage/PhabricatorCalendarHoliday.php',
|
||||
'PhabricatorCalendarHolidayTestCase' => 'applications/calendar/storage/__tests__/PhabricatorCalendarHolidayTestCase.php',
|
||||
'PhabricatorCampfireProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorCampfireProtocolAdapter.php',
|
||||
|
@ -3907,9 +3908,14 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCalendarEventDeleteController' => 'PhabricatorCalendarController',
|
||||
'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController',
|
||||
'PhabricatorCalendarEventInvalidEpochException' => 'Exception',
|
||||
'PhabricatorCalendarEventListController' => 'PhabricatorCalendarController',
|
||||
'PhabricatorCalendarEventListController' =>
|
||||
array(
|
||||
0 => 'PhabricatorCalendarController',
|
||||
1 => 'PhabricatorApplicationSearchResultsControllerInterface',
|
||||
),
|
||||
'PhabricatorCalendarEventOverlapException' => 'Exception',
|
||||
'PhabricatorCalendarEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorCalendarEventSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'PhabricatorCalendarHoliday' => 'PhabricatorCalendarDAO',
|
||||
'PhabricatorCalendarHolidayTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorCampfireProtocolAdapter' => 'PhabricatorBotBaseStreamingProtocolAdapter',
|
||||
|
|
|
@ -37,7 +37,8 @@ final class PhabricatorApplicationCalendar extends PhabricatorApplication {
|
|||
'/calendar/' => array(
|
||||
'' => 'PhabricatorCalendarBrowseController',
|
||||
'event/' => array(
|
||||
'' => 'PhabricatorCalendarEventListController',
|
||||
'(?:query/(?P<queryKey>[^/]+)/)?' =>
|
||||
'PhabricatorCalendarEventListController',
|
||||
'create/' =>
|
||||
'PhabricatorCalendarEventEditController',
|
||||
'edit/(?P<id>[1-9]\d*)/' =>
|
||||
|
|
|
@ -1,62 +1,66 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorCalendarEventListController
|
||||
extends PhabricatorCalendarController {
|
||||
extends PhabricatorCalendarController
|
||||
implements PhabricatorApplicationSearchResultsControllerInterface {
|
||||
|
||||
private $phid;
|
||||
private $queryKey;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$user = $this->getRequest()->getUser();
|
||||
$this->phid = idx($data, 'phid', $user->getPHID());
|
||||
$this->loadHandles(array($this->phid));
|
||||
$this->queryKey = idx($data, 'queryKey');
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$handle = $this->getHandle($this->phid);
|
||||
|
||||
$statuses = id(new PhabricatorCalendarEventQuery())
|
||||
->setViewer($user)
|
||||
->withInvitedPHIDs(array($this->phid))
|
||||
->withDateRange(time(), strtotime('2037-01-01 12:00:00'))
|
||||
->execute();
|
||||
|
||||
$nav = $this->buildSideNavView();
|
||||
$nav->selectFilter($this->getFilter());
|
||||
|
||||
$page_title = $this->getPageTitle();
|
||||
|
||||
$status_list = $this->buildStatusList($statuses);
|
||||
$status_list->setNoDataString($this->getNoDataString());
|
||||
|
||||
$nav->appendChild(
|
||||
array(
|
||||
id(new PHUIHeaderView())->setHeader($page_title),
|
||||
$status_list,
|
||||
));
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
$nav,
|
||||
array(
|
||||
'title' => $page_title,
|
||||
'device' => true
|
||||
));
|
||||
$request = $this->getRequest();
|
||||
$controller = id(new PhabricatorApplicationSearchController($request))
|
||||
->setQueryKey($this->queryKey)
|
||||
->setSearchEngine(new PhabricatorCalendarEventSearchEngine())
|
||||
->setNavigation($this->buildSideNav());
|
||||
return $this->delegateToController($controller);
|
||||
}
|
||||
|
||||
private function buildStatusList(array $statuses) {
|
||||
assert_instances_of($statuses, 'PhabricatorCalendarEvent');
|
||||
|
||||
public function buildSideNav() {
|
||||
$user = $this->getRequest()->getUser();
|
||||
|
||||
$nav = new AphrontSideNavFilterView();
|
||||
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
|
||||
|
||||
id(new PhabricatorCalendarEventSearchEngine())
|
||||
->setViewer($user)
|
||||
->addNavigationItems($nav->getMenu());
|
||||
|
||||
$nav->selectFilter(null);
|
||||
|
||||
return $nav;
|
||||
}
|
||||
|
||||
public function buildApplicationCrumbs() {
|
||||
$crumbs = parent::buildApplicationCrumbs();
|
||||
|
||||
$crumbs->addAction(
|
||||
id(new PHUIListItemView())
|
||||
->setIcon('create')
|
||||
->setName(pht('Create Event'))
|
||||
->setHref($this->getApplicationURI().'create/'));
|
||||
|
||||
return $crumbs;
|
||||
}
|
||||
|
||||
public function renderResultsList(
|
||||
array $events,
|
||||
PhabricatorSavedQuery $query) {
|
||||
assert_instances_of($events, 'PhabricatorCalendarEvent');
|
||||
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$list = new PHUIObjectItemListView();
|
||||
foreach ($statuses as $status) {
|
||||
if ($status->getUserPHID() == $user->getPHID()) {
|
||||
$href = $this->getApplicationURI('/event/edit/'.$status->getID().'/');
|
||||
foreach ($events as $event) {
|
||||
if ($event->getUserPHID() == $viewer->getPHID()) {
|
||||
$href = $this->getApplicationURI('/event/edit/'.$event->getID().'/');
|
||||
} else {
|
||||
$from = $status->getDateFrom();
|
||||
$month = phabricator_format_local_time($from, $user, 'm');
|
||||
$year = phabricator_format_local_time($from, $user, 'Y');
|
||||
$from = $event->getDateFrom();
|
||||
$month = phabricator_format_local_time($from, $viewer, 'm');
|
||||
$year = phabricator_format_local_time($from, $viewer, 'Y');
|
||||
$uri = new PhutilURI($this->getApplicationURI());
|
||||
$uri->setQueryParams(
|
||||
array(
|
||||
|
@ -65,20 +69,20 @@ final class PhabricatorCalendarEventListController
|
|||
));
|
||||
$href = (string) $uri;
|
||||
}
|
||||
$from = phabricator_datetime($status->getDateFrom(), $user);
|
||||
$to = phabricator_datetime($status->getDateTo(), $user);
|
||||
$from = phabricator_datetime($event->getDateFrom(), $viewer);
|
||||
$to = phabricator_datetime($event->getDateTo(), $viewer);
|
||||
|
||||
$color = ($status->getStatus() == PhabricatorCalendarEvent::STATUS_AWAY)
|
||||
$color = ($event->getStatus() == PhabricatorCalendarEvent::STATUS_AWAY)
|
||||
? 'red'
|
||||
: 'yellow';
|
||||
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setHeader($status->getTerseSummary($user))
|
||||
->setHeader($event->getTerseSummary($viewer))
|
||||
->setHref($href)
|
||||
->setBarColor($color)
|
||||
->addAttribute(pht('From %s to %s', $from, $to))
|
||||
->addAttribute(
|
||||
phutil_utf8_shorten($status->getDescription(), 64));
|
||||
phutil_utf8_shorten($event->getDescription(), 64));
|
||||
|
||||
$list->addItem($item);
|
||||
}
|
||||
|
@ -86,38 +90,4 @@ final class PhabricatorCalendarEventListController
|
|||
return $list;
|
||||
}
|
||||
|
||||
private function getNoDataString() {
|
||||
if ($this->isUserRequest()) {
|
||||
$no_data =
|
||||
pht('You do not have any upcoming status events.');
|
||||
} else {
|
||||
$no_data =
|
||||
pht('%s does not have any upcoming status events.',
|
||||
$this->getHandle($this->phid)->getName());
|
||||
}
|
||||
return $no_data;
|
||||
}
|
||||
|
||||
private function getFilter() {
|
||||
$filter = 'event/';
|
||||
|
||||
return $filter;
|
||||
}
|
||||
|
||||
private function getPageTitle() {
|
||||
if ($this->isUserRequest()) {
|
||||
$page_title = pht('Upcoming Statuses');
|
||||
} else {
|
||||
$page_title = pht(
|
||||
'Upcoming Statuses for %s',
|
||||
$this->getHandle($this->phid)->getName());
|
||||
}
|
||||
return $page_title;
|
||||
}
|
||||
|
||||
private function isUserRequest() {
|
||||
$user = $this->getRequest()->getUser();
|
||||
return $this->phid == $user->getPHID();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ final class PhabricatorCalendarEventQuery
|
|||
private $rangeBegin;
|
||||
private $rangeEnd;
|
||||
private $invitedPHIDs;
|
||||
private $creatorPHIDs;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -24,6 +25,11 @@ final class PhabricatorCalendarEventQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withCreatorPHIDs(array $phids) {
|
||||
$this->creatorPHIDs = $phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$table = new PhabricatorCalendarEvent();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
@ -49,14 +55,23 @@ final class PhabricatorCalendarEventQuery
|
|||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->rangeBegin || $this->rangeEnd) {
|
||||
if ($this->rangeBegin) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'dateTo >= %d AND dateFrom <= %d',
|
||||
$this->rangeBegin,
|
||||
'dateTo >= %d',
|
||||
$this->rangeBegin);
|
||||
}
|
||||
|
||||
if ($this->rangeEnd) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'dateFrom <= %d',
|
||||
$this->rangeEnd);
|
||||
}
|
||||
|
||||
// TODO: Currently, the creator is always the only invitee, but you can
|
||||
// query them separately since this won't always be true.
|
||||
|
||||
if ($this->invitedPHIDs) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
|
@ -64,6 +79,13 @@ final class PhabricatorCalendarEventQuery
|
|||
$this->invitedPHIDs);
|
||||
}
|
||||
|
||||
if ($this->creatorPHIDs) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'userPHID IN (%Ls)',
|
||||
$this->creatorPHIDs);
|
||||
}
|
||||
|
||||
$where[] = $this->buildPagingClause($conn_r);
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorCalendarEventSearchEngine
|
||||
extends PhabricatorApplicationSearchEngine {
|
||||
|
||||
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
||||
$saved = new PhabricatorSavedQuery();
|
||||
|
||||
$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'));
|
||||
|
||||
return $saved;
|
||||
}
|
||||
|
||||
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
||||
$query = id(new PhabricatorCalendarEventQuery());
|
||||
|
||||
$min_range = null;
|
||||
$max_range = null;
|
||||
|
||||
if ($saved->getParameter('rangeStart')) {
|
||||
$min_range = $saved->getParameter('rangeStart');
|
||||
}
|
||||
|
||||
if ($saved->getParameter('rangeEnd')) {
|
||||
$max_range = $saved->getParameter('rangeEnd');
|
||||
}
|
||||
|
||||
if ($saved->getParameter('upcoming')) {
|
||||
if ($min_range) {
|
||||
$min_range = max(time(), $min_range);
|
||||
} else {
|
||||
$min_range = time();
|
||||
}
|
||||
}
|
||||
|
||||
if ($min_range || $max_range) {
|
||||
$query->withDateRange($min_range, $max_range);
|
||||
}
|
||||
|
||||
$invited_phids = $saved->getParameter('invitedPHIDs');
|
||||
if ($invited_phids) {
|
||||
$query->withInvitedPHIDs($invited_phids);
|
||||
}
|
||||
|
||||
$creator_phids = $saved->getParameter('creatorPHIDs');
|
||||
if ($creator_phids) {
|
||||
$query->withCreatorPHIDs($creator_phids);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function buildSearchForm(
|
||||
AphrontFormView $form,
|
||||
PhabricatorSavedQuery $saved) {
|
||||
|
||||
$range_start = $saved->getParameter('rangeStart');
|
||||
$range_end = $saved->getParameter('rangeEnd');
|
||||
$upcoming = $saved->getParameter('upcoming');
|
||||
|
||||
$invited_phids = $saved->getParameter('invitedPHIDs', array());
|
||||
$creator_phids = $saved->getParameter('creatorPHIDs', array());
|
||||
|
||||
$all_phids = array_merge(
|
||||
$invited_phids,
|
||||
$creator_phids);
|
||||
|
||||
if ($all_phids) {
|
||||
$handles = id(new PhabricatorHandleQuery())
|
||||
->setViewer($this->requireViewer())
|
||||
->withPHIDs($all_phids)
|
||||
->execute();
|
||||
} else {
|
||||
$handles = array();
|
||||
}
|
||||
|
||||
$invited_handles = array_select_keys($handles, $invited_phids);
|
||||
$creator_handles = array_select_keys($handles, $creator_phids);
|
||||
|
||||
$form
|
||||
->appendChild(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource('/typeahead/common/accounts/')
|
||||
->setName('creators')
|
||||
->setLabel(pht('Created By'))
|
||||
->setValue($creator_handles))
|
||||
->appendChild(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource('/typeahead/common/accounts/')
|
||||
->setName('invited')
|
||||
->setLabel(pht('Invited'))
|
||||
->setValue($invited_handles))
|
||||
->appendChild(
|
||||
id(new AphrontFormDateControl())
|
||||
->setLabel(pht('Occurs After'))
|
||||
->setUser($this->requireViewer())
|
||||
->setName('rangeStart')
|
||||
->setAllowNull(true)
|
||||
->setValue($range_start))
|
||||
->appendChild(
|
||||
id(new AphrontFormDateControl())
|
||||
->setLabel(pht('Occurs Before'))
|
||||
->setUser($this->requireViewer())
|
||||
->setName('rangeEnd')
|
||||
->setAllowNull(true)
|
||||
->setValue($range_end))
|
||||
->appendChild(
|
||||
id(new AphrontFormCheckboxControl())
|
||||
->addCheckbox(
|
||||
'upcoming',
|
||||
1,
|
||||
pht('Show only upcoming events.'),
|
||||
$upcoming));
|
||||
|
||||
}
|
||||
|
||||
protected function getURI($path) {
|
||||
return '/calendar/event/'.$path;
|
||||
}
|
||||
|
||||
public function getBuiltinQueryNames() {
|
||||
$names = array(
|
||||
'upcoming' => pht('Upcoming Events'),
|
||||
'all' => pht('All Events'),
|
||||
);
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
public function buildSavedQueryFromBuiltin($query_key) {
|
||||
|
||||
$query = $this->newSavedQuery();
|
||||
$query->setQueryKey($query_key);
|
||||
|
||||
switch ($query_key) {
|
||||
case 'upcoming':
|
||||
return $query->setParameter('upcoming', true);
|
||||
case 'all':
|
||||
return $query;
|
||||
}
|
||||
|
||||
return parent::buildSavedQueryFromBuiltin($query_key);
|
||||
}
|
||||
|
||||
}
|
|
@ -368,6 +368,17 @@ abstract class PhabricatorApplicationSearchEngine {
|
|||
return $list;
|
||||
}
|
||||
|
||||
protected function readDateFromRequest(
|
||||
AphrontRequest $request,
|
||||
$key) {
|
||||
|
||||
return id(new AphrontFormDateControl())
|
||||
->setUser($this->requireViewer())
|
||||
->setName($key)
|
||||
->setAllowNull(true)
|
||||
->readValueFromRequest($request);
|
||||
}
|
||||
|
||||
protected function readBoolFromRequest(
|
||||
AphrontRequest $request,
|
||||
$key) {
|
||||
|
|
|
@ -87,7 +87,7 @@ final class AphrontFormDateControl extends AphrontFormControl {
|
|||
$result = parent::setValue($epoch);
|
||||
|
||||
if ($epoch === null) {
|
||||
return;
|
||||
return $result;
|
||||
}
|
||||
|
||||
$readable = $this->formatTime($epoch, 'Y!m!d!g:i A');
|
||||
|
|
Loading…
Reference in a new issue