Page MenuHomePhabricator

D15174.id36632.diff
No OneTemporary

D15174.id36632.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1811,6 +1811,7 @@
'PhabricatorBcryptPasswordHasher' => 'infrastructure/util/password/PhabricatorBcryptPasswordHasher.php',
'PhabricatorBinariesSetupCheck' => 'applications/config/check/PhabricatorBinariesSetupCheck.php',
'PhabricatorBitbucketAuthProvider' => 'applications/auth/provider/PhabricatorBitbucketAuthProvider.php',
+ 'PhabricatorBoardLayoutEngine' => 'applications/project/engine/PhabricatorBoardLayoutEngine.php',
'PhabricatorBot' => 'infrastructure/daemon/bot/PhabricatorBot.php',
'PhabricatorBotChannel' => 'infrastructure/daemon/bot/target/PhabricatorBotChannel.php',
'PhabricatorBotDebugLogHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotDebugLogHandler.php',
@@ -6035,6 +6036,7 @@
'PhabricatorBcryptPasswordHasher' => 'PhabricatorPasswordHasher',
'PhabricatorBinariesSetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorBitbucketAuthProvider' => 'PhabricatorOAuth1AuthProvider',
+ 'PhabricatorBoardLayoutEngine' => 'Phobject',
'PhabricatorBot' => 'PhabricatorDaemon',
'PhabricatorBotChannel' => 'PhabricatorBotTarget',
'PhabricatorBotDebugLogHandler' => 'PhabricatorBotHandler',
diff --git a/src/applications/project/controller/PhabricatorProjectMoveController.php b/src/applications/project/controller/PhabricatorProjectMoveController.php
--- a/src/applications/project/controller/PhabricatorProjectMoveController.php
+++ b/src/applications/project/controller/PhabricatorProjectMoveController.php
@@ -26,6 +26,8 @@
return new Aphront404Response();
}
+ $board_phid = $project->getPHID();
+
$object = id(new ManiphestTaskQuery())
->setViewer($viewer)
->withPHIDs(array($object_phid))
@@ -54,11 +56,14 @@
return new Aphront404Response();
}
- $positions = id(new PhabricatorProjectColumnPositionQuery())
+ $engine = id(new PhabricatorBoardLayoutEngine())
->setViewer($viewer)
- ->withColumns($columns)
- ->withObjectPHIDs(array($object_phid))
- ->execute();
+ ->setBoardPHIDs(array($board_phid))
+ ->setObjectPHIDs(array($object_phid))
+ ->executeLayout();
+
+ $columns = $engine->getObjectColumns($board_phid, $object_phid);
+ $old_column_phids = mpull($columns, 'getPHID');
$xactions = array();
@@ -80,7 +85,7 @@
) + $order_params)
->setOldValue(
array(
- 'columnPHIDs' => mpull($positions, 'getColumnPHID'),
+ 'columnPHIDs' => $old_column_phids,
'projectPHID' => $column->getProjectPHID(),
));
diff --git a/src/applications/project/engine/PhabricatorBoardLayoutEngine.php b/src/applications/project/engine/PhabricatorBoardLayoutEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/engine/PhabricatorBoardLayoutEngine.php
@@ -0,0 +1,187 @@
+<?php
+
+final class PhabricatorBoardLayoutEngine extends Phobject {
+
+ private $viewer;
+ private $boardPHIDs;
+ private $objectPHIDs;
+ private $boards;
+ private $columnMap;
+ private $objectColumnMap = array();
+ private $boardLayout = array();
+
+ public function setViewer(PhabricatorUser $viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
+ public function getViewer() {
+ return $this->viewer;
+ }
+
+ public function setBoardPHIDs(array $board_phids) {
+ $this->boardPHIDs = $board_phids;
+ return $this;
+ }
+
+ public function getBoardPHIDs() {
+ return $this->boardPHIDs;
+ }
+
+ public function setObjectPHIDs(array $object_phids) {
+ $this->objectPHIDs = $object_phids;
+ return $this;
+ }
+
+ public function getObjectPHIDs() {
+ return $this->objectPHIDs;
+ }
+
+ public function executeLayout() {
+ $viewer = $this->getViewer();
+
+ $boards = $this->loadBoards();
+ if (!$boards) {
+ return $this;
+ }
+
+ $columns = $this->loadColumns($boards);
+ $positions = $this->loadPositions($boards);
+
+ foreach ($boards as $board_phid => $board) {
+ $board_columns = idx($columns, $board_phid);
+
+ // Don't layout boards with no columns. These boards need to be formally
+ // created first.
+ if (!$columns) {
+ continue;
+ }
+
+ $board_positions = idx($positions, $board_phid, array());
+
+ $this->layoutBoard($board, $board_columns, $board_positions);
+ }
+
+ return $this;
+ }
+
+ public function getObjectColumns($board_phid, $object_phid) {
+ $board_map = idx($this->objectColumnMap, $board_phid, array());
+
+ $column_phids = idx($board_map, $object_phid);
+ if (!$column_phids) {
+ return array();
+ }
+
+ return array_select_keys($this->columnMap, $column_phids);
+ }
+
+ private function loadBoards() {
+ $viewer = $this->getViewer();
+ $board_phids = $this->getBoardPHIDs();
+
+ $boards = id(new PhabricatorObjectQuery())
+ ->setViewer($viewer)
+ ->withPHIDs($board_phids)
+ ->execute();
+ $boards = mpull($boards, null, 'getPHID');
+
+ foreach ($boards as $key => $board) {
+ if (!$board->getHasWorkboard()) {
+ unset($boards[$key]);
+ }
+ }
+
+ return $boards;
+ }
+
+ private function loadColumns(array $boards) {
+ $viewer = $this->getViewer();
+
+ $columns = id(new PhabricatorProjectColumnQuery())
+ ->setViewer($viewer)
+ ->withProjectPHIDs(array_keys($boards))
+ ->execute();
+ $columns = msort($columns, 'getSequence');
+ $columns = mpull($columns, null, 'getPHID');
+
+ $this->columnMap = $columns;
+ $columns = mgroup($columns, 'getProjectPHID');
+
+ return $columns;
+ }
+
+ private function loadPositions(array $boards) {
+ $viewer = $this->getViewer();
+
+ $positions = id(new PhabricatorProjectColumnPositionQuery())
+ ->setViewer($viewer)
+ ->withBoardPHIDs(array_keys($boards))
+ ->withObjectPHIDs($this->getObjectPHIDs())
+ ->execute();
+ $positions = msort($positions, 'getOrderingKey');
+ $positions = mgroup($positions, 'getBoardPHID');
+
+ return $positions;
+ }
+
+ private function layoutBoard(
+ $board,
+ array $columns,
+ array $positions) {
+
+ $board_phid = $board->getPHID();
+ $position_groups = mgroup($positions, 'getObjectPHID');
+
+ foreach ($columns as $column) {
+ if ($column->isDefaultColumn()) {
+ $default_phid = $column->getPHID();
+ break;
+ }
+ }
+
+ $layout = array();
+
+ $object_phids = $this->getObjectPHIDs();
+ foreach ($object_phids as $object_phid) {
+ $positions = idx($position_groups, $object_phid, array());
+
+ // Remove any positions in columns which no longer exist.
+ foreach ($positions as $key => $position) {
+ $column_phid = $position->getColumnPHID();
+ if (empty($columns[$column_phid])) {
+ unset($positions[$key]);
+ }
+ }
+
+ // If the object has no position, put it on the default column.
+ if (!$positions) {
+ $new_position = id(new PhabricatorProjectColumnPosition())
+ ->setBoardPHID($board_phid)
+ ->setColumnPHID($default_phid)
+ ->setObjectPHID($object_phid)
+ ->setSequence(0);
+ $positions = array(
+ $new_position,
+ );
+ }
+
+ foreach ($positions as $position) {
+ $column_phid = $position->getColumnPHID();
+ $layout[$column_phid][$object_phid] = $position;
+ }
+ }
+
+ foreach ($layout as $column_phid => $map) {
+ $map = msort($map, 'getOrderingKey');
+ $layout[$column_phid] = $map;
+
+ foreach ($map as $object_phid => $position) {
+ $this->objectColumnMap[$board_phid][$object_phid][] = $column_phid;
+ }
+ }
+
+ $this->boardLayout[$board_phid] = $layout;
+ }
+
+}
diff --git a/src/applications/project/events/PhabricatorProjectUIEventListener.php b/src/applications/project/events/PhabricatorProjectUIEventListener.php
--- a/src/applications/project/events/PhabricatorProjectUIEventListener.php
+++ b/src/applications/project/events/PhabricatorProjectUIEventListener.php
@@ -49,37 +49,24 @@
$annotations = array();
if ($handles && $can_appear_on_boards) {
+ $engine = id(new PhabricatorBoardLayoutEngine())
+ ->setViewer($user)
+ ->setBoardPHIDs($project_phids)
+ ->setObjectPHIDs(array($object->getPHID()))
+ ->executeLayout();
// TDOO: Generalize this UI and move it out of Maniphest.
-
require_celerity_resource('maniphest-task-summary-css');
- $positions_query = id(new PhabricatorProjectColumnPositionQuery())
- ->setViewer($user)
- ->withBoardPHIDs($project_phids)
- ->withObjectPHIDs(array($object->getPHID()))
- ->needColumns(true);
-
- // This is important because positions will be created "on demand"
- // based on the set of columns. If we don't specify it, positions
- // won't be created.
- $columns = id(new PhabricatorProjectColumnQuery())
- ->setViewer($user)
- ->withProjectPHIDs($project_phids)
- ->execute();
- if ($columns) {
- $positions_query->withColumns($columns);
- }
- $positions = $positions_query->execute();
- $positions = mpull($positions, null, 'getBoardPHID');
-
foreach ($project_phids as $project_phid) {
$handle = $handles[$project_phid];
- $position = idx($positions, $project_phid);
- if ($position) {
- $column = $position->getColumn();
+ $columns = $engine->getObjectColumns(
+ $project_phid,
+ $object->getPHID());
+ $annotation = array();
+ foreach ($columns as $column) {
$column_name = pht('(%s)', $column->getDisplayName());
$column_link = phutil_tag(
'a',
@@ -89,9 +76,13 @@
),
$column_name);
+ $annotation[] = $column_link;
+ }
+
+ if ($annotation) {
$annotations[$project_phid] = array(
' ',
- $column_link,
+ phutil_implode_html(', ', $annotation),
);
}
}
diff --git a/src/applications/project/storage/PhabricatorProjectColumnPosition.php b/src/applications/project/storage/PhabricatorProjectColumnPosition.php
--- a/src/applications/project/storage/PhabricatorProjectColumnPosition.php
+++ b/src/applications/project/storage/PhabricatorProjectColumnPosition.php
@@ -41,6 +41,10 @@
}
public function getOrderingKey() {
+ if (!$this->getID()) {
+ return 0;
+ }
+
// Low sequence numbers go above high sequence numbers.
// High position IDs go above low position IDs.
// Broadly, this makes newly added stuff float to the top.

File Metadata

Mime Type
text/plain
Expires
Sun, Mar 16, 5:20 AM (2 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7705996
Default Alt Text
D15174.id36632.diff (10 KB)

Event Timeline