From e25a40236fe29afe6ffcbbdb138bc45b545526f6 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 3 Feb 2016 11:58:14 -0800 Subject: [PATCH] Nearly complete lifting card-move code out of workboards Summary: Ref T10010. This gets rid of the last dependency on the weird ColumnPositionQuery code. Test Plan: - Viewed workboards. - Used batch editor. - Created a new workboard. - Dragged stuff around. - Created new tasks into columns. - Changed order from natural to priority, dragged things around. - Switched filter to custom filter, "all tasks", etc. Reviewers: chad Reviewed By: chad Maniphest Tasks: T10010 Differential Revision: https://secure.phabricator.com/D15176 --- .../PhabricatorProjectBoardViewController.php | 251 ++++++++---------- .../engine/PhabricatorBoardLayoutEngine.php | 22 +- 2 files changed, 125 insertions(+), 148 deletions(-) diff --git a/src/applications/project/controller/PhabricatorProjectBoardViewController.php b/src/applications/project/controller/PhabricatorProjectBoardViewController.php index 06669aa2be..d2fdf8d763 100644 --- a/src/applications/project/controller/PhabricatorProjectBoardViewController.php +++ b/src/applications/project/controller/PhabricatorProjectBoardViewController.php @@ -28,10 +28,93 @@ final class PhabricatorProjectBoardViewController $project = $this->getProject(); $this->readRequestState(); - $columns = $this->loadColumns($project); - // TODO: Expand the checks here if we add the ability - // to hide the Backlog column + $board_uri = $this->getApplicationURI('board/'.$project->getID().'/'); + + $search_engine = id(new ManiphestTaskSearchEngine()) + ->setViewer($viewer) + ->setBaseURI($board_uri) + ->setIsBoardView(true); + + if ($request->isFormPost() && !$request->getBool('initialize')) { + $saved = $search_engine->buildSavedQueryFromRequest($request); + $search_engine->saveQuery($saved); + $filter_form = id(new AphrontFormView()) + ->setUser($viewer); + $search_engine->buildSearchForm($filter_form, $saved); + if ($search_engine->getErrors()) { + return $this->newDialog() + ->setWidth(AphrontDialogView::WIDTH_FULL) + ->setTitle(pht('Advanced Filter')) + ->appendChild($filter_form->buildLayoutView()) + ->setErrors($search_engine->getErrors()) + ->setSubmitURI($board_uri) + ->addSubmitButton(pht('Apply Filter')) + ->addCancelButton($board_uri); + } + return id(new AphrontRedirectResponse())->setURI( + $this->getURIWithState( + $search_engine->getQueryResultsPageURI($saved->getQueryKey()))); + } + + $query_key = $request->getURIData('queryKey'); + if (!$query_key) { + $query_key = 'open'; + } + $this->queryKey = $query_key; + + $custom_query = null; + if ($search_engine->isBuiltinQuery($query_key)) { + $saved = $search_engine->buildSavedQueryFromBuiltin($query_key); + } else { + $saved = id(new PhabricatorSavedQueryQuery()) + ->setViewer($viewer) + ->withQueryKeys(array($query_key)) + ->executeOne(); + + if (!$saved) { + return new Aphront404Response(); + } + + $custom_query = $saved; + } + + if ($request->getURIData('filter')) { + $filter_form = id(new AphrontFormView()) + ->setUser($viewer); + $search_engine->buildSearchForm($filter_form, $saved); + + return $this->newDialog() + ->setWidth(AphrontDialogView::WIDTH_FULL) + ->setTitle(pht('Advanced Filter')) + ->appendChild($filter_form->buildLayoutView()) + ->setSubmitURI($board_uri) + ->addSubmitButton(pht('Apply Filter')) + ->addCancelButton($board_uri); + } + + $task_query = $search_engine->buildQueryFromSavedQuery($saved); + + $tasks = $task_query + ->withEdgeLogicPHIDs( + PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, + PhabricatorQueryConstraint::OPERATOR_AND, + array($project->getPHID())) + ->setOrder(ManiphestTaskQuery::ORDER_PRIORITY) + ->setViewer($viewer) + ->execute(); + $tasks = mpull($tasks, null, 'getPHID'); + + + $board_phid = $project->getPHID(); + + $layout_engine = id(new PhabricatorBoardLayoutEngine()) + ->setViewer($viewer) + ->setBoardPHIDs(array($board_phid)) + ->setObjectPHIDs(array_keys($tasks)) + ->executeLayout(); + + $columns = $layout_engine->getColumns($board_phid); if (!$columns) { $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, @@ -64,124 +147,6 @@ final class PhabricatorProjectBoardViewController ->appendChild($content); } - $board_uri = $this->getApplicationURI('board/'.$project->getID().'/'); - - $engine = id(new ManiphestTaskSearchEngine()) - ->setViewer($viewer) - ->setBaseURI($board_uri) - ->setIsBoardView(true); - - if ($request->isFormPost()) { - $saved = $engine->buildSavedQueryFromRequest($request); - $engine->saveQuery($saved); - $filter_form = id(new AphrontFormView()) - ->setUser($viewer); - $engine->buildSearchForm($filter_form, $saved); - if ($engine->getErrors()) { - return $this->newDialog() - ->setWidth(AphrontDialogView::WIDTH_FULL) - ->setTitle(pht('Advanced Filter')) - ->appendChild($filter_form->buildLayoutView()) - ->setErrors($engine->getErrors()) - ->setSubmitURI($board_uri) - ->addSubmitButton(pht('Apply Filter')) - ->addCancelButton($board_uri); - } - return id(new AphrontRedirectResponse())->setURI( - $this->getURIWithState( - $engine->getQueryResultsPageURI($saved->getQueryKey()))); - } - - $query_key = $request->getURIData('queryKey'); - if (!$query_key) { - $query_key = 'open'; - } - $this->queryKey = $query_key; - - $custom_query = null; - if ($engine->isBuiltinQuery($query_key)) { - $saved = $engine->buildSavedQueryFromBuiltin($query_key); - } else { - $saved = id(new PhabricatorSavedQueryQuery()) - ->setViewer($viewer) - ->withQueryKeys(array($query_key)) - ->executeOne(); - - if (!$saved) { - return new Aphront404Response(); - } - - $custom_query = $saved; - } - - if ($request->getURIData('filter')) { - $filter_form = id(new AphrontFormView()) - ->setUser($viewer); - $engine->buildSearchForm($filter_form, $saved); - - return $this->newDialog() - ->setWidth(AphrontDialogView::WIDTH_FULL) - ->setTitle(pht('Advanced Filter')) - ->appendChild($filter_form->buildLayoutView()) - ->setSubmitURI($board_uri) - ->addSubmitButton(pht('Apply Filter')) - ->addCancelButton($board_uri); - } - - $task_query = $engine->buildQueryFromSavedQuery($saved); - - $tasks = $task_query - ->withEdgeLogicPHIDs( - PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, - PhabricatorQueryConstraint::OPERATOR_AND, - array($project->getPHID())) - ->setOrder(ManiphestTaskQuery::ORDER_PRIORITY) - ->setViewer($viewer) - ->execute(); - $tasks = mpull($tasks, null, 'getPHID'); - - if ($tasks) { - $positions = id(new PhabricatorProjectColumnPositionQuery()) - ->setViewer($viewer) - ->withObjectPHIDs(mpull($tasks, 'getPHID')) - ->withColumns($columns) - ->execute(); - $positions = mpull($positions, null, 'getObjectPHID'); - } else { - $positions = array(); - } - - $task_map = array(); - foreach ($tasks as $task) { - $task_phid = $task->getPHID(); - if (empty($positions[$task_phid])) { - // This shouldn't normally be possible because we create positions on - // demand, but we might have raced as an object was removed from the - // board. Just drop the task if we don't have a position for it. - continue; - } - - $position = $positions[$task_phid]; - $task_map[$position->getColumnPHID()][] = $task_phid; - } - - // If we're showing the board in "natural" order, sort columns by their - // column positions. - if ($this->sortKey == PhabricatorProjectColumn::ORDER_NATURAL) { - foreach ($task_map as $column_phid => $task_phids) { - $order = array(); - foreach ($task_phids as $task_phid) { - if (isset($positions[$task_phid])) { - $order[$task_phid] = $positions[$task_phid]->getOrderingKey(); - } else { - $order[$task_phid] = 0; - } - } - asort($order); - $task_map[$column_phid] = array_keys($order); - } - } - $task_can_edit_map = id(new PhabricatorPolicyFilter()) ->setViewer($viewer) ->requireCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT)) @@ -198,7 +163,10 @@ final class PhabricatorProjectBoardViewController return new Aphront404Response(); } - $batch_task_phids = idx($task_map, $batch_column->getPHID(), array()); + $batch_task_phids = $layout_engine->getColumnObjectPHIDs( + $board_phid, + $batch_column->getPHID()); + foreach ($batch_task_phids as $key => $batch_task_phid) { if (empty($task_can_edit_map[$batch_task_phid])) { unset($batch_task_phids[$key]); @@ -251,9 +219,24 @@ final class PhabricatorProjectBoardViewController $this->handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks); foreach ($columns as $column) { - $task_phids = idx($task_map, $column->getPHID(), array()); + if (!$this->showHidden) { + if ($column->isHidden()) { + continue; + } + } + + $task_phids = $layout_engine->getColumnObjectPHIDs( + $board_phid, + $column->getPHID()); + $column_tasks = array_select_keys($tasks, $task_phids); + // If we aren't using "natural" order, reorder the column by the original + // query order. + if ($this->sortKey != PhabricatorProjectColumn::ORDER_NATURAL) { + $column_tasks = array_select_keys($column_tasks, array_keys($tasks)); + } + $panel = id(new PHUIWorkpanelView()) ->setHeader($column->getDisplayName()) ->setSubHeader($column->getDisplayType()) @@ -322,7 +305,7 @@ final class PhabricatorProjectBoardViewController $filter_menu = $this->buildFilterMenu( $viewer, $custom_query, - $engine, + $search_engine, $query_key); $manage_menu = $this->buildManageMenu($project, $this->showHidden); @@ -383,25 +366,6 @@ final class PhabricatorProjectBoardViewController $this->sortKey = $sort_key; } - private function loadColumns(PhabricatorProject $project) { - $viewer = $this->getViewer(); - - $column_query = id(new PhabricatorProjectColumnQuery()) - ->setViewer($viewer) - ->withProjectPHIDs(array($project->getPHID())); - - if (!$this->showHidden) { - $column_query->withStatuses( - array(PhabricatorProjectColumn::STATUS_ACTIVE)); - } - - $columns = $column_query->execute(); - $columns = mpull($columns, null, 'getSequence'); - ksort($columns); - - return $columns; - } - private function buildSortMenu( PhabricatorUser $viewer, $sort_key) { @@ -797,6 +761,7 @@ final class PhabricatorProjectBoardViewController $form = id(new AphrontFormView()) ->setUser($viewer) + ->addHiddenInput('initialize', 1) ->appendRemarkupInstructions( pht('The workboard for this project has not been created yet.')) ->appendControl($new_selector) diff --git a/src/applications/project/engine/PhabricatorBoardLayoutEngine.php b/src/applications/project/engine/PhabricatorBoardLayoutEngine.php index 28cecd81ea..8a6143c81d 100644 --- a/src/applications/project/engine/PhabricatorBoardLayoutEngine.php +++ b/src/applications/project/engine/PhabricatorBoardLayoutEngine.php @@ -6,7 +6,7 @@ final class PhabricatorBoardLayoutEngine extends Phobject { private $boardPHIDs; private $objectPHIDs; private $boards; - private $columnMap; + private $columnMap = array(); private $objectColumnMap = array(); private $boardLayout = array(); @@ -68,6 +68,17 @@ final class PhabricatorBoardLayoutEngine extends Phobject { return $this; } + public function getColumns($board_phid) { + $columns = idx($this->boardLayout, $board_phid, array()); + return array_select_keys($this->columnMap, array_keys($columns)); + } + + public function getColumnObjectPHIDs($board_phid, $column_phid) { + $columns = idx($this->boardLayout, $board_phid, array()); + $positions = idx($columns, $column_phid, array()); + return mpull($positions, 'getObjectPHID'); + } + public function getObjectColumns($board_phid, $object_phid) { $board_map = idx($this->objectColumnMap, $board_phid, array()); @@ -342,15 +353,16 @@ final class PhabricatorBoardLayoutEngine extends Phobject { $board_phid = $board->getPHID(); $position_groups = mgroup($positions, 'getObjectPHID'); + $layout = array(); foreach ($columns as $column) { + $column_phid = $column->getPHID(); + $layout[$column_phid] = array(); + if ($column->isDefaultColumn()) { - $default_phid = $column->getPHID(); - break; + $default_phid = $column_phid; } } - $layout = array(); - $object_phids = $this->getObjectPHIDs(); foreach ($object_phids as $object_phid) { $positions = idx($position_groups, $object_phid, array());