@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.

Nearly complete lifting card-move code out of workboards

Summary: Ref T10010. This gets rid of the last dependency on the weird ColumnPositionQuery code.

Test Plan:
- Viewed workboards.
- Used batch editor.
- Created a new workboard.
- Dragged stuff around.
- Created new tasks into columns.
- Changed order from natural to priority, dragged things around.
- Switched filter to custom filter, "all tasks", etc.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10010

Differential Revision: https://secure.phabricator.com/D15176

+87 -110
+70 -105
src/applications/project/controller/PhabricatorProjectBoardViewController.php
··· 28 28 $project = $this->getProject(); 29 29 30 30 $this->readRequestState(); 31 - $columns = $this->loadColumns($project); 32 - 33 - // TODO: Expand the checks here if we add the ability 34 - // to hide the Backlog column 35 - if (!$columns) { 36 - $can_edit = PhabricatorPolicyFilter::hasCapability( 37 - $viewer, 38 - $project, 39 - PhabricatorPolicyCapability::CAN_EDIT); 40 - if (!$can_edit) { 41 - $content = $this->buildNoAccessContent($project); 42 - } else { 43 - $content = $this->buildInitializeContent($project); 44 - } 45 - 46 - if ($content instanceof AphrontResponse) { 47 - return $content; 48 - } 49 - 50 - $nav = $this->getProfileMenu(); 51 - $nav->selectFilter(PhabricatorProject::PANEL_WORKBOARD); 52 - 53 - $crumbs = $this->buildApplicationCrumbs(); 54 - $crumbs->addTextCrumb(pht('Workboard')); 55 - 56 - return $this->newPage() 57 - ->setTitle( 58 - array( 59 - pht('Workboard'), 60 - $project->getName(), 61 - )) 62 - ->setNavigation($nav) 63 - ->setCrumbs($crumbs) 64 - ->appendChild($content); 65 - } 66 31 67 32 $board_uri = $this->getApplicationURI('board/'.$project->getID().'/'); 68 33 69 - $engine = id(new ManiphestTaskSearchEngine()) 34 + $search_engine = id(new ManiphestTaskSearchEngine()) 70 35 ->setViewer($viewer) 71 36 ->setBaseURI($board_uri) 72 37 ->setIsBoardView(true); 73 38 74 - if ($request->isFormPost()) { 75 - $saved = $engine->buildSavedQueryFromRequest($request); 76 - $engine->saveQuery($saved); 39 + if ($request->isFormPost() && !$request->getBool('initialize')) { 40 + $saved = $search_engine->buildSavedQueryFromRequest($request); 41 + $search_engine->saveQuery($saved); 77 42 $filter_form = id(new AphrontFormView()) 78 43 ->setUser($viewer); 79 - $engine->buildSearchForm($filter_form, $saved); 80 - if ($engine->getErrors()) { 44 + $search_engine->buildSearchForm($filter_form, $saved); 45 + if ($search_engine->getErrors()) { 81 46 return $this->newDialog() 82 47 ->setWidth(AphrontDialogView::WIDTH_FULL) 83 48 ->setTitle(pht('Advanced Filter')) 84 49 ->appendChild($filter_form->buildLayoutView()) 85 - ->setErrors($engine->getErrors()) 50 + ->setErrors($search_engine->getErrors()) 86 51 ->setSubmitURI($board_uri) 87 52 ->addSubmitButton(pht('Apply Filter')) 88 53 ->addCancelButton($board_uri); 89 54 } 90 55 return id(new AphrontRedirectResponse())->setURI( 91 56 $this->getURIWithState( 92 - $engine->getQueryResultsPageURI($saved->getQueryKey()))); 57 + $search_engine->getQueryResultsPageURI($saved->getQueryKey()))); 93 58 } 94 59 95 60 $query_key = $request->getURIData('queryKey'); ··· 99 64 $this->queryKey = $query_key; 100 65 101 66 $custom_query = null; 102 - if ($engine->isBuiltinQuery($query_key)) { 103 - $saved = $engine->buildSavedQueryFromBuiltin($query_key); 67 + if ($search_engine->isBuiltinQuery($query_key)) { 68 + $saved = $search_engine->buildSavedQueryFromBuiltin($query_key); 104 69 } else { 105 70 $saved = id(new PhabricatorSavedQueryQuery()) 106 71 ->setViewer($viewer) ··· 117 82 if ($request->getURIData('filter')) { 118 83 $filter_form = id(new AphrontFormView()) 119 84 ->setUser($viewer); 120 - $engine->buildSearchForm($filter_form, $saved); 85 + $search_engine->buildSearchForm($filter_form, $saved); 121 86 122 87 return $this->newDialog() 123 88 ->setWidth(AphrontDialogView::WIDTH_FULL) ··· 128 93 ->addCancelButton($board_uri); 129 94 } 130 95 131 - $task_query = $engine->buildQueryFromSavedQuery($saved); 96 + $task_query = $search_engine->buildQueryFromSavedQuery($saved); 132 97 133 98 $tasks = $task_query 134 99 ->withEdgeLogicPHIDs( ··· 140 105 ->execute(); 141 106 $tasks = mpull($tasks, null, 'getPHID'); 142 107 143 - if ($tasks) { 144 - $positions = id(new PhabricatorProjectColumnPositionQuery()) 145 - ->setViewer($viewer) 146 - ->withObjectPHIDs(mpull($tasks, 'getPHID')) 147 - ->withColumns($columns) 148 - ->execute(); 149 - $positions = mpull($positions, null, 'getObjectPHID'); 150 - } else { 151 - $positions = array(); 152 - } 153 108 154 - $task_map = array(); 155 - foreach ($tasks as $task) { 156 - $task_phid = $task->getPHID(); 157 - if (empty($positions[$task_phid])) { 158 - // This shouldn't normally be possible because we create positions on 159 - // demand, but we might have raced as an object was removed from the 160 - // board. Just drop the task if we don't have a position for it. 161 - continue; 162 - } 109 + $board_phid = $project->getPHID(); 163 110 164 - $position = $positions[$task_phid]; 165 - $task_map[$position->getColumnPHID()][] = $task_phid; 166 - } 111 + $layout_engine = id(new PhabricatorBoardLayoutEngine()) 112 + ->setViewer($viewer) 113 + ->setBoardPHIDs(array($board_phid)) 114 + ->setObjectPHIDs(array_keys($tasks)) 115 + ->executeLayout(); 167 116 168 - // If we're showing the board in "natural" order, sort columns by their 169 - // column positions. 170 - if ($this->sortKey == PhabricatorProjectColumn::ORDER_NATURAL) { 171 - foreach ($task_map as $column_phid => $task_phids) { 172 - $order = array(); 173 - foreach ($task_phids as $task_phid) { 174 - if (isset($positions[$task_phid])) { 175 - $order[$task_phid] = $positions[$task_phid]->getOrderingKey(); 176 - } else { 177 - $order[$task_phid] = 0; 178 - } 179 - } 180 - asort($order); 181 - $task_map[$column_phid] = array_keys($order); 117 + $columns = $layout_engine->getColumns($board_phid); 118 + if (!$columns) { 119 + $can_edit = PhabricatorPolicyFilter::hasCapability( 120 + $viewer, 121 + $project, 122 + PhabricatorPolicyCapability::CAN_EDIT); 123 + if (!$can_edit) { 124 + $content = $this->buildNoAccessContent($project); 125 + } else { 126 + $content = $this->buildInitializeContent($project); 182 127 } 128 + 129 + if ($content instanceof AphrontResponse) { 130 + return $content; 131 + } 132 + 133 + $nav = $this->getProfileMenu(); 134 + $nav->selectFilter(PhabricatorProject::PANEL_WORKBOARD); 135 + 136 + $crumbs = $this->buildApplicationCrumbs(); 137 + $crumbs->addTextCrumb(pht('Workboard')); 138 + 139 + return $this->newPage() 140 + ->setTitle( 141 + array( 142 + pht('Workboard'), 143 + $project->getName(), 144 + )) 145 + ->setNavigation($nav) 146 + ->setCrumbs($crumbs) 147 + ->appendChild($content); 183 148 } 184 149 185 150 $task_can_edit_map = id(new PhabricatorPolicyFilter()) ··· 198 163 return new Aphront404Response(); 199 164 } 200 165 201 - $batch_task_phids = idx($task_map, $batch_column->getPHID(), array()); 166 + $batch_task_phids = $layout_engine->getColumnObjectPHIDs( 167 + $board_phid, 168 + $batch_column->getPHID()); 169 + 202 170 foreach ($batch_task_phids as $key => $batch_task_phid) { 203 171 if (empty($task_can_edit_map[$batch_task_phid])) { 204 172 unset($batch_task_phids[$key]); ··· 251 219 $this->handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks); 252 220 253 221 foreach ($columns as $column) { 254 - $task_phids = idx($task_map, $column->getPHID(), array()); 222 + if (!$this->showHidden) { 223 + if ($column->isHidden()) { 224 + continue; 225 + } 226 + } 227 + 228 + $task_phids = $layout_engine->getColumnObjectPHIDs( 229 + $board_phid, 230 + $column->getPHID()); 231 + 255 232 $column_tasks = array_select_keys($tasks, $task_phids); 233 + 234 + // If we aren't using "natural" order, reorder the column by the original 235 + // query order. 236 + if ($this->sortKey != PhabricatorProjectColumn::ORDER_NATURAL) { 237 + $column_tasks = array_select_keys($column_tasks, array_keys($tasks)); 238 + } 256 239 257 240 $panel = id(new PHUIWorkpanelView()) 258 241 ->setHeader($column->getDisplayName()) ··· 322 305 $filter_menu = $this->buildFilterMenu( 323 306 $viewer, 324 307 $custom_query, 325 - $engine, 308 + $search_engine, 326 309 $query_key); 327 310 328 311 $manage_menu = $this->buildManageMenu($project, $this->showHidden); ··· 381 364 break; 382 365 } 383 366 $this->sortKey = $sort_key; 384 - } 385 - 386 - private function loadColumns(PhabricatorProject $project) { 387 - $viewer = $this->getViewer(); 388 - 389 - $column_query = id(new PhabricatorProjectColumnQuery()) 390 - ->setViewer($viewer) 391 - ->withProjectPHIDs(array($project->getPHID())); 392 - 393 - if (!$this->showHidden) { 394 - $column_query->withStatuses( 395 - array(PhabricatorProjectColumn::STATUS_ACTIVE)); 396 - } 397 - 398 - $columns = $column_query->execute(); 399 - $columns = mpull($columns, null, 'getSequence'); 400 - ksort($columns); 401 - 402 - return $columns; 403 367 } 404 368 405 369 private function buildSortMenu( ··· 797 761 798 762 $form = id(new AphrontFormView()) 799 763 ->setUser($viewer) 764 + ->addHiddenInput('initialize', 1) 800 765 ->appendRemarkupInstructions( 801 766 pht('The workboard for this project has not been created yet.')) 802 767 ->appendControl($new_selector)
+17 -5
src/applications/project/engine/PhabricatorBoardLayoutEngine.php
··· 6 6 private $boardPHIDs; 7 7 private $objectPHIDs; 8 8 private $boards; 9 - private $columnMap; 9 + private $columnMap = array(); 10 10 private $objectColumnMap = array(); 11 11 private $boardLayout = array(); 12 12 ··· 66 66 } 67 67 68 68 return $this; 69 + } 70 + 71 + public function getColumns($board_phid) { 72 + $columns = idx($this->boardLayout, $board_phid, array()); 73 + return array_select_keys($this->columnMap, array_keys($columns)); 74 + } 75 + 76 + public function getColumnObjectPHIDs($board_phid, $column_phid) { 77 + $columns = idx($this->boardLayout, $board_phid, array()); 78 + $positions = idx($columns, $column_phid, array()); 79 + return mpull($positions, 'getObjectPHID'); 69 80 } 70 81 71 82 public function getObjectColumns($board_phid, $object_phid) { ··· 342 353 $board_phid = $board->getPHID(); 343 354 $position_groups = mgroup($positions, 'getObjectPHID'); 344 355 356 + $layout = array(); 345 357 foreach ($columns as $column) { 358 + $column_phid = $column->getPHID(); 359 + $layout[$column_phid] = array(); 360 + 346 361 if ($column->isDefaultColumn()) { 347 - $default_phid = $column->getPHID(); 348 - break; 362 + $default_phid = $column_phid; 349 363 } 350 364 } 351 - 352 - $layout = array(); 353 365 354 366 $object_phids = $this->getObjectPHIDs(); 355 367 foreach ($object_phids as $object_phid) {