diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -8,7 +8,7 @@ return array( 'names' => array( 'core.pkg.css' => 'bf29d341', - 'core.pkg.js' => 'dfea788f', + 'core.pkg.js' => 'a626d14c', 'darkconsole.pkg.js' => '8ab24e01', 'differential.pkg.css' => '3500921f', 'differential.pkg.js' => 'c0506961', @@ -450,7 +450,7 @@ 'rsrc/js/core/KeyboardShortcutManager.js' => 'c1700f6f', 'rsrc/js/core/MultirowRowManager.js' => 'b5d57730', 'rsrc/js/core/Notification.js' => '0c6946e7', - 'rsrc/js/core/Prefab.js' => '6920d200', + 'rsrc/js/core/Prefab.js' => 'b972bdcd', 'rsrc/js/core/ShapedRequest.js' => '7cbe244b', 'rsrc/js/core/TextAreaUtils.js' => '5c93c52c', 'rsrc/js/core/Title.js' => 'df5e11d2', @@ -744,7 +744,7 @@ 'phabricator-notification-menu-css' => '3c9d8aa1', 'phabricator-object-selector-css' => '029a133d', 'phabricator-phtize' => 'd254d646', - 'phabricator-prefab' => '6920d200', + 'phabricator-prefab' => 'b972bdcd', 'phabricator-profile-css' => '1a20dcbf', 'phabricator-remarkup-css' => 'e10512ff', 'phabricator-search-results-css' => '15c71110', @@ -1296,18 +1296,6 @@ '6882e80a' => array( 'javelin-dom', ), - '6920d200' => array( - 'javelin-install', - 'javelin-util', - 'javelin-dom', - 'javelin-typeahead', - 'javelin-tokenizer', - 'javelin-typeahead-preloaded-source', - 'javelin-typeahead-ondemand-source', - 'javelin-dom', - 'javelin-stratcom', - 'javelin-util', - ), '69adf288' => array( 'javelin-install', ), @@ -1719,6 +1707,18 @@ 'javelin-dom', 'javelin-util', ), + 'b972bdcd' => array( + 'javelin-install', + 'javelin-util', + 'javelin-dom', + 'javelin-typeahead', + 'javelin-tokenizer', + 'javelin-typeahead-preloaded-source', + 'javelin-typeahead-ondemand-source', + 'javelin-dom', + 'javelin-stratcom', + 'javelin-util', + ), 'bba9eedf' => array( 'javelin-behavior', 'javelin-stratcom', diff --git a/src/applications/maniphest/controller/ManiphestBatchEditController.php b/src/applications/maniphest/controller/ManiphestBatchEditController.php --- a/src/applications/maniphest/controller/ManiphestBatchEditController.php +++ b/src/applications/maniphest/controller/ManiphestBatchEditController.php @@ -2,16 +2,31 @@ final class ManiphestBatchEditController extends ManiphestController { - public function processRequest() { + public function handleRequest(AphrontRequest $request) { + $viewer = $this->getViewer(); + $this->requireApplicationCapability( ManiphestBulkEditCapability::CAPABILITY); - $request = $this->getRequest(); - $user = $request->getUser(); + $project = null; + $board_id = $request->getInt('board'); + if ($board_id) { + $project = id(new PhabricatorProjectQuery()) + ->setViewer($viewer) + ->withIDs(array($board_id)) + ->executeOne(); + if (!$project) { + return new Aphront404Response(); + } + } $task_ids = $request->getArr('batch'); + if (!$task_ids) { + $task_ids = $request->getStrList('batch'); + } + $tasks = id(new ManiphestTaskQuery()) - ->setViewer($user) + ->setViewer($viewer) ->withIDs($task_ids) ->requireCapabilities( array( @@ -22,6 +37,14 @@ ->needProjectPHIDs(true) ->execute(); + if ($project) { + $cancel_uri = '/project/board/'.$project->getID().'/'; + $redirect_uri = $cancel_uri; + } else { + $cancel_uri = '/maniphest/'; + $redirect_uri = '/maniphest/?ids='.implode(',', mpull($tasks, 'getID')); + } + $actions = $request->getStr('actions'); if ($actions) { $actions = json_decode($actions, true); @@ -39,7 +62,7 @@ // TODO: Set content source to "batch edit". $editor = id(new ManiphestTransactionEditor()) - ->setActor($user) + ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) ->setContinueOnMissingFields(true) @@ -47,17 +70,14 @@ } } - $task_ids = implode(',', mpull($tasks, 'getID')); - - return id(new AphrontRedirectResponse()) - ->setURI('/maniphest/?ids='.$task_ids); + return id(new AphrontRedirectResponse())->setURI($redirect_uri); } - $handles = ManiphestTaskListView::loadTaskHandles($user, $tasks); + $handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks); $list = new ManiphestTaskListView(); $list->setTasks($tasks); - $list->setUser($user); + $list->setUser($viewer); $list->setHandles($handles); $template = new AphrontTokenizerTemplateView(); @@ -65,9 +85,9 @@ $projects_source = new PhabricatorProjectDatasource(); $mailable_source = new PhabricatorMetaMTAMailableDatasource(); - $mailable_source->setViewer($user); + $mailable_source->setViewer($viewer); $owner_source = new PhabricatorTypeaheadOwnerDatasource(); - $owner_source->setViewer($user); + $owner_source->setViewer($viewer); require_celerity_resource('maniphest-batch-editor'); Javelin::initBehavior( @@ -98,9 +118,10 @@ 'statusMap' => ManiphestTaskStatus::getTaskStatusMap(), )); - $form = new AphrontFormView(); - $form->setUser($user); - $form->setID('maniphest-batch-edit-form'); + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->addHiddenInput('board', $board_id) + ->setID('maniphest-batch-edit-form'); foreach ($tasks as $task) { $form->appendChild( @@ -143,7 +164,7 @@ ->appendChild( id(new AphrontFormSubmitControl()) ->setValue(pht('Update Tasks')) - ->addCancelButton('/maniphest/')); + ->addCancelButton($cancel_uri)); $title = pht('Batch Editor'); diff --git a/src/applications/project/controller/PhabricatorProjectBoardViewController.php b/src/applications/project/controller/PhabricatorProjectBoardViewController.php --- a/src/applications/project/controller/PhabricatorProjectBoardViewController.php +++ b/src/applications/project/controller/PhabricatorProjectBoardViewController.php @@ -3,6 +3,8 @@ final class PhabricatorProjectBoardViewController extends PhabricatorProjectBoardController { + const BATCH_EDIT_ALL = 'all'; + private $id; private $slug; private $handles; @@ -211,6 +213,50 @@ ->requireCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT)) ->apply($tasks); + // If this is a batch edit, select the editable tasks in the chosen column + // and ship the user into the batch editor. + $batch_edit = $request->getStr('batch'); + if ($batch_edit) { + if ($batch_edit !== self::BATCH_EDIT_ALL) { + $column_id_map = mpull($columns, null, 'getID'); + $batch_column = idx($column_id_map, $batch_edit); + if (!$batch_column) { + return new Aphront404Response(); + } + + $batch_task_phids = idx($task_map, $batch_column->getPHID(), array()); + foreach ($batch_task_phids as $key => $batch_task_phid) { + if (empty($task_can_edit_map[$batch_task_phid])) { + unset($batch_task_phids[$key]); + } + } + + $batch_tasks = array_select_keys($tasks, $batch_task_phids); + } else { + $batch_tasks = $task_can_edit_map; + } + + if (!$batch_tasks) { + $cancel_uri = $this->getURIWithState($board_uri); + return $this->newDialog() + ->setTitle(pht('No Editable Tasks')) + ->appendParagraph( + pht( + 'The selected column contains no visible tasks which you '. + 'have permission to edit.')) + ->addCancelButton($board_uri); + } + + $batch_ids = mpull($batch_tasks, 'getID'); + $batch_ids = implode(',', $batch_ids); + + $batch_uri = new PhutilURI('/maniphest/batch/'); + $batch_uri->setQueryParam('board', $this->id); + $batch_uri->setQueryParam('batch', $batch_ids); + return id(new AphrontRedirectResponse()) + ->setURI($batch_uri); + } + $board_id = celerity_generate_unique_node_id(); $board = id(new PHUIWorkboardView()) @@ -518,6 +564,19 @@ ->setName($hidden_text) ->setHref($hidden_uri); + $batch_edit_uri = $request->getRequestURI(); + $batch_edit_uri->setQueryParam('batch', self::BATCH_EDIT_ALL); + $can_batch_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + PhabricatorApplication::getByClass('PhabricatorManiphestApplication'), + ManiphestBulkEditCapability::CAPABILITY); + + $manage_items[] = id(new PhabricatorActionView()) + ->setIcon('fa-list-ul') + ->setName(pht('Batch Edit Visible Tasks...')) + ->setHref($batch_edit_uri) + ->setDisabled(!$can_batch_edit); + $manage_menu = id(new PhabricatorActionListView()) ->setUser($viewer); foreach ($manage_items as $item) { @@ -563,6 +622,19 @@ )) ->setDisabled(!$can_edit); + $batch_edit_uri = $request->getRequestURI(); + $batch_edit_uri->setQueryParam('batch', $column->getID()); + $can_batch_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + PhabricatorApplication::getByClass('PhabricatorManiphestApplication'), + ManiphestBulkEditCapability::CAPABILITY); + + $column_items[] = id(new PhabricatorActionView()) + ->setIcon('fa-list-ul') + ->setName(pht('Batch Edit Tasks...')) + ->setHref($batch_edit_uri) + ->setDisabled(!$can_batch_edit); + $edit_uri = $this->getApplicationURI( 'board/'.$this->id.'/column/'.$column->getID().'/');