1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-22 23:02:42 +01:00

Fix an issue where editing cards on a workboard with implicit column ordering could reorder cards improperly

Summary:
Depends on D20680. Ref T4900. The "BoardLayoutEngine" operates on PHIDs without knowledge of the underlying objects, but this means it has to be sensitive to PHID input order when falling back to a default layout order.

We use "default layout order" on workboards which are sorted by "Natual" order but which have one or more cards which no user has ever reordered. For example, if you add 10 tasks to a project, then create a board, there's no existing order for those tasks in the "Backlog" column. The layout engine uses the input order to place them in the column, with the expectation that input order is ID/creation order, so new cards will end up on top.

I think this code never really made an explicit effort to guarantee that the LayoutEngine received objects in ID order, and it just sort of happened to by coincidence and good fortune. Some recent change has disrupted this, so the edit operation can end up with the PHIDs arranged in arbitrary order.

Explicitly put them in ID order so we always get an implicit default layout order to fall back to. Also, update to `msortv()`.

Test Plan:
  - Tagged several tasks with project X, a project without a board yet.
  - Created the project X workboard.
  - (Did not drag any tasks around on the project X board!)
  - Viewed the board in "Natural" order.

This creates a view of the board where tasks are ordered by implicit/virtual/input order. The expectation, and "view" behavior of this board, is that this order is "newest on top".

  - Edited one of the cards on the board, changing the title (don't reorder it!)
  - Before: page state synchronized with cards in arbitrary/random/different order.
  - After: page state synchronized with cards in the same order as before ("newest on top").

Reviewers: amckinley

Maniphest Tasks: T4900

Differential Revision: https://secure.phabricator.com/D20681
This commit is contained in:
epriestley 2019-07-24 11:00:27 -07:00
parent 7d41535010
commit d81d0c3ea0
3 changed files with 16 additions and 10 deletions

View file

@ -229,7 +229,7 @@ final class PhabricatorBoardLayoutEngine extends Phobject {
$this->addQueue[] = $object_position; $this->addQueue[] = $object_position;
$positions[$object_phid] = $object_position; $positions[$object_phid] = $object_position;
$positions = msort($positions, 'getOrderingKey'); $positions = msortv($positions, 'newColumnPositionOrderVector');
$this->boardLayout[$board_phid][$column_phid] = $positions; $this->boardLayout[$board_phid][$column_phid] = $positions;
@ -404,7 +404,7 @@ final class PhabricatorBoardLayoutEngine extends Phobject {
->withBoardPHIDs(array_keys($boards)) ->withBoardPHIDs(array_keys($boards))
->withObjectPHIDs($object_phids) ->withObjectPHIDs($object_phids)
->execute(); ->execute();
$positions = msort($positions, 'getOrderingKey'); $positions = msortv($positions, 'newColumnPositionOrderVector');
$positions = mgroup($positions, 'getBoardPHID'); $positions = mgroup($positions, 'getBoardPHID');
return $positions; return $positions;
@ -581,7 +581,7 @@ final class PhabricatorBoardLayoutEngine extends Phobject {
} }
foreach ($layout as $column_phid => $map) { foreach ($layout as $column_phid => $map) {
$map = msort($map, 'getOrderingKey'); $map = msortv($map, 'newColumnPositionOrderVector');
$layout[$column_phid] = $map; $layout[$column_phid] = $map;
foreach ($map as $object_phid => $position) { foreach ($map as $object_phid => $position) {

View file

@ -100,10 +100,17 @@ final class PhabricatorBoardResponseEngine extends Phobject {
$all_objects = mpull($all_objects, null, 'getPHID'); $all_objects = mpull($all_objects, null, 'getPHID');
} }
// NOTE: The board layout engine is sensitive to PHID input order, and uses
// the input order as a component of the "natural" column ordering if no
// explicit ordering is specified. Rearrange the PHIDs in ID order.
$all_objects = msort($all_objects, 'getID');
$ordered_phids = mpull($all_objects, 'getPHID');
$layout_engine = id(new PhabricatorBoardLayoutEngine()) $layout_engine = id(new PhabricatorBoardLayoutEngine())
->setViewer($viewer) ->setViewer($viewer)
->setBoardPHIDs(array($board_phid)) ->setBoardPHIDs(array($board_phid))
->setObjectPHIDs($all_phids) ->setObjectPHIDs($ordered_phids)
->executeLayout(); ->executeLayout();
$natural = array(); $natural = array();

View file

@ -46,7 +46,7 @@ final class PhabricatorProjectColumnPosition extends PhabricatorProjectDAO
return $this; return $this;
} }
public function getOrderingKey() { public function newColumnPositionOrderVector() {
// We're ordering both real positions and "virtual" positions which we have // We're ordering both real positions and "virtual" positions which we have
// created but not saved yet. // created but not saved yet.
@ -61,11 +61,10 @@ final class PhabricatorProjectColumnPosition extends PhabricatorProjectDAO
// Broadly, this collectively makes newly added stuff float to the top. // Broadly, this collectively makes newly added stuff float to the top.
return sprintf( return id(new PhutilSortVector())
'~%012d%012d%012d', ->addInt($this->getSequence())
$this->getSequence(), ->addInt(-1 * $this->viewSequence)
((1 << 31) - $this->viewSequence), ->addInt(-1 * $this->getID());
((1 << 31) - $this->getID()));
} }
/* -( PhabricatorPolicyInterface )----------------------------------------- */ /* -( PhabricatorPolicyInterface )----------------------------------------- */