Add a date range query to Macros
Summary: Ref T1163. Ref T2625. This could probably use some tweaks, but I kept things mostly-generic. I added a new control for freeform dates so we can have it render help or whatever later on. Test Plan: See screenshots. Reviewers: chad, btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T2625, T1163 Differential Revision: https://secure.phabricator.com/D6084
This commit is contained in:
parent
32f91557f8
commit
bccc1e1244
2
resources/sql/patches/20130530.macrodatekey.sql
Normal file
2
resources/sql/patches/20130530.macrodatekey.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_file.file_imagemacro
|
||||||
|
ADD KEY `key_dateCreated` (dateCreated);
|
|
@ -677,6 +677,7 @@ phutil_register_library_map(array(
|
||||||
'PHUIFeedStoryExample' => 'applications/uiexample/examples/PHUIFeedStoryExample.php',
|
'PHUIFeedStoryExample' => 'applications/uiexample/examples/PHUIFeedStoryExample.php',
|
||||||
'PHUIFeedStoryView' => 'view/phui/PHUIFeedStoryView.php',
|
'PHUIFeedStoryView' => 'view/phui/PHUIFeedStoryView.php',
|
||||||
'PHUIFormDividerControl' => 'view/form/control/PHUIFormDividerControl.php',
|
'PHUIFormDividerControl' => 'view/form/control/PHUIFormDividerControl.php',
|
||||||
|
'PHUIFormFreeformDateControl' => 'view/form/control/PHUIFormFreeformDateControl.php',
|
||||||
'PHUIFormMultiSubmitControl' => 'view/form/control/PHUIFormMultiSubmitControl.php',
|
'PHUIFormMultiSubmitControl' => 'view/form/control/PHUIFormMultiSubmitControl.php',
|
||||||
'PHUIFormPageView' => 'view/form/PHUIFormPageView.php',
|
'PHUIFormPageView' => 'view/form/PHUIFormPageView.php',
|
||||||
'PHUIIconExample' => 'applications/uiexample/examples/PHUIIconExample.php',
|
'PHUIIconExample' => 'applications/uiexample/examples/PHUIIconExample.php',
|
||||||
|
@ -2470,6 +2471,7 @@ phutil_register_library_map(array(
|
||||||
'PHUIFeedStoryExample' => 'PhabricatorUIExample',
|
'PHUIFeedStoryExample' => 'PhabricatorUIExample',
|
||||||
'PHUIFeedStoryView' => 'AphrontView',
|
'PHUIFeedStoryView' => 'AphrontView',
|
||||||
'PHUIFormDividerControl' => 'AphrontFormControl',
|
'PHUIFormDividerControl' => 'AphrontFormControl',
|
||||||
|
'PHUIFormFreeformDateControl' => 'AphrontFormControl',
|
||||||
'PHUIFormMultiSubmitControl' => 'AphrontFormControl',
|
'PHUIFormMultiSubmitControl' => 'AphrontFormControl',
|
||||||
'PHUIFormPageView' => 'AphrontView',
|
'PHUIFormPageView' => 'AphrontView',
|
||||||
'PHUIIconExample' => 'PhabricatorUIExample',
|
'PHUIIconExample' => 'PhabricatorUIExample',
|
||||||
|
|
|
@ -11,6 +11,8 @@ final class PhabricatorMacroQuery
|
||||||
private $authors;
|
private $authors;
|
||||||
private $names;
|
private $names;
|
||||||
private $nameLike;
|
private $nameLike;
|
||||||
|
private $dateCreatedAfter;
|
||||||
|
private $dateCreatedBefore;
|
||||||
|
|
||||||
private $status = 'status-any';
|
private $status = 'status-any';
|
||||||
const STATUS_ANY = 'status-any';
|
const STATUS_ANY = 'status-any';
|
||||||
|
@ -55,6 +57,16 @@ final class PhabricatorMacroQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withDateCreatedBefore($date_created_before) {
|
||||||
|
$this->dateCreatedBefore = $date_created_before;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withDateCreatedAfter($date_created_after) {
|
||||||
|
$this->dateCreatedAfter = $date_created_after;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
protected function loadPage() {
|
protected function loadPage() {
|
||||||
$macro_table = new PhabricatorFileImageMacro();
|
$macro_table = new PhabricatorFileImageMacro();
|
||||||
$conn = $macro_table->establishConnection('r');
|
$conn = $macro_table->establishConnection('r');
|
||||||
|
@ -125,6 +137,20 @@ final class PhabricatorMacroQuery
|
||||||
throw new Exception("Unknown status '{$this->status}'!");
|
throw new Exception("Unknown status '{$this->status}'!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->dateCreatedAfter) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'm.dateCreated >= %d',
|
||||||
|
$this->dateCreatedAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->dateCreatedBefore) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'm.dateCreated <= %d',
|
||||||
|
$this->dateCreatedBefore);
|
||||||
|
}
|
||||||
|
|
||||||
$where[] = $this->buildPagingClause($conn);
|
$where[] = $this->buildPagingClause($conn);
|
||||||
|
|
||||||
return $this->formatWhereClause($where);
|
return $this->formatWhereClause($where);
|
||||||
|
|
|
@ -12,6 +12,8 @@ final class PhabricatorMacroSearchEngine
|
||||||
$saved->setParameter('status', $request->getStr('status'));
|
$saved->setParameter('status', $request->getStr('status'));
|
||||||
$saved->setParameter('names', $request->getStrList('names'));
|
$saved->setParameter('names', $request->getStrList('names'));
|
||||||
$saved->setParameter('nameLike', $request->getStr('nameLike'));
|
$saved->setParameter('nameLike', $request->getStr('nameLike'));
|
||||||
|
$saved->setParameter('createdStart', $request->getStr('createdStart'));
|
||||||
|
$saved->setParameter('createdEnd', $request->getStr('createdEnd'));
|
||||||
|
|
||||||
return $saved;
|
return $saved;
|
||||||
}
|
}
|
||||||
|
@ -39,6 +41,17 @@ final class PhabricatorMacroSearchEngine
|
||||||
$query->withNameLike($like);
|
$query->withNameLike($like);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$start = $this->parseDateTime($saved->getParameter('createdStart'));
|
||||||
|
$end = $this->parseDateTime($saved->getParameter('createdEnd'));
|
||||||
|
|
||||||
|
if ($start) {
|
||||||
|
$query->withDateCreatedAfter($start);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($end) {
|
||||||
|
$query->withDateCreatedBefore($end);
|
||||||
|
}
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +92,14 @@ final class PhabricatorMacroSearchEngine
|
||||||
->setName('names')
|
->setName('names')
|
||||||
->setLabel(pht('Exact Names'))
|
->setLabel(pht('Exact Names'))
|
||||||
->setValue($names));
|
->setValue($names));
|
||||||
|
|
||||||
|
$this->buildDateRange(
|
||||||
|
$form,
|
||||||
|
$saved_query,
|
||||||
|
'createdStart',
|
||||||
|
pht('Created After'),
|
||||||
|
'createdEnd',
|
||||||
|
pht('Created Before'));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getURI($path) {
|
protected function getURI($path) {
|
||||||
|
|
|
@ -131,6 +131,14 @@ final class PhabricatorApplicationSearchController
|
||||||
|
|
||||||
$engine->buildSearchForm($form, $saved_query);
|
$engine->buildSearchForm($form, $saved_query);
|
||||||
|
|
||||||
|
$errors = $engine->getErrors();
|
||||||
|
if ($errors) {
|
||||||
|
$run_query = false;
|
||||||
|
$errors = id(new AphrontErrorView())
|
||||||
|
->setTitle(pht('Query Errors'))
|
||||||
|
->setErrors($errors);
|
||||||
|
}
|
||||||
|
|
||||||
$submit = id(new AphrontFormSubmitControl())
|
$submit = id(new AphrontFormSubmitControl())
|
||||||
->setValue(pht('Execute Query'));
|
->setValue(pht('Execute Query'));
|
||||||
|
|
||||||
|
@ -184,6 +192,10 @@ final class PhabricatorApplicationSearchController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($errors) {
|
||||||
|
$nav->appendChild($errors);
|
||||||
|
}
|
||||||
|
|
||||||
if ($named_query) {
|
if ($named_query) {
|
||||||
$title = pht('Query: %s', $named_query->getQueryName());
|
$title = pht('Query: %s', $named_query->getQueryName());
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -6,12 +6,14 @@
|
||||||
*
|
*
|
||||||
* @task builtin Builtin Queries
|
* @task builtin Builtin Queries
|
||||||
* @task uri Query URIs
|
* @task uri Query URIs
|
||||||
|
* @task dates Date Filters
|
||||||
*
|
*
|
||||||
* @group search
|
* @group search
|
||||||
*/
|
*/
|
||||||
abstract class PhabricatorApplicationSearchEngine {
|
abstract class PhabricatorApplicationSearchEngine {
|
||||||
|
|
||||||
private $viewer;
|
private $viewer;
|
||||||
|
private $errors = array();
|
||||||
|
|
||||||
public function setViewer(PhabricatorUser $viewer) {
|
public function setViewer(PhabricatorUser $viewer) {
|
||||||
$this->viewer = $viewer;
|
$this->viewer = $viewer;
|
||||||
|
@ -54,6 +56,14 @@ abstract class PhabricatorApplicationSearchEngine {
|
||||||
AphrontFormView $form,
|
AphrontFormView $form,
|
||||||
PhabricatorSavedQuery $query);
|
PhabricatorSavedQuery $query);
|
||||||
|
|
||||||
|
public function getErrors() {
|
||||||
|
return $this->errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addError($error) {
|
||||||
|
$this->errors[] = $error;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an application URI corresponding to the results page of a query.
|
* Return an application URI corresponding to the results page of a query.
|
||||||
|
@ -182,4 +192,88 @@ abstract class PhabricatorApplicationSearchEngine {
|
||||||
public function buildSavedQueryFromBuiltin($query_key) {
|
public function buildSavedQueryFromBuiltin($query_key) {
|
||||||
throw new Exception("Builtin '{$query_key}' is not supported!");
|
throw new Exception("Builtin '{$query_key}' is not supported!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Dates )-------------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task dates
|
||||||
|
*/
|
||||||
|
protected function parseDateTime($date_time) {
|
||||||
|
if (!strlen($date_time)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
|
$timezone = new DateTimeZone($viewer->getTimezoneIdentifier());
|
||||||
|
|
||||||
|
try {
|
||||||
|
$date = new DateTime($date_time, $timezone);
|
||||||
|
$timestamp = $date->format('U');
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$timestamp = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task dates
|
||||||
|
*/
|
||||||
|
protected function buildDateRange(
|
||||||
|
AphrontFormView $form,
|
||||||
|
PhabricatorSavedQuery $saved_query,
|
||||||
|
$start_key,
|
||||||
|
$start_name,
|
||||||
|
$end_key,
|
||||||
|
$end_name) {
|
||||||
|
|
||||||
|
$start_str = $saved_query->getParameter($start_key);
|
||||||
|
$start = null;
|
||||||
|
if (strlen($start_str)) {
|
||||||
|
$start = $this->parseDateTime($start_str);
|
||||||
|
if (!$start) {
|
||||||
|
$this->addError(
|
||||||
|
pht(
|
||||||
|
'"%s" date can not be parsed.',
|
||||||
|
$start_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$end_str = $saved_query->getParameter($end_key);
|
||||||
|
$end = null;
|
||||||
|
if (strlen($end_str)) {
|
||||||
|
$end = $this->parseDateTime($end_str);
|
||||||
|
if (!$end) {
|
||||||
|
$this->addError(
|
||||||
|
pht(
|
||||||
|
'"%s" date can not be parsed.',
|
||||||
|
$end_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($start && $end && ($start >= $end)) {
|
||||||
|
$this->addError(
|
||||||
|
pht(
|
||||||
|
'"%s" must be a date before "%s".',
|
||||||
|
$start_name,
|
||||||
|
$end_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
$form
|
||||||
|
->appendChild(
|
||||||
|
id(new PHUIFormFreeformDateControl())
|
||||||
|
->setName($start_key)
|
||||||
|
->setLabel($start_name)
|
||||||
|
->setValue($start_str))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setName($end_key)
|
||||||
|
->setLabel($end_name)
|
||||||
|
->setValue($end_str));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1330,6 +1330,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
||||||
'type' => 'php',
|
'type' => 'php',
|
||||||
'name' => $this->getPatchPath('20130530.sessionhash.php'),
|
'name' => $this->getPatchPath('20130530.sessionhash.php'),
|
||||||
),
|
),
|
||||||
|
'20130530.macrodatekey.sql' => array(
|
||||||
|
'type' => 'sql',
|
||||||
|
'name' => $this->getPatchPath('20130530.macrodatekey.sql'),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
21
src/view/form/control/PHUIFormFreeformDateControl.php
Normal file
21
src/view/form/control/PHUIFormFreeformDateControl.php
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PHUIFormFreeformDateControl extends AphrontFormControl {
|
||||||
|
|
||||||
|
protected function getCustomControlClass() {
|
||||||
|
return 'aphront-form-control-text';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderInput() {
|
||||||
|
return javelin_tag(
|
||||||
|
'input',
|
||||||
|
array(
|
||||||
|
'type' => 'text',
|
||||||
|
'name' => $this->getName(),
|
||||||
|
'value' => $this->getValue(),
|
||||||
|
'disabled' => $this->getDisabled() ? 'disabled' : null,
|
||||||
|
'id' => $this->getID(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue