2011-02-08 10:53:59 -08:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
/*
|
2012-01-03 21:57:45 -08:00
|
|
|
* Copyright 2012 Facebook, Inc.
|
2011-02-08 10:53:59 -08:00
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
2011-07-04 13:04:22 -07:00
|
|
|
/**
|
|
|
|
|
* @group maniphest
|
|
|
|
|
*/
|
2012-03-09 15:46:25 -08:00
|
|
|
final class ManiphestTaskListController extends ManiphestController {
|
2011-02-08 10:53:59 -08:00
|
|
|
|
Allow Maniphest to scale to a massive size
Summary:
Maniphest is missing some keys and some query strategy which will make it
cumbersome to manage more than a few tens of thousands of tasks.
Test Plan:
Handily manipulated 100k-scale task groups. Maniphest takes about 250ms to
select and render pages of 1,000 tasks and has no problem paging and filtering
them, etc. We should be good to scale to multiple millions of tasks with these
changes.
Reviewed By: gc3
Reviewers: fratrik, jungejason, aran, tuomaspelkonen, gc3
Commenters: jungejason
CC: anjali, aran, epriestley, gc3, jungejason
Differential Revision: 534
2011-06-26 18:50:17 -07:00
|
|
|
const DEFAULT_PAGE_SIZE = 1000;
|
|
|
|
|
|
2011-02-08 10:53:59 -08:00
|
|
|
private $view;
|
|
|
|
|
|
|
|
|
|
public function willProcessRequest(array $data) {
|
|
|
|
|
$this->view = idx($data, 'view');
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-28 21:08:02 -08:00
|
|
|
private function getArrToStrList($key) {
|
|
|
|
|
$arr = $this->getRequest()->getArr($key);
|
|
|
|
|
$arr = implode(',', $arr);
|
|
|
|
|
return nonempty($arr, null);
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-08 10:53:59 -08:00
|
|
|
public function processRequest() {
|
|
|
|
|
|
2011-04-11 02:03:30 -07:00
|
|
|
$request = $this->getRequest();
|
|
|
|
|
$user = $request->getUser();
|
|
|
|
|
|
|
|
|
|
if ($request->isFormPost()) {
|
2011-06-29 16:16:33 -07:00
|
|
|
// Redirect to GET so URIs can be copy/pasted.
|
|
|
|
|
|
2011-12-02 07:30:20 -08:00
|
|
|
$task_ids = $request->getStr('set_tasks');
|
|
|
|
|
$task_ids = nonempty($task_ids, null);
|
2011-04-11 02:03:30 -07:00
|
|
|
|
2011-06-29 16:16:33 -07:00
|
|
|
$uri = $request->getRequestURI()
|
2012-02-28 21:08:02 -08:00
|
|
|
->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'))
|
2011-12-02 07:30:20 -08:00
|
|
|
->alter('tasks', $task_ids);
|
2011-06-29 16:16:33 -07:00
|
|
|
|
|
|
|
|
return id(new AphrontRedirectResponse())->setURI($uri);
|
|
|
|
|
}
|
2011-04-11 02:03:30 -07:00
|
|
|
|
2012-03-01 14:19:11 -08:00
|
|
|
$nav = $this->buildBaseSideNav();
|
2011-12-20 14:36:54 -08:00
|
|
|
|
|
|
|
|
$this->view = $nav->selectFilter($this->view, 'action');
|
2011-02-08 10:53:59 -08:00
|
|
|
|
2011-04-11 02:03:30 -07:00
|
|
|
$has_filter = array(
|
|
|
|
|
'action' => true,
|
|
|
|
|
'created' => true,
|
2011-07-07 10:24:49 -07:00
|
|
|
'subscribed' => true,
|
2011-04-11 02:03:30 -07:00
|
|
|
'triage' => true,
|
2012-03-14 18:01:14 -07:00
|
|
|
'projecttriage' => true,
|
|
|
|
|
'projectall' => true,
|
2011-04-11 02:03:30 -07:00
|
|
|
);
|
2011-02-08 10:53:59 -08:00
|
|
|
|
2012-02-27 12:59:05 -08:00
|
|
|
list($status_map, $status_control) = $this->renderStatusLinks();
|
|
|
|
|
list($grouping, $group_control) = $this->renderGroupLinks();
|
|
|
|
|
list($order, $order_control) = $this->renderOrderLinks();
|
2011-02-11 10:28:37 -08:00
|
|
|
|
2012-02-28 22:00:03 -08:00
|
|
|
$user_phids = $request->getStrList(
|
|
|
|
|
'users',
|
|
|
|
|
array($user->getPHID()));
|
2012-03-14 18:01:14 -07:00
|
|
|
if ($this->view == 'projecttriage' || $this->view == 'projectall') {
|
|
|
|
|
$project_query = new PhabricatorProjectQuery();
|
|
|
|
|
$project_query->setMembers($user_phids);
|
|
|
|
|
$projects = $project_query->execute();
|
|
|
|
|
$project_phids = mpull($projects, 'getPHID');
|
|
|
|
|
} else {
|
|
|
|
|
$project_phids = $request->getStrList('projects');
|
|
|
|
|
}
|
2012-02-28 21:08:02 -08:00
|
|
|
$exclude_project_phids = $request->getStrList('xprojects');
|
2012-01-03 21:57:45 -08:00
|
|
|
$task_ids = $request->getStrList('tasks');
|
2012-02-28 21:08:02 -08:00
|
|
|
$owner_phids = $request->getStrList('owners');
|
|
|
|
|
$author_phids = $request->getStrList('authors');
|
2011-12-02 07:30:20 -08:00
|
|
|
|
Allow Maniphest to scale to a massive size
Summary:
Maniphest is missing some keys and some query strategy which will make it
cumbersome to manage more than a few tens of thousands of tasks.
Test Plan:
Handily manipulated 100k-scale task groups. Maniphest takes about 250ms to
select and render pages of 1,000 tasks and has no problem paging and filtering
them, etc. We should be good to scale to multiple millions of tasks with these
changes.
Reviewed By: gc3
Reviewers: fratrik, jungejason, aran, tuomaspelkonen, gc3
Commenters: jungejason
CC: anjali, aran, epriestley, gc3, jungejason
Differential Revision: 534
2011-06-26 18:50:17 -07:00
|
|
|
$page = $request->getInt('page');
|
|
|
|
|
$page_size = self::DEFAULT_PAGE_SIZE;
|
|
|
|
|
|
2012-02-28 21:07:12 -08:00
|
|
|
$query = new PhabricatorSearchQuery();
|
|
|
|
|
$query->setQuery('<<maniphest>>');
|
|
|
|
|
$query->setParameters(
|
2011-02-11 10:28:37 -08:00
|
|
|
array(
|
2012-02-28 21:08:02 -08:00
|
|
|
'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,
|
|
|
|
|
'offset' => $page,
|
|
|
|
|
'limit' => $page_size,
|
|
|
|
|
'status' => $status_map,
|
2011-02-11 10:28:37 -08:00
|
|
|
));
|
2011-02-08 10:53:59 -08:00
|
|
|
|
2012-02-28 21:07:12 -08:00
|
|
|
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
|
|
|
|
$query->save();
|
|
|
|
|
unset($unguarded);
|
|
|
|
|
|
|
|
|
|
list($tasks, $handles, $total_count) = self::loadTasks($query);
|
|
|
|
|
|
2011-04-03 15:50:06 -07:00
|
|
|
$form = id(new AphrontFormView())
|
2011-06-29 16:16:33 -07:00
|
|
|
->setUser($user)
|
|
|
|
|
->setAction($request->getRequestURI());
|
2011-04-11 02:03:30 -07:00
|
|
|
|
|
|
|
|
if (isset($has_filter[$this->view])) {
|
2011-06-29 16:16:33 -07:00
|
|
|
$tokens = array();
|
|
|
|
|
foreach ($user_phids as $phid) {
|
|
|
|
|
$tokens[$phid] = $handles[$phid]->getFullName();
|
|
|
|
|
}
|
2011-04-11 02:03:30 -07:00
|
|
|
$form->appendChild(
|
|
|
|
|
id(new AphrontFormTokenizerControl())
|
2011-05-28 14:13:12 -07:00
|
|
|
->setDatasource('/typeahead/common/searchowner/')
|
2011-06-29 16:16:33 -07:00
|
|
|
->setName('set_users')
|
|
|
|
|
->setLabel('Users')
|
|
|
|
|
->setValue($tokens));
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-02 07:30:20 -08:00
|
|
|
if ($this->view == 'custom') {
|
|
|
|
|
$form->appendChild(
|
|
|
|
|
id(new AphrontFormTextControl())
|
|
|
|
|
->setName('set_tasks')
|
|
|
|
|
->setLabel('Task IDs')
|
|
|
|
|
->setValue(join(',', $task_ids))
|
|
|
|
|
);
|
2012-02-28 21:08:02 -08:00
|
|
|
|
|
|
|
|
$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));
|
2011-12-02 07:30:20 -08:00
|
|
|
}
|
|
|
|
|
|
2011-06-29 16:16:33 -07:00
|
|
|
$tokens = array();
|
|
|
|
|
foreach ($project_phids as $phid) {
|
|
|
|
|
$tokens[$phid] = $handles[$phid]->getFullName();
|
2011-04-11 02:03:30 -07:00
|
|
|
}
|
2012-03-14 18:01:14 -07:00
|
|
|
if ($this->view != 'projectall' && $this->view != 'projecttriage') {
|
|
|
|
|
$form->appendChild(
|
|
|
|
|
id(new AphrontFormTokenizerControl())
|
|
|
|
|
->setDatasource('/typeahead/common/searchproject/')
|
|
|
|
|
->setName('set_projects')
|
|
|
|
|
->setLabel('Projects')
|
|
|
|
|
->setValue($tokens));
|
|
|
|
|
}
|
2011-04-11 02:03:30 -07:00
|
|
|
|
2012-02-28 21:08:02 -08:00
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-11 02:03:30 -07:00
|
|
|
$form
|
2012-02-27 12:59:05 -08:00
|
|
|
->appendChild($status_control)
|
|
|
|
|
->appendChild($group_control)
|
|
|
|
|
->appendChild($order_control);
|
2011-04-03 15:50:06 -07:00
|
|
|
|
2011-06-29 16:16:33 -07:00
|
|
|
$form->appendChild(
|
|
|
|
|
id(new AphrontFormSubmitControl())
|
|
|
|
|
->setValue('Filter Tasks'));
|
|
|
|
|
|
2011-08-01 13:51:27 -07:00
|
|
|
$create_uri = new PhutilURI('/maniphest/task/create/');
|
|
|
|
|
if ($project_phids) {
|
|
|
|
|
// If we have project filters selected, use them as defaults for task
|
|
|
|
|
// creation.
|
|
|
|
|
$create_uri->setQueryParam('projects', implode(';', $project_phids));
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-03 15:50:06 -07:00
|
|
|
$filter = new AphrontListFilterView();
|
|
|
|
|
$filter->addButton(
|
|
|
|
|
phutil_render_tag(
|
|
|
|
|
'a',
|
|
|
|
|
array(
|
2011-08-01 13:51:27 -07:00
|
|
|
'href' => (string)$create_uri,
|
2011-04-03 15:50:06 -07:00
|
|
|
'class' => 'green button',
|
|
|
|
|
),
|
|
|
|
|
'Create New Task'));
|
|
|
|
|
$filter->appendChild($form);
|
|
|
|
|
|
|
|
|
|
$nav->appendChild($filter);
|
2011-02-11 10:28:37 -08:00
|
|
|
|
|
|
|
|
$have_tasks = false;
|
|
|
|
|
foreach ($tasks as $group => $list) {
|
|
|
|
|
if (count($list)) {
|
|
|
|
|
$have_tasks = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-03 15:50:06 -07:00
|
|
|
require_celerity_resource('maniphest-task-summary-css');
|
|
|
|
|
|
2012-03-05 13:51:35 -08:00
|
|
|
$list_container = new AphrontNullView();
|
|
|
|
|
$list_container->appendChild('<div class="maniphest-list-container">');
|
|
|
|
|
|
2011-02-11 10:28:37 -08:00
|
|
|
if (!$have_tasks) {
|
2012-03-05 13:51:35 -08:00
|
|
|
$list_container->appendChild(
|
2011-02-11 10:28:37 -08:00
|
|
|
'<h1 class="maniphest-task-group-header">'.
|
|
|
|
|
'No matching tasks.'.
|
|
|
|
|
'</h1>');
|
|
|
|
|
} else {
|
Allow Maniphest to scale to a massive size
Summary:
Maniphest is missing some keys and some query strategy which will make it
cumbersome to manage more than a few tens of thousands of tasks.
Test Plan:
Handily manipulated 100k-scale task groups. Maniphest takes about 250ms to
select and render pages of 1,000 tasks and has no problem paging and filtering
them, etc. We should be good to scale to multiple millions of tasks with these
changes.
Reviewed By: gc3
Reviewers: fratrik, jungejason, aran, tuomaspelkonen, gc3
Commenters: jungejason
CC: anjali, aran, epriestley, gc3, jungejason
Differential Revision: 534
2011-06-26 18:50:17 -07:00
|
|
|
$pager = new AphrontPagerView();
|
|
|
|
|
$pager->setURI($request->getRequestURI(), 'page');
|
|
|
|
|
$pager->setPageSize($page_size);
|
|
|
|
|
$pager->setOffset($page);
|
|
|
|
|
$pager->setCount($total_count);
|
|
|
|
|
|
|
|
|
|
$cur = ($pager->getOffset() + 1);
|
|
|
|
|
$max = min($pager->getOffset() + $page_size, $total_count);
|
|
|
|
|
$tot = $total_count;
|
|
|
|
|
|
|
|
|
|
$cur = number_format($cur);
|
|
|
|
|
$max = number_format($max);
|
|
|
|
|
$tot = number_format($tot);
|
|
|
|
|
|
2012-03-05 13:51:35 -08:00
|
|
|
$list_container->appendChild(
|
Allow Maniphest to scale to a massive size
Summary:
Maniphest is missing some keys and some query strategy which will make it
cumbersome to manage more than a few tens of thousands of tasks.
Test Plan:
Handily manipulated 100k-scale task groups. Maniphest takes about 250ms to
select and render pages of 1,000 tasks and has no problem paging and filtering
them, etc. We should be good to scale to multiple millions of tasks with these
changes.
Reviewed By: gc3
Reviewers: fratrik, jungejason, aran, tuomaspelkonen, gc3
Commenters: jungejason
CC: anjali, aran, epriestley, gc3, jungejason
Differential Revision: 534
2011-06-26 18:50:17 -07:00
|
|
|
'<div class="maniphest-total-result-count">'.
|
|
|
|
|
"Displaying tasks {$cur} - {$max} of {$tot}.".
|
|
|
|
|
'</div>');
|
|
|
|
|
|
2012-02-24 13:00:48 -08:00
|
|
|
$selector = new AphrontNullView();
|
|
|
|
|
|
2012-04-02 12:12:04 -07:00
|
|
|
$group = $query->getParameter('group');
|
|
|
|
|
$order = $query->getParameter('order');
|
|
|
|
|
$is_draggable =
|
|
|
|
|
($group == 'priority') ||
|
|
|
|
|
($group == 'none' && $order == 'priority');
|
|
|
|
|
|
|
|
|
|
$lists = new AphrontNullView();
|
2012-04-02 12:14:26 -07:00
|
|
|
$lists->appendChild('<div class="maniphest-group-container">');
|
2011-02-11 10:28:37 -08:00
|
|
|
foreach ($tasks as $group => $list) {
|
|
|
|
|
$task_list = new ManiphestTaskListView();
|
2012-02-24 13:00:48 -08:00
|
|
|
$task_list->setShowBatchControls(true);
|
2012-04-02 12:12:04 -07:00
|
|
|
if ($is_draggable) {
|
|
|
|
|
$task_list->setShowSubpriorityControls(true);
|
|
|
|
|
}
|
Use phabricator_ time functions in more places
Summary:
Replace some more date() calls with locale-aware calls.
Also, at least on my system, the DateTimeZone / DateTime stuff didn't actually
work and always rendered in UTC. Fixed that.
Test Plan:
Viewed daemon console, differential revisions, files, and maniphest timestamps
in multiple timezones.
Reviewed By: toulouse
Reviewers: toulouse, fratrik, jungejason, aran, tuomaspelkonen
CC: aran, toulouse
Differential Revision: 530
2011-06-26 09:22:52 -07:00
|
|
|
$task_list->setUser($user);
|
2011-02-11 10:28:37 -08:00
|
|
|
$task_list->setTasks($list);
|
|
|
|
|
$task_list->setHandles($handles);
|
|
|
|
|
|
2011-06-13 20:03:44 -07:00
|
|
|
$count = number_format(count($list));
|
2012-04-02 12:12:04 -07:00
|
|
|
|
|
|
|
|
$lists->appendChild(
|
|
|
|
|
javelin_render_tag(
|
|
|
|
|
'h1',
|
|
|
|
|
array(
|
|
|
|
|
'class' => 'maniphest-task-group-header',
|
|
|
|
|
'sigil' => 'task-group',
|
|
|
|
|
'meta' => array(
|
|
|
|
|
'priority' => head($list)->getPriority(),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
phutil_escape_html($group).' ('.$count.')'));
|
|
|
|
|
|
|
|
|
|
$lists->appendChild($task_list);
|
2011-02-11 10:28:37 -08:00
|
|
|
}
|
2012-04-02 12:12:04 -07:00
|
|
|
$lists->appendChild('</div>');
|
|
|
|
|
$selector->appendChild($lists);
|
Allow Maniphest to scale to a massive size
Summary:
Maniphest is missing some keys and some query strategy which will make it
cumbersome to manage more than a few tens of thousands of tasks.
Test Plan:
Handily manipulated 100k-scale task groups. Maniphest takes about 250ms to
select and render pages of 1,000 tasks and has no problem paging and filtering
them, etc. We should be good to scale to multiple millions of tasks with these
changes.
Reviewed By: gc3
Reviewers: fratrik, jungejason, aran, tuomaspelkonen, gc3
Commenters: jungejason
CC: anjali, aran, epriestley, gc3, jungejason
Differential Revision: 534
2011-06-26 18:50:17 -07:00
|
|
|
|
2012-02-24 13:00:48 -08:00
|
|
|
|
2012-02-28 21:07:12 -08:00
|
|
|
$selector->appendChild($this->renderBatchEditor($query));
|
2012-02-24 13:00:48 -08:00
|
|
|
|
2012-04-02 12:12:04 -07:00
|
|
|
$form_id = celerity_generate_unique_node_id();
|
2012-02-24 13:00:48 -08:00
|
|
|
$selector = phabricator_render_form(
|
|
|
|
|
$user,
|
|
|
|
|
array(
|
|
|
|
|
'method' => 'POST',
|
|
|
|
|
'action' => '/maniphest/batch/',
|
2012-04-02 12:12:04 -07:00
|
|
|
'id' => $form_id,
|
2012-02-24 13:00:48 -08:00
|
|
|
),
|
|
|
|
|
$selector->render());
|
|
|
|
|
|
2012-03-05 13:51:35 -08:00
|
|
|
$list_container->appendChild($selector);
|
|
|
|
|
$list_container->appendChild($pager);
|
2012-04-02 12:12:04 -07:00
|
|
|
|
|
|
|
|
Javelin::initBehavior(
|
|
|
|
|
'maniphest-subpriority-editor',
|
|
|
|
|
array(
|
|
|
|
|
'root' => $form_id,
|
|
|
|
|
'uri' => '/maniphest/subpriority/',
|
|
|
|
|
));
|
2011-02-11 10:28:37 -08:00
|
|
|
}
|
2011-02-08 10:53:59 -08:00
|
|
|
|
2012-03-05 13:51:35 -08:00
|
|
|
$list_container->appendChild('</div>');
|
|
|
|
|
$nav->appendChild($list_container);
|
|
|
|
|
|
2011-02-08 10:53:59 -08:00
|
|
|
return $this->buildStandardPageResponse(
|
|
|
|
|
$nav,
|
|
|
|
|
array(
|
|
|
|
|
'title' => 'Task List',
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-28 21:07:12 -08:00
|
|
|
public static function loadTasks(PhabricatorSearchQuery $search_query) {
|
2012-03-30 10:55:18 -07:00
|
|
|
$any_project = false;
|
2012-02-28 21:07:12 -08:00
|
|
|
$user_phids = $search_query->getParameter('userPHIDs', array());
|
|
|
|
|
$project_phids = $search_query->getParameter('projectPHIDs', array());
|
|
|
|
|
$task_ids = $search_query->getParameter('taskIDs', array());
|
2012-02-28 21:08:02 -08:00
|
|
|
$xproject_phids = $search_query->getParameter(
|
|
|
|
|
'excludeProjectPHIDs',
|
|
|
|
|
array());
|
|
|
|
|
$owner_phids = $search_query->getParameter('ownerPHIDs', array());
|
|
|
|
|
$author_phids = $search_query->getParameter('authorPHIDs', array());
|
2011-02-08 10:53:59 -08:00
|
|
|
|
2011-06-29 16:16:33 -07:00
|
|
|
$query = new ManiphestTaskQuery();
|
|
|
|
|
$query->withProjects($project_phids);
|
2011-12-02 07:30:20 -08:00
|
|
|
$query->withTaskIDs($task_ids);
|
2011-02-11 10:28:37 -08:00
|
|
|
|
2012-02-28 21:08:02 -08:00
|
|
|
if ($xproject_phids) {
|
|
|
|
|
$query->withoutProjects($xproject_phids);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($owner_phids) {
|
|
|
|
|
$query->withOwners($owner_phids);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($author_phids) {
|
|
|
|
|
$query->withAuthors($author_phids);
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-28 21:07:12 -08:00
|
|
|
$status = $search_query->getParameter('status', 'all');
|
2011-02-11 10:28:37 -08:00
|
|
|
if (!empty($status['open']) && !empty($status['closed'])) {
|
2011-06-29 16:16:33 -07:00
|
|
|
$query->withStatus(ManiphestTaskQuery::STATUS_ANY);
|
2011-02-11 10:28:37 -08:00
|
|
|
} else if (!empty($status['open'])) {
|
2011-06-29 16:16:33 -07:00
|
|
|
$query->withStatus(ManiphestTaskQuery::STATUS_OPEN);
|
2011-02-11 10:28:37 -08:00
|
|
|
} else {
|
2011-06-29 16:16:33 -07:00
|
|
|
$query->withStatus(ManiphestTaskQuery::STATUS_CLOSED);
|
2011-02-11 10:28:37 -08:00
|
|
|
}
|
|
|
|
|
|
2012-02-28 21:07:12 -08:00
|
|
|
switch ($search_query->getParameter('view')) {
|
2011-02-08 10:53:59 -08:00
|
|
|
case 'action':
|
2011-06-29 16:16:33 -07:00
|
|
|
$query->withOwners($user_phids);
|
2011-02-11 10:28:37 -08:00
|
|
|
break;
|
2011-02-08 10:53:59 -08:00
|
|
|
case 'created':
|
2011-06-29 16:16:33 -07:00
|
|
|
$query->withAuthors($user_phids);
|
2011-02-11 10:28:37 -08:00
|
|
|
break;
|
2011-07-07 10:24:49 -07:00
|
|
|
case 'subscribed':
|
|
|
|
|
$query->withSubscribers($user_phids);
|
|
|
|
|
break;
|
2011-02-08 10:53:59 -08:00
|
|
|
case 'triage':
|
2011-06-29 16:16:33 -07:00
|
|
|
$query->withOwners($user_phids);
|
|
|
|
|
$query->withPriority(ManiphestTaskPriority::PRIORITY_TRIAGE);
|
2011-02-11 10:28:37 -08:00
|
|
|
break;
|
2011-02-09 16:29:46 -08:00
|
|
|
case 'alltriage':
|
2011-06-29 16:16:33 -07:00
|
|
|
$query->withPriority(ManiphestTaskPriority::PRIORITY_TRIAGE);
|
2011-02-11 10:28:37 -08:00
|
|
|
break;
|
|
|
|
|
case 'all':
|
|
|
|
|
break;
|
2012-03-14 18:01:14 -07:00
|
|
|
case 'projecttriage':
|
|
|
|
|
$query->withPriority(ManiphestTaskPriority::PRIORITY_TRIAGE);
|
2012-03-30 10:55:18 -07:00
|
|
|
$any_project = true;
|
2012-03-14 18:01:14 -07:00
|
|
|
break;
|
|
|
|
|
case 'projectall':
|
2012-03-30 10:55:18 -07:00
|
|
|
$any_project = true;
|
2012-03-14 18:01:14 -07:00
|
|
|
break;
|
2011-02-11 10:28:37 -08:00
|
|
|
}
|
|
|
|
|
|
2012-03-30 10:55:18 -07:00
|
|
|
$query->withAnyProject($any_project);
|
|
|
|
|
|
2011-06-29 16:16:33 -07:00
|
|
|
$order_map = array(
|
|
|
|
|
'priority' => ManiphestTaskQuery::ORDER_PRIORITY,
|
|
|
|
|
'created' => ManiphestTaskQuery::ORDER_CREATED,
|
|
|
|
|
);
|
|
|
|
|
$query->setOrderBy(
|
|
|
|
|
idx(
|
|
|
|
|
$order_map,
|
2012-02-28 21:07:12 -08:00
|
|
|
$search_query->getParameter('order'),
|
2011-06-29 16:16:33 -07:00
|
|
|
ManiphestTaskQuery::ORDER_MODIFIED));
|
|
|
|
|
|
|
|
|
|
$group_map = array(
|
|
|
|
|
'priority' => ManiphestTaskQuery::GROUP_PRIORITY,
|
|
|
|
|
'owner' => ManiphestTaskQuery::GROUP_OWNER,
|
|
|
|
|
'status' => ManiphestTaskQuery::GROUP_STATUS,
|
Add "Group by: Project" to Maniphest
Summary:
Allow tasks to be grouped by project. Since this is many-to-many and we're a little deficient on indexes for doing this on the database, we pull all matching tasks and group them in PHP. This shouldn't be a huge issue for any existing installs, though, and we can add keys when we run into one.
- When a task is in multiple projects, it appears under multiple headers.
- When a query has a task filter, those projects are omitted from the grouping (they'd always show everything, which isn't useful). Notably, if you search for "Differential", you can now see "Bugs", "Feature Requests", etc.
Test Plan: Selected "Group by: Project".
Reviewers: btrahan, Josereyes
Reviewed By: btrahan
CC: aran, epriestley
Maniphest Tasks: T923
Differential Revision: https://secure.phabricator.com/D1953
2012-03-19 19:47:34 -07:00
|
|
|
'project' => ManiphestTaskQuery::GROUP_PROJECT,
|
2011-06-29 16:16:33 -07:00
|
|
|
);
|
|
|
|
|
$query->setGroupBy(
|
|
|
|
|
idx(
|
|
|
|
|
$group_map,
|
2012-02-28 21:07:12 -08:00
|
|
|
$search_query->getParameter('group'),
|
2011-06-29 16:16:33 -07:00
|
|
|
ManiphestTaskQuery::GROUP_NONE));
|
Allow Maniphest to scale to a massive size
Summary:
Maniphest is missing some keys and some query strategy which will make it
cumbersome to manage more than a few tens of thousands of tasks.
Test Plan:
Handily manipulated 100k-scale task groups. Maniphest takes about 250ms to
select and render pages of 1,000 tasks and has no problem paging and filtering
them, etc. We should be good to scale to multiple millions of tasks with these
changes.
Reviewed By: gc3
Reviewers: fratrik, jungejason, aran, tuomaspelkonen, gc3
Commenters: jungejason
CC: anjali, aran, epriestley, gc3, jungejason
Differential Revision: 534
2011-06-26 18:50:17 -07:00
|
|
|
|
2011-06-29 16:16:33 -07:00
|
|
|
$query->setCalculateRows(true);
|
2012-02-28 21:07:12 -08:00
|
|
|
$query->setLimit($search_query->getParameter('limit'));
|
|
|
|
|
$query->setOffset($search_query->getParameter('offset'));
|
Allow Maniphest to scale to a massive size
Summary:
Maniphest is missing some keys and some query strategy which will make it
cumbersome to manage more than a few tens of thousands of tasks.
Test Plan:
Handily manipulated 100k-scale task groups. Maniphest takes about 250ms to
select and render pages of 1,000 tasks and has no problem paging and filtering
them, etc. We should be good to scale to multiple millions of tasks with these
changes.
Reviewed By: gc3
Reviewers: fratrik, jungejason, aran, tuomaspelkonen, gc3
Commenters: jungejason
CC: anjali, aran, epriestley, gc3, jungejason
Differential Revision: 534
2011-06-26 18:50:17 -07:00
|
|
|
|
2011-06-29 16:16:33 -07:00
|
|
|
$data = $query->execute();
|
|
|
|
|
$total_row_count = $query->getRowCount();
|
2011-02-11 10:28:37 -08:00
|
|
|
|
Add "Group by: Project" to Maniphest
Summary:
Allow tasks to be grouped by project. Since this is many-to-many and we're a little deficient on indexes for doing this on the database, we pull all matching tasks and group them in PHP. This shouldn't be a huge issue for any existing installs, though, and we can add keys when we run into one.
- When a task is in multiple projects, it appears under multiple headers.
- When a query has a task filter, those projects are omitted from the grouping (they'd always show everything, which isn't useful). Notably, if you search for "Differential", you can now see "Bugs", "Feature Requests", etc.
Test Plan: Selected "Group by: Project".
Reviewers: btrahan, Josereyes
Reviewed By: btrahan
CC: aran, epriestley
Maniphest Tasks: T923
Differential Revision: https://secure.phabricator.com/D1953
2012-03-19 19:47:34 -07:00
|
|
|
$project_group_phids = array();
|
|
|
|
|
if ($search_query->getParameter('group') == 'project') {
|
|
|
|
|
foreach ($data as $task) {
|
|
|
|
|
foreach ($task->getProjectPHIDs() as $phid) {
|
|
|
|
|
$project_group_phids[] = $phid;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-11 10:28:37 -08:00
|
|
|
$handle_phids = mpull($data, 'getOwnerPHID');
|
2012-02-28 21:08:02 -08:00
|
|
|
$handle_phids = array_merge(
|
|
|
|
|
$handle_phids,
|
|
|
|
|
$project_phids,
|
|
|
|
|
$user_phids,
|
|
|
|
|
$xproject_phids,
|
|
|
|
|
$owner_phids,
|
Add "Group by: Project" to Maniphest
Summary:
Allow tasks to be grouped by project. Since this is many-to-many and we're a little deficient on indexes for doing this on the database, we pull all matching tasks and group them in PHP. This shouldn't be a huge issue for any existing installs, though, and we can add keys when we run into one.
- When a task is in multiple projects, it appears under multiple headers.
- When a query has a task filter, those projects are omitted from the grouping (they'd always show everything, which isn't useful). Notably, if you search for "Differential", you can now see "Bugs", "Feature Requests", etc.
Test Plan: Selected "Group by: Project".
Reviewers: btrahan, Josereyes
Reviewed By: btrahan
CC: aran, epriestley
Maniphest Tasks: T923
Differential Revision: https://secure.phabricator.com/D1953
2012-03-19 19:47:34 -07:00
|
|
|
$author_phids,
|
2012-04-02 10:27:31 -07:00
|
|
|
$project_group_phids,
|
|
|
|
|
array_mergev(mpull($data, 'getProjectPHIDs')));
|
2011-02-11 10:28:37 -08:00
|
|
|
$handles = id(new PhabricatorObjectHandleData($handle_phids))
|
|
|
|
|
->loadHandles();
|
|
|
|
|
|
2012-02-28 21:07:12 -08:00
|
|
|
switch ($search_query->getParameter('group')) {
|
2011-02-11 10:28:37 -08:00
|
|
|
case 'priority':
|
|
|
|
|
$data = mgroup($data, 'getPriority');
|
|
|
|
|
|
Allow Maniphest to scale to a massive size
Summary:
Maniphest is missing some keys and some query strategy which will make it
cumbersome to manage more than a few tens of thousands of tasks.
Test Plan:
Handily manipulated 100k-scale task groups. Maniphest takes about 250ms to
select and render pages of 1,000 tasks and has no problem paging and filtering
them, etc. We should be good to scale to multiple millions of tasks with these
changes.
Reviewed By: gc3
Reviewers: fratrik, jungejason, aran, tuomaspelkonen, gc3
Commenters: jungejason
CC: anjali, aran, epriestley, gc3, jungejason
Differential Revision: 534
2011-06-26 18:50:17 -07:00
|
|
|
// If we have invalid priorities, they'll all map to "???". Merge
|
|
|
|
|
// arrays to prevent them from overwriting each other.
|
|
|
|
|
|
2011-02-11 10:28:37 -08:00
|
|
|
$out = array();
|
|
|
|
|
foreach ($data as $pri => $tasks) {
|
Allow Maniphest to scale to a massive size
Summary:
Maniphest is missing some keys and some query strategy which will make it
cumbersome to manage more than a few tens of thousands of tasks.
Test Plan:
Handily manipulated 100k-scale task groups. Maniphest takes about 250ms to
select and render pages of 1,000 tasks and has no problem paging and filtering
them, etc. We should be good to scale to multiple millions of tasks with these
changes.
Reviewed By: gc3
Reviewers: fratrik, jungejason, aran, tuomaspelkonen, gc3
Commenters: jungejason
CC: anjali, aran, epriestley, gc3, jungejason
Differential Revision: 534
2011-06-26 18:50:17 -07:00
|
|
|
$out[ManiphestTaskPriority::getTaskPriorityName($pri)][] = $tasks;
|
|
|
|
|
}
|
|
|
|
|
foreach ($out as $pri => $tasks) {
|
|
|
|
|
$out[$pri] = array_mergev($tasks);
|
2011-02-11 10:28:37 -08:00
|
|
|
}
|
|
|
|
|
$data = $out;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case 'status':
|
|
|
|
|
$data = mgroup($data, 'getStatus');
|
|
|
|
|
|
|
|
|
|
$out = array();
|
|
|
|
|
foreach ($data as $status => $tasks) {
|
|
|
|
|
$out[ManiphestTaskStatus::getTaskStatusFullName($status)] = $tasks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$data = $out;
|
|
|
|
|
break;
|
|
|
|
|
case 'owner':
|
|
|
|
|
$data = mgroup($data, 'getOwnerPHID');
|
|
|
|
|
|
|
|
|
|
$out = array();
|
|
|
|
|
foreach ($data as $phid => $tasks) {
|
|
|
|
|
if ($phid) {
|
|
|
|
|
$out[$handles[$phid]->getFullName()] = $tasks;
|
|
|
|
|
} else {
|
|
|
|
|
$out['Unassigned'] = $tasks;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-22 13:55:22 -07:00
|
|
|
$data = $out;
|
2011-02-11 10:28:37 -08:00
|
|
|
ksort($data);
|
2012-03-22 13:55:22 -07:00
|
|
|
|
|
|
|
|
// Move "Unassigned" to the top of the list.
|
|
|
|
|
if (isset($data['Unassigned'])) {
|
|
|
|
|
$data = array('Unassigned' => $out['Unassigned']) + $out;
|
|
|
|
|
}
|
2011-02-11 10:28:37 -08:00
|
|
|
break;
|
Add "Group by: Project" to Maniphest
Summary:
Allow tasks to be grouped by project. Since this is many-to-many and we're a little deficient on indexes for doing this on the database, we pull all matching tasks and group them in PHP. This shouldn't be a huge issue for any existing installs, though, and we can add keys when we run into one.
- When a task is in multiple projects, it appears under multiple headers.
- When a query has a task filter, those projects are omitted from the grouping (they'd always show everything, which isn't useful). Notably, if you search for "Differential", you can now see "Bugs", "Feature Requests", etc.
Test Plan: Selected "Group by: Project".
Reviewers: btrahan, Josereyes
Reviewed By: btrahan
CC: aran, epriestley
Maniphest Tasks: T923
Differential Revision: https://secure.phabricator.com/D1953
2012-03-19 19:47:34 -07:00
|
|
|
case 'project':
|
|
|
|
|
$grouped = array();
|
|
|
|
|
foreach ($data as $task) {
|
|
|
|
|
$phids = $task->getProjectPHIDs();
|
2012-03-30 10:55:18 -07:00
|
|
|
if ($project_phids && $any_project !== true) {
|
Add "Group by: Project" to Maniphest
Summary:
Allow tasks to be grouped by project. Since this is many-to-many and we're a little deficient on indexes for doing this on the database, we pull all matching tasks and group them in PHP. This shouldn't be a huge issue for any existing installs, though, and we can add keys when we run into one.
- When a task is in multiple projects, it appears under multiple headers.
- When a query has a task filter, those projects are omitted from the grouping (they'd always show everything, which isn't useful). Notably, if you search for "Differential", you can now see "Bugs", "Feature Requests", etc.
Test Plan: Selected "Group by: Project".
Reviewers: btrahan, Josereyes
Reviewed By: btrahan
CC: aran, epriestley
Maniphest Tasks: T923
Differential Revision: https://secure.phabricator.com/D1953
2012-03-19 19:47:34 -07:00
|
|
|
// If the user is filtering on "Bugs", don't show a "Bugs" group
|
|
|
|
|
// with every result since that's silly (the query also does this
|
|
|
|
|
// on the backend).
|
|
|
|
|
$phids = array_diff($phids, $project_phids);
|
|
|
|
|
}
|
|
|
|
|
if ($phids) {
|
|
|
|
|
foreach ($phids as $phid) {
|
|
|
|
|
$grouped[$handles[$phid]->getName()][$task->getID()] = $task;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$grouped['No Project'][$task->getID()] = $task;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$data = $grouped;
|
2012-03-22 13:55:22 -07:00
|
|
|
ksort($data);
|
|
|
|
|
|
|
|
|
|
// Move "No Project" to the end of the list.
|
|
|
|
|
if (isset($data['No Project'])) {
|
|
|
|
|
$noproject = $data['No Project'];
|
|
|
|
|
unset($data['No Project']);
|
|
|
|
|
$data += array('No Project' => $noproject);
|
|
|
|
|
}
|
Add "Group by: Project" to Maniphest
Summary:
Allow tasks to be grouped by project. Since this is many-to-many and we're a little deficient on indexes for doing this on the database, we pull all matching tasks and group them in PHP. This shouldn't be a huge issue for any existing installs, though, and we can add keys when we run into one.
- When a task is in multiple projects, it appears under multiple headers.
- When a query has a task filter, those projects are omitted from the grouping (they'd always show everything, which isn't useful). Notably, if you search for "Differential", you can now see "Bugs", "Feature Requests", etc.
Test Plan: Selected "Group by: Project".
Reviewers: btrahan, Josereyes
Reviewed By: btrahan
CC: aran, epriestley
Maniphest Tasks: T923
Differential Revision: https://secure.phabricator.com/D1953
2012-03-19 19:47:34 -07:00
|
|
|
break;
|
2011-02-11 10:28:37 -08:00
|
|
|
default:
|
|
|
|
|
$data = array(
|
|
|
|
|
'Tasks' => $data,
|
|
|
|
|
);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
Allow Maniphest to scale to a massive size
Summary:
Maniphest is missing some keys and some query strategy which will make it
cumbersome to manage more than a few tens of thousands of tasks.
Test Plan:
Handily manipulated 100k-scale task groups. Maniphest takes about 250ms to
select and render pages of 1,000 tasks and has no problem paging and filtering
them, etc. We should be good to scale to multiple millions of tasks with these
changes.
Reviewed By: gc3
Reviewers: fratrik, jungejason, aran, tuomaspelkonen, gc3
Commenters: jungejason
CC: anjali, aran, epriestley, gc3, jungejason
Differential Revision: 534
2011-06-26 18:50:17 -07:00
|
|
|
return array($data, $handles, $total_row_count);
|
2011-02-11 10:28:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function renderStatusLinks() {
|
|
|
|
|
$request = $this->getRequest();
|
|
|
|
|
|
Simplify Maniphest button filter toggle things
Summary:
Although these filters work pretty well, you still end up doing a double take
sometimes. Make the behavior simpler and more consistent by adding an "All"
button to "Open / Closed" so all three rows behave the same way (before, the top
row was toggleable but the other rows were select-only-one).
I played around with the styles a little bit too to try to make the selected
state more obvious.
sandra/anjali, let me know if this is good enough once it lands or if I should
go further in playing around with the styles and making it more clear.
Test Plan:
Filtered tasks with the various filter buttons, verified the task list
accurately represented the filters.
Reviewed By: tuomaspelkonen
Reviewers: tuomaspelkonen, jungejason, aran
CC: anjali, sandra, aran, epriestley, tuomaspelkonen
Differential Revision: 364
2011-05-28 13:28:56 -07:00
|
|
|
$statuses = array(
|
|
|
|
|
'o' => array('open' => true),
|
|
|
|
|
'c' => array('closed' => true),
|
|
|
|
|
'oc' => array('open' => true, 'closed' => true),
|
2011-02-11 10:28:37 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$status = $request->getStr('s');
|
Simplify Maniphest button filter toggle things
Summary:
Although these filters work pretty well, you still end up doing a double take
sometimes. Make the behavior simpler and more consistent by adding an "All"
button to "Open / Closed" so all three rows behave the same way (before, the top
row was toggleable but the other rows were select-only-one).
I played around with the styles a little bit too to try to make the selected
state more obvious.
sandra/anjali, let me know if this is good enough once it lands or if I should
go further in playing around with the styles and making it more clear.
Test Plan:
Filtered tasks with the various filter buttons, verified the task list
accurately represented the filters.
Reviewed By: tuomaspelkonen
Reviewers: tuomaspelkonen, jungejason, aran
CC: anjali, sandra, aran, epriestley, tuomaspelkonen
Differential Revision: 364
2011-05-28 13:28:56 -07:00
|
|
|
if (empty($statuses[$status])) {
|
|
|
|
|
$status = 'o';
|
2011-02-11 10:28:37 -08:00
|
|
|
}
|
|
|
|
|
|
2012-02-27 12:59:05 -08:00
|
|
|
$status_control = id(new AphrontFormToggleButtonsControl())
|
|
|
|
|
->setLabel('Status')
|
|
|
|
|
->setValue($status)
|
|
|
|
|
->setBaseURI($request->getRequestURI(), 's')
|
|
|
|
|
->setButtons(
|
|
|
|
|
array(
|
|
|
|
|
'o' => 'Open',
|
|
|
|
|
'c' => 'Closed',
|
|
|
|
|
'oc' => 'All',
|
|
|
|
|
));
|
2011-02-11 10:28:37 -08:00
|
|
|
|
2012-02-27 12:59:05 -08:00
|
|
|
return array($statuses[$status], $status_control);
|
2011-02-11 10:28:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function renderOrderLinks() {
|
|
|
|
|
$request = $this->getRequest();
|
|
|
|
|
|
|
|
|
|
$order = $request->getStr('o');
|
|
|
|
|
$orders = array(
|
|
|
|
|
'u' => 'updated',
|
|
|
|
|
'c' => 'created',
|
|
|
|
|
'p' => 'priority',
|
|
|
|
|
);
|
|
|
|
|
if (empty($orders[$order])) {
|
2011-02-18 21:57:34 -08:00
|
|
|
$order = 'p';
|
2011-02-11 10:28:37 -08:00
|
|
|
}
|
|
|
|
|
$order_by = $orders[$order];
|
|
|
|
|
|
2012-02-27 12:59:05 -08:00
|
|
|
$order_control = id(new AphrontFormToggleButtonsControl())
|
|
|
|
|
->setLabel('Order')
|
|
|
|
|
->setValue($order)
|
|
|
|
|
->setBaseURI($request->getRequestURI(), 'o')
|
|
|
|
|
->setButtons(
|
|
|
|
|
array(
|
|
|
|
|
'p' => 'Priority',
|
|
|
|
|
'u' => 'Updated',
|
|
|
|
|
'c' => 'Created',
|
|
|
|
|
));
|
2011-02-11 10:28:37 -08:00
|
|
|
|
2012-02-27 12:59:05 -08:00
|
|
|
return array($order_by, $order_control);
|
2011-02-11 10:28:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function renderGroupLinks() {
|
|
|
|
|
$request = $this->getRequest();
|
|
|
|
|
|
|
|
|
|
$group = $request->getStr('g');
|
|
|
|
|
$groups = array(
|
|
|
|
|
'n' => 'none',
|
|
|
|
|
'p' => 'priority',
|
|
|
|
|
's' => 'status',
|
|
|
|
|
'o' => 'owner',
|
Add "Group by: Project" to Maniphest
Summary:
Allow tasks to be grouped by project. Since this is many-to-many and we're a little deficient on indexes for doing this on the database, we pull all matching tasks and group them in PHP. This shouldn't be a huge issue for any existing installs, though, and we can add keys when we run into one.
- When a task is in multiple projects, it appears under multiple headers.
- When a query has a task filter, those projects are omitted from the grouping (they'd always show everything, which isn't useful). Notably, if you search for "Differential", you can now see "Bugs", "Feature Requests", etc.
Test Plan: Selected "Group by: Project".
Reviewers: btrahan, Josereyes
Reviewed By: btrahan
CC: aran, epriestley
Maniphest Tasks: T923
Differential Revision: https://secure.phabricator.com/D1953
2012-03-19 19:47:34 -07:00
|
|
|
'j' => 'project',
|
2011-02-11 10:28:37 -08:00
|
|
|
);
|
|
|
|
|
if (empty($groups[$group])) {
|
2011-02-18 21:57:34 -08:00
|
|
|
$group = 'p';
|
2011-02-11 10:28:37 -08:00
|
|
|
}
|
|
|
|
|
$group_by = $groups[$group];
|
|
|
|
|
|
Simplify Maniphest button filter toggle things
Summary:
Although these filters work pretty well, you still end up doing a double take
sometimes. Make the behavior simpler and more consistent by adding an "All"
button to "Open / Closed" so all three rows behave the same way (before, the top
row was toggleable but the other rows were select-only-one).
I played around with the styles a little bit too to try to make the selected
state more obvious.
sandra/anjali, let me know if this is good enough once it lands or if I should
go further in playing around with the styles and making it more clear.
Test Plan:
Filtered tasks with the various filter buttons, verified the task list
accurately represented the filters.
Reviewed By: tuomaspelkonen
Reviewers: tuomaspelkonen, jungejason, aran
CC: anjali, sandra, aran, epriestley, tuomaspelkonen
Differential Revision: 364
2011-05-28 13:28:56 -07:00
|
|
|
|
2012-02-27 12:59:05 -08:00
|
|
|
$group_control = id(new AphrontFormToggleButtonsControl())
|
|
|
|
|
->setLabel('Group')
|
|
|
|
|
->setValue($group)
|
|
|
|
|
->setBaseURI($request->getRequestURI(), 'g')
|
|
|
|
|
->setButtons(
|
2011-02-11 10:28:37 -08:00
|
|
|
array(
|
2012-02-27 12:59:05 -08:00
|
|
|
'p' => 'Priority',
|
|
|
|
|
'o' => 'Owner',
|
|
|
|
|
's' => 'Status',
|
Add "Group by: Project" to Maniphest
Summary:
Allow tasks to be grouped by project. Since this is many-to-many and we're a little deficient on indexes for doing this on the database, we pull all matching tasks and group them in PHP. This shouldn't be a huge issue for any existing installs, though, and we can add keys when we run into one.
- When a task is in multiple projects, it appears under multiple headers.
- When a query has a task filter, those projects are omitted from the grouping (they'd always show everything, which isn't useful). Notably, if you search for "Differential", you can now see "Bugs", "Feature Requests", etc.
Test Plan: Selected "Group by: Project".
Reviewers: btrahan, Josereyes
Reviewed By: btrahan
CC: aran, epriestley
Maniphest Tasks: T923
Differential Revision: https://secure.phabricator.com/D1953
2012-03-19 19:47:34 -07:00
|
|
|
'j' => 'Project',
|
2012-02-27 12:59:05 -08:00
|
|
|
'n' => 'None',
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
return array($group_by, $group_control);
|
2011-02-08 10:53:59 -08:00
|
|
|
}
|
|
|
|
|
|
2012-02-28 21:07:12 -08:00
|
|
|
private function renderBatchEditor(PhabricatorSearchQuery $search_query) {
|
2012-02-24 13:00:48 -08:00
|
|
|
Javelin::initBehavior(
|
|
|
|
|
'maniphest-batch-selector',
|
|
|
|
|
array(
|
|
|
|
|
'selectAll' => 'batch-select-all',
|
|
|
|
|
'selectNone' => 'batch-select-none',
|
|
|
|
|
'submit' => 'batch-select-submit',
|
|
|
|
|
'status' => 'batch-select-status-cell',
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
$select_all = javelin_render_tag(
|
|
|
|
|
'a',
|
|
|
|
|
array(
|
|
|
|
|
'href' => '#',
|
|
|
|
|
'mustcapture' => true,
|
|
|
|
|
'class' => 'grey button',
|
|
|
|
|
'id' => 'batch-select-all',
|
|
|
|
|
),
|
|
|
|
|
'Select All');
|
|
|
|
|
|
|
|
|
|
$select_none = javelin_render_tag(
|
|
|
|
|
'a',
|
|
|
|
|
array(
|
|
|
|
|
'href' => '#',
|
|
|
|
|
'mustcapture' => true,
|
|
|
|
|
'class' => 'grey button',
|
|
|
|
|
'id' => 'batch-select-none',
|
|
|
|
|
),
|
|
|
|
|
'Clear Selection');
|
|
|
|
|
|
|
|
|
|
$submit = phutil_render_tag(
|
|
|
|
|
'button',
|
|
|
|
|
array(
|
|
|
|
|
'id' => 'batch-select-submit',
|
|
|
|
|
'disabled' => 'disabled',
|
|
|
|
|
'class' => 'disabled',
|
|
|
|
|
),
|
|
|
|
|
'Batch Edit Selected Tasks »');
|
|
|
|
|
|
2012-02-28 21:07:12 -08:00
|
|
|
$export = javelin_render_tag(
|
|
|
|
|
'a',
|
|
|
|
|
array(
|
|
|
|
|
'href' => '/maniphest/export/'.$search_query->getQueryKey().'/',
|
|
|
|
|
'class' => 'grey button',
|
|
|
|
|
),
|
|
|
|
|
'Export Tasks to Excel...');
|
|
|
|
|
|
2012-02-24 13:00:48 -08:00
|
|
|
return
|
|
|
|
|
'<div class="maniphest-batch-editor">'.
|
|
|
|
|
'<div class="batch-editor-header">Batch Task Editor</div>'.
|
|
|
|
|
'<table class="maniphest-batch-editor-layout">'.
|
|
|
|
|
'<tr>'.
|
|
|
|
|
'<td>'.
|
|
|
|
|
$select_all.
|
|
|
|
|
$select_none.
|
|
|
|
|
'</td>'.
|
2012-02-28 21:07:12 -08:00
|
|
|
'<td>'.
|
|
|
|
|
$export.
|
|
|
|
|
'</td>'.
|
2012-02-24 13:00:48 -08:00
|
|
|
'<td id="batch-select-status-cell">'.
|
|
|
|
|
'0 Selected Tasks'.
|
|
|
|
|
'</td>'.
|
|
|
|
|
'<td class="batch-select-submit-cell">'.$submit.'</td>'.
|
|
|
|
|
'</tr>'.
|
|
|
|
|
'</table>'.
|
|
|
|
|
'</table>';
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-08 10:53:59 -08:00
|
|
|
}
|