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

Rough cut of "Move tasks to column..."

Summary:
Ref T5523. See PHI50. See PHI40. This isn't perfect, but should improve things.

Add a "Move tasks to column..." action to workboards which moves all visible tasks in a column to another column, either on the same board or on a different board.

This is a two-step process so that I don't have to write Javascript, and because I'm not 100% sure this is what users actually want/need. If it sticks, the UI could be refined later.

- The first dialog asks you to choose a project, defaulting ot the current project.
- The second dialog asks you to choose a column on that project's board.

Test Plan:
- Moved tasks on the same board.
- Moved tasks to a different board.
- Tried to move tasks to the starting column, got a sensible error.
- Tried to move tasks to no project, got a sensible error.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T5523

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

+204 -1
+204 -1
src/applications/project/controller/PhabricatorProjectBoardViewController.php
··· 34 34 ->setBaseURI($board_uri) 35 35 ->setIsBoardView(true); 36 36 37 - if ($request->isFormPost() && !$request->getBool('initialize')) { 37 + if ($request->isFormPost() 38 + && !$request->getBool('initialize') 39 + && !$request->getStr('move')) { 38 40 $saved = $search_engine->buildSavedQueryFromRequest($request); 39 41 $search_engine->saveQuery($saved); 40 42 $filter_form = id(new AphrontFormView()) ··· 237 239 return id(new AphrontRedirectResponse()) 238 240 ->setURI($batch_uri); 239 241 } 242 + 243 + $move_id = $request->getStr('move'); 244 + if (strlen($move_id)) { 245 + $column_id_map = mpull($columns, null, 'getID'); 246 + $move_column = idx($column_id_map, $move_id); 247 + if (!$move_column) { 248 + return new Aphront404Response(); 249 + } 250 + 251 + $move_task_phids = $layout_engine->getColumnObjectPHIDs( 252 + $board_phid, 253 + $move_column->getPHID()); 254 + 255 + foreach ($move_task_phids as $key => $move_task_phid) { 256 + if (empty($task_can_edit_map[$move_task_phid])) { 257 + unset($move_task_phids[$key]); 258 + } 259 + } 260 + 261 + $move_tasks = array_select_keys($tasks, $move_task_phids); 262 + $cancel_uri = $this->getURIWithState($board_uri); 263 + 264 + if (!$move_tasks) { 265 + return $this->newDialog() 266 + ->setTitle(pht('No Movable Tasks')) 267 + ->appendParagraph( 268 + pht( 269 + 'The selected column contains no visible tasks which you '. 270 + 'have permission to move.')) 271 + ->addCancelButton($cancel_uri); 272 + } 273 + 274 + $move_project_phid = $project->getPHID(); 275 + $move_column_phid = null; 276 + $move_project = null; 277 + $move_column = null; 278 + $columns = null; 279 + $errors = array(); 280 + 281 + if ($request->isFormPost()) { 282 + $move_project_phid = head($request->getArr('moveProjectPHID')); 283 + if (!$move_project_phid) { 284 + $move_project_phid = $request->getStr('moveProjectPHID'); 285 + } 286 + 287 + if (!$move_project_phid) { 288 + if ($request->getBool('hasProject')) { 289 + $errors[] = pht('Choose a project to move tasks to.'); 290 + } 291 + } else { 292 + $target_project = id(new PhabricatorProjectQuery()) 293 + ->setViewer($viewer) 294 + ->withPHIDs(array($move_project_phid)) 295 + ->executeOne(); 296 + if (!$target_project) { 297 + $errors[] = pht('You must choose a valid project.'); 298 + } else if (!$project->getHasWorkboard()) { 299 + $errors[] = pht( 300 + 'You must choose a project with a workboard.'); 301 + } else { 302 + $move_project = $target_project; 303 + } 304 + } 305 + 306 + if ($move_project) { 307 + $move_engine = id(new PhabricatorBoardLayoutEngine()) 308 + ->setViewer($viewer) 309 + ->setBoardPHIDs(array($move_project->getPHID())) 310 + ->setFetchAllBoards(true) 311 + ->executeLayout(); 312 + 313 + $columns = $move_engine->getColumns($move_project->getPHID()); 314 + $columns = mpull($columns, null, 'getPHID'); 315 + 316 + $move_column_phid = $request->getStr('moveColumnPHID'); 317 + if (!$move_column_phid) { 318 + if ($request->getBool('hasColumn')) { 319 + $errors[] = pht('Choose a column to move tasks to.'); 320 + } 321 + } else { 322 + if (empty($columns[$move_column_phid])) { 323 + $errors[] = pht( 324 + 'Choose a valid column on the target workboard to move '. 325 + 'tasks to.'); 326 + } else if ($columns[$move_column_phid]->getID() == $move_id) { 327 + $errors[] = pht( 328 + 'You can not move tasks from a column to itself.'); 329 + } else { 330 + $move_column = $columns[$move_column_phid]; 331 + } 332 + } 333 + } 334 + } 335 + 336 + if ($move_column && $move_project) { 337 + foreach ($move_tasks as $move_task) { 338 + $xactions = array(); 339 + 340 + // If we're switching projects, get out of the old project first 341 + // and move to the new project. 342 + if ($move_project->getID() != $project->getID()) { 343 + $xactions[] = id(new ManiphestTransaction()) 344 + ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 345 + ->setMetadataValue( 346 + 'edge:type', 347 + PhabricatorProjectObjectHasProjectEdgeType::EDGECONST) 348 + ->setNewValue( 349 + array( 350 + '-' => array( 351 + $project->getPHID() => $project->getPHID(), 352 + ), 353 + '+' => array( 354 + $move_project->getPHID() => $move_project->getPHID(), 355 + ), 356 + )); 357 + } 358 + 359 + $xactions[] = id(new ManiphestTransaction()) 360 + ->setTransactionType(PhabricatorTransactions::TYPE_COLUMNS) 361 + ->setNewValue( 362 + array( 363 + array( 364 + 'columnPHID' => $move_column->getPHID(), 365 + ), 366 + )); 367 + 368 + $editor = id(new ManiphestTransactionEditor()) 369 + ->setActor($viewer) 370 + ->setContinueOnMissingFields(true) 371 + ->setContinueOnNoEffect(true) 372 + ->setContentSourceFromRequest($request); 373 + 374 + $editor->applyTransactions($move_task, $xactions); 375 + } 376 + 377 + return id(new AphrontRedirectResponse()) 378 + ->setURI($cancel_uri); 379 + } 380 + 381 + if ($move_project) { 382 + $column_form = id(new AphrontFormView()) 383 + ->setViewer($viewer) 384 + ->appendControl( 385 + id(new AphrontFormSelectControl()) 386 + ->setName('moveColumnPHID') 387 + ->setLabel(pht('Move to Column')) 388 + ->setValue($move_column_phid) 389 + ->setOptions(mpull($columns, 'getDisplayName', 'getPHID'))); 390 + 391 + return $this->newDialog() 392 + ->setTitle(pht('Move Tasks')) 393 + ->setWidth(AphrontDialogView::WIDTH_FORM) 394 + ->setErrors($errors) 395 + ->addHiddenInput('move', $move_id) 396 + ->addHiddenInput('moveProjectPHID', $move_project->getPHID()) 397 + ->addHiddenInput('hasColumn', true) 398 + ->addHiddenInput('hasProject', true) 399 + ->appendParagraph( 400 + pht( 401 + 'Choose a column on the %s workboard to move tasks to:', 402 + $viewer->renderHandle($move_project->getPHID()))) 403 + ->appendForm($column_form) 404 + ->addSubmitButton(pht('Move Tasks')) 405 + ->addCancelButton($cancel_uri); 406 + } 407 + 408 + if ($move_project_phid) { 409 + $move_project_phid_value = array($move_project_phid); 410 + } else { 411 + $move_project_phid_value = array(); 412 + } 413 + 414 + $project_form = id(new AphrontFormView()) 415 + ->setViewer($viewer) 416 + ->appendControl( 417 + id(new AphrontFormTokenizerControl()) 418 + ->setName('moveProjectPHID') 419 + ->setLimit(1) 420 + ->setLabel(pht('Move to Project')) 421 + ->setValue($move_project_phid_value) 422 + ->setDatasource(new PhabricatorProjectDatasource())); 423 + 424 + return $this->newDialog() 425 + ->setTitle(pht('Move Tasks')) 426 + ->setWidth(AphrontDialogView::WIDTH_FORM) 427 + ->setErrors($errors) 428 + ->addHiddenInput('move', $move_id) 429 + ->addHiddenInput('hasProject', true) 430 + ->appendForm($project_form) 431 + ->addSubmitButton(pht('Continue')) 432 + ->addCancelButton($cancel_uri); 433 + } 434 + 240 435 241 436 $board_id = celerity_generate_unique_node_id(); 242 437 ··· 850 1045 ->setName(pht('Batch Edit Tasks...')) 851 1046 ->setHref($batch_edit_uri) 852 1047 ->setDisabled(!$can_batch_edit); 1048 + 1049 + $batch_move_uri = $request->getRequestURI(); 1050 + $batch_move_uri->setQueryParam('move', $column->getID()); 1051 + $column_items[] = id(new PhabricatorActionView()) 1052 + ->setIcon('fa-arrow-right') 1053 + ->setName(pht('Move Tasks to Column...')) 1054 + ->setHref($batch_move_uri) 1055 + ->setWorkflow(true); 853 1056 854 1057 // Column Related Actions Below 855 1058 //