@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+326 -270
+6 -20
src/__phutil_library_map__.php
··· 932 932 'ManiphestTaskProject' => 'applications/maniphest/storage/ManiphestTaskProject.php', 933 933 'ManiphestTaskProjectsView' => 'applications/maniphest/view/ManiphestTaskProjectsView.php', 934 934 'ManiphestTaskQuery' => 'applications/maniphest/query/ManiphestTaskQuery.php', 935 + 'ManiphestTaskResultListView' => 'applications/maniphest/view/ManiphestTaskResultListView.php', 935 936 'ManiphestTaskSearchEngine' => 'applications/maniphest/query/ManiphestTaskSearchEngine.php', 936 937 'ManiphestTaskStatus' => 'applications/maniphest/constants/ManiphestTaskStatus.php', 937 938 'ManiphestTaskStatusTestCase' => 'applications/maniphest/constants/__tests__/ManiphestTaskStatusTestCase.php', ··· 3649 3650 'ManiphestTaskDescriptionPreviewController' => 'ManiphestController', 3650 3651 'ManiphestTaskDetailController' => 'ManiphestController', 3651 3652 'ManiphestTaskEditController' => 'ManiphestController', 3652 - 'ManiphestTaskListController' => 3653 - array( 3654 - 0 => 'ManiphestController', 3655 - 1 => 'PhabricatorApplicationSearchResultsControllerInterface', 3656 - ), 3653 + 'ManiphestTaskListController' => 'ManiphestController', 3657 3654 'ManiphestTaskListView' => 'ManiphestView', 3658 3655 'ManiphestTaskMailReceiver' => 'PhabricatorObjectMailReceiver', 3659 3656 'ManiphestTaskOwner' => 'ManiphestConstants', ··· 3661 3658 'ManiphestTaskProject' => 'ManiphestDAO', 3662 3659 'ManiphestTaskProjectsView' => 'ManiphestView', 3663 3660 'ManiphestTaskQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 3661 + 'ManiphestTaskResultListView' => 'ManiphestView', 3664 3662 'ManiphestTaskSearchEngine' => 'PhabricatorApplicationSearchEngine', 3665 3663 'ManiphestTaskStatus' => 'ManiphestConstants', 3666 3664 'ManiphestTaskStatusTestCase' => 'PhabricatorTestCase', ··· 4635 4633 'PhabricatorPasteDAO' => 'PhabricatorLiskDAO', 4636 4634 'PhabricatorPasteEditController' => 'PhabricatorPasteController', 4637 4635 'PhabricatorPasteEditor' => 'PhabricatorApplicationTransactionEditor', 4638 - 'PhabricatorPasteListController' => 4639 - array( 4640 - 0 => 'PhabricatorPasteController', 4641 - 1 => 'PhabricatorApplicationSearchResultsControllerInterface', 4642 - ), 4636 + 'PhabricatorPasteListController' => 'PhabricatorPasteController', 4643 4637 'PhabricatorPastePHIDTypePaste' => 'PhabricatorPHIDType', 4644 4638 'PhabricatorPasteQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 4645 4639 'PhabricatorPasteRemarkupRule' => 'PhabricatorRemarkupRuleObject', ··· 4658 4652 'PhabricatorPeopleEmpowerController' => 'PhabricatorPeopleController', 4659 4653 'PhabricatorPeopleHovercardEventListener' => 'PhabricatorEventListener', 4660 4654 'PhabricatorPeopleLdapController' => 'PhabricatorPeopleController', 4661 - 'PhabricatorPeopleListController' => 4662 - array( 4663 - 0 => 'PhabricatorPeopleController', 4664 - 1 => 'PhabricatorApplicationSearchResultsControllerInterface', 4665 - ), 4655 + 'PhabricatorPeopleListController' => 'PhabricatorPeopleController', 4666 4656 'PhabricatorPeopleLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 4667 4657 'PhabricatorPeopleLogSearchEngine' => 'PhabricatorApplicationSearchEngine', 4668 - 'PhabricatorPeopleLogsController' => 4669 - array( 4670 - 0 => 'PhabricatorPeopleController', 4671 - 1 => 'PhabricatorApplicationSearchResultsControllerInterface', 4672 - ), 4658 + 'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController', 4673 4659 'PhabricatorPeopleNewController' => 'PhabricatorPeopleController', 4674 4660 'PhabricatorPeoplePHIDTypeExternal' => 'PhabricatorPHIDType', 4675 4661 'PhabricatorPeoplePHIDTypeUser' => 'PhabricatorPHIDType',
+4 -250
src/applications/maniphest/controller/ManiphestTaskListController.php
··· 1 1 <?php 2 2 3 3 final class ManiphestTaskListController 4 - extends ManiphestController 5 - implements PhabricatorApplicationSearchResultsControllerInterface { 4 + extends ManiphestController { 6 5 7 6 private $queryKey; 8 7 ··· 18 17 $request = $this->getRequest(); 19 18 $controller = id(new PhabricatorApplicationSearchController($request)) 20 19 ->setQueryKey($this->queryKey) 21 - ->setSearchEngine(new ManiphestTaskSearchEngine()) 20 + ->setSearchEngine( 21 + id(new ManiphestTaskSearchEngine()) 22 + ->setShowBatchControls(true)) 22 23 ->setNavigation($this->buildSideNavView()); 23 24 24 25 return $this->delegateToController($controller); 25 - } 26 - 27 - public function renderResultsList( 28 - array $tasks, 29 - PhabricatorSavedQuery $query) { 30 - assert_instances_of($tasks, 'ManiphestTask'); 31 - 32 - $viewer = $this->getRequest()->getUser(); 33 - 34 - // If we didn't match anything, just pick up the default empty state. 35 - if (!$tasks) { 36 - return id(new PHUIObjectItemListView()) 37 - ->setUser($viewer); 38 - } 39 - 40 - $group_parameter = nonempty($query->getParameter('group'), 'priority'); 41 - $order_parameter = nonempty($query->getParameter('order'), 'priority'); 42 - 43 - $handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks); 44 - $groups = $this->groupTasks( 45 - $tasks, 46 - $group_parameter, 47 - $handles); 48 - 49 - $can_edit_priority = $this->hasApplicationCapability( 50 - ManiphestCapabilityEditPriority::CAPABILITY); 51 - 52 - $can_drag = ($order_parameter == 'priority') && 53 - ($can_edit_priority) && 54 - ($group_parameter == 'none' || $group_parameter == 'priority'); 55 - 56 - if (!$viewer->isLoggedIn()) { 57 - // TODO: (T603) Eventually, we conceivably need to make each task 58 - // draggable individually, since the user may be able to edit some but 59 - // not others. 60 - $can_drag = false; 61 - } 62 - 63 - $result = array(); 64 - 65 - $lists = array(); 66 - foreach ($groups as $group => $list) { 67 - $task_list = new ManiphestTaskListView(); 68 - $task_list->setShowBatchControls(true); 69 - if ($can_drag) { 70 - $task_list->setShowSubpriorityControls(true); 71 - } 72 - $task_list->setUser($viewer); 73 - $task_list->setTasks($list); 74 - $task_list->setHandles($handles); 75 - 76 - $header = javelin_tag( 77 - 'h1', 78 - array( 79 - 'class' => 'maniphest-task-group-header', 80 - 'sigil' => 'task-group', 81 - 'meta' => array( 82 - 'priority' => head($list)->getPriority(), 83 - ), 84 - ), 85 - pht('%s (%s)', $group, new PhutilNumber(count($list)))); 86 - 87 - $lists[] = phutil_tag( 88 - 'div', 89 - array( 90 - 'class' => 'maniphest-task-group' 91 - ), 92 - array( 93 - $header, 94 - $task_list, 95 - )); 96 - } 97 - 98 - if ($can_drag) { 99 - Javelin::initBehavior( 100 - 'maniphest-subpriority-editor', 101 - array( 102 - 'uri' => '/maniphest/subpriority/', 103 - )); 104 - } 105 - 106 - return phutil_tag( 107 - 'div', 108 - array( 109 - 'class' => 'maniphest-list-container', 110 - ), 111 - array( 112 - $lists, 113 - $this->renderBatchEditor($query), 114 - )); 115 - } 116 - 117 - private function groupTasks(array $tasks, $group, array $handles) { 118 - assert_instances_of($tasks, 'ManiphestTask'); 119 - assert_instances_of($handles, 'PhabricatorObjectHandle'); 120 - 121 - $groups = $this->getTaskGrouping($tasks, $group); 122 - 123 - $results = array(); 124 - foreach ($groups as $label_key => $tasks) { 125 - $label = $this->getTaskLabelName($group, $label_key, $handles); 126 - $results[$label][] = $tasks; 127 - } 128 - foreach ($results as $label => $task_groups) { 129 - $results[$label] = array_mergev($task_groups); 130 - } 131 - 132 - return $results; 133 - } 134 - 135 - private function getTaskGrouping(array $tasks, $group) { 136 - switch ($group) { 137 - case 'priority': 138 - return mgroup($tasks, 'getPriority'); 139 - case 'status': 140 - return mgroup($tasks, 'getStatus'); 141 - case 'assigned': 142 - return mgroup($tasks, 'getOwnerPHID'); 143 - case 'project': 144 - return mgroup($tasks, 'getGroupByProjectPHID'); 145 - default: 146 - return array(pht('Tasks') => $tasks); 147 - } 148 - } 149 - 150 - private function getTaskLabelName($group, $label_key, array $handles) { 151 - switch ($group) { 152 - case 'priority': 153 - return ManiphestTaskPriority::getTaskPriorityName($label_key); 154 - case 'status': 155 - return ManiphestTaskStatus::getTaskStatusFullName($label_key); 156 - case 'assigned': 157 - if ($label_key) { 158 - return $handles[$label_key]->getFullName(); 159 - } else { 160 - return pht('(Not Assigned)'); 161 - } 162 - case 'project': 163 - if ($label_key) { 164 - return $handles[$label_key]->getFullName(); 165 - } else { 166 - return pht('(No Project)'); 167 - } 168 - default: 169 - return pht('Tasks'); 170 - } 171 - } 172 - 173 - private function renderBatchEditor(PhabricatorSavedQuery $saved_query) { 174 - $user = $this->getRequest()->getUser(); 175 - 176 - $batch_capability = ManiphestCapabilityBulkEdit::CAPABILITY; 177 - if (!$this->hasApplicationCapability($batch_capability)) { 178 - return null; 179 - } 180 - 181 - if (!$user->isLoggedIn()) { 182 - // Don't show the batch editor or excel export for logged-out users. 183 - // Technically we //could// let them export, but ehh. 184 - return null; 185 - } 186 - 187 - Javelin::initBehavior( 188 - 'maniphest-batch-selector', 189 - array( 190 - 'selectAll' => 'batch-select-all', 191 - 'selectNone' => 'batch-select-none', 192 - 'submit' => 'batch-select-submit', 193 - 'status' => 'batch-select-status-cell', 194 - 'idContainer' => 'batch-select-id-container', 195 - 'formID' => 'batch-select-form', 196 - )); 197 - 198 - $select_all = javelin_tag( 199 - 'a', 200 - array( 201 - 'href' => '#', 202 - 'mustcapture' => true, 203 - 'class' => 'grey button', 204 - 'id' => 'batch-select-all', 205 - ), 206 - pht('Select All')); 207 - 208 - $select_none = javelin_tag( 209 - 'a', 210 - array( 211 - 'href' => '#', 212 - 'mustcapture' => true, 213 - 'class' => 'grey button', 214 - 'id' => 'batch-select-none', 215 - ), 216 - pht('Clear Selection')); 217 - 218 - $submit = phutil_tag( 219 - 'button', 220 - array( 221 - 'id' => 'batch-select-submit', 222 - 'disabled' => 'disabled', 223 - 'class' => 'disabled', 224 - ), 225 - pht("Batch Edit Selected \xC2\xBB")); 226 - 227 - $export = javelin_tag( 228 - 'a', 229 - array( 230 - 'href' => '/maniphest/export/'.$saved_query->getQueryKey().'/', 231 - 'class' => 'grey button', 232 - ), 233 - pht('Export to Excel')); 234 - 235 - $hidden = phutil_tag( 236 - 'div', 237 - array( 238 - 'id' => 'batch-select-id-container', 239 - ), 240 - ''); 241 - 242 - $editor = hsprintf( 243 - '<div class="maniphest-batch-editor">'. 244 - '<div class="batch-editor-header">%s</div>'. 245 - '<table class="maniphest-batch-editor-layout">'. 246 - '<tr>'. 247 - '<td>%s%s</td>'. 248 - '<td>%s</td>'. 249 - '<td id="batch-select-status-cell">%s</td>'. 250 - '<td class="batch-select-submit-cell">%s%s</td>'. 251 - '</tr>'. 252 - '</table>'. 253 - '</div>', 254 - pht('Batch Task Editor'), 255 - $select_all, 256 - $select_none, 257 - $export, 258 - '', 259 - $submit, 260 - $hidden); 261 - 262 - $editor = phabricator_form( 263 - $user, 264 - array( 265 - 'method' => 'POST', 266 - 'action' => '/maniphest/batch/', 267 - 'id' => 'batch-select-form', 268 - ), 269 - $editor); 270 - 271 - return $editor; 272 26 } 273 27 274 28 }
+37
src/applications/maniphest/query/ManiphestTaskSearchEngine.php
··· 3 3 final class ManiphestTaskSearchEngine 4 4 extends PhabricatorApplicationSearchEngine { 5 5 6 + private $showBatchControls; 7 + 8 + public function setShowBatchControls($show_batch_controls) { 9 + $this->showBatchControls = $show_batch_controls; 10 + return $this; 11 + } 12 + 13 + public function getApplicationClassName() { 14 + return 'PhabricatorApplicationManiphest'; 15 + } 16 + 6 17 public function getCustomFieldObject() { 7 18 return new ManiphestTask(); 8 19 } ··· 471 482 'project' => ManiphestTaskQuery::GROUP_PROJECT, 472 483 'none' => ManiphestTaskQuery::GROUP_NONE, 473 484 ); 485 + } 486 + 487 + protected function renderResultList( 488 + array $tasks, 489 + PhabricatorSavedQuery $saved, 490 + array $handles) { 491 + 492 + $viewer = $this->requireViewer(); 493 + 494 + $can_edit_priority = PhabricatorPolicyFilter::hasCapability( 495 + $viewer, 496 + $this->getApplication(), 497 + ManiphestCapabilityEditPriority::CAPABILITY); 498 + 499 + $can_bulk_edit = PhabricatorPolicyFilter::hasCapability( 500 + $viewer, 501 + $this->getApplication(), 502 + ManiphestCapabilityBulkEdit::CAPABILITY); 503 + 504 + return id(new ManiphestTaskResultListView()) 505 + ->setUser($viewer) 506 + ->setTasks($tasks) 507 + ->setSavedQuery($saved) 508 + ->setCanEditPriority($can_edit_priority) 509 + ->setCanBatchEdit($can_bulk_edit) 510 + ->setShowBatchControls($this->showBatchControls); 474 511 } 475 512 476 513 }
+279
src/applications/maniphest/view/ManiphestTaskResultListView.php
··· 1 + <?php 2 + 3 + final class ManiphestTaskResultListView extends ManiphestView { 4 + 5 + private $tasks; 6 + private $savedQuery; 7 + private $canEditPriority; 8 + private $canBatchEdit; 9 + private $showBatchControls; 10 + 11 + public function setSavedQuery(PhabricatorSavedQuery $query) { 12 + $this->savedQuery = $query; 13 + return $this; 14 + } 15 + 16 + public function setTasks(array $tasks) { 17 + $this->tasks = $tasks; 18 + return $this; 19 + } 20 + 21 + public function setCanEditPriority($can_edit_priority) { 22 + $this->canEditPriority = $can_edit_priority; 23 + return $this; 24 + } 25 + 26 + public function setCanBatchEdit($can_batch_edit) { 27 + $this->canBatchEdit = $can_batch_edit; 28 + return $this; 29 + } 30 + 31 + public function setShowBatchControls($show_batch_controls) { 32 + $this->showBatchControls = $show_batch_controls; 33 + return $this; 34 + } 35 + 36 + public function render() { 37 + $viewer = $this->getUser(); 38 + $tasks = $this->tasks; 39 + $query = $this->savedQuery; 40 + 41 + // If we didn't match anything, just pick up the default empty state. 42 + if (!$tasks) { 43 + return id(new PHUIObjectItemListView()) 44 + ->setUser($viewer); 45 + } 46 + 47 + $group_parameter = nonempty($query->getParameter('group'), 'priority'); 48 + $order_parameter = nonempty($query->getParameter('order'), 'priority'); 49 + 50 + $handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks); 51 + $groups = $this->groupTasks( 52 + $tasks, 53 + $group_parameter, 54 + $handles); 55 + 56 + $can_edit_priority = $this->canEditPriority; 57 + 58 + $can_drag = ($order_parameter == 'priority') && 59 + ($can_edit_priority) && 60 + ($group_parameter == 'none' || $group_parameter == 'priority'); 61 + 62 + if (!$viewer->isLoggedIn()) { 63 + // TODO: (T603) Eventually, we conceivably need to make each task 64 + // draggable individually, since the user may be able to edit some but 65 + // not others. 66 + $can_drag = false; 67 + } 68 + 69 + $result = array(); 70 + 71 + $lists = array(); 72 + foreach ($groups as $group => $list) { 73 + $task_list = new ManiphestTaskListView(); 74 + $task_list->setShowBatchControls($this->showBatchControls); 75 + if ($can_drag) { 76 + $task_list->setShowSubpriorityControls(true); 77 + } 78 + $task_list->setUser($viewer); 79 + $task_list->setTasks($list); 80 + $task_list->setHandles($handles); 81 + 82 + $header = javelin_tag( 83 + 'h1', 84 + array( 85 + 'class' => 'maniphest-task-group-header', 86 + 'sigil' => 'task-group', 87 + 'meta' => array( 88 + 'priority' => head($list)->getPriority(), 89 + ), 90 + ), 91 + pht('%s (%s)', $group, new PhutilNumber(count($list)))); 92 + 93 + $lists[] = phutil_tag( 94 + 'div', 95 + array( 96 + 'class' => 'maniphest-task-group' 97 + ), 98 + array( 99 + $header, 100 + $task_list, 101 + )); 102 + } 103 + 104 + if ($can_drag) { 105 + Javelin::initBehavior( 106 + 'maniphest-subpriority-editor', 107 + array( 108 + 'uri' => '/maniphest/subpriority/', 109 + )); 110 + } 111 + 112 + return phutil_tag( 113 + 'div', 114 + array( 115 + 'class' => 'maniphest-list-container', 116 + ), 117 + array( 118 + $lists, 119 + $this->showBatchControls ? $this->renderBatchEditor($query) : null, 120 + )); 121 + } 122 + 123 + 124 + private function groupTasks(array $tasks, $group, array $handles) { 125 + assert_instances_of($tasks, 'ManiphestTask'); 126 + assert_instances_of($handles, 'PhabricatorObjectHandle'); 127 + 128 + $groups = $this->getTaskGrouping($tasks, $group); 129 + 130 + $results = array(); 131 + foreach ($groups as $label_key => $tasks) { 132 + $label = $this->getTaskLabelName($group, $label_key, $handles); 133 + $results[$label][] = $tasks; 134 + } 135 + foreach ($results as $label => $task_groups) { 136 + $results[$label] = array_mergev($task_groups); 137 + } 138 + 139 + return $results; 140 + } 141 + 142 + private function getTaskGrouping(array $tasks, $group) { 143 + switch ($group) { 144 + case 'priority': 145 + return mgroup($tasks, 'getPriority'); 146 + case 'status': 147 + return mgroup($tasks, 'getStatus'); 148 + case 'assigned': 149 + return mgroup($tasks, 'getOwnerPHID'); 150 + case 'project': 151 + return mgroup($tasks, 'getGroupByProjectPHID'); 152 + default: 153 + return array(pht('Tasks') => $tasks); 154 + } 155 + } 156 + 157 + private function getTaskLabelName($group, $label_key, array $handles) { 158 + switch ($group) { 159 + case 'priority': 160 + return ManiphestTaskPriority::getTaskPriorityName($label_key); 161 + case 'status': 162 + return ManiphestTaskStatus::getTaskStatusFullName($label_key); 163 + case 'assigned': 164 + if ($label_key) { 165 + return $handles[$label_key]->getFullName(); 166 + } else { 167 + return pht('(Not Assigned)'); 168 + } 169 + case 'project': 170 + if ($label_key) { 171 + return $handles[$label_key]->getFullName(); 172 + } else { 173 + return pht('(No Project)'); 174 + } 175 + default: 176 + return pht('Tasks'); 177 + } 178 + } 179 + 180 + private function renderBatchEditor(PhabricatorSavedQuery $saved_query) { 181 + $user = $this->getUser(); 182 + 183 + if (!$this->canBatchEdit) { 184 + return null; 185 + } 186 + 187 + if (!$user->isLoggedIn()) { 188 + // Don't show the batch editor or excel export for logged-out users. 189 + // Technically we //could// let them export, but ehh. 190 + return null; 191 + } 192 + 193 + Javelin::initBehavior( 194 + 'maniphest-batch-selector', 195 + array( 196 + 'selectAll' => 'batch-select-all', 197 + 'selectNone' => 'batch-select-none', 198 + 'submit' => 'batch-select-submit', 199 + 'status' => 'batch-select-status-cell', 200 + 'idContainer' => 'batch-select-id-container', 201 + 'formID' => 'batch-select-form', 202 + )); 203 + 204 + $select_all = javelin_tag( 205 + 'a', 206 + array( 207 + 'href' => '#', 208 + 'mustcapture' => true, 209 + 'class' => 'grey button', 210 + 'id' => 'batch-select-all', 211 + ), 212 + pht('Select All')); 213 + 214 + $select_none = javelin_tag( 215 + 'a', 216 + array( 217 + 'href' => '#', 218 + 'mustcapture' => true, 219 + 'class' => 'grey button', 220 + 'id' => 'batch-select-none', 221 + ), 222 + pht('Clear Selection')); 223 + 224 + $submit = phutil_tag( 225 + 'button', 226 + array( 227 + 'id' => 'batch-select-submit', 228 + 'disabled' => 'disabled', 229 + 'class' => 'disabled', 230 + ), 231 + pht("Batch Edit Selected \xC2\xBB")); 232 + 233 + $export = javelin_tag( 234 + 'a', 235 + array( 236 + 'href' => '/maniphest/export/'.$saved_query->getQueryKey().'/', 237 + 'class' => 'grey button', 238 + ), 239 + pht('Export to Excel')); 240 + 241 + $hidden = phutil_tag( 242 + 'div', 243 + array( 244 + 'id' => 'batch-select-id-container', 245 + ), 246 + ''); 247 + 248 + $editor = hsprintf( 249 + '<div class="maniphest-batch-editor">'. 250 + '<div class="batch-editor-header">%s</div>'. 251 + '<table class="maniphest-batch-editor-layout">'. 252 + '<tr>'. 253 + '<td>%s%s</td>'. 254 + '<td>%s</td>'. 255 + '<td id="batch-select-status-cell">%s</td>'. 256 + '<td class="batch-select-submit-cell">%s%s</td>'. 257 + '</tr>'. 258 + '</table>'. 259 + '</div>', 260 + pht('Batch Task Editor'), 261 + $select_all, 262 + $select_none, 263 + $export, 264 + '', 265 + $submit, 266 + $hidden); 267 + 268 + $editor = phabricator_form( 269 + $user, 270 + array( 271 + 'method' => 'POST', 272 + 'action' => '/maniphest/batch/', 273 + 'id' => 'batch-select-form', 274 + ), 275 + $editor); 276 + 277 + return $editor; 278 + } 279 + }