mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-18 10:41:08 +01:00
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
This commit is contained in:
parent
a9e98e42f5
commit
e25a40236f
2 changed files with 125 additions and 148 deletions
|
@ -28,10 +28,93 @@ final class PhabricatorProjectBoardViewController
|
||||||
$project = $this->getProject();
|
$project = $this->getProject();
|
||||||
|
|
||||||
$this->readRequestState();
|
$this->readRequestState();
|
||||||
$columns = $this->loadColumns($project);
|
|
||||||
|
|
||||||
// TODO: Expand the checks here if we add the ability
|
$board_uri = $this->getApplicationURI('board/'.$project->getID().'/');
|
||||||
// to hide the Backlog column
|
|
||||||
|
$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) {
|
if (!$columns) {
|
||||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
$viewer,
|
$viewer,
|
||||||
|
@ -64,124 +147,6 @@ final class PhabricatorProjectBoardViewController
|
||||||
->appendChild($content);
|
->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())
|
$task_can_edit_map = id(new PhabricatorPolicyFilter())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->requireCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT))
|
->requireCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT))
|
||||||
|
@ -198,7 +163,10 @@ final class PhabricatorProjectBoardViewController
|
||||||
return new Aphront404Response();
|
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) {
|
foreach ($batch_task_phids as $key => $batch_task_phid) {
|
||||||
if (empty($task_can_edit_map[$batch_task_phid])) {
|
if (empty($task_can_edit_map[$batch_task_phid])) {
|
||||||
unset($batch_task_phids[$key]);
|
unset($batch_task_phids[$key]);
|
||||||
|
@ -251,9 +219,24 @@ final class PhabricatorProjectBoardViewController
|
||||||
$this->handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks);
|
$this->handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks);
|
||||||
|
|
||||||
foreach ($columns as $column) {
|
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);
|
$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())
|
$panel = id(new PHUIWorkpanelView())
|
||||||
->setHeader($column->getDisplayName())
|
->setHeader($column->getDisplayName())
|
||||||
->setSubHeader($column->getDisplayType())
|
->setSubHeader($column->getDisplayType())
|
||||||
|
@ -322,7 +305,7 @@ final class PhabricatorProjectBoardViewController
|
||||||
$filter_menu = $this->buildFilterMenu(
|
$filter_menu = $this->buildFilterMenu(
|
||||||
$viewer,
|
$viewer,
|
||||||
$custom_query,
|
$custom_query,
|
||||||
$engine,
|
$search_engine,
|
||||||
$query_key);
|
$query_key);
|
||||||
|
|
||||||
$manage_menu = $this->buildManageMenu($project, $this->showHidden);
|
$manage_menu = $this->buildManageMenu($project, $this->showHidden);
|
||||||
|
@ -383,25 +366,6 @@ final class PhabricatorProjectBoardViewController
|
||||||
$this->sortKey = $sort_key;
|
$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(
|
private function buildSortMenu(
|
||||||
PhabricatorUser $viewer,
|
PhabricatorUser $viewer,
|
||||||
$sort_key) {
|
$sort_key) {
|
||||||
|
@ -797,6 +761,7 @@ final class PhabricatorProjectBoardViewController
|
||||||
|
|
||||||
$form = id(new AphrontFormView())
|
$form = id(new AphrontFormView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
|
->addHiddenInput('initialize', 1)
|
||||||
->appendRemarkupInstructions(
|
->appendRemarkupInstructions(
|
||||||
pht('The workboard for this project has not been created yet.'))
|
pht('The workboard for this project has not been created yet.'))
|
||||||
->appendControl($new_selector)
|
->appendControl($new_selector)
|
||||||
|
|
|
@ -6,7 +6,7 @@ final class PhabricatorBoardLayoutEngine extends Phobject {
|
||||||
private $boardPHIDs;
|
private $boardPHIDs;
|
||||||
private $objectPHIDs;
|
private $objectPHIDs;
|
||||||
private $boards;
|
private $boards;
|
||||||
private $columnMap;
|
private $columnMap = array();
|
||||||
private $objectColumnMap = array();
|
private $objectColumnMap = array();
|
||||||
private $boardLayout = array();
|
private $boardLayout = array();
|
||||||
|
|
||||||
|
@ -68,6 +68,17 @@ final class PhabricatorBoardLayoutEngine extends Phobject {
|
||||||
return $this;
|
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) {
|
public function getObjectColumns($board_phid, $object_phid) {
|
||||||
$board_map = idx($this->objectColumnMap, $board_phid, array());
|
$board_map = idx($this->objectColumnMap, $board_phid, array());
|
||||||
|
|
||||||
|
@ -342,15 +353,16 @@ final class PhabricatorBoardLayoutEngine extends Phobject {
|
||||||
$board_phid = $board->getPHID();
|
$board_phid = $board->getPHID();
|
||||||
$position_groups = mgroup($positions, 'getObjectPHID');
|
$position_groups = mgroup($positions, 'getObjectPHID');
|
||||||
|
|
||||||
|
$layout = array();
|
||||||
foreach ($columns as $column) {
|
foreach ($columns as $column) {
|
||||||
|
$column_phid = $column->getPHID();
|
||||||
|
$layout[$column_phid] = array();
|
||||||
|
|
||||||
if ($column->isDefaultColumn()) {
|
if ($column->isDefaultColumn()) {
|
||||||
$default_phid = $column->getPHID();
|
$default_phid = $column_phid;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$layout = array();
|
|
||||||
|
|
||||||
$object_phids = $this->getObjectPHIDs();
|
$object_phids = $this->getObjectPHIDs();
|
||||||
foreach ($object_phids as $object_phid) {
|
foreach ($object_phids as $object_phid) {
|
||||||
$positions = idx($position_groups, $object_phid, array());
|
$positions = idx($position_groups, $object_phid, array());
|
||||||
|
|
Loading…
Reference in a new issue