@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

Remove the ability to drag tasks up and down on (non-Workboard) priority list views

Summary:
Ref T13074. Today, in normal task list views in Maniphest (not workboards), you can (sometimes) reorder tasks if the view is priority-sorted.

I suspect no one ever does this, few users know it's supported, and that it was basically rendered obsolete the day we shipped workboards.

This also means that we need to maintain a global "subpriority" for tasks, which distinguishes between different tasks at the same priority level (e.g., "High") and maintains a consistent ordering on workboards.

As we move toward making workboards more flexible (e.g., group by author / owner / custom fields), I'd like to try moving away from "subpriority" and possibly removing it entirely, in favor of "natural order", which basically means "we kind of remember where you put the card and it works a bit like a sticky note".

Currently, the "natural order" and "subpriority" systems are sort of similar but also sort of in conflict, and the "subpriority" system can't really be extended while the "natural order / column position" system can.

The only real reason to have a global "subpriority" is to support the list-view drag-and-drop.

It's possible I'm wrong about this and a bunch of users love this feature, but we can re-evaluate if we get feedback in this vein.

(This just removes UI, the actual subpriority system is still intact and still used on workboards.)

Test Plan: Viewed task lists, was no longer able to drag stuff. Grepped for affected symbols. Dragged stuff in remaining grippable lists, like "Edit Forms" in EditEngine config.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13074

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

+16 -240
+9 -19
resources/celerity/map.php
··· 16 16 'diffusion.pkg.css' => '42c75c37', 17 17 'diffusion.pkg.js' => '91192d85', 18 18 'maniphest.pkg.css' => '35995d6d', 19 - 'maniphest.pkg.js' => '286955ae', 19 + 'maniphest.pkg.js' => 'c9308721', 20 20 'rsrc/audio/basic/alert.mp3' => '17889334', 21 21 'rsrc/audio/basic/bing.mp3' => 'a817a0c3', 22 22 'rsrc/audio/basic/pock.mp3' => '0fa843d0', ··· 395 395 'rsrc/js/application/herald/HeraldRuleEditor.js' => '27daef73', 396 396 'rsrc/js/application/herald/PathTypeahead.js' => 'ad486db3', 397 397 'rsrc/js/application/herald/herald-rule-editor.js' => '0922e81d', 398 - 'rsrc/js/application/maniphest/behavior-batch-selector.js' => 'cffd39b4', 398 + 'rsrc/js/application/maniphest/behavior-batch-selector.js' => '139ef688', 399 399 'rsrc/js/application/maniphest/behavior-line-chart.js' => 'c8147a20', 400 400 'rsrc/js/application/maniphest/behavior-list-edit.js' => 'c687e867', 401 - 'rsrc/js/application/maniphest/behavior-subpriorityeditor.js' => '8400307c', 402 401 'rsrc/js/application/owners/OwnersPathEditor.js' => '2a8b62d9', 403 402 'rsrc/js/application/owners/owners-path-editor.js' => 'ff688a7a', 404 403 'rsrc/js/application/passphrase/passphrase-credential-control.js' => '48fe33d0', ··· 619 618 'javelin-behavior-lightbox-attachments' => 'c7e748bf', 620 619 'javelin-behavior-line-chart' => 'c8147a20', 621 620 'javelin-behavior-linked-container' => '74446546', 622 - 'javelin-behavior-maniphest-batch-selector' => 'cffd39b4', 621 + 'javelin-behavior-maniphest-batch-selector' => '139ef688', 623 622 'javelin-behavior-maniphest-list-editor' => 'c687e867', 624 - 'javelin-behavior-maniphest-subpriority-editor' => '8400307c', 625 623 'javelin-behavior-owners-path-editor' => 'ff688a7a', 626 624 'javelin-behavior-passphrase-credential-control' => '48fe33d0', 627 625 'javelin-behavior-phabricator-active-nav' => '7353f43d', ··· 997 995 'javelin-behavior', 998 996 'javelin-uri', 999 997 'phabricator-keyboard-shortcut', 998 + ), 999 + '139ef688' => array( 1000 + 'javelin-behavior', 1001 + 'javelin-dom', 1002 + 'javelin-stratcom', 1003 + 'javelin-util', 1000 1004 ), 1001 1005 '1c850a26' => array( 1002 1006 'javelin-install', ··· 1539 1543 'javelin-dom', 1540 1544 'javelin-vector', 1541 1545 ), 1542 - '8400307c' => array( 1543 - 'javelin-behavior', 1544 - 'javelin-dom', 1545 - 'javelin-stratcom', 1546 - 'javelin-workflow', 1547 - 'phabricator-draggable-list', 1548 - ), 1549 1546 '8437c663' => array( 1550 1547 'javelin-install', 1551 1548 'javelin-dom', ··· 1970 1967 'javelin-dom', 1971 1968 'javelin-stratcom', 1972 1969 ), 1973 - 'cffd39b4' => array( 1974 - 'javelin-behavior', 1975 - 'javelin-dom', 1976 - 'javelin-stratcom', 1977 - 'javelin-util', 1978 - ), 1979 1970 'd0a85a85' => array( 1980 1971 'javelin-dom', 1981 1972 'javelin-util', ··· 2362 2353 ), 2363 2354 'maniphest.pkg.js' => array( 2364 2355 'javelin-behavior-maniphest-batch-selector', 2365 - 'javelin-behavior-maniphest-subpriority-editor', 2366 2356 'javelin-behavior-maniphest-list-editor', 2367 2357 ), 2368 2358 ),
-1
resources/celerity/packages.php
··· 218 218 ), 219 219 'maniphest.pkg.js' => array( 220 220 'javelin-behavior-maniphest-batch-selector', 221 - 'javelin-behavior-maniphest-subpriority-editor', 222 221 'javelin-behavior-maniphest-list-editor', 223 222 ), 224 223 );
-2
src/__phutil_library_map__.php
··· 1709 1709 'ManiphestStatusEmailCommand' => 'applications/maniphest/command/ManiphestStatusEmailCommand.php', 1710 1710 'ManiphestStatusSearchConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestStatusSearchConduitAPIMethod.php', 1711 1711 'ManiphestStatusesConfigType' => 'applications/maniphest/config/ManiphestStatusesConfigType.php', 1712 - 'ManiphestSubpriorityController' => 'applications/maniphest/controller/ManiphestSubpriorityController.php', 1713 1712 'ManiphestSubtypesConfigType' => 'applications/maniphest/config/ManiphestSubtypesConfigType.php', 1714 1713 'ManiphestTask' => 'applications/maniphest/storage/ManiphestTask.php', 1715 1714 'ManiphestTaskAssignHeraldAction' => 'applications/maniphest/herald/ManiphestTaskAssignHeraldAction.php', ··· 7406 7405 'ManiphestStatusEmailCommand' => 'ManiphestEmailCommand', 7407 7406 'ManiphestStatusSearchConduitAPIMethod' => 'ManiphestConduitAPIMethod', 7408 7407 'ManiphestStatusesConfigType' => 'PhabricatorJSONConfigType', 7409 - 'ManiphestSubpriorityController' => 'ManiphestController', 7410 7408 'ManiphestSubtypesConfigType' => 'PhabricatorJSONConfigType', 7411 7409 'ManiphestTask' => array( 7412 7410 'ManiphestDAO',
-1
src/applications/maniphest/application/PhabricatorManiphestApplication.php
··· 54 54 => 'ManiphestTaskEditController', 55 55 'subtask/(?P<id>[1-9]\d*)/' => 'ManiphestTaskSubtaskController', 56 56 ), 57 - 'subpriority/' => 'ManiphestSubpriorityController', 58 57 'graph/(?P<id>[1-9]\d*)/' => 'ManiphestTaskGraphController', 59 58 ), 60 59 );
-1
src/applications/maniphest/controller/ManiphestController.php
··· 53 53 54 54 $view = id(new ManiphestTaskListView()) 55 55 ->setUser($user) 56 - ->setShowSubpriorityControls(!$request->getStr('ungrippable')) 57 56 ->setShowBatchControls(true) 58 57 ->setHandles($handles) 59 58 ->setTasks(array($task));
-70
src/applications/maniphest/controller/ManiphestSubpriorityController.php
··· 1 - <?php 2 - 3 - final class ManiphestSubpriorityController extends ManiphestController { 4 - 5 - public function handleRequest(AphrontRequest $request) { 6 - $viewer = $this->getViewer(); 7 - 8 - if (!$request->validateCSRF()) { 9 - return new Aphront403Response(); 10 - } 11 - 12 - $task = id(new ManiphestTaskQuery()) 13 - ->setViewer($viewer) 14 - ->withIDs(array($request->getInt('task'))) 15 - ->needProjectPHIDs(true) 16 - ->requireCapabilities( 17 - array( 18 - PhabricatorPolicyCapability::CAN_VIEW, 19 - PhabricatorPolicyCapability::CAN_EDIT, 20 - )) 21 - ->executeOne(); 22 - if (!$task) { 23 - return new Aphront404Response(); 24 - } 25 - 26 - if ($request->getInt('after')) { 27 - $after_task = id(new ManiphestTaskQuery()) 28 - ->setViewer($viewer) 29 - ->withIDs(array($request->getInt('after'))) 30 - ->executeOne(); 31 - if (!$after_task) { 32 - return new Aphront404Response(); 33 - } 34 - list($pri, $sub) = ManiphestTransactionEditor::getAdjacentSubpriority( 35 - $after_task, 36 - $is_after = true); 37 - } else { 38 - list($pri, $sub) = ManiphestTransactionEditor::getEdgeSubpriority( 39 - $request->getInt('priority'), 40 - $is_end = false); 41 - } 42 - 43 - $keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); 44 - $keyword = head(idx($keyword_map, $pri)); 45 - 46 - $xactions = array(); 47 - 48 - $xactions[] = id(new ManiphestTransaction()) 49 - ->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE) 50 - ->setNewValue($keyword); 51 - 52 - $xactions[] = id(new ManiphestTransaction()) 53 - ->setTransactionType(ManiphestTaskSubpriorityTransaction::TRANSACTIONTYPE) 54 - ->setNewValue($sub); 55 - 56 - $editor = id(new ManiphestTransactionEditor()) 57 - ->setActor($viewer) 58 - ->setContinueOnMissingFields(true) 59 - ->setContinueOnNoEffect(true) 60 - ->setContentSourceFromRequest($request); 61 - 62 - $editor->applyTransactions($task, $xactions); 63 - 64 - return id(new AphrontAjaxResponse())->setContent( 65 - array( 66 - 'tasks' => $this->renderSingleTask($task), 67 - )); 68 - } 69 - 70 - }
-1
src/applications/maniphest/controller/ManiphestTaskEditController.php
··· 5 5 public function handleRequest(AphrontRequest $request) { 6 6 return id(new ManiphestEditEngine()) 7 7 ->setController($this) 8 - ->addContextParameter('ungrippable') 9 8 ->addContextParameter('responseType') 10 9 ->addContextParameter('columnPHID') 11 10 ->addContextParameter('order')
-3
src/applications/maniphest/query/ManiphestTaskSearchEngine.php
··· 366 366 $viewer = $this->requireViewer(); 367 367 368 368 if ($this->isPanelContext()) { 369 - $can_edit_priority = false; 370 369 $can_bulk_edit = false; 371 370 } else { 372 - $can_edit_priority = true; 373 371 $can_bulk_edit = PhabricatorPolicyFilter::hasCapability( 374 372 $viewer, 375 373 $this->getApplication(), ··· 380 378 ->setUser($viewer) 381 379 ->setTasks($tasks) 382 380 ->setSavedQuery($saved) 383 - ->setCanEditPriority($can_edit_priority) 384 381 ->setCanBatchEdit($can_bulk_edit) 385 382 ->setShowBatchControls($this->showBatchControls); 386 383
+1 -13
src/applications/maniphest/view/ManiphestTaskListView.php
··· 5 5 private $tasks; 6 6 private $handles; 7 7 private $showBatchControls; 8 - private $showSubpriorityControls; 9 8 private $noDataString; 10 9 11 10 public function setTasks(array $tasks) { ··· 22 21 23 22 public function setShowBatchControls($show_batch_controls) { 24 23 $this->showBatchControls = $show_batch_controls; 25 - return $this; 26 - } 27 - 28 - public function setShowSubpriorityControls($show_subpriority_controls) { 29 - $this->showSubpriorityControls = $show_subpriority_controls; 30 24 return $this; 31 25 } 32 26 ··· 102 96 phabricator_datetime($task->getDateModified(), $this->getUser())); 103 97 } 104 98 105 - if ($this->showSubpriorityControls) { 106 - $item->setGrippable(true); 107 - } 108 - if ($this->showSubpriorityControls || $this->showBatchControls) { 99 + if ($this->showBatchControls) { 109 100 $item->addSigil('maniphest-task'); 110 101 } 111 102 ··· 134 125 135 126 if ($this->showBatchControls) { 136 127 $href = new PhutilURI('/maniphest/task/edit/'.$task->getID().'/'); 137 - if (!$this->showSubpriorityControls) { 138 - $href->replaceQueryParam('ungrippable', 'true'); 139 - } 140 128 $item->addAction( 141 129 id(new PHUIListItemView()) 142 130 ->setIcon('fa-pencil')
-30
src/applications/maniphest/view/ManiphestTaskResultListView.php
··· 4 4 5 5 private $tasks; 6 6 private $savedQuery; 7 - private $canEditPriority; 8 7 private $canBatchEdit; 9 8 private $showBatchControls; 10 9 ··· 15 14 16 15 public function setTasks(array $tasks) { 17 16 $this->tasks = $tasks; 18 - return $this; 19 - } 20 - 21 - public function setCanEditPriority($can_edit_priority) { 22 - $this->canEditPriority = $can_edit_priority; 23 17 return $this; 24 18 } 25 19 ··· 54 48 $group_parameter, 55 49 $handles); 56 50 57 - $can_edit_priority = $this->canEditPriority; 58 - 59 - $can_drag = ($order_parameter == 'priority') && 60 - ($can_edit_priority) && 61 - ($group_parameter == 'none' || $group_parameter == 'priority'); 62 - 63 - if (!$viewer->isLoggedIn()) { 64 - // TODO: (T7131) Eventually, we conceivably need to make each task 65 - // draggable individually, since the user may be able to edit some but 66 - // not others. 67 - $can_drag = false; 68 - } 69 - 70 51 $result = array(); 71 52 72 53 $lists = array(); 73 54 foreach ($groups as $group => $list) { 74 55 $task_list = new ManiphestTaskListView(); 75 56 $task_list->setShowBatchControls($this->showBatchControls); 76 - if ($can_drag) { 77 - $task_list->setShowSubpriorityControls(true); 78 - } 79 57 $task_list->setUser($viewer); 80 58 $task_list->setTasks($list); 81 59 $task_list->setHandles($handles); ··· 89 67 ->setHeader($header) 90 68 ->setObjectList($task_list); 91 69 92 - } 93 - 94 - if ($can_drag) { 95 - Javelin::initBehavior( 96 - 'maniphest-subpriority-editor', 97 - array( 98 - 'uri' => '/maniphest/subpriority/', 99 - )); 100 70 } 101 71 102 72 return array(
+6 -14
src/view/phui/PHUIObjectItemView.php
··· 414 414 )); 415 415 } 416 416 417 - // Wrap the header content in a <span> with the "slippery" sigil. This 418 - // prevents us from beginning a drag if you click the text (like "T123"), 419 - // but not if you click the white space after the header. 420 417 $header = phutil_tag( 421 418 'div', 422 419 array( 423 420 'class' => 'phui-oi-name', 424 421 ), 425 - javelin_tag( 426 - 'span', 427 - array( 428 - 'sigil' => 'slippery', 429 - ), 430 - array( 431 - $this->headIcons, 432 - $header_name, 433 - $header_link, 434 - $description_tag, 435 - ))); 422 + array( 423 + $this->headIcons, 424 + $header_name, 425 + $header_link, 426 + $description_tag, 427 + )); 436 428 437 429 $icons = array(); 438 430 if ($this->icons) {
-13
webroot/rsrc/js/application/maniphest/behavior-batch-selector.js
··· 41 41 update(); 42 42 }; 43 43 44 - var redraw = function (task) { 45 - var selected = is_selected(task); 46 - change(task, selected); 47 - }; 48 - JX.Stratcom.listen( 49 - 'subpriority-changed', 50 - null, 51 - function (e) { 52 - e.kill(); 53 - var data = e.getData(); 54 - redraw(data.task); 55 - }); 56 - 57 44 // Change all tasks to some state (used by "select all" / "clear selection" 58 45 // buttons). 59 46
-72
webroot/rsrc/js/application/maniphest/behavior-subpriorityeditor.js
··· 1 - /** 2 - * @provides javelin-behavior-maniphest-subpriority-editor 3 - * @requires javelin-behavior 4 - * javelin-dom 5 - * javelin-stratcom 6 - * javelin-workflow 7 - * phabricator-draggable-list 8 - */ 9 - 10 - JX.behavior('maniphest-subpriority-editor', function(config) { 11 - 12 - var draggable = new JX.DraggableList('maniphest-task') 13 - .setFindItemsHandler(function() { 14 - var tasks = JX.DOM.scry(document.body, 'li', 'maniphest-task'); 15 - var heads = JX.DOM.scry(document.body, 'div', 'task-group'); 16 - return tasks.concat(heads); 17 - }) 18 - .setGhostHandler(function(ghost, target) { 19 - if (!target) { 20 - // The user is trying to drag a task above the first group header; 21 - // don't permit that since it doesn't make sense. 22 - return false; 23 - } 24 - 25 - if (target.nextSibling) { 26 - if (JX.DOM.isType(target, 'div')) { 27 - target.nextSibling.insertBefore(ghost, target.nextSibling.firstChild); 28 - } else { 29 - target.parentNode.insertBefore(ghost, target.nextSibling); 30 - } 31 - } else { 32 - target.parentNode.appendChild(ghost); 33 - } 34 - }); 35 - 36 - draggable.listen('shouldBeginDrag', function(e) { 37 - if (e.getNode('slippery') || e.getNode('maniphest-edit-task')) { 38 - JX.Stratcom.context().kill(); 39 - } 40 - }); 41 - 42 - draggable.listen('didDrop', function(node, after) { 43 - var data = { 44 - task: JX.Stratcom.getData(node).taskID 45 - }; 46 - 47 - if (JX.DOM.isType(after, 'div')) { 48 - data.priority = JX.Stratcom.getData(after).priority; 49 - } else { 50 - data.after = JX.Stratcom.getData(after).taskID; 51 - } 52 - 53 - draggable.lock(); 54 - JX.DOM.alterClass(node, 'drag-sending', true); 55 - 56 - var onresponse = function(r) { 57 - var nodes = JX.$H(r.tasks).getFragment().firstChild; 58 - var task = JX.DOM.find(nodes, 'li', 'maniphest-task'); 59 - JX.DOM.replace(node, task); 60 - draggable.unlock(); 61 - JX.Stratcom.invoke( 62 - 'subpriority-changed', 63 - null, 64 - { 'task' : task }); 65 - }; 66 - 67 - new JX.Workflow(config.uri, data) 68 - .setHandler(onresponse) 69 - .start(); 70 - }); 71 - 72 - });