diff --git a/resources/celerity/map.php b/resources/celerity/map.php index a548811fcc..7aeb049f96 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -401,7 +401,7 @@ return array( 'rsrc/js/application/policy/behavior-policy-control.js' => 'c01153ea', 'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '263aeb8c', 'rsrc/js/application/ponder/behavior-votebox.js' => '327dbe61', - 'rsrc/js/application/projects/behavior-project-boards.js' => 'cbdc9b22', + 'rsrc/js/application/projects/behavior-project-boards.js' => '04c59172', 'rsrc/js/application/projects/behavior-project-create.js' => '065227cc', 'rsrc/js/application/releeph/releeph-preview-branch.js' => '9eb2cedb', 'rsrc/js/application/releeph/releeph-request-state-change.js' => 'fe7fc914', @@ -610,7 +610,7 @@ return array( 'javelin-behavior-policy-control' => 'c01153ea', 'javelin-behavior-policy-rule-editor' => '263aeb8c', 'javelin-behavior-ponder-votebox' => '327dbe61', - 'javelin-behavior-project-boards' => 'cbdc9b22', + 'javelin-behavior-project-boards' => '04c59172', 'javelin-behavior-project-create' => '065227cc', 'javelin-behavior-refresh-csrf' => 'c4b31646', 'javelin-behavior-releeph-preview-branch' => '9eb2cedb', @@ -839,6 +839,15 @@ return array( 3 => 'javelin-vector', 4 => 'javelin-install', ), + '04c59172' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-dom', + 2 => 'javelin-util', + 3 => 'javelin-stratcom', + 4 => 'javelin-workflow', + 5 => 'phabricator-draggable-list', + ), '065227cc' => array( 0 => 'javelin-behavior', @@ -1216,6 +1225,13 @@ return array( 2 => 'javelin-util', 3 => 'phabricator-shaped-request', ), + '62e18640' => + array( + 0 => 'javelin-install', + 1 => 'javelin-util', + 2 => 'javelin-dom', + 3 => 'javelin-typeahead-normalizer', + ), '6453c869' => array( 0 => 'javelin-install', @@ -1249,13 +1265,6 @@ return array( 0 => 'javelin-behavior', 1 => 'javelin-dom', ), - '62e18640' => - array( - 0 => 'javelin-install', - 1 => 'javelin-util', - 2 => 'javelin-dom', - 3 => 'javelin-typeahead-normalizer', - ), '75903ee1' => array( 0 => 'javelin-behavior', @@ -1689,15 +1698,6 @@ return array( 2 => 'javelin-stratcom', 3 => 'phabricator-phtize', ), - 'cbdc9b22' => - array( - 0 => 'javelin-behavior', - 1 => 'javelin-dom', - 2 => 'javelin-util', - 3 => 'javelin-stratcom', - 4 => 'javelin-workflow', - 5 => 'phabricator-draggable-list', - ), 'cd9e7094' => array( 0 => 'javelin-behavior', diff --git a/src/applications/maniphest/controller/ManiphestTaskEditController.php b/src/applications/maniphest/controller/ManiphestTaskEditController.php index a4ca313d7a..053b69bebf 100644 --- a/src/applications/maniphest/controller/ManiphestTaskEditController.php +++ b/src/applications/maniphest/controller/ManiphestTaskEditController.php @@ -12,7 +12,7 @@ final class ManiphestTaskEditController extends ManiphestController { $request = $this->getRequest(); $user = $request->getUser(); - $response_type = $request->getStr('response_type', 'task'); + $response_type = $request->getStr('responseType', 'task'); $can_edit_assign = $this->hasApplicationCapability( ManiphestCapabilityEditAssign::CAPABILITY); @@ -242,8 +242,28 @@ final class ManiphestTaskEditController extends ManiphestController { $changes[ManiphestTransaction::TYPE_CCS] = $request->getArr('cc'); if ($can_edit_projects) { + $projects = $request->getArr('projects'); $changes[ManiphestTransaction::TYPE_PROJECTS] = - $request->getArr('projects'); + $projects; + $column_phid = $request->getStr('columnPHID'); + // allow for putting a task in a project column at creation -only- + if (!$task->getID() && $column_phid && $projects) { + $column = id(new PhabricatorProjectColumnQuery()) + ->setViewer($user) + ->withProjectPHIDs($projects) + ->withPHIDs(array($column_phid)) + ->executeOne(); + if ($column) { + $changes[ManiphestTransaction::TYPE_PROJECT_COLUMN] = + array( + 'new' => array( + 'projectPHID' => $column->getProjectPHID(), + 'columnPHIDs' => array($column_phid)), + 'old' => array( + 'projectPHID' => $column->getProjectPHID(), + 'columnPHIDs' => array())); + } + } } if ($can_edit_policies) { @@ -267,7 +287,12 @@ final class ManiphestTaskEditController extends ManiphestController { foreach ($changes as $type => $value) { $transaction = clone $template; $transaction->setTransactionType($type); - $transaction->setNewValue($value); + if ($type == ManiphestTransaction::TYPE_PROJECT_COLUMN) { + $transaction->setNewValue($value['new']); + $transaction->setOldValue($value['old']); + } else { + $transaction->setNewValue($value); + } $transactions[] = $transaction; } @@ -351,15 +376,72 @@ final class ManiphestTaskEditController extends ManiphestController { ->setOwner($owner) ->setCanEdit(true) ->getItem(); + $column_phid = $request->getStr('columnPHID'); + $column = id(new PhabricatorProjectColumnQuery()) + ->setViewer($user) + ->withPHIDs(array($column_phid)) + ->executeOne(); + if ($column->isDefaultColumn()) { + $column_tasks = array(); + $potential_col_tasks = id(new ManiphestTaskQuery()) + ->setViewer($user) + ->withAllProjects(array($column->getProjectPHID())) + ->withStatuses(ManiphestTaskStatus::getOpenStatusConstants()) + ->setOrderBy(ManiphestTaskQuery::ORDER_PRIORITY) + ->execute(); + $potential_col_tasks = mpull( + $potential_col_tasks, + null, + 'getPHID'); + $potential_task_phids = array_keys($potential_col_tasks); + if ($potential_task_phids) { + $edge_type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_COLUMN; + $edge_query = id(new PhabricatorEdgeQuery()) + ->withSourcePHIDs($potential_task_phids) + ->withEdgeTypes(array($edge_type)); + $edges = $edge_query->execute(); + foreach ($potential_col_tasks as $task_phid => $curr_task) { + $curr_column_phids = $edges[$task_phid][$edge_type]; + $curr_column_phid = head_key($curr_column_phids); + if (!$curr_column_phid || + $curr_column_phid == $column_phid) { + $column_tasks[] = $curr_task; + } + } + } + } else { + $column_task_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( + $column_phid, + PhabricatorEdgeConfig::TYPE_COLUMN_HAS_OBJECT); + $column_tasks = id(new ManiphestTaskQuery()) + ->setViewer($user) + ->withPHIDs($column_task_phids) + ->withStatuses(ManiphestTaskStatus::getOpenStatusConstants()) + ->setOrderBy(ManiphestTaskQuery::ORDER_PRIORITY) + ->execute(); + } + $column_task_phids = mpull($column_tasks, 'getPHID'); + $task_phid = $task->getPHID(); + $after_phid = null; + foreach ($column_task_phids as $phid) { + if ($phid == $task_phid) { + break; + } + $after_phid = $phid; + } + $data = array( + 'insertAfterPHID' => $after_phid); break; case 'task': default: $tasks = $this->renderSingleTask($task); + $data = array(); break; } return id(new AphrontAjaxResponse())->setContent( array( 'tasks' => $tasks, + 'data' => $data, )); } @@ -486,7 +568,8 @@ final class ManiphestTaskEditController extends ManiphestController { $form ->setUser($user) ->addHiddenInput('template', $template_id) - ->addHiddenInput('response_type', $response_type); + ->addHiddenInput('responseType', $response_type) + ->addHiddenInput('columnPHID', $request->getStr('columnPHID')); if ($parent_task) { $form diff --git a/src/applications/project/controller/PhabricatorProjectBoardController.php b/src/applications/project/controller/PhabricatorProjectBoardController.php index 9365014fe0..b5304f1e56 100644 --- a/src/applications/project/controller/PhabricatorProjectBoardController.php +++ b/src/applications/project/controller/PhabricatorProjectBoardController.php @@ -94,7 +94,9 @@ final class PhabricatorProjectBoardController 'project-boards', array( 'boardID' => $board_id, + 'projectPHID' => $project->getPHID(), 'moveURI' => $this->getApplicationURI('move/'.$project->getID().'/'), + 'createURI' => '/maniphest/task/create/', )); $this->handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks); @@ -106,6 +108,13 @@ final class PhabricatorProjectBoardController if (!$column->isDefaultColumn()) { $panel->setEditURI('edit/'.$column->getID().'/'); } + $panel->setHeaderAction(id(new PHUIIconView()) + ->setSpriteSheet(PHUIIconView::SPRITE_ACTIONS) + ->setSpriteIcon('new-grey') + ->setHref('/maniphest/task/create/') + ->addSigil('column-add-task') + ->setMetadata( + array('columnPHID' => $column->getPHID()))); $cards = id(new PHUIObjectItemListView()) ->setUser($viewer) diff --git a/src/view/phui/PHUIWorkpanelView.php b/src/view/phui/PHUIWorkpanelView.php index dd80edd587..94c25ff85d 100644 --- a/src/view/phui/PHUIWorkpanelView.php +++ b/src/view/phui/PHUIWorkpanelView.php @@ -5,9 +5,15 @@ final class PHUIWorkpanelView extends AphrontTagView { private $cards = array(); private $header; private $editURI; + private $headerAction; private $footerAction; private $headerColor = PhabricatorActionHeaderView::HEADER_GREY; + public function setHeaderAction(PHUIIconView $header_action) { + $this->headerAction = $header_action; + return $this; + } + public function setCards(PHUIObjectItemListView $cards) { $this->cards[] = $cards; return $this; @@ -60,13 +66,15 @@ final class PHUIWorkpanelView extends AphrontTagView { ->setSpriteIcon('settings-grey') ->setHref($this->editURI); } - $header = id(new PhabricatorActionHeaderView()) ->setHeaderTitle($this->header) ->setHeaderColor($this->headerColor); if ($header_edit) { $header->addAction($header_edit); } + if ($this->headerAction) { + $header->addAction($this->headerAction); + } $body = phutil_tag( 'div', diff --git a/webroot/rsrc/js/application/projects/behavior-project-boards.js b/webroot/rsrc/js/application/projects/behavior-project-boards.js index 5f9c66f900..3ad9d0de9d 100644 --- a/webroot/rsrc/js/application/projects/behavior-project-boards.js +++ b/webroot/rsrc/js/application/projects/behavior-project-boards.js @@ -65,10 +65,31 @@ JX.behavior('project-boards', function(config) { lists[ii].setGroup(lists); } - var onedit = function(card, r) { - var nodes = JX.$H(r.tasks).getFragment().firstChild; + var onedit = function(card, column, r) { var new_card = JX.$H(r.tasks); - JX.DOM.replace(card, new_card); + var items = finditems(column); + var insert_after = r.data.insertAfterPHID; + if (!insert_after) { + JX.DOM.prependContent(column, new_card); + if (card) { + JX.DOM.remove(card); + } + return; + } + var ii; + var item; + var item_phid; + for (ii = 0; ii< items.length; ii++) { + item = items[ii]; + item_phid = JX.Stratcom.getData(item).objectPHID; + if (item_phid == insert_after) { + JX.DOM.replace(item, [item, new_card]); + if (card) { + JX.DOM.remove(card); + } + return; + } + } }; JX.Stratcom.listen( @@ -77,9 +98,36 @@ JX.behavior('project-boards', function(config) { function(e) { e.kill(); var card = e.getNode('project-card'); - new JX.Workflow(e.getNode('tag:a').href, { 'response_type' : 'card' }) - .setHandler(JX.bind(null, onedit, card)) - .start(); + var column = e.getNode('project-column'); + var request_data = { + 'responseType' : 'card', + 'columnPHID' : JX.Stratcom.getData(column).columnPHID }; + new JX.Workflow(e.getNode('tag:a').href, request_data) + .setHandler(JX.bind(null, onedit, card, column)) + .start(); }); + JX.Stratcom.listen( + 'click', + ['column-add-task'], + function (e) { + e.kill(); + var column_phid = e.getNodeData('column-add-task').columnPHID; + var request_data = { + 'responseType' : 'card', + 'columnPHID' : column_phid, + 'projects' : config.projectPHID }; + var cols = JX.DOM.scry(JX.$(config.boardID), 'ul', 'project-column'); + var ii; + var column; + for (ii = 0; ii < cols.length; ii++) { + if (JX.Stratcom.getData(cols[ii]).columnPHID == column_phid) { + column = cols[ii]; + break; + } + } + new JX.Workflow(config.createURI, request_data) + .setHandler(JX.bind(null, onedit, null, column)) + .start(); + }); });