1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-30 01:10:58 +01:00

Move Maniphest list rendering to SearchEngine

Summary: Ref T4986. Moves Maniphest over. Nothing tricky here, just a complex block of rendering.

Test Plan: Viewed Maniphest list. Created Maniphest panel. Used batch editor, drag-and-drop.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T4986

Differential Revision: https://secure.phabricator.com/D9139
This commit is contained in:
epriestley 2014-05-15 19:17:38 -07:00
parent d653fa13de
commit e5e95352c7
4 changed files with 326 additions and 270 deletions

View file

@ -932,6 +932,7 @@ phutil_register_library_map(array(
'ManiphestTaskProject' => 'applications/maniphest/storage/ManiphestTaskProject.php', 'ManiphestTaskProject' => 'applications/maniphest/storage/ManiphestTaskProject.php',
'ManiphestTaskProjectsView' => 'applications/maniphest/view/ManiphestTaskProjectsView.php', 'ManiphestTaskProjectsView' => 'applications/maniphest/view/ManiphestTaskProjectsView.php',
'ManiphestTaskQuery' => 'applications/maniphest/query/ManiphestTaskQuery.php', 'ManiphestTaskQuery' => 'applications/maniphest/query/ManiphestTaskQuery.php',
'ManiphestTaskResultListView' => 'applications/maniphest/view/ManiphestTaskResultListView.php',
'ManiphestTaskSearchEngine' => 'applications/maniphest/query/ManiphestTaskSearchEngine.php', 'ManiphestTaskSearchEngine' => 'applications/maniphest/query/ManiphestTaskSearchEngine.php',
'ManiphestTaskStatus' => 'applications/maniphest/constants/ManiphestTaskStatus.php', 'ManiphestTaskStatus' => 'applications/maniphest/constants/ManiphestTaskStatus.php',
'ManiphestTaskStatusTestCase' => 'applications/maniphest/constants/__tests__/ManiphestTaskStatusTestCase.php', 'ManiphestTaskStatusTestCase' => 'applications/maniphest/constants/__tests__/ManiphestTaskStatusTestCase.php',
@ -3649,11 +3650,7 @@ phutil_register_library_map(array(
'ManiphestTaskDescriptionPreviewController' => 'ManiphestController', 'ManiphestTaskDescriptionPreviewController' => 'ManiphestController',
'ManiphestTaskDetailController' => 'ManiphestController', 'ManiphestTaskDetailController' => 'ManiphestController',
'ManiphestTaskEditController' => 'ManiphestController', 'ManiphestTaskEditController' => 'ManiphestController',
'ManiphestTaskListController' => 'ManiphestTaskListController' => 'ManiphestController',
array(
0 => 'ManiphestController',
1 => 'PhabricatorApplicationSearchResultsControllerInterface',
),
'ManiphestTaskListView' => 'ManiphestView', 'ManiphestTaskListView' => 'ManiphestView',
'ManiphestTaskMailReceiver' => 'PhabricatorObjectMailReceiver', 'ManiphestTaskMailReceiver' => 'PhabricatorObjectMailReceiver',
'ManiphestTaskOwner' => 'ManiphestConstants', 'ManiphestTaskOwner' => 'ManiphestConstants',
@ -3661,6 +3658,7 @@ phutil_register_library_map(array(
'ManiphestTaskProject' => 'ManiphestDAO', 'ManiphestTaskProject' => 'ManiphestDAO',
'ManiphestTaskProjectsView' => 'ManiphestView', 'ManiphestTaskProjectsView' => 'ManiphestView',
'ManiphestTaskQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ManiphestTaskQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'ManiphestTaskResultListView' => 'ManiphestView',
'ManiphestTaskSearchEngine' => 'PhabricatorApplicationSearchEngine', 'ManiphestTaskSearchEngine' => 'PhabricatorApplicationSearchEngine',
'ManiphestTaskStatus' => 'ManiphestConstants', 'ManiphestTaskStatus' => 'ManiphestConstants',
'ManiphestTaskStatusTestCase' => 'PhabricatorTestCase', 'ManiphestTaskStatusTestCase' => 'PhabricatorTestCase',
@ -4635,11 +4633,7 @@ phutil_register_library_map(array(
'PhabricatorPasteDAO' => 'PhabricatorLiskDAO', 'PhabricatorPasteDAO' => 'PhabricatorLiskDAO',
'PhabricatorPasteEditController' => 'PhabricatorPasteController', 'PhabricatorPasteEditController' => 'PhabricatorPasteController',
'PhabricatorPasteEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorPasteEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorPasteListController' => 'PhabricatorPasteListController' => 'PhabricatorPasteController',
array(
0 => 'PhabricatorPasteController',
1 => 'PhabricatorApplicationSearchResultsControllerInterface',
),
'PhabricatorPastePHIDTypePaste' => 'PhabricatorPHIDType', 'PhabricatorPastePHIDTypePaste' => 'PhabricatorPHIDType',
'PhabricatorPasteQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPasteQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorPasteRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'PhabricatorPasteRemarkupRule' => 'PhabricatorRemarkupRuleObject',
@ -4658,18 +4652,10 @@ phutil_register_library_map(array(
'PhabricatorPeopleEmpowerController' => 'PhabricatorPeopleController', 'PhabricatorPeopleEmpowerController' => 'PhabricatorPeopleController',
'PhabricatorPeopleHovercardEventListener' => 'PhabricatorEventListener', 'PhabricatorPeopleHovercardEventListener' => 'PhabricatorEventListener',
'PhabricatorPeopleLdapController' => 'PhabricatorPeopleController', 'PhabricatorPeopleLdapController' => 'PhabricatorPeopleController',
'PhabricatorPeopleListController' => 'PhabricatorPeopleListController' => 'PhabricatorPeopleController',
array(
0 => 'PhabricatorPeopleController',
1 => 'PhabricatorApplicationSearchResultsControllerInterface',
),
'PhabricatorPeopleLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPeopleLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorPeopleLogSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorPeopleLogSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorPeopleLogsController' => 'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController',
array(
0 => 'PhabricatorPeopleController',
1 => 'PhabricatorApplicationSearchResultsControllerInterface',
),
'PhabricatorPeopleNewController' => 'PhabricatorPeopleController', 'PhabricatorPeopleNewController' => 'PhabricatorPeopleController',
'PhabricatorPeoplePHIDTypeExternal' => 'PhabricatorPHIDType', 'PhabricatorPeoplePHIDTypeExternal' => 'PhabricatorPHIDType',
'PhabricatorPeoplePHIDTypeUser' => 'PhabricatorPHIDType', 'PhabricatorPeoplePHIDTypeUser' => 'PhabricatorPHIDType',

View file

@ -1,8 +1,7 @@
<?php <?php
final class ManiphestTaskListController final class ManiphestTaskListController
extends ManiphestController extends ManiphestController {
implements PhabricatorApplicationSearchResultsControllerInterface {
private $queryKey; private $queryKey;
@ -18,257 +17,12 @@ final class ManiphestTaskListController
$request = $this->getRequest(); $request = $this->getRequest();
$controller = id(new PhabricatorApplicationSearchController($request)) $controller = id(new PhabricatorApplicationSearchController($request))
->setQueryKey($this->queryKey) ->setQueryKey($this->queryKey)
->setSearchEngine(new ManiphestTaskSearchEngine()) ->setSearchEngine(
id(new ManiphestTaskSearchEngine())
->setShowBatchControls(true))
->setNavigation($this->buildSideNavView()); ->setNavigation($this->buildSideNavView());
return $this->delegateToController($controller); return $this->delegateToController($controller);
} }
public function renderResultsList(
array $tasks,
PhabricatorSavedQuery $query) {
assert_instances_of($tasks, 'ManiphestTask');
$viewer = $this->getRequest()->getUser();
// If we didn't match anything, just pick up the default empty state.
if (!$tasks) {
return id(new PHUIObjectItemListView())
->setUser($viewer);
}
$group_parameter = nonempty($query->getParameter('group'), 'priority');
$order_parameter = nonempty($query->getParameter('order'), 'priority');
$handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks);
$groups = $this->groupTasks(
$tasks,
$group_parameter,
$handles);
$can_edit_priority = $this->hasApplicationCapability(
ManiphestCapabilityEditPriority::CAPABILITY);
$can_drag = ($order_parameter == 'priority') &&
($can_edit_priority) &&
($group_parameter == 'none' || $group_parameter == 'priority');
if (!$viewer->isLoggedIn()) {
// TODO: (T603) Eventually, we conceivably need to make each task
// draggable individually, since the user may be able to edit some but
// not others.
$can_drag = false;
}
$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,
));
}
if ($can_drag) {
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 groupTasks(array $tasks, $group, array $handles) {
assert_instances_of($tasks, 'ManiphestTask');
assert_instances_of($handles, 'PhabricatorObjectHandle');
$groups = $this->getTaskGrouping($tasks, $group);
$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 $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');
}
}
private function renderBatchEditor(PhabricatorSavedQuery $saved_query) {
$user = $this->getRequest()->getUser();
$batch_capability = ManiphestCapabilityBulkEdit::CAPABILITY;
if (!$this->hasApplicationCapability($batch_capability)) {
return null;
}
if (!$user->isLoggedIn()) {
// Don't show the batch editor or excel export for logged-out users.
// Technically we //could// let them export, but ehh.
return null;
}
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;
}
} }

View file

@ -3,6 +3,17 @@
final class ManiphestTaskSearchEngine final class ManiphestTaskSearchEngine
extends PhabricatorApplicationSearchEngine { extends PhabricatorApplicationSearchEngine {
private $showBatchControls;
public function setShowBatchControls($show_batch_controls) {
$this->showBatchControls = $show_batch_controls;
return $this;
}
public function getApplicationClassName() {
return 'PhabricatorApplicationManiphest';
}
public function getCustomFieldObject() { public function getCustomFieldObject() {
return new ManiphestTask(); return new ManiphestTask();
} }
@ -473,4 +484,30 @@ final class ManiphestTaskSearchEngine
); );
} }
protected function renderResultList(
array $tasks,
PhabricatorSavedQuery $saved,
array $handles) {
$viewer = $this->requireViewer();
$can_edit_priority = PhabricatorPolicyFilter::hasCapability(
$viewer,
$this->getApplication(),
ManiphestCapabilityEditPriority::CAPABILITY);
$can_bulk_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$this->getApplication(),
ManiphestCapabilityBulkEdit::CAPABILITY);
return id(new ManiphestTaskResultListView())
->setUser($viewer)
->setTasks($tasks)
->setSavedQuery($saved)
->setCanEditPriority($can_edit_priority)
->setCanBatchEdit($can_bulk_edit)
->setShowBatchControls($this->showBatchControls);
}
} }

View file

@ -0,0 +1,279 @@
<?php
final class ManiphestTaskResultListView extends ManiphestView {
private $tasks;
private $savedQuery;
private $canEditPriority;
private $canBatchEdit;
private $showBatchControls;
public function setSavedQuery(PhabricatorSavedQuery $query) {
$this->savedQuery = $query;
return $this;
}
public function setTasks(array $tasks) {
$this->tasks = $tasks;
return $this;
}
public function setCanEditPriority($can_edit_priority) {
$this->canEditPriority = $can_edit_priority;
return $this;
}
public function setCanBatchEdit($can_batch_edit) {
$this->canBatchEdit = $can_batch_edit;
return $this;
}
public function setShowBatchControls($show_batch_controls) {
$this->showBatchControls = $show_batch_controls;
return $this;
}
public function render() {
$viewer = $this->getUser();
$tasks = $this->tasks;
$query = $this->savedQuery;
// If we didn't match anything, just pick up the default empty state.
if (!$tasks) {
return id(new PHUIObjectItemListView())
->setUser($viewer);
}
$group_parameter = nonempty($query->getParameter('group'), 'priority');
$order_parameter = nonempty($query->getParameter('order'), 'priority');
$handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks);
$groups = $this->groupTasks(
$tasks,
$group_parameter,
$handles);
$can_edit_priority = $this->canEditPriority;
$can_drag = ($order_parameter == 'priority') &&
($can_edit_priority) &&
($group_parameter == 'none' || $group_parameter == 'priority');
if (!$viewer->isLoggedIn()) {
// TODO: (T603) Eventually, we conceivably need to make each task
// draggable individually, since the user may be able to edit some but
// not others.
$can_drag = false;
}
$result = array();
$lists = array();
foreach ($groups as $group => $list) {
$task_list = new ManiphestTaskListView();
$task_list->setShowBatchControls($this->showBatchControls);
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,
));
}
if ($can_drag) {
Javelin::initBehavior(
'maniphest-subpriority-editor',
array(
'uri' => '/maniphest/subpriority/',
));
}
return phutil_tag(
'div',
array(
'class' => 'maniphest-list-container',
),
array(
$lists,
$this->showBatchControls ? $this->renderBatchEditor($query) : null,
));
}
private function groupTasks(array $tasks, $group, array $handles) {
assert_instances_of($tasks, 'ManiphestTask');
assert_instances_of($handles, 'PhabricatorObjectHandle');
$groups = $this->getTaskGrouping($tasks, $group);
$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 $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');
}
}
private function renderBatchEditor(PhabricatorSavedQuery $saved_query) {
$user = $this->getUser();
if (!$this->canBatchEdit) {
return null;
}
if (!$user->isLoggedIn()) {
// Don't show the batch editor or excel export for logged-out users.
// Technically we //could// let them export, but ehh.
return null;
}
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;
}
}