Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2984278
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
21 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/applications/maniphest/controller/ManiphestTaskListControllerPro.php b/src/applications/maniphest/controller/ManiphestTaskListControllerPro.php
index 47650dd711..07337602a6 100644
--- a/src/applications/maniphest/controller/ManiphestTaskListControllerPro.php
+++ b/src/applications/maniphest/controller/ManiphestTaskListControllerPro.php
@@ -1,68 +1,293 @@
<?php
final class ManiphestTaskListControllerPro
extends ManiphestController
implements PhabricatorApplicationSearchResultsControllerInterface {
private $queryKey;
public function shouldAllowPublic() {
return true;
}
public function willProcessRequest(array $data) {
$this->queryKey = idx($data, 'queryKey');
}
public function processRequest() {
$request = $this->getRequest();
$controller = id(new PhabricatorApplicationSearchController($request))
->setQueryKey($this->queryKey)
->setSearchEngine(new ManiphestTaskSearchEngine())
->setNavigation($this->buildSideNavView());
return $this->delegateToController($controller);
}
public function renderResultsList(
array $tasks,
PhabricatorSavedQuery $query) {
assert_instances_of($tasks, 'ManiphestTask');
$viewer = $this->getRequest()->getUser();
- $list = new PHUIObjectItemListView();
- $list->setUser($viewer);
+ // If we didn't match anything, just pick up the default empty state.
+ if (!$tasks) {
+ return id(new PHUIObjectItemListView())
+ ->setUser($viewer);
+ }
+
+ $group_parameter = $query->getParameter('group', 'priority');
+ $order_parameter = $query->getParameter('order', 'priority');
+
+ $handles = $this->loadTaskHandles($tasks);
+ $groups = $this->groupTasks(
+ $tasks,
+ $group_parameter,
+ $handles);
+
+ $can_drag = ($order_parameter == 'priority') &&
+ ($group_parameter == 'none' || $group_parameter == 'priority');
+
+ $result = array();
+
+ $lists = array();
+ foreach ($groups as $group => $list) {
+ $task_list = new ManiphestTaskListView();
+ $task_list->setShowBatchControls(true);
+ if ($can_drag) {
+ $task_list->setShowSubpriorityControls(true);
+ }
+ $task_list->setUser($viewer);
+ $task_list->setTasks($list);
+ $task_list->setHandles($handles);
+
+ $header = javelin_tag(
+ 'h1',
+ array(
+ 'class' => 'maniphest-task-group-header',
+ 'sigil' => 'task-group',
+ 'meta' => array(
+ 'priority' => head($list)->getPriority(),
+ ),
+ ),
+ pht('%s (%s)', $group, new PhutilNumber(count($list))));
+
+ $lists[] = phutil_tag(
+ 'div',
+ array(
+ 'class' => 'maniphest-task-group'
+ ),
+ array(
+ $header,
+ $task_list,
+ ));
+ }
+
+ Javelin::initBehavior(
+ 'maniphest-subpriority-editor',
+ array(
+ 'uri' => '/maniphest/subpriority/',
+ ));
+
+ return phutil_tag(
+ 'div',
+ array(
+ 'class' => 'maniphest-list-container',
+ ),
+ array(
+ $lists,
+ $this->renderBatchEditor($query),
+ ));
+ }
+
+ private function loadTaskHandles(array $tasks) {
+ assert_instances_of($tasks, 'ManiphestTask');
+
+ $phids = array();
foreach ($tasks as $task) {
- $item = id(new PHUIObjectItemView())
- ->setObjectName('T'.$task->getID())
- ->setHeader($task->getTitle())
- ->setHref('/T'.$task->getID())
- ->setObject($task);
+ $assigned_phid = $task->getOwnerPHID();
+ if ($assigned_phid) {
+ $phids[] = $assigned_phid;
+ }
+ foreach ($task->getProjectPHIDs() as $project_phid) {
+ $phids[] = $project_phid;
+ }
+ }
+
+ if (!$phids) {
+ return array();
+ }
+
+ return id(new PhabricatorHandleQuery())
+ ->setViewer($this->getRequest()->getUser())
+ ->withPHIDs($phids)
+ ->execute();
+ }
+
+ private function groupTasks(array $tasks, $group, array $handles) {
+ assert_instances_of($tasks, 'ManiphestTask');
+ assert_instances_of($handles, 'PhabricatorObjectHandle');
+
+ $groups = $this->getTaskGrouping($tasks, $group);
- $list->addItem($item);
+ $results = array();
+ foreach ($groups as $label_key => $tasks) {
+ $label = $this->getTaskLabelName($group, $label_key, $handles);
+ $results[$label][] = $tasks;
+ }
+ foreach ($results as $label => $task_groups) {
+ $results[$label] = array_mergev($task_groups);
}
- return $list;
+ return $results;
+ }
+
+ private function getTaskGrouping(array $tasks, $group) {
+ switch ($group) {
+ case 'priority':
+ return mgroup($tasks, 'getPriority');
+ case 'status':
+ return mgroup($tasks, 'getStatus');
+ case 'assigned':
+ return mgroup($tasks, 'getOwnerPHID');
+ case 'project':
+ return mgroup($tasks, 'getGroupByProjectPHID');
+ default:
+ return array(pht('Tasks') => $tasks);
+ }
+ }
+
+ private function getTaskLabelName($group, $label_key, array $handles) {
+ switch ($group) {
+ case 'priority':
+ return ManiphestTaskPriority::getTaskPriorityName($label_key);
+ case 'status':
+ return ManiphestTaskStatus::getTaskStatusFullName($label_key);
+ case 'assigned':
+ if ($label_key) {
+ return $handles[$label_key]->getFullName();
+ } else {
+ return pht('(Not Assigned)');
+ }
+ case 'project':
+ if ($label_key) {
+ return $handles[$label_key]->getFullName();
+ } else {
+ return pht('(No Project)');
+ }
+ default:
+ return pht('Tasks');
+ }
}
public function buildSideNavView($for_app = false) {
$user = $this->getRequest()->getUser();
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
if ($for_app) {
$nav->addFilter('create', pht('Create Task'));
}
id(new ManiphestTaskSearchEngine())
->setViewer($user)
->addNavigationItems($nav->getMenu());
$nav->selectFilter(null);
return $nav;
}
+ private function renderBatchEditor(PhabricatorSavedQuery $saved_query) {
+ $user = $this->getRequest()->getUser();
+
+ Javelin::initBehavior(
+ 'maniphest-batch-selector',
+ array(
+ 'selectAll' => 'batch-select-all',
+ 'selectNone' => 'batch-select-none',
+ 'submit' => 'batch-select-submit',
+ 'status' => 'batch-select-status-cell',
+ 'idContainer' => 'batch-select-id-container',
+ 'formID' => 'batch-select-form',
+ ));
+
+ $select_all = javelin_tag(
+ 'a',
+ array(
+ 'href' => '#',
+ 'mustcapture' => true,
+ 'class' => 'grey button',
+ 'id' => 'batch-select-all',
+ ),
+ pht('Select All'));
+
+ $select_none = javelin_tag(
+ 'a',
+ array(
+ 'href' => '#',
+ 'mustcapture' => true,
+ 'class' => 'grey button',
+ 'id' => 'batch-select-none',
+ ),
+ pht('Clear Selection'));
+
+ $submit = phutil_tag(
+ 'button',
+ array(
+ 'id' => 'batch-select-submit',
+ 'disabled' => 'disabled',
+ 'class' => 'disabled',
+ ),
+ pht("Batch Edit Selected \xC2\xBB"));
+
+ $export = javelin_tag(
+ 'a',
+ array(
+ 'href' => '/maniphest/export/'.$saved_query->getQueryKey().'/',
+ 'class' => 'grey button',
+ ),
+ pht('Export to Excel'));
+
+ $hidden = phutil_tag(
+ 'div',
+ array(
+ 'id' => 'batch-select-id-container',
+ ),
+ '');
+
+ $editor = hsprintf(
+ '<div class="maniphest-batch-editor">'.
+ '<div class="batch-editor-header">%s</div>'.
+ '<table class="maniphest-batch-editor-layout">'.
+ '<tr>'.
+ '<td>%s%s</td>'.
+ '<td>%s</td>'.
+ '<td id="batch-select-status-cell">%s</td>'.
+ '<td class="batch-select-submit-cell">%s%s</td>'.
+ '</tr>'.
+ '</table>'.
+ '</div>',
+ pht('Batch Task Editor'),
+ $select_all,
+ $select_none,
+ $export,
+ '',
+ $submit,
+ $hidden);
+
+ $editor = phabricator_form(
+ $user,
+ array(
+ 'method' => 'POST',
+ 'action' => '/maniphest/batch/',
+ 'id' => 'batch-select-form',
+ ),
+ $editor);
+
+ return $editor;
+ }
+
}
diff --git a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php
index fb90035d59..ed07eaaa35 100644
--- a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php
+++ b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php
@@ -1,396 +1,398 @@
<?php
final class ManiphestTaskSearchEngine
extends PhabricatorApplicationSearchEngine {
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
$saved->setParameter(
'assignedPHIDs',
$this->readUsersFromRequest($request, 'assigned'));
$saved->setParameter('withUnassigned', $request->getBool('withUnassigned'));
$saved->setParameter(
'authorPHIDs',
$this->readUsersFromRequest($request, 'authors'));
$saved->setParameter('statuses', $request->getArr('statuses'));
$saved->setParameter('priorities', $request->getArr('priorities'));
$saved->setParameter('group', $request->getStr('group'));
$saved->setParameter('order', $request->getStr('order'));
$ids = $request->getStrList('ids');
foreach ($ids as $key => $id) {
$id = trim($id, ' Tt');
if (!$id || !is_numeric($id)) {
unset($ids[$key]);
} else {
$ids[$key] = $id;
}
}
$saved->setParameter('ids', $ids);
$saved->setParameter('fulltext', $request->getStr('fulltext'));
$saved->setParameter(
'allProjectPHIDs',
$request->getArr('allProjects'));
$saved->setParameter(
'withNoProject',
$request->getBool('withNoProject'));
$saved->setParameter(
'anyProjectPHIDs',
$request->getArr('anyProjects'));
$saved->setParameter(
'excludeProjectPHIDs',
$request->getArr('excludeProjects'));
$saved->setParameter(
'userProjectPHIDs',
$this->readUsersFromRequest($request, 'userProjects'));
$saved->setParameter('createdStart', $request->getStr('createdStart'));
$saved->setParameter('createdEnd', $request->getStr('createdEnd'));
return $saved;
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new ManiphestTaskQuery());
$author_phids = $saved->getParameter('authorPHIDs');
if ($author_phids) {
$query->withAuthors($author_phids);
}
$with_unassigned = $saved->getParameter('withUnassigned');
if ($with_unassigned) {
$query->withOwners(array(null));
} else {
$assigned_phids = $saved->getParameter('assignedPHIDs', array());
if ($assigned_phids) {
$query->withOwners($assigned_phids);
}
}
$statuses = $saved->getParameter('statuses');
if ($statuses) {
$query->withStatuses($statuses);
}
$priorities = $saved->getParameter('priorities');
if ($priorities) {
$query->withPriorities($priorities);
}
$order = $saved->getParameter('order');
$order = idx($this->getOrderValues(), $order);
if ($order) {
$query->setOrderBy($order);
} else {
$query->setOrderBy(head($this->getOrderValues()));
}
$group = $saved->getParameter('group');
$group = idx($this->getGroupValues(), $group);
if ($group) {
$query->setGroupBy($group);
} else {
$query->setGroupBy(head($this->getGroupValues()));
}
$ids = $saved->getParameter('ids');
if ($ids) {
$query->withIDs($ids);
}
$fulltext = $saved->getParameter('fulltext');
if (strlen($fulltext)) {
$query->withFullTextSearch($fulltext);
}
$with_no_project = $saved->getParameter('withNoProject');
if ($with_no_project) {
$query->withAllProjects(array(ManiphestTaskOwner::PROJECT_NO_PROJECT));
} else {
$project_phids = $saved->getParameter('allProjectPHIDs');
if ($project_phids) {
$query->withAllProjects($project_phids);
}
}
$any_project_phids = $saved->getParameter('anyProjectPHIDs');
if ($any_project_phids) {
$query->withAnyProjects($any_project_phids);
}
$exclude_project_phids = $saved->getParameter('excludeProjectPHIDs');
if ($exclude_project_phids) {
$query->withoutProjects($exclude_project_phids);
}
$user_project_phids = $saved->getParameter('userProjectPHIDs');
if ($user_project_phids) {
$query->withAnyUserProjects($user_project_phids);
}
$start = $this->parseDateTime($saved->getParameter('createdStart'));
$end = $this->parseDateTime($saved->getParameter('createdEnd'));
if ($start) {
$query->withDateCreatedAfter($start);
}
if ($end) {
$query->withDateCreatedBefore($end);
}
return $query;
}
public function buildSearchForm(
AphrontFormView $form,
PhabricatorSavedQuery $saved) {
$assigned_phids = $saved->getParameter('assignedPHIDs', array());
$author_phids = $saved->getParameter('authorPHIDs', array());
$all_project_phids = $saved->getParameter(
'allProjectPHIDs',
array());
$any_project_phids = $saved->getParameter(
'anyProjectPHIDs',
array());
$exclude_project_phids = $saved->getParameter(
'excludeProjectPHIDs',
array());
$user_project_phids = $saved->getParameter(
'userProjectPHIDs',
array());
$all_phids = array_merge(
$assigned_phids,
$author_phids,
$all_project_phids,
$any_project_phids,
$exclude_project_phids,
$user_project_phids);
if ($all_phids) {
$handles = id(new PhabricatorHandleQuery())
->setViewer($this->requireViewer())
->withPHIDs($all_phids)
->execute();
} else {
$handles = array();
}
$assigned_handles = array_select_keys($handles, $assigned_phids);
$author_handles = array_select_keys($handles, $author_phids);
$all_project_handles = array_select_keys($handles, $all_project_phids);
$any_project_handles = array_select_keys($handles, $any_project_phids);
$exclude_project_handles = array_select_keys(
$handles,
$exclude_project_phids);
$user_project_handles = array_select_keys($handles, $user_project_phids);
$with_unassigned = $saved->getParameter('withUnassigned');
$with_no_projects = $saved->getParameter('withNoProject');
$statuses = $saved->getParameter('statuses', array());
$statuses = array_fuse($statuses);
$status_control = id(new AphrontFormCheckboxControl())
->setLabel(pht('Status'));
foreach (ManiphestTaskStatus::getTaskStatusMap() as $status => $name) {
$status_control->addCheckbox(
'statuses[]',
$status,
$name,
isset($statuses[$status]));
}
$priorities = $saved->getParameter('priorities', array());
$priorities = array_fuse($priorities);
$priority_control = id(new AphrontFormCheckboxControl())
->setLabel(pht('Priority'));
foreach (ManiphestTaskPriority::getTaskPriorityMap() as $pri => $name) {
$priority_control->addCheckbox(
'priorities[]',
$pri,
$name,
isset($priorities[$pri]));
}
$ids = $saved->getParameter('ids', array());
$form
->appendChild(
id(new AphrontFormTokenizerControl())
->setDatasource('/typeahead/common/accounts/')
->setName('assigned')
->setLabel(pht('Assigned To'))
->setValue($assigned_handles))
->appendChild(
id(new AphrontFormCheckboxControl())
->addCheckbox(
'withUnassigned',
1,
pht('Show only unassigned tasks.'),
$with_unassigned))
->appendChild(
id(new AphrontFormTokenizerControl())
->setDatasource('/typeahead/common/projects/')
->setName('allProjects')
->setLabel(pht('In All Projects'))
->setValue($all_project_handles))
->appendChild(
id(new AphrontFormCheckboxControl())
->addCheckbox(
'withNoProject',
1,
pht('Show only tasks with no projects.'),
$with_no_projects))
->appendChild(
id(new AphrontFormTokenizerControl())
->setDatasource('/typeahead/common/projects/')
->setName('anyProjects')
->setLabel(pht('In Any Project'))
->setValue($any_project_handles))
->appendChild(
id(new AphrontFormTokenizerControl())
->setDatasource('/typeahead/common/projects/')
->setName('excludeProjects')
->setLabel(pht('Not In Projects'))
->setValue($exclude_project_handles))
->appendChild(
id(new AphrontFormTokenizerControl())
->setDatasource('/typeahead/common/accounts/')
->setName('userProjects')
->setLabel(pht('In Users\' Projects'))
->setValue($user_project_handles))
->appendChild(
id(new AphrontFormTokenizerControl())
->setDatasource('/typeahead/common/accounts/')
->setName('authors')
->setLabel(pht('Authors'))
->setValue($author_handles))
->appendChild($status_control)
->appendChild($priority_control)
->appendChild(
id(new AphrontFormSelectControl())
->setName('group')
->setLabel(pht('Group By'))
->setValue($saved->getParameter('group'))
->setOptions($this->getGroupOptions()))
->appendChild(
id(new AphrontFormSelectControl())
->setName('order')
->setLabel(pht('Order By'))
->setValue($saved->getParameter('order'))
->setOptions($this->getOrderOptions()))
->appendChild(
id(new AphrontFormTextControl())
->setName('fulltext')
->setLabel(pht('Contains Text'))
->setValue($saved->getParameter('fulltext')))
->appendChild(
id(new AphrontFormTextControl())
->setName('ids')
->setLabel(pht('Task IDs'))
->setValue(implode(', ', $ids)));
$this->buildDateRange(
$form,
$saved,
'createdStart',
pht('Created After'),
'createdEnd',
pht('Created Before'));
}
protected function getURI($path) {
return '/maniphest/'.$path;
}
public function getBuiltinQueryNames() {
$names = array();
if ($this->requireViewer()->isLoggedIn()) {
$names['assigned'] = pht('Assigned');
$names['authored'] = pht('Authored');
}
$names['open'] = pht('Open Tasks');
$names['all'] = pht('All Tasks');
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
$viewer_phid = $this->requireViewer()->getPHID();
switch ($query_key) {
case 'all':
return $query;
case 'assigned':
return $query
->setParameter('assignedPHIDs', array($viewer_phid))
->setParameter('statuses', array(ManiphestTaskStatus::STATUS_OPEN));
case 'open':
return $query
->setParameter('statuses', array(ManiphestTaskStatus::STATUS_OPEN));
case 'authored':
return $query
- ->setParameter('authorPHIDs', array($viewer_phid));
+ ->setParameter('authorPHIDs', array($viewer_phid))
+ ->setParameter('order', 'created')
+ ->setParameter('group', 'none');
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
private function getOrderOptions() {
return array(
'priority' => pht('Priority'),
'updated' => pht('Date Updated'),
'created' => pht('Date Created'),
'title' => pht('Title'),
);
}
private function getOrderValues() {
return array(
'priority' => ManiphestTaskQuery::ORDER_PRIORITY,
'updated' => ManiphestTaskQuery::ORDER_MODIFIED,
'created' => ManiphestTaskQuery::ORDER_CREATED,
'title' => ManiphestTaskQuery::ORDER_TITLE,
);
}
private function getGroupOptions() {
return array(
'priority' => pht('Priority'),
'assigned' => pht('Assigned'),
'status' => pht('Status'),
'project' => pht('Project'),
'none' => pht('None'),
);
}
private function getGroupValues() {
return array(
'priority' => ManiphestTaskQuery::GROUP_PRIORITY,
'assigned' => ManiphestTaskQuery::GROUP_OWNER,
'status' => ManiphestTaskQuery::GROUP_STATUS,
'project' => ManiphestTaskQuery::GROUP_PROJECT,
'none' => ManiphestTaskQuery::GROUP_NONE,
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Feb 20, 22:50 (2 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1163493
Default Alt Text
(21 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment