mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 00:32:42 +01:00
Improve search functionality.
Summary: Test Plan: Reviewers: CC:
This commit is contained in:
parent
eec3e8e3aa
commit
505c82236d
14 changed files with 232 additions and 22 deletions
|
@ -26,6 +26,20 @@ class ManiphestTaskSelectorSearchController extends ManiphestController {
|
|||
$query->setQuery($request->getStr('query'));
|
||||
$query->setParameter('type', 'TASK');
|
||||
|
||||
switch ($request->getStr('filter')) {
|
||||
case 'assigned':
|
||||
$query->setParameter('owner', array($user->getPHID()));
|
||||
$query->setParameter('open', 1);
|
||||
break;
|
||||
case 'created';
|
||||
$query->setParameter('author', array($user->getPHID()));
|
||||
$query->setParameter('open', 1);
|
||||
break;
|
||||
case 'open':
|
||||
$query->setParameter('open', 1);
|
||||
break;
|
||||
}
|
||||
|
||||
$exec = new PhabricatorSearchMySQLExecutor();
|
||||
$results = $exec->executeSearch($query);
|
||||
$results = ipull($results, 'phid');
|
||||
|
|
|
@ -29,7 +29,7 @@ class PhabricatorHandleObjectSelectorDataView {
|
|||
return array(
|
||||
'phid' => $handle->getPHID(),
|
||||
'name' => $handle->getFullName(),
|
||||
'href' => $handle->getURI(),
|
||||
'uri' => $handle->getURI(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,5 +21,6 @@ final class PhabricatorSearchField {
|
|||
const FIELD_TITLE = 'titl';
|
||||
const FIELD_BODY = 'body';
|
||||
const FIELD_TEST_PLAN = 'tpln';
|
||||
const FIELD_COMMENT = 'cmnt';
|
||||
|
||||
}
|
||||
|
|
|
@ -22,5 +22,9 @@ final class PhabricatorSearchRelationship {
|
|||
const RELATIONSHIP_REVIEWER = 'revw';
|
||||
const RELATIONSHIP_SUBSCRIBER = 'subs';
|
||||
const RELATIONSHIP_COMMENTER = 'comm';
|
||||
const RELATIONSHIP_OWNER = 'ownr';
|
||||
|
||||
const RELATIONSHIP_OPEN = 'open';
|
||||
const RELATIONSHIP_TOUCH = 'poke';
|
||||
|
||||
}
|
||||
|
|
|
@ -38,12 +38,47 @@ class PhabricatorSearchController extends PhabricatorSearchBaseController {
|
|||
|
||||
if ($request->isFormPost()) {
|
||||
$query->setQuery($request->getStr('query'));
|
||||
|
||||
if (strlen($request->getStr('type'))) {
|
||||
$query->setParameter('type', $request->getStr('type'));
|
||||
}
|
||||
|
||||
if ($request->getArr('author')) {
|
||||
$query->setParameter('author', $request->getArr('author'));
|
||||
}
|
||||
|
||||
if ($request->getInt('open')) {
|
||||
$query->setParameter('open', $request->getInt('open'));
|
||||
}
|
||||
|
||||
$query->save();
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/search/'.$query->getID().'/');
|
||||
}
|
||||
}
|
||||
|
||||
$options = array(
|
||||
'' => 'All Documents',
|
||||
'DREV' => 'Differential Revisions',
|
||||
'TASK' => 'Maniphest Tasks',
|
||||
);
|
||||
|
||||
$status_options = array(
|
||||
0 => 'Open and Closed Documents',
|
||||
1 => 'Open Documents',
|
||||
);
|
||||
|
||||
$phids = array_merge(
|
||||
$query->getParameter('author', array())
|
||||
);
|
||||
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))
|
||||
->loadHandles();
|
||||
|
||||
$author_value = array_select_keys(
|
||||
$handles,
|
||||
$query->getParameter('author', array()));
|
||||
$author_value = mpull($author_value, 'getFullName', 'getPHID');
|
||||
|
||||
$search_form = new AphrontFormView();
|
||||
$search_form
|
||||
|
@ -54,6 +89,24 @@ class PhabricatorSearchController extends PhabricatorSearchBaseController {
|
|||
->setLabel('Search')
|
||||
->setName('query')
|
||||
->setValue($query->getQuery()))
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setLabel('Document Type')
|
||||
->setName('type')
|
||||
->setOptions($options)
|
||||
->setValue($query->getParameter('type')))
|
||||
->appendChild(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setName('author')
|
||||
->setLabel('Author')
|
||||
->setDatasource('/typeahead/common/users/')
|
||||
->setValue($author_value))
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setLabel('Document Status')
|
||||
->setName('open')
|
||||
->setOptions($status_options)
|
||||
->setValue($query->getParameter('open')))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue('Search'));
|
||||
|
|
|
@ -60,18 +60,33 @@ class PhabricatorSearchMySQLExecutor extends PhabricatorSearchExecutor {
|
|||
}
|
||||
|
||||
if ($query->getParameter('type')) {
|
||||
if (strlen($q)) {
|
||||
// TODO: verify that this column actually does something useful in query
|
||||
// plans once we have nontrivial amounts of data.
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'field.phidType = %s',
|
||||
$query->getParameter('type'));
|
||||
}
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'document.documentType = %s',
|
||||
$query->getParameter('type'));
|
||||
}
|
||||
|
||||
/*
|
||||
$join[] = $this->joinRelationship(
|
||||
$conn_r,
|
||||
$query,
|
||||
'author',
|
||||
AdjutantRelationship::RELATIONSHIP_AUTHOR);
|
||||
PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR);
|
||||
|
||||
$join[] = $this->joinRelationship(
|
||||
$conn_r,
|
||||
$query,
|
||||
'open',
|
||||
PhabricatorSearchRelationship::RELATIONSHIP_OPEN);
|
||||
|
||||
/*
|
||||
$join[] = $this->joinRelationship(
|
||||
$conn_r,
|
||||
$query,
|
||||
|
@ -118,20 +133,36 @@ class PhabricatorSearchMySQLExecutor extends PhabricatorSearchExecutor {
|
|||
}
|
||||
|
||||
protected function joinRelationship($conn, $query, $field, $type) {
|
||||
$fbids = $query->getParameter($field, array());
|
||||
if (!$fbids) {
|
||||
$phids = $query->getParameter($field, array());
|
||||
if (!$phids) {
|
||||
return null;
|
||||
}
|
||||
return qsprintf(
|
||||
|
||||
$is_existence = false;
|
||||
switch ($type) {
|
||||
case PhabricatorSearchRelationship::RELATIONSHIP_OPEN:
|
||||
$is_existence = true;
|
||||
break;
|
||||
}
|
||||
|
||||
$sql = qsprintf(
|
||||
$conn,
|
||||
'relationship AS %C ON %C.fbid = data.fbid AND %C.relation = %s
|
||||
AND %C.relatedFBID in (%Ld)',
|
||||
'%T AS %C ON %C.phid = document.phid AND %C.relation = %s',
|
||||
id(new PhabricatorSearchDocumentRelationship())->getTableName(),
|
||||
$field,
|
||||
$field,
|
||||
$field,
|
||||
$type,
|
||||
$type);
|
||||
|
||||
if (!$is_existence) {
|
||||
$sql .= qsprintf(
|
||||
$conn,
|
||||
' AND %C.relatedPHID in (%Ls)',
|
||||
$field,
|
||||
$fbids);
|
||||
$phids);
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -6,11 +6,15 @@
|
|||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/search/constants/relationship');
|
||||
phutil_require_module('phabricator', 'applications/search/execute/base');
|
||||
phutil_require_module('phabricator', 'applications/search/storage/document/document');
|
||||
phutil_require_module('phabricator', 'applications/search/storage/document/field');
|
||||
phutil_require_module('phabricator', 'applications/search/storage/document/relationship');
|
||||
phutil_require_module('phabricator', 'storage/qsprintf');
|
||||
phutil_require_module('phabricator', 'storage/queryfx');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorSearchMySQLExecutor.php');
|
||||
|
|
|
@ -47,8 +47,8 @@ final class PhabricatorSearchAbstractDocument {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function addRelationship($type, $related_phid) {
|
||||
$this->relationships[] = array($type, $related_phid);
|
||||
public function addRelationship($type, $related_phid, $rtype, $time) {
|
||||
$this->relationships[] = array($type, $related_phid, $rtype, $time);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,9 @@ class PhabricatorSearchDifferentialIndexer
|
|||
|
||||
$doc->addRelationship(
|
||||
PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR,
|
||||
$rev->getAuthorPHID());
|
||||
$rev->getAuthorPHID(),
|
||||
'USER',
|
||||
$rev->getDateCreated());
|
||||
|
||||
PhabricatorSearchDocument::reindexAbstractDocument($doc);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,87 @@ class PhabricatorSearchManiphestIndexer
|
|||
|
||||
$doc->addRelationship(
|
||||
PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR,
|
||||
$task->getAuthorPHID());
|
||||
$task->getAuthorPHID(),
|
||||
'USER',
|
||||
$task->getDateCreated());
|
||||
|
||||
if ($task->getStatus() == ManiphestTaskStatus::STATUS_OPEN) {
|
||||
$doc->addRelationship(
|
||||
PhabricatorSearchRelationship::RELATIONSHIP_OPEN,
|
||||
$task->getPHID(),
|
||||
'TASK',
|
||||
time());
|
||||
}
|
||||
|
||||
$transactions = id(new ManiphestTransaction())->loadAllWhere(
|
||||
'taskID = %d',
|
||||
$task->getID());
|
||||
|
||||
$current_ccs = $task->getCCPHIDs();
|
||||
$touches = array();
|
||||
$owner = null;
|
||||
$ccs = array();
|
||||
foreach ($transactions as $transaction) {
|
||||
if ($transaction->hasComments()) {
|
||||
$doc->addField(
|
||||
PhabricatorSearchField::FIELD_COMMENT,
|
||||
$transaction->getComments());
|
||||
}
|
||||
|
||||
$author = $transaction->getAuthorPHID();
|
||||
|
||||
// Record the most recent time they touched this object.
|
||||
$touches[$author] = $transaction->getDateCreated();
|
||||
|
||||
switch ($transaction->getTransactionType()) {
|
||||
case ManiphestTransactionType::TYPE_OWNER:
|
||||
$owner = $transaction;
|
||||
break;
|
||||
case ManiphestTransactionType::TYPE_CCS:
|
||||
// For users who are still CC'd, record the first time they were
|
||||
// added to CC.
|
||||
foreach ($transaction->getNewValue() as $added_cc) {
|
||||
if (in_array($added_cc, $current_ccs)) {
|
||||
if (empty($ccs[$added_cc])) {
|
||||
$ccs[$added_cc] = $transaction->getDateCreated();
|
||||
|
||||
// CCs count as touches, even if you didn't technically
|
||||
// interact with the object directly.
|
||||
$touches[$added_cc] = $transaction->getDateCreated();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($owner && $owner->getNewValue()) {
|
||||
$doc->addRelationship(
|
||||
PhabricatorSearchRelationship::RELATIONSHIP_OWNER,
|
||||
$owner->getNewValue(),
|
||||
'USER',
|
||||
$owner->getDateCreated());
|
||||
}
|
||||
|
||||
foreach ($touches as $touch => $time) {
|
||||
$doc->addRelationship(
|
||||
PhabricatorSearchRelationship::RELATIONSHIP_TOUCH,
|
||||
$touch,
|
||||
'USER',
|
||||
$time);
|
||||
}
|
||||
|
||||
// We need to load handles here since non-users may subscribe (mailing
|
||||
// lists, e.g.)
|
||||
$handles = id(new PhabricatorObjectHandleData(array_keys($ccs)))
|
||||
->loadHandles();
|
||||
foreach ($ccs as $cc => $time) {
|
||||
$doc->addRelationship(
|
||||
PhabricatorSearchRelationship::RELATIONSHIP_SUBSCRIBER,
|
||||
$handles[$cc]->getPHID(),
|
||||
$handles[$cc]->getType(),
|
||||
$time);
|
||||
}
|
||||
|
||||
PhabricatorSearchDocument::reindexAbstractDocument($doc);
|
||||
}
|
||||
|
|
|
@ -6,11 +6,17 @@
|
|||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/maniphest/constants/status');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/constants/transactiontype');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/storage/transaction');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'applications/search/constants/field');
|
||||
phutil_require_module('phabricator', 'applications/search/constants/relationship');
|
||||
phutil_require_module('phabricator', 'applications/search/index/abstractdocument');
|
||||
phutil_require_module('phabricator', 'applications/search/index/indexer/base');
|
||||
phutil_require_module('phabricator', 'applications/search/storage/document/document');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorSearchManiphestIndexer.php');
|
||||
|
|
|
@ -63,10 +63,11 @@ class PhabricatorSearchDocument extends PhabricatorSearchDAO {
|
|||
list($ftype, $corpus, $aux_phid) = $field;
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'INSERT INTO %T (phid, field, auxPHId, corpus) '.
|
||||
' VALUES (%s, %s, %ns, %s)',
|
||||
'INSERT INTO %T (phid, phidType, field, auxPHID, corpus) '.
|
||||
' VALUES (%s, %s, %s, %ns, %s)',
|
||||
$field_dao->getTableName(),
|
||||
$phid,
|
||||
$doc->getDocumentType(),
|
||||
$ftype,
|
||||
$aux_phid,
|
||||
$corpus);
|
||||
|
@ -75,13 +76,15 @@ class PhabricatorSearchDocument extends PhabricatorSearchDAO {
|
|||
|
||||
$sql = array();
|
||||
foreach ($doc->getRelationshipData() as $relationship) {
|
||||
list($rtype, $toPHID) = $relationship;
|
||||
list($rtype, $to_phid, $to_type, $time) = $relationship;
|
||||
$sql[] = qsprintf(
|
||||
$conn_w,
|
||||
'(%s, %s, %s)',
|
||||
'(%s, %s, %s, %s, %d)',
|
||||
$phid,
|
||||
$toPHID,
|
||||
$rtype);
|
||||
$to_phid,
|
||||
$rtype,
|
||||
$to_type,
|
||||
$time);
|
||||
}
|
||||
|
||||
$rship_dao = new PhabricatorSearchDocumentRelationship();
|
||||
|
@ -93,7 +96,8 @@ class PhabricatorSearchDocument extends PhabricatorSearchDAO {
|
|||
if ($sql) {
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'INSERT INTO %T (phid, relatedPHID, relation) '.
|
||||
'INSERT INTO %T'.
|
||||
' (phid, relatedPHID, relation, relatedType, relatedTime) '.
|
||||
' VALUES %Q',
|
||||
$rship_dao->getTableName(),
|
||||
implode(', ', $sql));
|
||||
|
|
|
@ -21,6 +21,8 @@ class PhabricatorSearchDocumentRelationship extends PhabricatorSearchDAO {
|
|||
protected $phid;
|
||||
protected $relatedPHID;
|
||||
protected $relation;
|
||||
protected $relatedType;
|
||||
protected $relatedTime;
|
||||
|
||||
public function getConfiguration() {
|
||||
return array(
|
||||
|
|
|
@ -111,6 +111,15 @@ JX.behavior('phabricator-object-selector', function(config) {
|
|||
e.kill();
|
||||
sendQuery();
|
||||
});
|
||||
JX.DOM.listen(
|
||||
JX.$(config.search),
|
||||
'click',
|
||||
'tag:button',
|
||||
function(e) {
|
||||
e.kill();
|
||||
sendQuery();
|
||||
});
|
||||
|
||||
|
||||
JX.DOM.listen(
|
||||
JX.$(config.results),
|
||||
|
|
Loading…
Reference in a new issue