mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-18 02:31:10 +01:00
Enhance Maniphest custom queries
Summary: Improve the custom query interface: - Allow search for tasks not in projects. - Allow search for tasks with no projects. - Allow custom search to include author/owner constraints. Test Plan: Searched for various sorts of tasks. Reviewers: btrahan Reviewed By: btrahan CC: aran, epriestley Maniphest Tasks: T911 Differential Revision: https://secure.phabricator.com/D1722
This commit is contained in:
parent
280d7cd294
commit
4117cdbdfb
5 changed files with 171 additions and 45 deletions
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -22,5 +22,6 @@
|
|||
final class ManiphestTaskOwner extends ManiphestConstants {
|
||||
|
||||
const OWNER_UP_FOR_GRABS = 'PHID-!!!!-UP-FOR-GRABS';
|
||||
const PROJECT_NO_PROJECT = 'PHID-!!!!-NO-PROJECT';
|
||||
|
||||
}
|
||||
|
|
|
@ -29,6 +29,12 @@ class ManiphestTaskListController extends ManiphestController {
|
|||
$this->view = idx($data, 'view');
|
||||
}
|
||||
|
||||
private function getArrToStrList($key) {
|
||||
$arr = $this->getRequest()->getArr($key);
|
||||
$arr = implode(',', $arr);
|
||||
return nonempty($arr, null);
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
|
||||
$request = $this->getRequest();
|
||||
|
@ -37,18 +43,15 @@ class ManiphestTaskListController extends ManiphestController {
|
|||
if ($request->isFormPost()) {
|
||||
// Redirect to GET so URIs can be copy/pasted.
|
||||
|
||||
$user_phids = $request->getArr('set_users');
|
||||
$proj_phids = $request->getArr('set_projects');
|
||||
$task_ids = $request->getStr('set_tasks');
|
||||
$user_phids = implode(',', $user_phids);
|
||||
$proj_phids = implode(',', $proj_phids);
|
||||
$user_phids = nonempty($user_phids, null);
|
||||
$proj_phids = nonempty($proj_phids, null);
|
||||
$task_ids = nonempty($task_ids, null);
|
||||
|
||||
$uri = $request->getRequestURI()
|
||||
->alter('users', $user_phids)
|
||||
->alter('projects', $proj_phids)
|
||||
->alter('users', $this->getArrToStrList('set_users'))
|
||||
->alter('projects', $this->getArrToStrList('set_projects'))
|
||||
->alter('xprojects', $this->getArrToStrList('set_xprojects'))
|
||||
->alter('owners', $this->getArrToStrList('set_owners'))
|
||||
->alter('authors', $this->getArrToStrList('set_authors'))
|
||||
->alter('tasks', $task_ids);
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($uri);
|
||||
|
@ -66,7 +69,8 @@ class ManiphestTaskListController extends ManiphestController {
|
|||
$nav->addFilter('alltriage', 'Need Triage');
|
||||
$nav->addFilter('all', 'All Tasks');
|
||||
$nav->addSpacer();
|
||||
$nav->addFilter('custom', 'Custom');
|
||||
$nav->addLabel('Custom');
|
||||
$nav->addFilter('custom', 'Custom Query');
|
||||
|
||||
$this->view = $nav->selectFilter($this->view, 'action');
|
||||
|
||||
|
@ -81,21 +85,12 @@ class ManiphestTaskListController extends ManiphestController {
|
|||
list($grouping, $group_control) = $this->renderGroupLinks();
|
||||
list($order, $order_control) = $this->renderOrderLinks();
|
||||
|
||||
$user_phids = $request->getStr('users');
|
||||
if (strlen($user_phids)) {
|
||||
$user_phids = explode(',', $user_phids);
|
||||
} else {
|
||||
$user_phids = array($user->getPHID());
|
||||
}
|
||||
|
||||
$project_phids = $request->getStr('projects');
|
||||
if (strlen($project_phids)) {
|
||||
$project_phids = explode(',', $project_phids);
|
||||
} else {
|
||||
$project_phids = array();
|
||||
}
|
||||
|
||||
$user_phids = $request->getStrList('users');
|
||||
$project_phids = $request->getStrList('projects');
|
||||
$exclude_project_phids = $request->getStrList('xprojects');
|
||||
$task_ids = $request->getStrList('tasks');
|
||||
$owner_phids = $request->getStrList('owners');
|
||||
$author_phids = $request->getStrList('authors');
|
||||
|
||||
$page = $request->getInt('page');
|
||||
$page_size = self::DEFAULT_PAGE_SIZE;
|
||||
|
@ -107,6 +102,9 @@ class ManiphestTaskListController extends ManiphestController {
|
|||
'view' => $this->view,
|
||||
'userPHIDs' => $user_phids,
|
||||
'projectPHIDs' => $project_phids,
|
||||
'excludeProjectPHIDs' => $exclude_project_phids,
|
||||
'ownerPHIDs' => $owner_phids,
|
||||
'authorPHIDs' => $author_phids,
|
||||
'taskIDs' => $task_ids,
|
||||
'group' => $grouping,
|
||||
'order' => $order,
|
||||
|
@ -145,6 +143,28 @@ class ManiphestTaskListController extends ManiphestController {
|
|||
->setLabel('Task IDs')
|
||||
->setValue(join(',', $task_ids))
|
||||
);
|
||||
|
||||
$tokens = array();
|
||||
foreach ($owner_phids as $phid) {
|
||||
$tokens[$phid] = $handles[$phid]->getFullName();
|
||||
}
|
||||
$form->appendChild(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource('/typeahead/common/searchowner/')
|
||||
->setName('set_owners')
|
||||
->setLabel('Owners')
|
||||
->setValue($tokens));
|
||||
|
||||
$tokens = array();
|
||||
foreach ($author_phids as $phid) {
|
||||
$tokens[$phid] = $handles[$phid]->getFullName();
|
||||
}
|
||||
$form->appendChild(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource('/typeahead/common/users/')
|
||||
->setName('set_authors')
|
||||
->setLabel('Authors')
|
||||
->setValue($tokens));
|
||||
}
|
||||
|
||||
$tokens = array();
|
||||
|
@ -153,11 +173,24 @@ class ManiphestTaskListController extends ManiphestController {
|
|||
}
|
||||
$form->appendChild(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource('/typeahead/common/projects/')
|
||||
->setDatasource('/typeahead/common/searchproject/')
|
||||
->setName('set_projects')
|
||||
->setLabel('Projects')
|
||||
->setValue($tokens));
|
||||
|
||||
if ($this->view == 'custom') {
|
||||
$tokens = array();
|
||||
foreach ($exclude_project_phids as $phid) {
|
||||
$tokens[$phid] = $handles[$phid]->getFullName();
|
||||
}
|
||||
$form->appendChild(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource('/typeahead/common/projects/')
|
||||
->setName('set_xprojects')
|
||||
->setLabel('Exclude Projects')
|
||||
->setValue($tokens));
|
||||
}
|
||||
|
||||
$form
|
||||
->appendChild($status_control)
|
||||
->appendChild($group_control)
|
||||
|
@ -266,11 +299,28 @@ class ManiphestTaskListController extends ManiphestController {
|
|||
$user_phids = $search_query->getParameter('userPHIDs', array());
|
||||
$project_phids = $search_query->getParameter('projectPHIDs', array());
|
||||
$task_ids = $search_query->getParameter('taskIDs', array());
|
||||
$xproject_phids = $search_query->getParameter(
|
||||
'excludeProjectPHIDs',
|
||||
array());
|
||||
$owner_phids = $search_query->getParameter('ownerPHIDs', array());
|
||||
$author_phids = $search_query->getParameter('authorPHIDs', array());
|
||||
|
||||
$query = new ManiphestTaskQuery();
|
||||
$query->withProjects($project_phids);
|
||||
$query->withTaskIDs($task_ids);
|
||||
|
||||
if ($xproject_phids) {
|
||||
$query->withoutProjects($xproject_phids);
|
||||
}
|
||||
|
||||
if ($owner_phids) {
|
||||
$query->withOwners($owner_phids);
|
||||
}
|
||||
|
||||
if ($author_phids) {
|
||||
$query->withAuthors($author_phids);
|
||||
}
|
||||
|
||||
$status = $search_query->getParameter('status', 'all');
|
||||
if (!empty($status['open']) && !empty($status['closed'])) {
|
||||
$query->withStatus(ManiphestTaskQuery::STATUS_ANY);
|
||||
|
@ -330,7 +380,13 @@ class ManiphestTaskListController extends ManiphestController {
|
|||
$total_row_count = $query->getRowCount();
|
||||
|
||||
$handle_phids = mpull($data, 'getOwnerPHID');
|
||||
$handle_phids = array_merge($handle_phids, $project_phids, $user_phids);
|
||||
$handle_phids = array_merge(
|
||||
$handle_phids,
|
||||
$project_phids,
|
||||
$user_phids,
|
||||
$xproject_phids,
|
||||
$owner_phids,
|
||||
$author_phids);
|
||||
$handles = id(new PhabricatorObjectHandleData($handle_phids))
|
||||
->loadHandles();
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -29,8 +29,10 @@ final class ManiphestTaskQuery {
|
|||
private $ownerPHIDs = array();
|
||||
private $includeUnowned = null;
|
||||
private $projectPHIDs = array();
|
||||
private $xprojectPHIDs = array();
|
||||
private $subscriberPHIDs = array();
|
||||
private $anyProject = false;
|
||||
private $includeNoProject = null;
|
||||
|
||||
private $status = 'status-any';
|
||||
const STATUS_ANY = 'status-any';
|
||||
|
@ -83,10 +85,22 @@ final class ManiphestTaskQuery {
|
|||
}
|
||||
|
||||
public function withProjects(array $projects) {
|
||||
$this->includeNoProject = false;
|
||||
foreach ($projects as $k => $phid) {
|
||||
if ($phid == ManiphestTaskOwner::PROJECT_NO_PROJECT) {
|
||||
$this->includeNoProject = true;
|
||||
unset($projects[$k]);
|
||||
}
|
||||
}
|
||||
$this->projectPHIDs = $projects;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withoutProjects(array $projects) {
|
||||
$this->xprojectPHIDs = $projects;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withStatus($status) {
|
||||
$this->status = $status;
|
||||
return $this;
|
||||
|
@ -160,6 +174,7 @@ final class ManiphestTaskQuery {
|
|||
$where[] = $this->buildOwnerWhereClause($conn);
|
||||
$where[] = $this->buildSubscriberWhereClause($conn);
|
||||
$where[] = $this->buildProjectWhereClause($conn);
|
||||
$where[] = $this->buildXProjectWhereClause($conn);
|
||||
|
||||
$where = array_filter($where);
|
||||
if ($where) {
|
||||
|
@ -170,6 +185,7 @@ final class ManiphestTaskQuery {
|
|||
|
||||
$join = array();
|
||||
$join[] = $this->buildProjectJoinClause($conn);
|
||||
$join[] = $this->buildXProjectJoinClause($conn);
|
||||
$join[] = $this->buildSubscriberJoinClause($conn);
|
||||
|
||||
$join = array_filter($join);
|
||||
|
@ -195,7 +211,7 @@ final class ManiphestTaskQuery {
|
|||
$group = 'GROUP BY task.id';
|
||||
|
||||
if (!$this->anyProject) {
|
||||
$count = ', COUNT(1) projectCount';
|
||||
$count = ', COUNT(project.projectPHID) projectCount';
|
||||
$having = qsprintf(
|
||||
$conn,
|
||||
'HAVING projectCount = %d',
|
||||
|
@ -320,28 +336,63 @@ final class ManiphestTaskQuery {
|
|||
}
|
||||
|
||||
private function buildProjectWhereClause($conn) {
|
||||
if (!$this->projectPHIDs) {
|
||||
if (!$this->projectPHIDs && !$this->includeNoProject) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return qsprintf(
|
||||
$parts = array();
|
||||
if ($this->projectPHIDs) {
|
||||
$parts[] = qsprintf(
|
||||
$conn,
|
||||
'project.projectPHID IN (%Ls)',
|
||||
'project.projectPHID in (%Ls)',
|
||||
$this->projectPHIDs);
|
||||
}
|
||||
if ($this->includeNoProject) {
|
||||
$parts[] = qsprintf(
|
||||
$conn,
|
||||
'project.projectPHID IS NULL');
|
||||
}
|
||||
|
||||
return '('.implode(') OR (', $parts).')';
|
||||
}
|
||||
|
||||
private function buildProjectJoinClause($conn) {
|
||||
if (!$this->projectPHIDs) {
|
||||
if (!$this->projectPHIDs && !$this->includeNoProject) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$project_dao = new ManiphestTaskProject();
|
||||
return qsprintf(
|
||||
$conn,
|
||||
'JOIN %T project ON project.taskPHID = task.phid',
|
||||
'%Q JOIN %T project ON project.taskPHID = task.phid',
|
||||
($this->includeNoProject ? 'LEFT' : ''),
|
||||
$project_dao->getTableName());
|
||||
}
|
||||
|
||||
private function buildXProjectWhereClause($conn) {
|
||||
if (!$this->xprojectPHIDs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return qsprintf(
|
||||
$conn,
|
||||
'xproject.projectPHID IS NULL');
|
||||
}
|
||||
|
||||
private function buildXProjectJoinClause($conn) {
|
||||
if (!$this->xprojectPHIDs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$project_dao = new ManiphestTaskProject();
|
||||
return qsprintf(
|
||||
$conn,
|
||||
'LEFT JOIN %T xproject ON xproject.taskPHID = task.phid
|
||||
AND xproject.projectPHID IN (%Ls)',
|
||||
$project_dao->getTableName(),
|
||||
$this->xprojectPHIDs);
|
||||
}
|
||||
|
||||
private function buildSubscriberJoinClause($conn) {
|
||||
if (!$this->subscriberPHIDs) {
|
||||
return null;
|
||||
|
|
|
@ -117,6 +117,11 @@ class PhabricatorObjectHandleData {
|
|||
$handle->setFullName('upforgrabs (Up For Grabs)');
|
||||
$handle->setComplete(true);
|
||||
break;
|
||||
case ManiphestTaskOwner::PROJECT_NO_PROJECT:
|
||||
$handle->setName('No Project');
|
||||
$handle->setFullName('noproject (No Project)');
|
||||
$handle->setComplete(true);
|
||||
break;
|
||||
default:
|
||||
$handle->setName('Foul Magicks');
|
||||
break;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -36,11 +36,16 @@ class PhabricatorTypeaheadCommonDatasourceController
|
|||
$need_packages = false;
|
||||
$need_upforgrabs = false;
|
||||
$need_arcanist_projects = false;
|
||||
$need_noproject = false;
|
||||
switch ($this->type) {
|
||||
case 'searchowner':
|
||||
$need_users = true;
|
||||
$need_upforgrabs = true;
|
||||
break;
|
||||
case 'searchproject':
|
||||
$need_projs = true;
|
||||
$need_noproject = true;
|
||||
break;
|
||||
case 'users':
|
||||
$need_users = true;
|
||||
break;
|
||||
|
@ -77,6 +82,14 @@ class PhabricatorTypeaheadCommonDatasourceController
|
|||
);
|
||||
}
|
||||
|
||||
if ($need_noproject) {
|
||||
$data[] = array(
|
||||
'noproject (No Project)',
|
||||
null,
|
||||
ManiphestTaskOwner::PROJECT_NO_PROJECT,
|
||||
);
|
||||
}
|
||||
|
||||
if ($need_users) {
|
||||
$columns = array(
|
||||
'isSystemAgent',
|
||||
|
|
Loading…
Reference in a new issue