@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 workboard "Move Tasks to Column..." workflow to a separate controller

Summary: Depends on D20634. Ref T4900. Ref T13316. I'm planning to do a bit of additional cleanup here in followups, but this separates the main workflow out of the common controller.

Test Plan:
- Used "Move Tasks to Column..." to move some tasks on a board.
- Tried to move an empty column, hit an error.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13316, T4900

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

+229 -203
+2
src/__phutil_library_map__.php
··· 4173 4173 'PhabricatorProjectColumn' => 'applications/project/storage/PhabricatorProjectColumn.php', 4174 4174 'PhabricatorProjectColumnAuthorOrder' => 'applications/project/order/PhabricatorProjectColumnAuthorOrder.php', 4175 4175 'PhabricatorProjectColumnBulkEditController' => 'applications/project/controller/PhabricatorProjectColumnBulkEditController.php', 4176 + 'PhabricatorProjectColumnBulkMoveController' => 'applications/project/controller/PhabricatorProjectColumnBulkMoveController.php', 4176 4177 'PhabricatorProjectColumnCreatedOrder' => 'applications/project/order/PhabricatorProjectColumnCreatedOrder.php', 4177 4178 'PhabricatorProjectColumnDetailController' => 'applications/project/controller/PhabricatorProjectColumnDetailController.php', 4178 4179 'PhabricatorProjectColumnEditController' => 'applications/project/controller/PhabricatorProjectColumnEditController.php', ··· 10447 10448 ), 10448 10449 'PhabricatorProjectColumnAuthorOrder' => 'PhabricatorProjectColumnOrder', 10449 10450 'PhabricatorProjectColumnBulkEditController' => 'PhabricatorProjectBoardController', 10451 + 'PhabricatorProjectColumnBulkMoveController' => 'PhabricatorProjectBoardController', 10450 10452 'PhabricatorProjectColumnCreatedOrder' => 'PhabricatorProjectColumnOrder', 10451 10453 'PhabricatorProjectColumnDetailController' => 'PhabricatorProjectBoardController', 10452 10454 'PhabricatorProjectColumnEditController' => 'PhabricatorProjectBoardController',
+2
src/applications/project/application/PhabricatorProjectApplication.php
··· 83 83 => 'PhabricatorProjectColumnViewQueryController', 84 84 'bulk/(?P<columnID>\d+)/' 85 85 => 'PhabricatorProjectColumnBulkEditController', 86 + 'bulkmove/(?P<columnID>\d+)/(?P<mode>project|column)/' 87 + => 'PhabricatorProjectColumnBulkMoveController', 86 88 'import/' 87 89 => 'PhabricatorProjectBoardImportController', 88 90 'reorder/'
+6 -203
src/applications/project/controller/PhabricatorProjectBoardViewController.php
··· 94 94 ->requireCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT)) 95 95 ->apply($tasks); 96 96 97 - $move_id = $request->getStr('move'); 98 - if (strlen($move_id)) { 99 - $column_id_map = mpull($columns, null, 'getID'); 100 - $move_column = idx($column_id_map, $move_id); 101 - if (!$move_column) { 102 - return new Aphront404Response(); 103 - } 104 - 105 - $move_task_phids = $layout_engine->getColumnObjectPHIDs( 106 - $board_phid, 107 - $move_column->getPHID()); 108 - 109 - foreach ($move_task_phids as $key => $move_task_phid) { 110 - if (empty($task_can_edit_map[$move_task_phid])) { 111 - unset($move_task_phids[$key]); 112 - } 113 - } 114 - 115 - $move_tasks = array_select_keys($tasks, $move_task_phids); 116 - $cancel_uri = $state->newWorkboardURI(); 117 - 118 - if (!$move_tasks) { 119 - return $this->newDialog() 120 - ->setTitle(pht('No Movable Tasks')) 121 - ->appendParagraph( 122 - pht( 123 - 'The selected column contains no visible tasks which you '. 124 - 'have permission to move.')) 125 - ->addCancelButton($cancel_uri); 126 - } 127 - 128 - $move_project_phid = $project->getPHID(); 129 - $move_column_phid = null; 130 - $move_project = null; 131 - $move_column = null; 132 - $columns = null; 133 - $errors = array(); 134 - 135 - if ($request->isFormOrHiSecPost()) { 136 - $move_project_phid = head($request->getArr('moveProjectPHID')); 137 - if (!$move_project_phid) { 138 - $move_project_phid = $request->getStr('moveProjectPHID'); 139 - } 140 - 141 - if (!$move_project_phid) { 142 - if ($request->getBool('hasProject')) { 143 - $errors[] = pht('Choose a project to move tasks to.'); 144 - } 145 - } else { 146 - $target_project = id(new PhabricatorProjectQuery()) 147 - ->setViewer($viewer) 148 - ->withPHIDs(array($move_project_phid)) 149 - ->executeOne(); 150 - if (!$target_project) { 151 - $errors[] = pht('You must choose a valid project.'); 152 - } else if (!$project->getHasWorkboard()) { 153 - $errors[] = pht( 154 - 'You must choose a project with a workboard.'); 155 - } else { 156 - $move_project = $target_project; 157 - } 158 - } 159 - 160 - if ($move_project) { 161 - $move_engine = id(new PhabricatorBoardLayoutEngine()) 162 - ->setViewer($viewer) 163 - ->setBoardPHIDs(array($move_project->getPHID())) 164 - ->setFetchAllBoards(true) 165 - ->executeLayout(); 166 - 167 - $columns = $move_engine->getColumns($move_project->getPHID()); 168 - $columns = mpull($columns, null, 'getPHID'); 169 - 170 - foreach ($columns as $key => $column) { 171 - if ($column->isHidden()) { 172 - unset($columns[$key]); 173 - } 174 - } 175 - 176 - $move_column_phid = $request->getStr('moveColumnPHID'); 177 - if (!$move_column_phid) { 178 - if ($request->getBool('hasColumn')) { 179 - $errors[] = pht('Choose a column to move tasks to.'); 180 - } 181 - } else { 182 - if (empty($columns[$move_column_phid])) { 183 - $errors[] = pht( 184 - 'Choose a valid column on the target workboard to move '. 185 - 'tasks to.'); 186 - } else if ($columns[$move_column_phid]->getID() == $move_id) { 187 - $errors[] = pht( 188 - 'You can not move tasks from a column to itself.'); 189 - } else { 190 - $move_column = $columns[$move_column_phid]; 191 - } 192 - } 193 - } 194 - } 195 - 196 - if ($move_column && $move_project) { 197 - foreach ($move_tasks as $move_task) { 198 - $xactions = array(); 199 - 200 - // If we're switching projects, get out of the old project first 201 - // and move to the new project. 202 - if ($move_project->getID() != $project->getID()) { 203 - $xactions[] = id(new ManiphestTransaction()) 204 - ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 205 - ->setMetadataValue( 206 - 'edge:type', 207 - PhabricatorProjectObjectHasProjectEdgeType::EDGECONST) 208 - ->setNewValue( 209 - array( 210 - '-' => array( 211 - $project->getPHID() => $project->getPHID(), 212 - ), 213 - '+' => array( 214 - $move_project->getPHID() => $move_project->getPHID(), 215 - ), 216 - )); 217 - } 218 - 219 - $xactions[] = id(new ManiphestTransaction()) 220 - ->setTransactionType(PhabricatorTransactions::TYPE_COLUMNS) 221 - ->setNewValue( 222 - array( 223 - array( 224 - 'columnPHID' => $move_column->getPHID(), 225 - ), 226 - )); 227 - 228 - $editor = id(new ManiphestTransactionEditor()) 229 - ->setActor($viewer) 230 - ->setContinueOnMissingFields(true) 231 - ->setContinueOnNoEffect(true) 232 - ->setContentSourceFromRequest($request) 233 - ->setCancelURI($cancel_uri); 234 - 235 - $editor->applyTransactions($move_task, $xactions); 236 - } 237 - 238 - return id(new AphrontRedirectResponse()) 239 - ->setURI($cancel_uri); 240 - } 241 - 242 - if ($move_project) { 243 - $column_form = id(new AphrontFormView()) 244 - ->setViewer($viewer) 245 - ->appendControl( 246 - id(new AphrontFormSelectControl()) 247 - ->setName('moveColumnPHID') 248 - ->setLabel(pht('Move to Column')) 249 - ->setValue($move_column_phid) 250 - ->setOptions(mpull($columns, 'getDisplayName', 'getPHID'))); 251 - 252 - return $this->newDialog() 253 - ->setTitle(pht('Move Tasks')) 254 - ->setWidth(AphrontDialogView::WIDTH_FORM) 255 - ->setErrors($errors) 256 - ->addHiddenInput('move', $move_id) 257 - ->addHiddenInput('moveProjectPHID', $move_project->getPHID()) 258 - ->addHiddenInput('hasColumn', true) 259 - ->addHiddenInput('hasProject', true) 260 - ->appendParagraph( 261 - pht( 262 - 'Choose a column on the %s workboard to move tasks to:', 263 - $viewer->renderHandle($move_project->getPHID()))) 264 - ->appendForm($column_form) 265 - ->addSubmitButton(pht('Move Tasks')) 266 - ->addCancelButton($cancel_uri); 267 - } 268 - 269 - if ($move_project_phid) { 270 - $move_project_phid_value = array($move_project_phid); 271 - } else { 272 - $move_project_phid_value = array(); 273 - } 274 - 275 - $project_form = id(new AphrontFormView()) 276 - ->setViewer($viewer) 277 - ->appendControl( 278 - id(new AphrontFormTokenizerControl()) 279 - ->setName('moveProjectPHID') 280 - ->setLimit(1) 281 - ->setLabel(pht('Move to Project')) 282 - ->setValue($move_project_phid_value) 283 - ->setDatasource(new PhabricatorProjectDatasource())); 284 - 285 - return $this->newDialog() 286 - ->setTitle(pht('Move Tasks')) 287 - ->setWidth(AphrontDialogView::WIDTH_FORM) 288 - ->setErrors($errors) 289 - ->addHiddenInput('move', $move_id) 290 - ->addHiddenInput('hasProject', true) 291 - ->appendForm($project_form) 292 - ->addSubmitButton(pht('Continue')) 293 - ->addCancelButton($cancel_uri); 294 - } 295 - 296 - 297 97 $board_id = celerity_generate_unique_node_id(); 298 98 299 99 $board = id(new PHUIWorkboardView()) ··· 924 724 ->setHref($bulk_edit_uri) 925 725 ->setDisabled(!$can_bulk_edit); 926 726 927 - $batch_move_uri = $request->getRequestURI(); 928 - $batch_move_uri->replaceQueryParam('move', $column->getID()); 727 + $project_move_uri = $state->newWorkboardURI( 728 + urisprintf( 729 + 'bulkmove/%d/project/', 730 + $column->getID())); 731 + 929 732 $column_items[] = id(new PhabricatorActionView()) 930 733 ->setIcon('fa-arrow-right') 931 734 ->setName(pht('Move Tasks to Column...')) 932 - ->setHref($batch_move_uri) 735 + ->setHref($project_move_uri) 933 736 ->setWorkflow(true); 934 737 935 738 $query_uri = urisprintf('viewquery/%d/', $column->getID());
+219
src/applications/project/controller/PhabricatorProjectColumnBulkMoveController.php
··· 1 + <?php 2 + 3 + final class PhabricatorProjectColumnBulkMoveController 4 + extends PhabricatorProjectBoardController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $request->getViewer(); 8 + 9 + $response = $this->loadProject(); 10 + if ($response) { 11 + return $response; 12 + } 13 + 14 + $project = $this->getProject(); 15 + $state = $this->getViewState(); 16 + $board_uri = $state->newWorkboardURI(); 17 + 18 + $layout_engine = $state->getLayoutEngine(); 19 + 20 + $board_phid = $project->getPHID(); 21 + $columns = $layout_engine->getColumns($board_phid); 22 + $columns = mpull($columns, null, 'getID'); 23 + 24 + $column_id = $request->getURIData('columnID'); 25 + $move_column = idx($columns, $column_id); 26 + if (!$move_column) { 27 + return new Aphront404Response(); 28 + } 29 + 30 + $move_task_phids = $layout_engine->getColumnObjectPHIDs( 31 + $board_phid, 32 + $move_column->getPHID()); 33 + 34 + $tasks = $state->getObjects(); 35 + 36 + $move_tasks = array_select_keys($tasks, $move_task_phids); 37 + 38 + $move_tasks = id(new PhabricatorPolicyFilter()) 39 + ->setViewer($viewer) 40 + ->requireCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT)) 41 + ->apply($move_tasks); 42 + 43 + if (!$move_tasks) { 44 + return $this->newDialog() 45 + ->setTitle(pht('No Movable Tasks')) 46 + ->appendParagraph( 47 + pht( 48 + 'The selected column contains no visible tasks which you '. 49 + 'have permission to move.')) 50 + ->addCancelButton($board_uri); 51 + } 52 + 53 + $move_project_phid = $project->getPHID(); 54 + $move_column_phid = null; 55 + $move_project = null; 56 + $move_column = null; 57 + $columns = null; 58 + $errors = array(); 59 + 60 + if ($request->isFormOrHiSecPost()) { 61 + $move_project_phid = head($request->getArr('moveProjectPHID')); 62 + if (!$move_project_phid) { 63 + $move_project_phid = $request->getStr('moveProjectPHID'); 64 + } 65 + 66 + if (!$move_project_phid) { 67 + if ($request->getBool('hasProject')) { 68 + $errors[] = pht('Choose a project to move tasks to.'); 69 + } 70 + } else { 71 + $target_project = id(new PhabricatorProjectQuery()) 72 + ->setViewer($viewer) 73 + ->withPHIDs(array($move_project_phid)) 74 + ->executeOne(); 75 + if (!$target_project) { 76 + $errors[] = pht('You must choose a valid project.'); 77 + } else if (!$project->getHasWorkboard()) { 78 + $errors[] = pht( 79 + 'You must choose a project with a workboard.'); 80 + } else { 81 + $move_project = $target_project; 82 + } 83 + } 84 + 85 + if ($move_project) { 86 + $move_engine = id(new PhabricatorBoardLayoutEngine()) 87 + ->setViewer($viewer) 88 + ->setBoardPHIDs(array($move_project->getPHID())) 89 + ->setFetchAllBoards(true) 90 + ->executeLayout(); 91 + 92 + $columns = $move_engine->getColumns($move_project->getPHID()); 93 + $columns = mpull($columns, null, 'getPHID'); 94 + 95 + foreach ($columns as $key => $column) { 96 + if ($column->isHidden()) { 97 + unset($columns[$key]); 98 + } 99 + } 100 + 101 + $move_column_phid = $request->getStr('moveColumnPHID'); 102 + if (!$move_column_phid) { 103 + if ($request->getBool('hasColumn')) { 104 + $errors[] = pht('Choose a column to move tasks to.'); 105 + } 106 + } else { 107 + if (empty($columns[$move_column_phid])) { 108 + $errors[] = pht( 109 + 'Choose a valid column on the target workboard to move '. 110 + 'tasks to.'); 111 + } else if ($columns[$move_column_phid]->getID() == $column_id) { 112 + $errors[] = pht( 113 + 'You can not move tasks from a column to itself.'); 114 + } else { 115 + $move_column = $columns[$move_column_phid]; 116 + } 117 + } 118 + } 119 + } 120 + 121 + if ($move_column && $move_project) { 122 + foreach ($move_tasks as $move_task) { 123 + $xactions = array(); 124 + 125 + // If we're switching projects, get out of the old project first 126 + // and move to the new project. 127 + if ($move_project->getID() != $project->getID()) { 128 + $xactions[] = id(new ManiphestTransaction()) 129 + ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 130 + ->setMetadataValue( 131 + 'edge:type', 132 + PhabricatorProjectObjectHasProjectEdgeType::EDGECONST) 133 + ->setNewValue( 134 + array( 135 + '-' => array( 136 + $project->getPHID() => $project->getPHID(), 137 + ), 138 + '+' => array( 139 + $move_project->getPHID() => $move_project->getPHID(), 140 + ), 141 + )); 142 + } 143 + 144 + $xactions[] = id(new ManiphestTransaction()) 145 + ->setTransactionType(PhabricatorTransactions::TYPE_COLUMNS) 146 + ->setNewValue( 147 + array( 148 + array( 149 + 'columnPHID' => $move_column->getPHID(), 150 + ), 151 + )); 152 + 153 + $editor = id(new ManiphestTransactionEditor()) 154 + ->setActor($viewer) 155 + ->setContinueOnMissingFields(true) 156 + ->setContinueOnNoEffect(true) 157 + ->setContentSourceFromRequest($request) 158 + ->setCancelURI($board_uri); 159 + 160 + $editor->applyTransactions($move_task, $xactions); 161 + } 162 + 163 + return id(new AphrontRedirectResponse()) 164 + ->setURI($board_uri); 165 + } 166 + 167 + if ($move_project) { 168 + $column_form = id(new AphrontFormView()) 169 + ->setViewer($viewer) 170 + ->appendControl( 171 + id(new AphrontFormSelectControl()) 172 + ->setName('moveColumnPHID') 173 + ->setLabel(pht('Move to Column')) 174 + ->setValue($move_column_phid) 175 + ->setOptions(mpull($columns, 'getDisplayName', 'getPHID'))); 176 + 177 + return $this->newWorkboardDialog() 178 + ->setTitle(pht('Move Tasks')) 179 + ->setWidth(AphrontDialogView::WIDTH_FORM) 180 + ->setErrors($errors) 181 + ->addHiddenInput('moveProjectPHID', $move_project->getPHID()) 182 + ->addHiddenInput('hasColumn', true) 183 + ->addHiddenInput('hasProject', true) 184 + ->appendParagraph( 185 + pht( 186 + 'Choose a column on the %s workboard to move tasks to:', 187 + $viewer->renderHandle($move_project->getPHID()))) 188 + ->appendForm($column_form) 189 + ->addSubmitButton(pht('Move Tasks')) 190 + ->addCancelButton($board_uri); 191 + } 192 + 193 + if ($move_project_phid) { 194 + $move_project_phid_value = array($move_project_phid); 195 + } else { 196 + $move_project_phid_value = array(); 197 + } 198 + 199 + $project_form = id(new AphrontFormView()) 200 + ->setViewer($viewer) 201 + ->appendControl( 202 + id(new AphrontFormTokenizerControl()) 203 + ->setName('moveProjectPHID') 204 + ->setLimit(1) 205 + ->setLabel(pht('Move to Project')) 206 + ->setValue($move_project_phid_value) 207 + ->setDatasource(new PhabricatorProjectDatasource())); 208 + 209 + return $this->newWorkboardDialog() 210 + ->setTitle(pht('Move Tasks')) 211 + ->setWidth(AphrontDialogView::WIDTH_FORM) 212 + ->setErrors($errors) 213 + ->addHiddenInput('hasProject', true) 214 + ->appendForm($project_form) 215 + ->addSubmitButton(pht('Continue')) 216 + ->addCancelButton($board_uri); 217 + } 218 + 219 + }